aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Dependency/wixext
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-04 12:07:04 -0700
committerRob Mensching <rob@firegiant.com>2021-05-04 12:07:04 -0700
commit3caaf742fcd19170a8732570654d3b2cbb18830f (patch)
tree2b0d1bf83b0ced8f0620be4aaec4c597b825d372 /src/ext/Dependency/wixext
parentfb095340926a93e3eec9592e3e255b7d7b04d9d5 (diff)
downloadwix-3caaf742fcd19170a8732570654d3b2cbb18830f.tar.gz
wix-3caaf742fcd19170a8732570654d3b2cbb18830f.tar.bz2
wix-3caaf742fcd19170a8732570654d3b2cbb18830f.zip
Move Dependency.wixext into ext
Diffstat (limited to 'src/ext/Dependency/wixext')
-rw-r--r--src/ext/Dependency/wixext/DependencyCompiler.cs61
-rw-r--r--src/ext/Dependency/wixext/DependencyDecompiler.cs347
-rw-r--r--src/ext/Dependency/wixext/DependencyExtensionData.cs29
-rw-r--r--src/ext/Dependency/wixext/DependencyExtensionFactory.cs17
-rw-r--r--src/ext/Dependency/wixext/WixToolset.Dependency.wixext.csproj32
-rw-r--r--src/ext/Dependency/wixext/WixToolset.Dependency.wixext.nuspec25
-rw-r--r--src/ext/Dependency/wixext/WixToolset.Dependency.wixext.targets11
7 files changed, 522 insertions, 0 deletions
diff --git a/src/ext/Dependency/wixext/DependencyCompiler.cs b/src/ext/Dependency/wixext/DependencyCompiler.cs
new file mode 100644
index 00000000..3d6c84a7
--- /dev/null
+++ b/src/ext/Dependency/wixext/DependencyCompiler.cs
@@ -0,0 +1,61 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dependency
4{
5 using System.Collections.Generic;
6 using System.Xml.Linq;
7 using WixToolset.Data;
8 using WixToolset.Extensibility;
9 using WixToolset.Extensibility.Data;
10
11 /// <summary>
12 /// The compiler for the WiX Toolset Dependency Extension.
13 /// </summary>
14 public sealed class DependencyCompiler : BaseCompilerExtension
15 {
16 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/dependency";
17
18 /// <summary>
19 /// Processes an attribute for the Compiler.
20 /// </summary>
21 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
22 /// <param name="parentElement">Parent element of attribute.</param>
23 /// <param name="attribute">Attribute to process.</param>
24 public override void ParseAttribute(Intermediate intermediate, IntermediateSection section, XElement parentElement, XAttribute attribute, IDictionary<string, string> context)
25 {
26 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(parentElement);
27 var addCheck = YesNoType.NotSet;
28 var addRequire = YesNoType.NotSet;
29
30 switch (parentElement.Name.LocalName)
31 {
32 case "Provides":
33 if (attribute.Name.LocalName == "Check" && parentElement.Parent?.Name.LocalName == "Component")
34 {
35 addCheck = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute);
36 }
37 break;
38 case "Requires":
39 case "RequiresRef":
40 if (attribute.Name.LocalName == "Enforce" && parentElement.Parent?.Parent?.Name.LocalName == "Component")
41 {
42 addRequire = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute);
43 }
44 break;
45 }
46
47 if (addCheck == YesNoType.NotSet && addRequire == YesNoType.NotSet)
48 {
49 this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
50 }
51 else if (addCheck == YesNoType.Yes)
52 {
53 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4DependencyCheck", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
54 }
55 else if (addRequire == YesNoType.Yes)
56 {
57 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4DependencyRequire", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
58 }
59 }
60 }
61}
diff --git a/src/ext/Dependency/wixext/DependencyDecompiler.cs b/src/ext/Dependency/wixext/DependencyDecompiler.cs
new file mode 100644
index 00000000..31de3097
--- /dev/null
+++ b/src/ext/Dependency/wixext/DependencyDecompiler.cs
@@ -0,0 +1,347 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dependency
4{
5#if TODO_CONSIDER_DECOMPILER
6 using System;
7 using System.Collections.Generic;
8 using System.Collections.ObjectModel;
9 using WixToolset;
10 using WixToolset.Data;
11 using WixToolset.Extensibility;
12 using WixToolset.Extensions.Serialize.Dependency;
13 using Dependency = WixToolset.Extensions.Serialize.Dependency;
14 using Wix = WixToolset.Data.Serialize;
15
16 /// <summary>
17 /// The decompiler for the WiX toolset dependency extension.
18 /// </summary>
19 public sealed class DependencyDecompiler : DecompilerExtension
20 {
21 private RegistryKeyValueCollection registryValues;
22 private Dictionary<string, string> keyCache;
23
24 /// <summary>
25 /// Creates a new instance of the <see cref="DependencyDecompiler"/> class.
26 /// </summary>
27 public DependencyDecompiler()
28 {
29 this.registryValues = new RegistryKeyValueCollection();
30 this.keyCache = new Dictionary<string, string>();
31
32 this.TableDefinitions = DependencyExtensionData.GetExtensionTableDefinitions();
33 }
34
35 /// <summary>
36 /// Get the extensions library to be removed.
37 /// </summary>
38 /// <param name="tableDefinitions">Table definitions for library.</param>
39 /// <returns>Library to remove from decompiled output.</returns>
40 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
41 {
42 return DependencyExtensionData.GetExtensionLibrary(tableDefinitions);
43 }
44
45 /// <summary>
46 /// Decompiles an extension table.
47 /// </summary>
48 /// <param name="table">The table to decompile.</param>
49 public override void DecompileTable(Table table)
50 {
51 switch (table.Name)
52 {
53 case "WixDependencyProvider":
54 this.DecompileWixDependencyProviderTable(table);
55 break;
56
57 case "WixDependency":
58 this.DecompileWixDependencyTable(table);
59 break;
60
61 case "WixDependencyRef":
62 this.DecompileWixDependencyRefTable(table);
63 break;
64
65 default:
66 base.DecompileTable(table);
67 break;
68 }
69 }
70
71 /// <summary>
72 /// Finalize decompilation by removing registry values that the compiler writes.
73 /// </summary>
74 /// <param name="tables">The collection of all tables.</param>
75 public override void Finish(TableIndexedCollection tables)
76 {
77 // Remove generated registry rows.
78 this.FinalizeRegistryTable(tables);
79
80 // Remove extension properties.
81 this.FinalizeProperties();
82 }
83
84 /// <summary>
85 /// Decompiles the WixDependencyProvider table.
86 /// </summary>
87 /// <param name="table">The table to decompile.</param>
88 private void DecompileWixDependencyProviderTable(Table table)
89 {
90 foreach (Row row in table.Rows)
91 {
92 Provides provides = new Provides();
93
94 provides.Id = (string)row[0];
95 provides.Key = (string)row[2];
96
97 if (null != row[3])
98 {
99 provides.Version = (string)row[3];
100 }
101
102 if (null != row[4])
103 {
104 provides.DisplayName = (string)row[4];
105 }
106
107 // Nothing to parse for attributes currently.
108
109 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
110 if (null != component)
111 {
112 component.AddChild(provides);
113 }
114 else
115 {
116 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
117 }
118
119 // Index the provider to parent the RequiresRef elements.
120 this.Core.IndexElement(row, provides);
121
122 // Add the provider-specific registry keys to be removed during finalization.
123 // Only remove specific keys that the compiler writes.
124 string keyProvides = String.Concat(DependencyCommon.RegistryRoot, provides.Key);
125
126 this.registryValues.Add(keyProvides, null);
127 this.registryValues.Add(keyProvides, "Version");
128 this.registryValues.Add(keyProvides, "DisplayName");
129 this.registryValues.Add(keyProvides, "Attributes");
130
131 // Cache the provider key.
132 this.keyCache[provides.Id] = provides.Key;
133 }
134 }
135
136 /// <summary>
137 /// Decompiles the WixDependency table.
138 /// </summary>
139 /// <param name="table">The table to decompile.</param>
140 private void DecompileWixDependencyTable(Table table)
141 {
142 foreach (Row row in table.Rows)
143 {
144 Requires requires = new Requires();
145
146 requires.Id = (string)row[0];
147 requires.ProviderKey = (string)row[1];
148
149 if (null != row[2])
150 {
151 requires.Minimum = (string)row[2];
152 }
153
154 if (null != row[3])
155 {
156 requires.Maximum = (string)row[3];
157 }
158
159 if (null != row[4])
160 {
161 int attributes = (int)row[4];
162
163 if (0 != (attributes & DependencyCommon.RequiresAttributesMinVersionInclusive))
164 {
165 requires.IncludeMinimum = Dependency.YesNoType.yes;
166 }
167
168 if (0 != (attributes & DependencyCommon.RequiresAttributesMaxVersionInclusive))
169 {
170 requires.IncludeMaximum = Dependency.YesNoType.yes;
171 }
172 }
173
174 this.Core.RootElement.AddChild(requires);
175
176 // Cache the requires key.
177 this.keyCache[requires.Id] = requires.ProviderKey;
178 }
179 }
180
181 /// <summary>
182 /// Decompiles the WixDependencyRef table.
183 /// </summary>
184 /// <param name="table">The table to decompile.</param>
185 private void DecompileWixDependencyRefTable(Table table)
186 {
187 foreach (Row row in table.Rows)
188 {
189 RequiresRef requiresRef = new RequiresRef();
190
191 requiresRef.Id = (string)row[1];
192
193 Provides provides = (Provides)this.Core.GetIndexedElement("WixDependencyProvider", (string)row[0]);
194 if (null != provides)
195 {
196 provides.AddChild(requiresRef);
197 }
198 else
199 {
200 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "WixDependencyProvider_", (string)row[0], "WixDependencyProvider"));
201 }
202
203 // Get the cached keys for the provider and dependency IDs and generate registry rows.
204 string providesKey = null;
205 string requiresKey = null;
206
207 if (null != provides && this.keyCache.ContainsKey(provides.Id))
208 {
209 providesKey = this.keyCache[provides.Id];
210 }
211 else
212 {
213 this.Core.OnMessage(DependencyWarnings.ProvidesKeyNotFound(row.SourceLineNumbers, provides.Id));
214 }
215
216 if (this.keyCache.ContainsKey(requiresRef.Id))
217 {
218 requiresKey = this.keyCache[requiresRef.Id];
219 }
220 else
221 {
222 this.Core.OnMessage(DependencyWarnings.RequiresKeyNotFound(row.SourceLineNumbers, requiresRef.Id));
223 }
224
225 if (!this.Core.EncounteredError)
226 {
227 // Add the dependency-specific registry keys to be removed during finalization.
228 // Only remove specific keys that the compiler writes.
229 string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey);
230
231 this.registryValues.Add(keyRequires, "*");
232 this.registryValues.Add(keyRequires, "MinVersion");
233 this.registryValues.Add(keyRequires, "MaxVersion");
234 this.registryValues.Add(keyRequires, "Attributes");
235 }
236 }
237 }
238
239 /// <summary>
240 /// Removes rows from the Registry table that are generated by this extension.
241 /// </summary>
242 /// <param name="tables">The collection of tables.</param>
243 private void FinalizeRegistryTable(TableIndexedCollection tables)
244 {
245 Table registryTable = tables["Registry"];
246 if (null != registryTable)
247 {
248 foreach (Row registryRow in registryTable.Rows)
249 {
250 // Check if the compiler writes this registry value; if so, it should be removed.
251 if (this.registryValues.Contains(registryRow))
252 {
253 Wix.ISchemaElement elem = this.Core.GetIndexedElement(registryRow);
254
255 // If the registry row was found, remove it from its parent.
256 if (null != elem && null != elem.ParentElement)
257 {
258 Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement;
259 if (null != elemParent)
260 {
261 elemParent.RemoveChild(elem);
262 }
263 }
264 }
265 }
266 }
267 }
268
269 /// <summary>
270 /// Removes properties defined by this extension.
271 /// </summary>
272 /// <param name="tables">The collection of tables.</param>
273 private void FinalizeProperties()
274 {
275 string[] properties = new string[] { "DISABLEDEPENDENCYCHECK", "IGNOREDEPENDENCIES" };
276 foreach (string property in properties)
277 {
278 Wix.Property elem = this.Core.GetIndexedElement("Property", property) as Wix.Property;
279 if (null != elem)
280 {
281 // If a value is defined, log a warning we're removing it.
282 if (!String.IsNullOrEmpty(elem.Value))
283 {
284 this.Core.OnMessage(DependencyWarnings.PropertyRemoved(elem.Id));
285 }
286
287 // If the property row was found, remove it from its parent.
288 if (null != elem.ParentElement)
289 {
290 Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement;
291 if (null != elemParent)
292 {
293 elemParent.RemoveChild(elem);
294 }
295 }
296 }
297 }
298 }
299
300 /// <summary>
301 /// Provides an O(1) lookup for registry key and value name pairs for use in the decompiler.
302 /// </summary>
303 private sealed class RegistryKeyValueCollection : KeyedCollection<int, KeyValuePair<string, string>>
304 {
305 /// <summary>
306 /// Adds the registry key and value name pair to the collection if it doesn't already exist.
307 /// </summary>
308 /// <param name="key">The registry key to add.</param>
309 /// <param name="name">The registry value name to add.</param>
310 internal void Add(string key, string name)
311 {
312 KeyValuePair<string, string> pair = new KeyValuePair<string, string>(key, name);
313 if (!this.Contains(pair))
314 {
315 this.Add(pair);
316 }
317 }
318
319 /// <summary>
320 /// Returns whether the collection contains the registry key and value name pair from the <see cref="Row"/>.
321 /// </summary>
322 /// <param name="row">The registry <see cref="Row"/> to search for.</param>
323 /// <returns>True if the collection contains the registry key and value name pair from the <see cref="Row"/>; otherwise, false.</returns>
324 internal bool Contains(Row row)
325 {
326 if (null == row)
327 {
328 return false;
329 }
330
331 KeyValuePair<string, string> pair = new KeyValuePair<string, string>((string)row[2], (string)row[3]);
332 return this.Contains(pair);
333 }
334
335 /// <summary>
336 /// Return the hash code of the key and value pair concatenated with a colon as a delimiter.
337 /// </summary>
338 /// <param name="pair">The registry key and value name pair.</param>
339 /// <returns></returns>
340 protected override int GetKeyForItem(KeyValuePair<string, string> pair)
341 {
342 return String.Concat(pair.Key, ":", pair.Value).GetHashCode();
343 }
344 }
345 }
346#endif
347}
diff --git a/src/ext/Dependency/wixext/DependencyExtensionData.cs b/src/ext/Dependency/wixext/DependencyExtensionData.cs
new file mode 100644
index 00000000..2f30c2bf
--- /dev/null
+++ b/src/ext/Dependency/wixext/DependencyExtensionData.cs
@@ -0,0 +1,29 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dependency
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset Dependency Extension.
10 /// </summary>
11 public sealed class DependencyExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 /// <summary>
20 /// Gets the contained .wixlib content.
21 /// </summary>
22 /// <param name="symbolDefinitions">Strong typed symbold definitions.</param>
23 /// <returns>The .wixlib.</returns>
24 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
25 {
26 return Intermediate.Load(typeof(DependencyExtensionData).Assembly, "WixToolset.Dependency.dependency.wixlib", symbolDefinitions);
27 }
28 }
29}
diff --git a/src/ext/Dependency/wixext/DependencyExtensionFactory.cs b/src/ext/Dependency/wixext/DependencyExtensionFactory.cs
new file mode 100644
index 00000000..413f99ae
--- /dev/null
+++ b/src/ext/Dependency/wixext/DependencyExtensionFactory.cs
@@ -0,0 +1,17 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dependency
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class DependencyExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(DependencyCompiler),
14 typeof(DependencyExtensionData),
15 };
16 }
17}
diff --git a/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.csproj b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.csproj
new file mode 100644
index 00000000..b2663231
--- /dev/null
+++ b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.csproj
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <DebugType>embedded</DebugType>
8 <RootNamespace>WixToolset.Dependency</RootNamespace>
9 <Description>WiX Toolset Dependency Extension</Description>
10 <Title>WiX Toolset Dependency Extension</Title>
11 <IsTool>true</IsTool>
12 <IncludeSymbols>true</IncludeSymbols>
13 </PropertyGroup>
14
15 <ItemGroup>
16 <EmbeddedResource Include="$(OutputPath)..\dependency.wixlib" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <ProjectReference Include="..\wixlib\dependency.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
21 </ItemGroup>
22
23 <ItemGroup>
24 <PackageReference Include="WixToolset.Data" Version="4.0.*" PrivateAssets="all" />
25 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="all" />
26 </ItemGroup>
27
28 <ItemGroup>
29 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
30 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
31 </ItemGroup>
32</Project>
diff --git a/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.nuspec b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.nuspec
new file mode 100644
index 00000000..ba3eaade
--- /dev/null
+++ b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.nuspec
@@ -0,0 +1,25 @@
1<?xml version="1.0"?>
2<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
3 <metadata minClientVersion="4.0">
4 <id>$id$</id>
5 <version>$version$</version>
6 <title>$title$</title>
7 <description>$description$</description>
8 <authors>$authors$</authors>
9 <license type="expression">MS-RL</license>
10 <requireLicenseAcceptance>false</requireLicenseAcceptance>
11 <copyright>$copyright$</copyright>
12 <projectUrl>$projectUrl$</projectUrl>
13 <repository type="$repositorytype$" url="$repositoryurl$" commit="$repositorycommit$" />
14 </metadata>
15
16 <files>
17 <file src="$projectFolder$$id$.targets" target="build" />
18
19 <file src="netstandard2.0\$id$.dll" target="tools" />
20
21 <file src="ARM64\*.pdb" target="pdbs\ARM64" />
22 <file src="x86\*.pdb" target="pdbs\x86" />
23 <file src="x64\*.pdb" target="pdbs\x64" />
24 </files>
25</package>
diff --git a/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.targets b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.targets
new file mode 100644
index 00000000..2b298736
--- /dev/null
+++ b/src/ext/Dependency/wixext/WixToolset.Dependency.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetDependencyWixextPath Condition=" '$(WixToolsetDependencyWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Dependency.wixext.dll</WixToolsetDependencyWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetDependencyWixextPath)" />
10 </ItemGroup>
11</Project>