diff options
author | Rob Mensching <rob@firegiant.com> | 2020-06-06 15:40:38 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2020-06-08 16:40:24 -0700 |
commit | 60c9a081d337bf432a61bee6784d4c05da1a049a (patch) | |
tree | d77a4393283b0b80b84e5c36747d5cfa42549e0e /src | |
parent | a783c83bc1e1efaf054d957c8a097386cb8f6b4a (diff) | |
download | wix-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')
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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | ||