summaryrefslogtreecommitdiff
path: root/src/tools/heat/DirectoryHarvester.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/heat/DirectoryHarvester.cs')
-rw-r--r--src/tools/heat/DirectoryHarvester.cs308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/tools/heat/DirectoryHarvester.cs b/src/tools/heat/DirectoryHarvester.cs
new file mode 100644
index 00000000..c1cc3edb
--- /dev/null
+++ b/src/tools/heat/DirectoryHarvester.cs
@@ -0,0 +1,308 @@
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.Harvesters
4{
5 using System;
6 using System.IO;
7 using WixToolset.Data;
8 using WixToolset.Harvesters.Data;
9 using WixToolset.Harvesters.Extensibility;
10 using Wix = WixToolset.Harvesters.Serialize;
11
12 /// <summary>
13 /// Harvest WiX authoring for a directory from the file system.
14 /// </summary>
15 public sealed class DirectoryHarvester : BaseHarvesterExtension
16 {
17 private FileHarvester fileHarvester;
18
19 private const string ComponentPrefix = "cmp";
20 private const string DirectoryPrefix = "dir";
21 private const string FilePrefix = "fil";
22
23 /// <summary>
24 /// Instantiate a new DirectoryHarvester.
25 /// </summary>
26 public DirectoryHarvester()
27 {
28 this.fileHarvester = new FileHarvester();
29 this.SetUniqueIdentifiers = true;
30 }
31
32 /// <summary>
33 /// Gets or sets what type of elements are to be generated.
34 /// </summary>
35 /// <value>The type of elements being generated.</value>
36 public GenerateType GenerateType { get; set; }
37
38 /// <summary>
39 /// Gets or sets the option to keep empty directories.
40 /// </summary>
41 /// <value>The option to keep empty directories.</value>
42 public bool KeepEmptyDirectories { get; set; }
43
44 /// <summary>
45 /// Gets or sets the rooted DirectoryRef Id if the user has supplied it.
46 /// </summary>
47 /// <value>The DirectoryRef Id to use as the root.</value>
48 public string RootedDirectoryRef { get; set; }
49
50 /// <summary>
51 /// Gets of sets the option to set unique identifiers.
52 /// </summary>
53 /// <value>The option to set unique identifiers.</value>
54 public bool SetUniqueIdentifiers { get; set; }
55
56 /// <summary>
57 /// Gets or sets the option to suppress including the root directory as an element.
58 /// </summary>
59 /// <value>The option to suppress including the root directory as an element.</value>
60 public bool SuppressRootDirectory { get; set; }
61
62 /// <summary>
63 /// Harvest a directory.
64 /// </summary>
65 /// <param name="argument">The path of the directory.</param>
66 /// <returns>The harvested directory.</returns>
67 public override Wix.Fragment[] Harvest(string argument)
68 {
69 if (null == argument)
70 {
71 throw new ArgumentNullException("argument");
72 }
73
74 Wix.IParentElement harvestParent = this.HarvestDirectory(argument, true, this.GenerateType);
75 Wix.ISchemaElement harvestElement;
76
77 if (this.GenerateType == GenerateType.PayloadGroup)
78 {
79 Wix.PayloadGroup payloadGroup = (Wix.PayloadGroup)harvestParent;
80 payloadGroup.Id = this.RootedDirectoryRef;
81 harvestElement = payloadGroup;
82 }
83 else
84 {
85 Wix.Directory directory = (Wix.Directory)harvestParent;
86
87 Wix.DirectoryRef directoryRef = new Wix.DirectoryRef();
88 directoryRef.Id = this.RootedDirectoryRef;
89
90 if (this.SuppressRootDirectory)
91 {
92 foreach (Wix.ISchemaElement element in directory.Children)
93 {
94 directoryRef.AddChild(element);
95 }
96 }
97 else
98 {
99 directoryRef.AddChild(directory);
100 }
101 harvestElement = directoryRef;
102 }
103
104 Wix.Fragment fragment = new Wix.Fragment();
105 fragment.AddChild(harvestElement);
106
107 return new Wix.Fragment[] { fragment };
108 }
109
110 /// <summary>
111 /// Harvest a directory.
112 /// </summary>
113 /// <param name="path">The path of the directory.</param>
114 /// <param name="harvestChildren">The option to harvest child directories and files.</param>
115 /// <returns>The harvested directory.</returns>
116 public Wix.Directory HarvestDirectory(string path, bool harvestChildren)
117 {
118 if (null == path)
119 {
120 throw new ArgumentNullException("path");
121 }
122
123 return (Wix.Directory)this.HarvestDirectory(path, harvestChildren, GenerateType.Components);
124 }
125
126 /// <summary>
127 /// Harvest a directory.
128 /// </summary>
129 /// <param name="path">The path of the directory.</param>
130 /// <param name="harvestChildren">The option to harvest child directories and files.</param>
131 /// <param name="generateType">The type to generate.</param>
132 /// <returns>The harvested directory.</returns>
133 private Wix.IParentElement HarvestDirectory(string path, bool harvestChildren, GenerateType generateType)
134 {
135 if (File.Exists(path))
136 {
137 throw new WixException(ErrorMessages.ExpectedDirectoryGotFile("dir", path));
138 }
139
140 if (null == this.RootedDirectoryRef)
141 {
142 this.RootedDirectoryRef = "TARGETDIR";
143 }
144
145 // use absolute paths
146 path = Path.GetFullPath(path);
147
148 // Remove any trailing separator to ensure Path.GetFileName() will return the directory name.
149 path = path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
150
151 Wix.IParentElement harvestParent;
152 if (generateType == GenerateType.PayloadGroup)
153 {
154 harvestParent = new Wix.PayloadGroup();
155 }
156 else
157 {
158 Wix.Directory directory = new Wix.Directory();
159 directory.Name = Path.GetFileName(path);
160 directory.FileSource = path;
161
162 if (this.SetUniqueIdentifiers)
163 {
164 if (this.SuppressRootDirectory)
165 {
166 directory.Id = this.Core.GenerateIdentifier(DirectoryPrefix, this.RootedDirectoryRef);
167 }
168 else
169 {
170 directory.Id = this.Core.GenerateIdentifier(DirectoryPrefix, this.RootedDirectoryRef, directory.Name);
171 }
172 }
173 harvestParent = directory;
174 }
175
176 if (harvestChildren)
177 {
178 try
179 {
180 int fileCount = this.HarvestDirectory(path, "SourceDir\\", harvestParent, generateType);
181
182 if (generateType != GenerateType.PayloadGroup)
183 {
184 // its an error to not harvest anything with the option to keep empty directories off
185 if (0 == fileCount && !this.KeepEmptyDirectories)
186 {
187 throw new WixException(HarvesterErrors.EmptyDirectory(path));
188 }
189 }
190 }
191 catch (DirectoryNotFoundException)
192 {
193 throw new WixException(HarvesterErrors.DirectoryNotFound(path));
194 }
195 }
196
197 return harvestParent;
198 }
199
200 /// <summary>
201 /// Harvest a directory.
202 /// </summary>
203 /// <param name="path">The path of the directory.</param>
204 /// <param name="relativePath">The relative path that will be used when harvesting.</param>
205 /// <param name="harvestParent">The directory for this path.</param>
206 /// <param name="generateType"></param>
207 /// <returns>The number of files harvested.</returns>
208 private int HarvestDirectory(string path, string relativePath, Wix.IParentElement harvestParent, GenerateType generateType)
209 {
210 int fileCount = 0;
211 Wix.Directory directory = generateType != GenerateType.PayloadGroup ? (Wix.Directory)harvestParent : null;
212
213 // harvest the child directories
214 foreach (string childDirectoryPath in Directory.GetDirectories(path))
215 {
216 var childDirectoryName = Path.GetFileName(childDirectoryPath);
217 Wix.IParentElement newParent;
218 Wix.Directory childDirectory = null;
219
220 if (generateType == GenerateType.PayloadGroup)
221 {
222 newParent = harvestParent;
223 }
224 else
225 {
226 childDirectory = new Wix.Directory();
227 newParent = childDirectory;
228
229 childDirectory.Name = childDirectoryName;
230 childDirectory.FileSource = childDirectoryPath;
231
232 if (this.SetUniqueIdentifiers)
233 {
234 childDirectory.Id = this.Core.GenerateIdentifier(DirectoryPrefix, directory.Id, childDirectory.Name);
235 }
236 }
237
238 int childFileCount = this.HarvestDirectory(childDirectoryPath, String.Concat(relativePath, childDirectoryName, "\\"), newParent, generateType);
239
240 if (generateType != GenerateType.PayloadGroup)
241 {
242 // keep the directory if it contained any files (or empty directories are being kept)
243 if (0 < childFileCount || this.KeepEmptyDirectories)
244 {
245 directory.AddChild(childDirectory);
246 }
247 }
248
249 fileCount += childFileCount;
250 }
251
252 // harvest the files
253 string[] files = Directory.GetFiles(path);
254 if (0 < files.Length)
255 {
256 foreach (string filePath in Directory.GetFiles(path))
257 {
258 string fileName = Path.GetFileName(filePath);
259 string source = String.Concat(relativePath, fileName);
260
261 Wix.ISchemaElement newChild;
262 if (generateType == GenerateType.PayloadGroup)
263 {
264 Wix.Payload payload = new Wix.Payload();
265 newChild = payload;
266
267 payload.SourceFile = source;
268 }
269 else
270 {
271 Wix.Component component = new Wix.Component();
272 newChild = component;
273
274 Wix.File file = this.fileHarvester.HarvestFile(filePath);
275 file.Source = source;
276
277 if (this.SetUniqueIdentifiers)
278 {
279 file.Id = this.Core.GenerateIdentifier(FilePrefix, directory.Id, fileName);
280 component.Id = this.Core.GenerateIdentifier(ComponentPrefix, directory.Id, file.Id);
281 }
282
283 component.AddChild(file);
284 }
285
286 harvestParent.AddChild(newChild);
287 }
288 }
289 else if (generateType != GenerateType.PayloadGroup && 0 == fileCount && this.KeepEmptyDirectories)
290 {
291 Wix.Component component = new Wix.Component();
292 component.KeyPath = Wix.YesNoType.yes;
293
294 if (this.SetUniqueIdentifiers)
295 {
296 component.Id = this.Core.GenerateIdentifier(ComponentPrefix, directory.Id);
297 }
298
299 Wix.CreateFolder createFolder = new Wix.CreateFolder();
300 component.AddChild(createFolder);
301
302 directory.AddChild(component);
303 }
304
305 return fileCount + files.Length;
306 }
307 }
308}