aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2020-06-06 15:40:38 -0700
committerRob Mensching <rob@firegiant.com>2020-06-08 16:40:24 -0700
commit60c9a081d337bf432a61bee6784d4c05da1a049a (patch)
treed77a4393283b0b80b84e5c36747d5cfa42549e0e /src
parenta783c83bc1e1efaf054d957c8a097386cb8f6b4a (diff)
downloadwix-60c9a081d337bf432a61bee6784d4c05da1a049a.tar.gz
wix-60c9a081d337bf432a61bee6784d4c05da1a049a.tar.bz2
wix-60c9a081d337bf432a61bee6784d4c05da1a049a.zip
Expose converter as a command-line command for use by wix.exe
Diffstat (limited to 'src')
-rw-r--r--src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj2
-rw-r--r--src/WixToolset.Converters/ConvertCommand.cs281
-rw-r--r--src/WixToolset.Converters/ConverterExtensionCommandLine.cs39
-rw-r--r--src/WixToolset.Converters/ConverterExtensionFactory.cs30
-rw-r--r--src/WixToolset.Converters/WixToolset.Converters.csproj2
-rw-r--r--src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs17
-rw-r--r--src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject9
7 files changed, 378 insertions, 2 deletions
diff --git a/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj
index 3fa1b57d..cafb5feb 100644
--- a/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj
+++ b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj
@@ -28,7 +28,7 @@
28 </ItemGroup> 28 </ItemGroup>
29 29
30 <ItemGroup> 30 <ItemGroup>
31 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/> 31 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
32 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> 32 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" />
33 </ItemGroup> 33 </ItemGroup>
34</Project> 34</Project>
diff --git a/src/WixToolset.Converters/ConvertCommand.cs b/src/WixToolset.Converters/ConvertCommand.cs
new file mode 100644
index 00000000..a684bc95
--- /dev/null
+++ b/src/WixToolset.Converters/ConvertCommand.cs
@@ -0,0 +1,281 @@
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.Converters
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Xml;
9 using WixToolset.Extensibility.Data;
10 using WixToolset.Extensibility.Services;
11
12 internal class ConvertCommand : ICommandLineCommand
13 {
14 private const string SettingsFileDefault = "wixcop.settings.xml";
15
16 public ConvertCommand(IWixToolsetServiceProvider serviceProvider)
17 {
18 this.Messaging = serviceProvider.GetService<IMessaging>();
19
20 this.IndentationAmount = 4; // default indentation amount
21 this.ErrorsAsWarnings = new HashSet<string>();
22 this.ExemptFiles = new HashSet<string>();
23 this.IgnoreErrors = new HashSet<string>();
24 this.SearchPatternResults = new HashSet<string>();
25 this.SearchPatterns = new List<string>();
26 }
27
28 private IMessaging Messaging { get; }
29
30 public bool ShowLogo { get; private set; }
31
32 public bool StopParsing { get; private set; }
33
34 private bool ShowHelp { get; set; }
35
36 private HashSet<string> ErrorsAsWarnings { get; }
37
38 private HashSet<string> ExemptFiles { get; }
39
40 private bool FixErrors { get; set; }
41
42 private int IndentationAmount { get; set; }
43
44 private HashSet<string> IgnoreErrors { get; }
45
46 private HashSet<string> SearchPatternResults { get; }
47
48 private List<string> SearchPatterns { get; }
49
50 private string SettingsFile1 { get; set; }
51
52 private string SettingsFile2 { get; set; }
53
54 private bool SubDirectories { get; set; }
55
56 public bool TryParseArgument(ICommandLineParser parser, string argument)
57 {
58 if (!parser.IsSwitch(argument))
59 {
60 this.SearchPatterns.Add(argument);
61 return true;
62 }
63
64 var parameter = argument.Substring(1);
65 switch (parameter.ToLowerInvariant())
66 {
67 case "?":
68 this.ShowHelp = true;
69 this.ShowLogo = true;
70 this.StopParsing = true;
71 return true;
72
73 case "f":
74 this.FixErrors = true;
75 return true;
76
77 case "nologo":
78 this.ShowLogo = false;
79 return true;
80
81 case "s":
82 this.SubDirectories = true;
83 return true;
84
85 default: // other parameters
86 if (parameter.StartsWith("set1", StringComparison.Ordinal))
87 {
88 this.SettingsFile1 = parameter.Substring(4);
89 return true;
90 }
91 else if (parameter.StartsWith("set2", StringComparison.Ordinal))
92 {
93 this.SettingsFile2 = parameter.Substring(4);
94 return true;
95 }
96 else if (parameter.StartsWith("indent:", StringComparison.Ordinal))
97 {
98 try
99 {
100 this.IndentationAmount = Convert.ToInt32(parameter.Substring(7));
101 }
102 catch
103 {
104 parser.ErrorArgument = parameter; // $"Invalid numeric argument: {parameter}";
105 }
106 return true;
107 }
108
109 return false;
110 }
111 }
112
113 public int Execute()
114 {
115 if (this.ShowHelp)
116 {
117 DisplayHelp();
118 return 1;
119 }
120
121 // parse the settings if any were specified
122 if (null != this.SettingsFile1 || null != this.SettingsFile2)
123 {
124 this.ParseSettingsFiles(this.SettingsFile1, this.SettingsFile2);
125 }
126 else
127 {
128 if (File.Exists(ConvertCommand.SettingsFileDefault))
129 {
130 this.ParseSettingsFiles(ConvertCommand.SettingsFileDefault, null);
131 }
132 }
133
134 var converter = new Wix3Converter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors);
135
136 var errors = this.InspectSubDirectories(converter, Path.GetFullPath("."));
137
138 foreach (var searchPattern in this.SearchPatterns)
139 {
140 if (!this.SearchPatternResults.Contains(searchPattern))
141 {
142 Console.Error.WriteLine("Could not find file \"{0}\"", searchPattern);
143 errors++;
144 }
145 }
146
147 return errors != 0 ? 2 : 0;
148 }
149
150 private static void DisplayHelp()
151 {
152 Console.WriteLine(" usage: wix.exe convert sourceFile [sourceFile ...]");
153 Console.WriteLine();
154 Console.WriteLine(" -f fix errors automatically for writable files");
155 Console.WriteLine(" -nologo suppress displaying the logo information");
156 Console.WriteLine(" -s search for matching files in current dir and subdirs");
157 Console.WriteLine(" -set1<file> primary settings file");
158 Console.WriteLine(" -set2<file> secondary settings file (overrides primary)");
159 Console.WriteLine(" -indent:<n> indentation multiple (overrides default of 4)");
160 Console.WriteLine(" -? this help information");
161 Console.WriteLine();
162 Console.WriteLine(" sourceFile may use wildcards like *.wxs");
163 }
164
165 /// <summary>
166 /// Get the files that match a search path pattern.
167 /// </summary>
168 /// <param name="baseDir">The base directory at which to begin the search.</param>
169 /// <param name="searchPath">The search path pattern.</param>
170 /// <returns>The files matching the pattern.</returns>
171 private static string[] GetFiles(string baseDir, string searchPath)
172 {
173 // convert alternate directory separators to the standard one
174 var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
175 var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar);
176 string[] files = null;
177
178 try
179 {
180 if (0 > lastSeparator)
181 {
182 files = Directory.GetFiles(baseDir, filePath);
183 }
184 else // found directory separator
185 {
186 var searchPattern = filePath.Substring(lastSeparator + 1);
187
188 files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), searchPattern);
189 }
190 }
191 catch (DirectoryNotFoundException)
192 {
193 // don't let this function throw the DirectoryNotFoundException. (this exception
194 // occurs for non-existant directories and invalid characters in the searchPattern)
195 }
196
197 return files;
198 }
199
200 /// <summary>
201 /// Inspect sub-directories.
202 /// </summary>
203 /// <param name="directory">The directory whose sub-directories will be inspected.</param>
204 /// <returns>The number of errors that were found.</returns>
205 private int InspectSubDirectories(Wix3Converter converter, string directory)
206 {
207 var errors = 0;
208
209 foreach (var searchPattern in this.SearchPatterns)
210 {
211 foreach (var sourceFilePath in GetFiles(directory, searchPattern))
212 {
213 var file = new FileInfo(sourceFilePath);
214
215 if (!this.ExemptFiles.Contains(file.Name.ToUpperInvariant()))
216 {
217 this.SearchPatternResults.Add(searchPattern);
218 errors += converter.ConvertFile(file.FullName, this.FixErrors);
219 }
220 }
221 }
222
223 if (this.SubDirectories)
224 {
225 foreach (var childDirectoryPath in Directory.GetDirectories(directory))
226 {
227 errors += this.InspectSubDirectories(converter, childDirectoryPath);
228 }
229 }
230
231 return errors;
232 }
233
234 /// <summary>
235 /// Parse the primary and secondary settings files.
236 /// </summary>
237 /// <param name="localSettingsFile1">The primary settings file.</param>
238 /// <param name="localSettingsFile2">The secondary settings file.</param>
239 private void ParseSettingsFiles(string localSettingsFile1, string localSettingsFile2)
240 {
241 if (null == localSettingsFile1 && null != localSettingsFile2)
242 {
243 throw new ArgumentException("Cannot specify a secondary settings file (set2) without a primary settings file (set1).", nameof(localSettingsFile2));
244 }
245
246 var settingsFile = localSettingsFile1;
247 while (null != settingsFile)
248 {
249 var doc = new XmlDocument();
250 doc.Load(settingsFile);
251
252 // get the types of tests that will have their errors displayed as warnings
253 var testsIgnoredElements = doc.SelectNodes("/Settings/IgnoreErrors/Test");
254 foreach (XmlElement test in testsIgnoredElements)
255 {
256 var key = test.GetAttribute("Id");
257 this.IgnoreErrors.Add(key);
258 }
259
260 // get the types of tests that will have their errors displayed as warnings
261 var testsAsWarningsElements = doc.SelectNodes("/Settings/ErrorsAsWarnings/Test");
262 foreach (XmlElement test in testsAsWarningsElements)
263 {
264 var key = test.GetAttribute("Id");
265 this.ErrorsAsWarnings.Add(key);
266 }
267
268 // get the exempt files
269 var localExemptFiles = doc.SelectNodes("/Settings/ExemptFiles/File");
270 foreach (XmlElement file in localExemptFiles)
271 {
272 var key = file.GetAttribute("Name").ToUpperInvariant();
273 this.ExemptFiles.Add(key);
274 }
275
276 settingsFile = localSettingsFile2;
277 localSettingsFile2 = null;
278 }
279 }
280 }
281}
diff --git a/src/WixToolset.Converters/ConverterExtensionCommandLine.cs b/src/WixToolset.Converters/ConverterExtensionCommandLine.cs
new file mode 100644
index 00000000..ed4b613e
--- /dev/null
+++ b/src/WixToolset.Converters/ConverterExtensionCommandLine.cs
@@ -0,0 +1,39 @@
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.Converters
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8 using WixToolset.Extensibility.Data;
9 using WixToolset.Extensibility.Services;
10
11 /// <summary>
12 /// Parses the "convert" command-line command. See <c>ConvertCommand</c> for
13 /// the bulk of the command-line processing.
14 /// </summary>
15 internal class ConverterExtensionCommandLine : BaseExtensionCommandLine
16 {
17 public ConverterExtensionCommandLine(IWixToolsetServiceProvider serviceProvider)
18 {
19 this.ServiceProvider = serviceProvider;
20 }
21
22 private IWixToolsetServiceProvider ServiceProvider { get; }
23
24 // TODO: Do something with CommandLineSwitches
25 public override IEnumerable<ExtensionCommandLineSwitch> CommandLineSwitches => base.CommandLineSwitches;
26
27 public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command)
28 {
29 command = null;
30
31 if ("convert".Equals(argument, StringComparison.OrdinalIgnoreCase))
32 {
33 command = new ConvertCommand(this.ServiceProvider);
34 }
35
36 return command != null;
37 }
38 }
39}
diff --git a/src/WixToolset.Converters/ConverterExtensionFactory.cs b/src/WixToolset.Converters/ConverterExtensionFactory.cs
new file mode 100644
index 00000000..51099e67
--- /dev/null
+++ b/src/WixToolset.Converters/ConverterExtensionFactory.cs
@@ -0,0 +1,30 @@
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.Converters
4{
5 using System;
6 using WixToolset.Extensibility;
7 using WixToolset.Extensibility.Services;
8
9 internal class ConverterExtensionFactory : IExtensionFactory
10 {
11 public ConverterExtensionFactory(IWixToolsetServiceProvider serviceProvider)
12 {
13 this.ServiceProvider = serviceProvider;
14 }
15
16 private IWixToolsetServiceProvider ServiceProvider { get; }
17
18 public bool TryCreateExtension(Type extensionType, out object extension)
19 {
20 extension = null;
21
22 if (extensionType == typeof(IExtensionCommandLine))
23 {
24 extension = new ConverterExtensionCommandLine(this.ServiceProvider);
25 }
26
27 return extension != null;
28 }
29 }
30}
diff --git a/src/WixToolset.Converters/WixToolset.Converters.csproj b/src/WixToolset.Converters/WixToolset.Converters.csproj
index d223cf44..1e443877 100644
--- a/src/WixToolset.Converters/WixToolset.Converters.csproj
+++ b/src/WixToolset.Converters/WixToolset.Converters.csproj
@@ -20,7 +20,7 @@
20 </ItemGroup> 20 </ItemGroup>
21 21
22 <ItemGroup> 22 <ItemGroup>
23 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/> 23 <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
24 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> 24 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" />
25 </ItemGroup> 25 </ItemGroup>
26</Project> 26</Project>
diff --git a/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs b/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs
new file mode 100644
index 00000000..afc33f62
--- /dev/null
+++ b/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs
@@ -0,0 +1,17 @@
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.Converters
4{
5 using WixToolset.Extensibility.Services;
6
7 public static class WixToolsetCoreServiceProviderExtensions
8 {
9 public static IWixToolsetCoreServiceProvider AddConverter(this IWixToolsetCoreServiceProvider serviceProvider)
10 {
11 var extensionManager = serviceProvider.GetService<IExtensionManager>();
12 extensionManager.Add(typeof(ConverterExtensionFactory).Assembly);
13
14 return serviceProvider;
15 }
16 }
17}
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject
new file mode 100644
index 00000000..bb70cf0f
--- /dev/null
+++ b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject
@@ -0,0 +1,9 @@
1<ProjectConfiguration>
2 <Settings>
3 <IgnoredTests>
4 <NamedTestSelector>
5 <TestName>WixToolsetTest.Converters.Tupleizer.ConvertTuplesFixture.CanLoadWixoutAndConvertToIntermediate</TestName>
6 </NamedTestSelector>
7 </IgnoredTests>
8 </Settings>
9</ProjectConfiguration> \ No newline at end of file