diff options
Diffstat (limited to 'src/api/burn/WixToolset.BootstrapperApplicationApi/PackageInfo.cs')
-rw-r--r-- | src/api/burn/WixToolset.BootstrapperApplicationApi/PackageInfo.cs | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/api/burn/WixToolset.BootstrapperApplicationApi/PackageInfo.cs b/src/api/burn/WixToolset.BootstrapperApplicationApi/PackageInfo.cs new file mode 100644 index 00000000..e835f9ea --- /dev/null +++ b/src/api/burn/WixToolset.BootstrapperApplicationApi/PackageInfo.cs | |||
@@ -0,0 +1,391 @@ | |||
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 | |||
3 | namespace WixToolset.BootstrapperApplicationApi | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Xml; | ||
8 | using System.Xml.XPath; | ||
9 | |||
10 | /// <summary> | ||
11 | /// The type of package. | ||
12 | /// </summary> | ||
13 | public enum PackageType | ||
14 | { | ||
15 | /// <summary> | ||
16 | /// Invalid type. | ||
17 | /// </summary> | ||
18 | Unknown, | ||
19 | |||
20 | /// <summary> | ||
21 | /// ExePackage | ||
22 | /// </summary> | ||
23 | Exe, | ||
24 | |||
25 | /// <summary> | ||
26 | /// MsiPackage | ||
27 | /// </summary> | ||
28 | Msi, | ||
29 | |||
30 | /// <summary> | ||
31 | /// MspPackage | ||
32 | /// </summary> | ||
33 | Msp, | ||
34 | |||
35 | /// <summary> | ||
36 | /// MsuPackage | ||
37 | /// </summary> | ||
38 | Msu, | ||
39 | |||
40 | /// <summary> | ||
41 | /// Related bundle of type Upgrade | ||
42 | /// </summary> | ||
43 | UpgradeBundle, | ||
44 | |||
45 | /// <summary> | ||
46 | /// Related bundle of type Addon | ||
47 | /// </summary> | ||
48 | AddonBundle, | ||
49 | |||
50 | /// <summary> | ||
51 | /// Related bundle of type Patch | ||
52 | /// </summary> | ||
53 | PatchBundle, | ||
54 | |||
55 | /// <summary> | ||
56 | /// Related bundle of type Update | ||
57 | /// </summary> | ||
58 | UpdateBundle, | ||
59 | |||
60 | /// <summary> | ||
61 | /// BundlePackage | ||
62 | /// </summary> | ||
63 | ChainBundle, | ||
64 | } | ||
65 | |||
66 | /// <summary> | ||
67 | /// Metadata for BAs like WixInternalUIBootstrapperApplication that only support one main package. | ||
68 | /// </summary> | ||
69 | public enum PrimaryPackageType | ||
70 | { | ||
71 | /// <summary> | ||
72 | /// Not a primary package. | ||
73 | /// </summary> | ||
74 | None, | ||
75 | |||
76 | /// <summary> | ||
77 | /// The default package if no architecture specific package is available for the current architecture. | ||
78 | /// </summary> | ||
79 | Default, | ||
80 | |||
81 | /// <summary> | ||
82 | /// The package to use on x86 machines. | ||
83 | /// </summary> | ||
84 | X86, | ||
85 | |||
86 | /// <summary> | ||
87 | /// The package to use on x64 machines. | ||
88 | /// </summary> | ||
89 | X64, | ||
90 | |||
91 | /// <summary> | ||
92 | /// The package to use on ARM64 machines. | ||
93 | /// </summary> | ||
94 | ARM64, | ||
95 | } | ||
96 | |||
97 | /// <summary> | ||
98 | /// Default implementation of <see cref="IPackageInfo"/>. | ||
99 | /// </summary> | ||
100 | public class PackageInfo : IPackageInfo | ||
101 | { | ||
102 | /// <inheritdoc/> | ||
103 | public string Id { get; internal set; } | ||
104 | |||
105 | /// <inheritdoc/> | ||
106 | public string DisplayName { get; internal set; } | ||
107 | |||
108 | /// <inheritdoc/> | ||
109 | public string Description { get; internal set; } | ||
110 | |||
111 | /// <inheritdoc/> | ||
112 | public PackageType Type { get; internal set; } | ||
113 | |||
114 | /// <inheritdoc/> | ||
115 | public bool Permanent { get; internal set; } | ||
116 | |||
117 | /// <inheritdoc/> | ||
118 | public bool Vital { get; internal set; } | ||
119 | |||
120 | /// <inheritdoc/> | ||
121 | public string DisplayInternalUICondition { get; internal set; } | ||
122 | |||
123 | /// <inheritdoc/> | ||
124 | public string ProductCode { get; internal set; } | ||
125 | |||
126 | /// <inheritdoc/> | ||
127 | public string UpgradeCode { get; internal set; } | ||
128 | |||
129 | /// <inheritdoc/> | ||
130 | public string Version { get; internal set; } | ||
131 | |||
132 | /// <inheritdoc/> | ||
133 | public string InstallCondition { get; internal set; } | ||
134 | |||
135 | /// <inheritdoc/> | ||
136 | public string RepairCondition { get; internal set; } | ||
137 | |||
138 | /// <inheritdoc/> | ||
139 | public BOOTSTRAPPER_CACHE_TYPE CacheType { get; internal set; } | ||
140 | |||
141 | /// <inheritdoc/> | ||
142 | public bool PrereqPackage { get; internal set; } | ||
143 | |||
144 | /// <inheritdoc/> | ||
145 | public string PrereqLicenseFile { get; internal set; } | ||
146 | |||
147 | /// <inheritdoc/> | ||
148 | public string PrereqLicenseUrl { get; internal set; } | ||
149 | |||
150 | /// <inheritdoc/> | ||
151 | public PrimaryPackageType PrimaryPackageType { get; internal set; } | ||
152 | |||
153 | /// <inheritdoc/> | ||
154 | public object CustomData { get; set; } | ||
155 | |||
156 | internal PackageInfo() { } | ||
157 | |||
158 | /// <summary> | ||
159 | /// Parse packages from BootstrapperApplicationData.xml. | ||
160 | /// </summary> | ||
161 | /// <param name="root">The root node.</param> | ||
162 | /// <returns>A dictionary of the packages by Id.</returns> | ||
163 | public static IDictionary<string, IPackageInfo> ParsePackagesFromXml(XPathNavigator root) | ||
164 | { | ||
165 | var packagesById = new Dictionary<string, IPackageInfo>(); | ||
166 | XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); | ||
167 | namespaceManager.AddNamespace("p", BootstrapperApplicationData.XMLNamespace); | ||
168 | XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixPackageProperties", namespaceManager); | ||
169 | |||
170 | foreach (XPathNavigator node in nodes) | ||
171 | { | ||
172 | var package = new PackageInfo(); | ||
173 | |||
174 | string id = BootstrapperApplicationData.GetAttribute(node, "Package"); | ||
175 | if (id == null) | ||
176 | { | ||
177 | throw new Exception("Failed to get package identifier for package."); | ||
178 | } | ||
179 | package.Id = id; | ||
180 | |||
181 | package.DisplayName = BootstrapperApplicationData.GetAttribute(node, "DisplayName"); | ||
182 | |||
183 | package.Description = BootstrapperApplicationData.GetAttribute(node, "Description"); | ||
184 | |||
185 | PackageType? packageType = GetPackageTypeAttribute(node, "PackageType"); | ||
186 | if (!packageType.HasValue) | ||
187 | { | ||
188 | throw new Exception("Failed to get package type for package."); | ||
189 | } | ||
190 | package.Type = packageType.Value; | ||
191 | |||
192 | bool? permanent = BootstrapperApplicationData.GetYesNoAttribute(node, "Permanent"); | ||
193 | if (!permanent.HasValue) | ||
194 | { | ||
195 | throw new Exception("Failed to get permanent settings for package."); | ||
196 | } | ||
197 | package.Permanent = permanent.Value; | ||
198 | |||
199 | bool? vital = BootstrapperApplicationData.GetYesNoAttribute(node, "Vital"); | ||
200 | if (!vital.HasValue) | ||
201 | { | ||
202 | throw new Exception("Failed to get vital setting for package."); | ||
203 | } | ||
204 | package.Vital = vital.Value; | ||
205 | |||
206 | package.ProductCode = BootstrapperApplicationData.GetAttribute(node, "ProductCode"); | ||
207 | |||
208 | package.UpgradeCode = BootstrapperApplicationData.GetAttribute(node, "UpgradeCode"); | ||
209 | |||
210 | package.Version = BootstrapperApplicationData.GetAttribute(node, "Version"); | ||
211 | |||
212 | package.InstallCondition = BootstrapperApplicationData.GetAttribute(node, "InstallCondition"); | ||
213 | |||
214 | package.RepairCondition = BootstrapperApplicationData.GetAttribute(node, "RepairCondition"); | ||
215 | |||
216 | BOOTSTRAPPER_CACHE_TYPE? cacheType = GetCacheTypeAttribute(node, "Cache"); | ||
217 | if (!cacheType.HasValue) | ||
218 | { | ||
219 | throw new Exception("Failed to get cache type for package."); | ||
220 | } | ||
221 | package.CacheType = cacheType.Value; | ||
222 | |||
223 | packagesById.Add(package.Id, package); | ||
224 | } | ||
225 | |||
226 | ParseBalPackageInfoFromXml(root, namespaceManager, packagesById); | ||
227 | return packagesById; | ||
228 | } | ||
229 | |||
230 | /// <summary> | ||
231 | /// Parse the cache type attribute. | ||
232 | /// </summary> | ||
233 | /// <param name="node">Package node</param> | ||
234 | /// <param name="attributeName">Attribute name</param> | ||
235 | /// <returns>The cache type</returns> | ||
236 | public static BOOTSTRAPPER_CACHE_TYPE? GetCacheTypeAttribute(XPathNavigator node, string attributeName) | ||
237 | { | ||
238 | string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName); | ||
239 | |||
240 | if (attributeValue == null) | ||
241 | { | ||
242 | return null; | ||
243 | } | ||
244 | |||
245 | if (attributeValue.Equals("keep", StringComparison.InvariantCulture)) | ||
246 | { | ||
247 | return BOOTSTRAPPER_CACHE_TYPE.Keep; | ||
248 | } | ||
249 | else if (attributeValue.Equals("force", StringComparison.InvariantCulture)) | ||
250 | { | ||
251 | return BOOTSTRAPPER_CACHE_TYPE.Force; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | return BOOTSTRAPPER_CACHE_TYPE.Remove; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /// <summary> | ||
260 | /// Parse the package type attribute | ||
261 | /// </summary> | ||
262 | /// <param name="node">Package node</param> | ||
263 | /// <param name="attributeName">Attribute name</param> | ||
264 | /// <returns>The package type</returns> | ||
265 | public static PackageType? GetPackageTypeAttribute(XPathNavigator node, string attributeName) | ||
266 | { | ||
267 | string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName); | ||
268 | |||
269 | if (attributeValue == null) | ||
270 | { | ||
271 | return null; | ||
272 | } | ||
273 | |||
274 | if (attributeValue.Equals("Bundle", StringComparison.InvariantCulture)) | ||
275 | { | ||
276 | return PackageType.ChainBundle; | ||
277 | } | ||
278 | else if (attributeValue.Equals("Exe", StringComparison.InvariantCulture)) | ||
279 | { | ||
280 | return PackageType.Exe; | ||
281 | } | ||
282 | else if (attributeValue.Equals("Msi", StringComparison.InvariantCulture)) | ||
283 | { | ||
284 | return PackageType.Msi; | ||
285 | } | ||
286 | else if (attributeValue.Equals("Msp", StringComparison.InvariantCulture)) | ||
287 | { | ||
288 | return PackageType.Msp; | ||
289 | } | ||
290 | else if (attributeValue.Equals("Msu", StringComparison.InvariantCulture)) | ||
291 | { | ||
292 | return PackageType.Msu; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | return PackageType.Unknown; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | /// <summary> | ||
301 | /// Create <see cref="IPackageInfo"/> from a related bundle. | ||
302 | /// </summary> | ||
303 | /// <param name="id">Package id</param> | ||
304 | /// <param name="relationType">Relation type</param> | ||
305 | /// <param name="perMachine">Whether the related bundle is per-machine</param> | ||
306 | /// <param name="version">The related bundle's version</param> | ||
307 | /// <returns>The package info</returns> | ||
308 | public static IPackageInfo GetRelatedBundleAsPackage(string id, RelationType relationType, bool perMachine, string version) | ||
309 | { | ||
310 | PackageInfo package = new PackageInfo(); | ||
311 | package.Id = id; | ||
312 | package.Version = version; | ||
313 | |||
314 | switch (relationType) | ||
315 | { | ||
316 | case RelationType.Addon: | ||
317 | package.Type = PackageType.AddonBundle; | ||
318 | break; | ||
319 | case RelationType.Patch: | ||
320 | package.Type = PackageType.PatchBundle; | ||
321 | break; | ||
322 | case RelationType.Upgrade: | ||
323 | package.Type = PackageType.UpgradeBundle; | ||
324 | break; | ||
325 | default: | ||
326 | throw new Exception(String.Format("Unknown related bundle type: {0}", relationType)); | ||
327 | } | ||
328 | |||
329 | return package; | ||
330 | } | ||
331 | |||
332 | /// <summary> | ||
333 | /// Create <see cref="IPackageInfo"/> from an update bundle. | ||
334 | /// </summary> | ||
335 | /// <param name="id">Package id</param> | ||
336 | /// <returns>The package info</returns> | ||
337 | public static IPackageInfo GetUpdateBundleAsPackage(string id) | ||
338 | { | ||
339 | PackageInfo package = new PackageInfo(); | ||
340 | package.Id = id; | ||
341 | package.Type = PackageType.UpdateBundle; | ||
342 | |||
343 | return package; | ||
344 | } | ||
345 | |||
346 | internal static void ParseBalPackageInfoFromXml(XPathNavigator root, XmlNamespaceManager namespaceManager, Dictionary<string, IPackageInfo> packagesById) | ||
347 | { | ||
348 | XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixBalPackageInfo", namespaceManager); | ||
349 | |||
350 | foreach (XPathNavigator node in nodes) | ||
351 | { | ||
352 | string id = BootstrapperApplicationData.GetAttribute(node, "PackageId"); | ||
353 | if (id == null) | ||
354 | { | ||
355 | throw new Exception("Failed to get package identifier for WixBalPackageInfo."); | ||
356 | } | ||
357 | |||
358 | if (!packagesById.TryGetValue(id, out var ipackage)) | ||
359 | { | ||
360 | throw new Exception(String.Format("Failed to find package specified in WixBalPackageInfo: {0}", id)); | ||
361 | } | ||
362 | |||
363 | var package = (PackageInfo)ipackage; | ||
364 | |||
365 | package.DisplayInternalUICondition = BootstrapperApplicationData.GetAttribute(node, "DisplayInternalUICondition"); | ||
366 | } | ||
367 | |||
368 | nodes = root.Select("/p:BootstrapperApplicationData/p:WixPrereqInformation", namespaceManager); | ||
369 | |||
370 | foreach (XPathNavigator node in nodes) | ||
371 | { | ||
372 | string id = BootstrapperApplicationData.GetAttribute(node, "PackageId"); | ||
373 | if (id == null) | ||
374 | { | ||
375 | throw new Exception("Failed to get package identifier for WixPrereqInformation."); | ||
376 | } | ||
377 | |||
378 | if (!packagesById.TryGetValue(id, out var ipackage)) | ||
379 | { | ||
380 | throw new Exception(String.Format("Failed to find package specified in WixPrereqInformation: {0}", id)); | ||
381 | } | ||
382 | |||
383 | var package = (PackageInfo)ipackage; | ||
384 | |||
385 | package.PrereqPackage = true; | ||
386 | package.PrereqLicenseFile = BootstrapperApplicationData.GetAttribute(node, "LicenseFile"); | ||
387 | package.PrereqLicenseUrl = BootstrapperApplicationData.GetAttribute(node, "LicenseUrl"); | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | } | ||