main
cs 157 lines 5.29 KB
Raw
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.Core
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
13
14 /// <summary>
15 /// Layout for the WiX toolset.
16 /// </summary>
17 internal class LayoutCreator : ILayoutCreator
18 {
19 private const string TrackedLineTypePathSeparator = "\t";
20
21 internal LayoutCreator(IServiceProvider serviceProvider)
22 {
23 this.Messaging = serviceProvider.GetService<IMessaging>();
24 this.FileSystem = serviceProvider.GetService<IFileSystem>();
25 }
26
27 private IMessaging Messaging { get; }
28
29 private IFileSystem FileSystem { get; }
30
31 public void Layout(ILayoutContext context)
32 {
33 // Pre-layout.
34 //
35 foreach (var extension in context.Extensions)
36 {
37 extension.PreLayout(context);
38 }
39
40 try
41 {
42 // Final step in binding that transfers (moves/copies) all files generated into the appropriate
43 // location in the source image.
44 if (context.FileTransfers?.Any() == true)
45 {
46 this.Messaging.Write(VerboseMessages.LayingOutMedia());
47
48 var command = new TransferFilesCommand(this.Messaging, this.FileSystem, context.Extensions, context.FileTransfers, context.ResetAcls);
49 command.Execute();
50 }
51
52 if (context.TrackedFiles != null)
53 {
54 this.CleanTempFiles(context.IntermediateFolder, context.TrackedFiles);
55 }
56 }
57 finally
58 {
59 if (context.TrackedFiles != null && !String.IsNullOrEmpty(context.TrackingFile))
60 {
61 this.CreateTrackingFile(context.TrackingFile, context.TrackedFiles);
62 }
63 }
64
65 // Post-layout.
66 foreach (var extension in context.Extensions)
67 {
68 extension.PostLayout();
69 }
70 }
71
72 /// <summary>
73 /// Writes the paths of the track files to a text file.
74 /// </summary>
75 /// <param name="path">Path to write file.</param>
76 /// <param name="trackedFiles">Collection of files that were tracked.</param>
77 private void CreateTrackingFile(string path, IEnumerable<ITrackedFile> trackedFiles)
78 {
79 var uniqueTrackingLines = new SortedSet<string>(trackedFiles.Where(t => t.Type != TrackedFileType.Temporary).Select(TrackedFileLine), StringComparer.OrdinalIgnoreCase);
80
81 if (!uniqueTrackingLines.Any())
82 {
83 return;
84 }
85
86 var directory = Path.GetDirectoryName(path);
87 Directory.CreateDirectory(directory);
88
89 using (var stream = new StreamWriter(path, false))
90 {
91 foreach (var trackingLine in uniqueTrackingLines)
92 {
93 stream.WriteLine(trackingLine);
94 }
95 }
96 }
97
98 private void CleanTempFiles(string intermediateFolder, IEnumerable<ITrackedFile> trackedFiles)
99 {
100 var uniqueTempPaths = new SortedSet<string>(trackedFiles.Where(t => t.Type == TrackedFileType.Temporary).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
101
102 if (!uniqueTempPaths.Any())
103 {
104 return;
105 }
106
107 var uniqueFolders = new SortedSet<string>(StringComparer.OrdinalIgnoreCase)
108 {
109 intermediateFolder
110 };
111
112 // Clean up temp files.
113 foreach (var tempPath in uniqueTempPaths)
114 {
115 this.SplitUniqueFolders(intermediateFolder, tempPath, uniqueFolders);
116
117 this.FileSystem.DeleteFile(null, tempPath);
118 }
119
120 // Clean up empty temp folders.
121 foreach (var folder in uniqueFolders.Reverse())
122 {
123 try
124 {
125 Directory.Delete(folder);
126 }
127 catch // delete is best effort.
128 {
129 }
130 }
131 }
132
133 private void SplitUniqueFolders(string intermediateFolder, string tempPath, SortedSet<string> uniqueFolders)
134 {
135 if (tempPath.StartsWith(intermediateFolder, StringComparison.OrdinalIgnoreCase))
136 {
137 var folder = Path.GetDirectoryName(tempPath.Substring(intermediateFolder.Length));
138
139 var parts = folder.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
140
141 folder = intermediateFolder;
142
143 foreach (var part in parts)
144 {
145 folder = Path.Combine(folder, part);
146
147 uniqueFolders.Add(folder);
148 }
149 }
150 }
151
152 private static string TrackedFileLine(ITrackedFile trackedFile)
153 {
154 return trackedFile.Type + TrackedLineTypePathSeparator + trackedFile.Path;
155 }
156 }
157 }