diff options
Diffstat (limited to 'src/WixToolset.Core/Binder.cs')
-rw-r--r-- | src/WixToolset.Core/Binder.cs | 686 |
1 files changed, 686 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Binder.cs b/src/WixToolset.Core/Binder.cs new file mode 100644 index 00000000..18ad2d62 --- /dev/null +++ b/src/WixToolset.Core/Binder.cs | |||
@@ -0,0 +1,686 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Diagnostics; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Linq; | ||
12 | using System.Reflection; | ||
13 | using WixToolset.Bind; | ||
14 | using WixToolset.Data; | ||
15 | using WixToolset.Data.Rows; | ||
16 | using WixToolset.Extensibility; | ||
17 | using WixToolset.Msi; | ||
18 | |||
19 | // TODO: (4.0) Refactor so that these don't need to be copied. | ||
20 | // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs | ||
21 | [Flags] | ||
22 | internal enum WixFileSearchAttributes | ||
23 | { | ||
24 | Default = 0x001, | ||
25 | MinVersionInclusive = 0x002, | ||
26 | MaxVersionInclusive = 0x004, | ||
27 | MinSizeInclusive = 0x008, | ||
28 | MaxSizeInclusive = 0x010, | ||
29 | MinDateInclusive = 0x020, | ||
30 | MaxDateInclusive = 0x040, | ||
31 | WantVersion = 0x080, | ||
32 | WantExists = 0x100, | ||
33 | IsDirectory = 0x200, | ||
34 | } | ||
35 | |||
36 | [Flags] | ||
37 | internal enum WixRegistrySearchAttributes | ||
38 | { | ||
39 | Raw = 0x01, | ||
40 | Compatible = 0x02, | ||
41 | ExpandEnvironmentVariables = 0x04, | ||
42 | WantValue = 0x08, | ||
43 | WantExists = 0x10, | ||
44 | Win64 = 0x20, | ||
45 | } | ||
46 | |||
47 | internal enum WixComponentSearchAttributes | ||
48 | { | ||
49 | KeyPath = 0x1, | ||
50 | State = 0x2, | ||
51 | WantDirectory = 0x4, | ||
52 | } | ||
53 | |||
54 | [Flags] | ||
55 | internal enum WixProductSearchAttributes | ||
56 | { | ||
57 | Version = 0x1, | ||
58 | Language = 0x2, | ||
59 | State = 0x4, | ||
60 | Assignment = 0x8, | ||
61 | UpgradeCode = 0x10, | ||
62 | } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Binder of the WiX toolset. | ||
66 | /// </summary> | ||
67 | public sealed class Binder | ||
68 | { | ||
69 | private BinderCore core; | ||
70 | private BinderFileManagerCore fileManagerCore; | ||
71 | private List<IBinderExtension> extensions; | ||
72 | private List<IBinderFileManager> fileManagers; | ||
73 | private List<InspectorExtension> inspectorExtensions; | ||
74 | |||
75 | public Binder() | ||
76 | { | ||
77 | this.DefaultCompressionLevel = CompressionLevel.High; | ||
78 | |||
79 | this.BindPaths = new List<BindPath>(); | ||
80 | this.TargetBindPaths = new List<BindPath>(); | ||
81 | this.UpdatedBindPaths = new List<BindPath>(); | ||
82 | |||
83 | this.extensions = new List<IBinderExtension>(); | ||
84 | this.fileManagers = new List<IBinderFileManager>(); | ||
85 | this.inspectorExtensions = new List<InspectorExtension>(); | ||
86 | |||
87 | this.Ices = new List<string>(); | ||
88 | this.SuppressIces = new List<string>(); | ||
89 | } | ||
90 | |||
91 | public string ContentsFile { private get; set; } | ||
92 | |||
93 | public string OutputsFile { private get; set; } | ||
94 | |||
95 | public string BuiltOutputsFile { private get; set; } | ||
96 | |||
97 | public string WixprojectFile { private get; set; } | ||
98 | |||
99 | /// <summary> | ||
100 | /// Gets the list of bindpaths. | ||
101 | /// </summary> | ||
102 | public List<BindPath> BindPaths { get; private set; } | ||
103 | |||
104 | /// <summary> | ||
105 | /// Gets the list of target bindpaths. | ||
106 | /// </summary> | ||
107 | public List<BindPath> TargetBindPaths { get; private set; } | ||
108 | |||
109 | /// <summary> | ||
110 | /// Gets the list of updated bindpaths. | ||
111 | /// </summary> | ||
112 | public List<BindPath> UpdatedBindPaths { get; private set; } | ||
113 | |||
114 | /// <summary> | ||
115 | /// Gets or sets the option to enable building binary delta patches. | ||
116 | /// </summary> | ||
117 | /// <value>The option to enable building binary delta patches.</value> | ||
118 | public bool DeltaBinaryPatch { get; set; } | ||
119 | |||
120 | /// <summary> | ||
121 | /// Gets or sets the cabinet cache location. | ||
122 | /// </summary> | ||
123 | public string CabCachePath { get; set; } | ||
124 | |||
125 | /// <summary> | ||
126 | /// Gets or sets the number of threads to use for cabinet creation. | ||
127 | /// </summary> | ||
128 | /// <value>The number of threads to use for cabinet creation.</value> | ||
129 | public int CabbingThreadCount { get; set; } | ||
130 | |||
131 | /// <summary> | ||
132 | /// Gets or sets the default compression level to use for cabinets | ||
133 | /// that don't have their compression level explicitly set. | ||
134 | /// </summary> | ||
135 | public CompressionLevel DefaultCompressionLevel { get; set; } | ||
136 | |||
137 | /// <summary> | ||
138 | /// Gets and sets the location to save the WixPdb. | ||
139 | /// </summary> | ||
140 | /// <value>The location in which to save the WixPdb. Null if the the WixPdb should not be output.</value> | ||
141 | public string PdbFile { get; set; } | ||
142 | |||
143 | public List<string> Ices { get; private set; } | ||
144 | |||
145 | public List<string> SuppressIces { get; private set; } | ||
146 | |||
147 | /// <summary> | ||
148 | /// Gets and sets the option to suppress resetting ACLs by the binder. | ||
149 | /// </summary> | ||
150 | /// <value>The option to suppress resetting ACLs by the binder.</value> | ||
151 | public bool SuppressAclReset { get; set; } | ||
152 | |||
153 | /// <summary> | ||
154 | /// Gets and sets the option to suppress creating an image for MSI/MSM. | ||
155 | /// </summary> | ||
156 | /// <value>The option to suppress creating an image for MSI/MSM.</value> | ||
157 | public bool SuppressLayout { get; set; } | ||
158 | |||
159 | /// <summary> | ||
160 | /// Gets and sets the option to suppress MSI/MSM validation. | ||
161 | /// </summary> | ||
162 | /// <value>The option to suppress MSI/MSM validation.</value> | ||
163 | /// <remarks>This must be set before calling Bind.</remarks> | ||
164 | public bool SuppressValidation { get; set; } | ||
165 | |||
166 | /// <summary> | ||
167 | /// Gets and sets the option to suppress adding _Validation table rows. | ||
168 | /// </summary> | ||
169 | public bool SuppressAddingValidationRows { get; set; } | ||
170 | |||
171 | /// <summary> | ||
172 | /// Gets or sets the localizer. | ||
173 | /// </summary> | ||
174 | /// <value>The localizer.</value> | ||
175 | public Localizer Localizer { get; set; } | ||
176 | |||
177 | /// <summary> | ||
178 | /// Gets or sets the temporary path for the Binder. If left null, the binder | ||
179 | /// will use %TEMP% environment variable. | ||
180 | /// </summary> | ||
181 | /// <value>Path to temp files.</value> | ||
182 | public string TempFilesLocation { get; set; } | ||
183 | |||
184 | /// <summary> | ||
185 | /// Gets or sets the Wix variable resolver. | ||
186 | /// </summary> | ||
187 | /// <value>The Wix variable resolver.</value> | ||
188 | public WixVariableResolver WixVariableResolver { get; set; } | ||
189 | |||
190 | /// <summary> | ||
191 | /// Add a binder extension. | ||
192 | /// </summary> | ||
193 | /// <param name="extension">New extension.</param> | ||
194 | public void AddExtension(IBinderExtension extension) | ||
195 | { | ||
196 | this.extensions.Add(extension); | ||
197 | } | ||
198 | |||
199 | /// <summary> | ||
200 | /// Add a file manager extension. | ||
201 | /// </summary> | ||
202 | /// <param name="extension">New file manager.</param> | ||
203 | public void AddExtension(IBinderFileManager extension) | ||
204 | { | ||
205 | this.fileManagers.Add(extension); | ||
206 | } | ||
207 | |||
208 | /// <summary> | ||
209 | /// Binds an output. | ||
210 | /// </summary> | ||
211 | /// <param name="output">The output to bind.</param> | ||
212 | /// <param name="file">The Windows Installer file to create.</param> | ||
213 | /// <remarks>The Binder.DeleteTempFiles method should be called after calling this method.</remarks> | ||
214 | /// <returns>true if binding completed successfully; false otherwise</returns> | ||
215 | public bool Bind(Output output, string file) | ||
216 | { | ||
217 | // Ensure the cabinet cache path exists if we are going to use it. | ||
218 | if (!String.IsNullOrEmpty(this.CabCachePath)) | ||
219 | { | ||
220 | Directory.CreateDirectory(this.CabCachePath); | ||
221 | } | ||
222 | |||
223 | this.fileManagerCore = new BinderFileManagerCore(); | ||
224 | this.fileManagerCore.CabCachePath = this.CabCachePath; | ||
225 | this.fileManagerCore.Output = output; | ||
226 | this.fileManagerCore.TempFilesLocation = this.TempFilesLocation; | ||
227 | this.fileManagerCore.AddBindPaths(this.BindPaths, BindStage.Normal); | ||
228 | this.fileManagerCore.AddBindPaths(this.TargetBindPaths, BindStage.Target); | ||
229 | this.fileManagerCore.AddBindPaths(this.UpdatedBindPaths, BindStage.Updated); | ||
230 | foreach (IBinderFileManager fileManager in this.fileManagers) | ||
231 | { | ||
232 | fileManager.Core = this.fileManagerCore; | ||
233 | } | ||
234 | |||
235 | this.core = new BinderCore(); | ||
236 | this.core.FileManagerCore = this.fileManagerCore; | ||
237 | |||
238 | this.WriteBuildInfoTable(output, file); | ||
239 | |||
240 | // Initialize extensions. | ||
241 | foreach (IBinderExtension extension in this.extensions) | ||
242 | { | ||
243 | extension.Core = this.core; | ||
244 | |||
245 | extension.Initialize(output); | ||
246 | } | ||
247 | |||
248 | // Gather all the wix variables. | ||
249 | Table wixVariableTable = output.Tables["WixVariable"]; | ||
250 | if (null != wixVariableTable) | ||
251 | { | ||
252 | foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) | ||
253 | { | ||
254 | this.WixVariableResolver.AddVariable(wixVariableRow); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | IEnumerable<FileTransfer> fileTransfers = null; | ||
259 | IEnumerable<string> contentPaths = null; | ||
260 | |||
261 | switch (output.Type) | ||
262 | { | ||
263 | case OutputType.Bundle: | ||
264 | this.BindBundle(output, file, out fileTransfers, out contentPaths); | ||
265 | break; | ||
266 | |||
267 | case OutputType.Transform: | ||
268 | this.BindTransform(output, file); | ||
269 | break; | ||
270 | |||
271 | default: | ||
272 | this.BindDatabase(output, file, out fileTransfers, out contentPaths); | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | |||
277 | // Layout media | ||
278 | try | ||
279 | { | ||
280 | this.LayoutMedia(fileTransfers); | ||
281 | } | ||
282 | finally | ||
283 | { | ||
284 | if (!String.IsNullOrEmpty(this.ContentsFile) && contentPaths != null) | ||
285 | { | ||
286 | this.CreateContentsFile(this.ContentsFile, contentPaths); | ||
287 | } | ||
288 | |||
289 | if (!String.IsNullOrEmpty(this.OutputsFile) && fileTransfers != null) | ||
290 | { | ||
291 | this.CreateOutputsFile(this.OutputsFile, fileTransfers, this.PdbFile); | ||
292 | } | ||
293 | |||
294 | if (!String.IsNullOrEmpty(this.BuiltOutputsFile) && fileTransfers != null) | ||
295 | { | ||
296 | this.CreateBuiltOutputsFile(this.BuiltOutputsFile, fileTransfers, this.PdbFile); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | this.core = null; | ||
301 | |||
302 | return Messaging.Instance.EncounteredError; | ||
303 | } | ||
304 | |||
305 | /// <summary> | ||
306 | /// Does any housekeeping after Bind. | ||
307 | /// </summary> | ||
308 | /// <param name="tidy">Whether or not any actual tidying should be done.</param> | ||
309 | public void Cleanup(bool tidy) | ||
310 | { | ||
311 | if (tidy) | ||
312 | { | ||
313 | if (!this.DeleteTempFiles()) | ||
314 | { | ||
315 | this.core.OnMessage(WixWarnings.FailedToDeleteTempDir(this.TempFilesLocation)); | ||
316 | } | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | this.core.OnMessage(WixVerboses.BinderTempDirLocatedAt(this.TempFilesLocation)); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /// <summary> | ||
325 | /// Cleans up the temp files used by the Binder. | ||
326 | /// </summary> | ||
327 | /// <returns>True if all files were deleted, false otherwise.</returns> | ||
328 | private bool DeleteTempFiles() | ||
329 | { | ||
330 | bool deleted = Common.DeleteTempFiles(this.TempFilesLocation, this.core); | ||
331 | return deleted; | ||
332 | } | ||
333 | |||
334 | /// <summary> | ||
335 | /// Populates the WixBuildInfo table in an output. | ||
336 | /// </summary> | ||
337 | /// <param name="output">The output.</param> | ||
338 | /// <param name="databaseFile">The output file if OutputFile not set.</param> | ||
339 | private void WriteBuildInfoTable(Output output, string outputFile) | ||
340 | { | ||
341 | Table buildInfoTable = output.EnsureTable(this.core.TableDefinitions["WixBuildInfo"]); | ||
342 | Row buildInfoRow = buildInfoTable.CreateRow(null); | ||
343 | |||
344 | Assembly executingAssembly = Assembly.GetExecutingAssembly(); | ||
345 | FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(executingAssembly.Location); | ||
346 | buildInfoRow[0] = fileVersion.FileVersion; | ||
347 | buildInfoRow[1] = outputFile; | ||
348 | |||
349 | if (!String.IsNullOrEmpty(this.WixprojectFile)) | ||
350 | { | ||
351 | buildInfoRow[2] = this.WixprojectFile; | ||
352 | } | ||
353 | |||
354 | if (!String.IsNullOrEmpty(this.PdbFile)) | ||
355 | { | ||
356 | buildInfoRow[3] = this.PdbFile; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | /// <summary> | ||
361 | /// Binds a bundle. | ||
362 | /// </summary> | ||
363 | /// <param name="bundle">The bundle to bind.</param> | ||
364 | /// <param name="bundleFile">The bundle to create.</param> | ||
365 | private void BindBundle(Output bundle, string bundleFile, out IEnumerable<FileTransfer> fileTransfers, out IEnumerable<string> contentPaths) | ||
366 | { | ||
367 | BindBundleCommand command = new BindBundleCommand(); | ||
368 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; | ||
369 | command.Extensions = this.extensions; | ||
370 | command.FileManagerCore = this.fileManagerCore; | ||
371 | command.FileManagers = this.fileManagers; | ||
372 | command.Output = bundle; | ||
373 | command.OutputPath = bundleFile; | ||
374 | command.PdbFile = this.PdbFile; | ||
375 | command.TableDefinitions = this.core.TableDefinitions; | ||
376 | command.TempFilesLocation = this.TempFilesLocation; | ||
377 | command.WixVariableResolver = this.WixVariableResolver; | ||
378 | command.Execute(); | ||
379 | |||
380 | fileTransfers = command.FileTransfers; | ||
381 | contentPaths = command.ContentFilePaths; | ||
382 | } | ||
383 | |||
384 | /// <summary> | ||
385 | /// Binds a databse. | ||
386 | /// </summary> | ||
387 | /// <param name="output">The output to bind.</param> | ||
388 | /// <param name="databaseFile">The database file to create.</param> | ||
389 | private void BindDatabase(Output output, string databaseFile, out IEnumerable<FileTransfer> fileTransfers, out IEnumerable<string> contentPaths) | ||
390 | { | ||
391 | Validator validator = null; | ||
392 | |||
393 | // tell the binder about the validator if validation isn't suppressed | ||
394 | if (!this.SuppressValidation && (OutputType.Module == output.Type || OutputType.Product == output.Type)) | ||
395 | { | ||
396 | validator = new Validator(); | ||
397 | validator.TempFilesLocation = Path.Combine(this.TempFilesLocation, "validate"); | ||
398 | |||
399 | // set the default cube file | ||
400 | string lightDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); | ||
401 | string cubePath = (OutputType.Module == output.Type) ? Path.Combine(lightDirectory, "mergemod.cub") : Path.Combine(lightDirectory, "darice.cub"); | ||
402 | validator.AddCubeFile(cubePath); | ||
403 | |||
404 | // by default, disable ICEs that have equivalent-or-better checks in WiX | ||
405 | this.SuppressIces.Add("ICE08"); | ||
406 | this.SuppressIces.Add("ICE33"); | ||
407 | this.SuppressIces.Add("ICE47"); | ||
408 | this.SuppressIces.Add("ICE66"); | ||
409 | |||
410 | // set the ICEs | ||
411 | validator.ICEs = this.Ices.ToArray(); | ||
412 | |||
413 | // set the suppressed ICEs | ||
414 | validator.SuppressedICEs = this.SuppressIces.ToArray(); | ||
415 | } | ||
416 | |||
417 | BindDatabaseCommand command = new BindDatabaseCommand(); | ||
418 | command.CabbingThreadCount = this.CabbingThreadCount; | ||
419 | command.Codepage = this.Localizer == null ? -1 : this.Localizer.Codepage; | ||
420 | command.DefaultCompressionLevel = this.DefaultCompressionLevel; | ||
421 | command.Extensions = this.extensions; | ||
422 | command.FileManagerCore = this.fileManagerCore; | ||
423 | command.FileManagers = this.fileManagers; | ||
424 | command.InspectorExtensions = this.inspectorExtensions; | ||
425 | command.Localizer = this.Localizer; | ||
426 | command.PdbFile = this.PdbFile; | ||
427 | command.Output = output; | ||
428 | command.OutputPath = databaseFile; | ||
429 | command.SuppressAddingValidationRows = this.SuppressAddingValidationRows; | ||
430 | command.SuppressLayout = this.SuppressLayout; | ||
431 | command.TableDefinitions = this.core.TableDefinitions; | ||
432 | command.TempFilesLocation = this.TempFilesLocation; | ||
433 | command.Validator = validator; | ||
434 | command.WixVariableResolver = this.WixVariableResolver; | ||
435 | command.Execute(); | ||
436 | |||
437 | fileTransfers = command.FileTransfers; | ||
438 | contentPaths = command.ContentFilePaths; | ||
439 | } | ||
440 | |||
441 | /// <summary> | ||
442 | /// Binds a transform. | ||
443 | /// </summary> | ||
444 | /// <param name="transform">The transform to bind.</param> | ||
445 | /// <param name="outputPath">The transform to create.</param> | ||
446 | private void BindTransform(Output transform, string outputPath) | ||
447 | { | ||
448 | BindTransformCommand command = new BindTransformCommand(); | ||
449 | command.Extensions = this.extensions; | ||
450 | command.FileManagers = this.fileManagers; | ||
451 | command.TableDefinitions = this.core.TableDefinitions; | ||
452 | command.TempFilesLocation = this.TempFilesLocation; | ||
453 | command.Transform = transform; | ||
454 | command.OutputPath = outputPath; | ||
455 | command.Execute(); | ||
456 | } | ||
457 | |||
458 | /// <summary> | ||
459 | /// Final step in binding that transfers (moves/copies) all files generated into the appropriate | ||
460 | /// location in the source image | ||
461 | /// </summary> | ||
462 | /// <param name="fileTransfers">List of files to transfer.</param> | ||
463 | private void LayoutMedia(IEnumerable<FileTransfer> transfers) | ||
464 | { | ||
465 | if (null != transfers && transfers.Any()) | ||
466 | { | ||
467 | this.core.OnMessage(WixVerboses.LayingOutMedia()); | ||
468 | |||
469 | TransferFilesCommand command = new TransferFilesCommand(); | ||
470 | command.FileManagers = this.fileManagers; | ||
471 | command.FileTransfers = transfers; | ||
472 | command.SuppressAclReset = this.SuppressAclReset; | ||
473 | command.Execute(); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /// <summary> | ||
478 | /// Get the source path of a directory. | ||
479 | /// </summary> | ||
480 | /// <param name="directories">All cached directories.</param> | ||
481 | /// <param name="componentIdGenSeeds">Hash table of Component GUID generation seeds indexed by directory id.</param> | ||
482 | /// <param name="directory">Directory identifier.</param> | ||
483 | /// <param name="canonicalize">Canonicalize the path for standard directories.</param> | ||
484 | /// <returns>Source path of a directory.</returns> | ||
485 | internal static string GetDirectoryPath(Hashtable directories, Hashtable componentIdGenSeeds, string directory, bool canonicalize) | ||
486 | { | ||
487 | if (!directories.Contains(directory)) | ||
488 | { | ||
489 | throw new WixException(WixErrors.ExpectedDirectory(directory)); | ||
490 | } | ||
491 | |||
492 | ResolvedDirectory resolvedDirectory = (ResolvedDirectory)directories[directory]; | ||
493 | |||
494 | if (null == resolvedDirectory.Path) | ||
495 | { | ||
496 | if (null != componentIdGenSeeds && componentIdGenSeeds.Contains(directory)) | ||
497 | { | ||
498 | resolvedDirectory.Path = (string)componentIdGenSeeds[directory]; | ||
499 | } | ||
500 | else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory)) | ||
501 | { | ||
502 | // when canonicalization is on, standard directories are treated equally | ||
503 | resolvedDirectory.Path = directory; | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | string name = resolvedDirectory.Name; | ||
508 | |||
509 | if (canonicalize && null != name) | ||
510 | { | ||
511 | name = name.ToLower(CultureInfo.InvariantCulture); | ||
512 | } | ||
513 | |||
514 | if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) | ||
515 | { | ||
516 | resolvedDirectory.Path = name; | ||
517 | } | ||
518 | else | ||
519 | { | ||
520 | string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize); | ||
521 | |||
522 | if (null != resolvedDirectory.Name) | ||
523 | { | ||
524 | resolvedDirectory.Path = Path.Combine(parentPath, name); | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | resolvedDirectory.Path = parentPath; | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | |||
534 | return resolvedDirectory.Path; | ||
535 | } | ||
536 | |||
537 | /// <summary> | ||
538 | /// Gets the source path of a file. | ||
539 | /// </summary> | ||
540 | /// <param name="directories">All cached directories in <see cref="ResolvedDirectory"/>.</param> | ||
541 | /// <param name="directoryId">Parent directory identifier.</param> | ||
542 | /// <param name="fileName">File name (in long|source format).</param> | ||
543 | /// <param name="compressed">Specifies the package is compressed.</param> | ||
544 | /// <param name="useLongName">Specifies the package uses long file names.</param> | ||
545 | /// <returns>Source path of file relative to package directory.</returns> | ||
546 | internal static string GetFileSourcePath(Hashtable directories, string directoryId, string fileName, bool compressed, bool useLongName) | ||
547 | { | ||
548 | string fileSourcePath = Installer.GetName(fileName, true, useLongName); | ||
549 | |||
550 | if (compressed) | ||
551 | { | ||
552 | // Use just the file name of the file since all uncompressed files must appear | ||
553 | // in the root of the image in a compressed package. | ||
554 | } | ||
555 | else | ||
556 | { | ||
557 | // Get the relative path of where we want the file to be layed out as specified | ||
558 | // in the Directory table. | ||
559 | string directoryPath = Binder.GetDirectoryPath(directories, null, directoryId, false); | ||
560 | fileSourcePath = Path.Combine(directoryPath, fileSourcePath); | ||
561 | } | ||
562 | |||
563 | // Strip off "SourceDir" if it's still on there. | ||
564 | if (fileSourcePath.StartsWith("SourceDir\\", StringComparison.Ordinal)) | ||
565 | { | ||
566 | fileSourcePath = fileSourcePath.Substring(10); | ||
567 | } | ||
568 | |||
569 | return fileSourcePath; | ||
570 | } | ||
571 | |||
572 | /// <summary> | ||
573 | /// Writes the paths to the content files included in the package to a text file. | ||
574 | /// </summary> | ||
575 | /// <param name="path">Path to write file.</param> | ||
576 | /// <param name="contentFilePaths">Collection of paths to content files that will be written to file.</param> | ||
577 | private void CreateContentsFile(string path, IEnumerable<string> contentFilePaths) | ||
578 | { | ||
579 | string directory = Path.GetDirectoryName(path); | ||
580 | if (!Directory.Exists(directory)) | ||
581 | { | ||
582 | Directory.CreateDirectory(directory); | ||
583 | } | ||
584 | |||
585 | using (StreamWriter contents = new StreamWriter(path, false)) | ||
586 | { | ||
587 | foreach (string contentPath in contentFilePaths) | ||
588 | { | ||
589 | contents.WriteLine(contentPath); | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /// <summary> | ||
595 | /// Writes the paths to the content files included in the bundle to a text file. | ||
596 | /// </summary> | ||
597 | /// <param name="path">Path to write file.</param> | ||
598 | /// <param name="payloads">Collection of payloads whose source will be written to file.</param> | ||
599 | private void CreateContentsFile(string path, IEnumerable<WixBundlePayloadRow> payloads) | ||
600 | { | ||
601 | string directory = Path.GetDirectoryName(path); | ||
602 | if (!Directory.Exists(directory)) | ||
603 | { | ||
604 | Directory.CreateDirectory(directory); | ||
605 | } | ||
606 | |||
607 | using (StreamWriter contents = new StreamWriter(path, false)) | ||
608 | { | ||
609 | foreach (WixBundlePayloadRow payload in payloads) | ||
610 | { | ||
611 | if (payload.ContentFile) | ||
612 | { | ||
613 | contents.WriteLine(payload.FullFileName); | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | } | ||
618 | |||
619 | /// <summary> | ||
620 | /// Writes the paths to the output files to a text file. | ||
621 | /// </summary> | ||
622 | /// <param name="path">Path to write file.</param> | ||
623 | /// <param name="fileTransfers">Collection of files that were transferred to the output directory.</param> | ||
624 | /// <param name="pdbPath">Optional path to created .wixpdb.</param> | ||
625 | private void CreateOutputsFile(string path, IEnumerable<FileTransfer> fileTransfers, string pdbPath) | ||
626 | { | ||
627 | string directory = Path.GetDirectoryName(path); | ||
628 | if (!Directory.Exists(directory)) | ||
629 | { | ||
630 | Directory.CreateDirectory(directory); | ||
631 | } | ||
632 | |||
633 | using (StreamWriter outputs = new StreamWriter(path, false)) | ||
634 | { | ||
635 | foreach (FileTransfer fileTransfer in fileTransfers) | ||
636 | { | ||
637 | // Don't list files where the source is the same as the destination since | ||
638 | // that might be the only place the file exists. The outputs file is often | ||
639 | // used to delete stuff and losing the original source would be bad. | ||
640 | if (!fileTransfer.Redundant) | ||
641 | { | ||
642 | outputs.WriteLine(fileTransfer.Destination); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | if (!String.IsNullOrEmpty(pdbPath)) | ||
647 | { | ||
648 | outputs.WriteLine(Path.GetFullPath(pdbPath)); | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
653 | /// <summary> | ||
654 | /// Writes the paths to the built output files to a text file. | ||
655 | /// </summary> | ||
656 | /// <param name="path">Path to write file.</param> | ||
657 | /// <param name="fileTransfers">Collection of files that were transferred to the output directory.</param> | ||
658 | /// <param name="pdbPath">Optional path to created .wixpdb.</param> | ||
659 | private void CreateBuiltOutputsFile(string path, IEnumerable<FileTransfer> fileTransfers, string pdbPath) | ||
660 | { | ||
661 | string directory = Path.GetDirectoryName(path); | ||
662 | if (!Directory.Exists(directory)) | ||
663 | { | ||
664 | Directory.CreateDirectory(directory); | ||
665 | } | ||
666 | |||
667 | using (StreamWriter outputs = new StreamWriter(path, false)) | ||
668 | { | ||
669 | foreach (FileTransfer fileTransfer in fileTransfers) | ||
670 | { | ||
671 | // Only write the built file transfers. Also, skip redundant | ||
672 | // files for the same reason spelled out in this.CreateOutputsFile(). | ||
673 | if (fileTransfer.Built && !fileTransfer.Redundant) | ||
674 | { | ||
675 | outputs.WriteLine(fileTransfer.Destination); | ||
676 | } | ||
677 | } | ||
678 | |||
679 | if (!String.IsNullOrEmpty(pdbPath)) | ||
680 | { | ||
681 | outputs.WriteLine(Path.GetFullPath(pdbPath)); | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | } | ||
686 | } | ||