aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/LayoutCreator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/LayoutCreator.cs')
-rw-r--r--src/WixToolset.Core/LayoutCreator.cs227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/WixToolset.Core/LayoutCreator.cs b/src/WixToolset.Core/LayoutCreator.cs
new file mode 100644
index 00000000..684465d2
--- /dev/null
+++ b/src/WixToolset.Core/LayoutCreator.cs
@@ -0,0 +1,227 @@
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.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 internal LayoutCreator(IServiceProvider serviceProvider)
20 {
21 this.ServiceProvider = serviceProvider;
22
23 this.Messaging = serviceProvider.GetService<IMessaging>();
24 }
25
26 private IServiceProvider ServiceProvider { get; }
27
28 private IMessaging Messaging { get; }
29
30 public void Layout(ILayoutContext context)
31 {
32 // Pre-layout.
33 //
34 foreach (var extension in context.Extensions)
35 {
36 extension.PreLayout(context);
37 }
38
39 try
40 {
41 // Final step in binding that transfers (moves/copies) all files generated into the appropriate
42 // location in the source image.
43 if (context.FileTransfers?.Any() == true)
44 {
45 this.Messaging.Write(VerboseMessages.LayingOutMedia());
46
47 var command = new TransferFilesCommand(this.Messaging, context.Extensions, context.FileTransfers, context.SuppressAclReset);
48 command.Execute();
49 }
50
51 if (context.TrackedFiles != null)
52 {
53 this.CleanTempFiles(context.IntermediateFolder, context.TrackedFiles);
54 }
55 }
56 finally
57 {
58 if (context.TrackedFiles != null)
59 {
60 if (!String.IsNullOrEmpty(context.ContentsFile))
61 {
62 this.CreateContentsFile(context.ContentsFile, context.TrackedFiles);
63 }
64
65 if (!String.IsNullOrEmpty(context.OutputsFile))
66 {
67 this.CreateOutputsFile(context.OutputsFile, context.TrackedFiles);
68 }
69
70 if (!String.IsNullOrEmpty(context.BuiltOutputsFile))
71 {
72 this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.TrackedFiles);
73 }
74 }
75 }
76
77 // Post-layout.
78 foreach (var extension in context.Extensions)
79 {
80 extension.PostLayout();
81 }
82 }
83
84 /// <summary>
85 /// Writes the paths to the content files to a text file.
86 /// </summary>
87 /// <param name="path">Path to write file.</param>
88 /// <param name="contentFilePaths">Collection of paths to content files that will be written to file.</param>
89 private void CreateContentsFile(string path, IEnumerable<ITrackedFile> trackedFiles)
90 {
91 var uniqueInputFilePaths = new SortedSet<string>(trackedFiles.Where(t => t.Type == TrackedFileType.Input).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
92
93 if (!uniqueInputFilePaths.Any())
94 {
95 return;
96 }
97
98 var directory = Path.GetDirectoryName(path);
99 Directory.CreateDirectory(directory);
100
101 using (var contents = new StreamWriter(path, false))
102 {
103 foreach (var inputPath in uniqueInputFilePaths)
104 {
105 contents.WriteLine(inputPath);
106 }
107 }
108 }
109
110 /// <summary>
111 /// Writes the paths to the output files to a text file.
112 /// </summary>
113 /// <param name="path">Path to write file.</param>
114 /// <param name="fileTransfers">Collection of files that were transferred to the output directory.</param>
115 private void CreateOutputsFile(string path, IEnumerable<ITrackedFile> trackedFiles)
116 {
117 var uniqueOutputPaths = new SortedSet<string>(trackedFiles.Where(t => t.Clean).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
118
119 if (!uniqueOutputPaths.Any())
120 {
121 return;
122 }
123
124 var directory = Path.GetDirectoryName(path);
125 Directory.CreateDirectory(directory);
126
127 using (var outputs = new StreamWriter(path, false))
128 {
129 //// Don't list files where the source is the same as the destination since
130 //// that might be the only place the file exists. The outputs file is often
131 //// used to delete stuff and losing the original source would be bad.
132 //var uniqueOutputPaths = new SortedSet<string>(fileTransfers.Where(ft => !ft.Redundant).Select(ft => ft.Destination), StringComparer.OrdinalIgnoreCase);
133
134 foreach (var outputPath in uniqueOutputPaths)
135 {
136 outputs.WriteLine(outputPath);
137 }
138 }
139 }
140
141 /// <summary>
142 /// Writes the paths to the built output files to a text file.
143 /// </summary>
144 /// <param name="path">Path to write file.</param>
145 /// <param name="fileTransfers">Collection of files that were transferred to the output directory.</param>
146 private void CreateBuiltOutputsFile(string path, IEnumerable<ITrackedFile> trackedFiles)
147 {
148 var uniqueBuiltPaths = new SortedSet<string>(trackedFiles.Where(t => t.Type == TrackedFileType.Final).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
149
150 if (!uniqueBuiltPaths.Any())
151 {
152 return;
153 }
154
155 var directory = Path.GetDirectoryName(path);
156 Directory.CreateDirectory(directory);
157
158 using (var outputs = new StreamWriter(path, false))
159 {
160 foreach (var builtPath in uniqueBuiltPaths)
161 {
162 outputs.WriteLine(builtPath);
163 }
164 }
165 }
166
167 private void CleanTempFiles(string intermediateFolder, IEnumerable<ITrackedFile> trackedFiles)
168 {
169 var uniqueTempPaths = new SortedSet<string>(trackedFiles.Where(t => t.Type == TrackedFileType.Temporary).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
170
171 if (!uniqueTempPaths.Any())
172 {
173 return;
174 }
175
176 var uniqueFolders = new SortedSet<string>(StringComparer.OrdinalIgnoreCase)
177 {
178 intermediateFolder
179 };
180
181 // Clean up temp files.
182 foreach (var tempPath in uniqueTempPaths)
183 {
184 try
185 {
186 this.SplitUniqueFolders(intermediateFolder, tempPath, uniqueFolders);
187
188 File.Delete(tempPath);
189 }
190 catch // delete is best effort.
191 {
192 }
193 }
194
195 // Clean up empty temp folders.
196 foreach (var folder in uniqueFolders.Reverse())
197 {
198 try
199 {
200 Directory.Delete(folder);
201 }
202 catch // delete is best effort.
203 {
204 }
205 }
206 }
207
208 private void SplitUniqueFolders(string intermediateFolder, string tempPath, SortedSet<string> uniqueFolders)
209 {
210 if (tempPath.StartsWith(intermediateFolder, StringComparison.OrdinalIgnoreCase))
211 {
212 var folder = Path.GetDirectoryName(tempPath).Substring(intermediateFolder.Length);
213
214 var parts = folder.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
215
216 folder = intermediateFolder;
217
218 foreach (var part in parts)
219 {
220 folder = Path.Combine(folder, part);
221
222 uniqueFolders.Add(folder);
223 }
224 }
225 }
226 }
227}