diff options
author | Rob Mensching <rob@firegiant.com> | 2017-08-15 01:31:51 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-08-15 01:31:51 -0700 |
commit | 4418bd52f1fca52a0d8d5f5b60abd2fdfc7146bd (patch) | |
tree | 02338abc93fb2e065c8717a84520d5ea8c7ea06c /src | |
parent | 0358780c77469974dd8bc87840364e790ccecc29 (diff) | |
download | wix-4418bd52f1fca52a0d8d5f5b60abd2fdfc7146bd.tar.gz wix-4418bd52f1fca52a0d8d5f5b60abd2fdfc7146bd.tar.bz2 wix-4418bd52f1fca52a0d8d5f5b60abd2fdfc7146bd.zip |
Migrate MsgGen
Diffstat (limited to 'src')
-rw-r--r-- | src/WixBuildTools.MsgGen/AssemblyInfo.cs | 8 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/GenerateMessageFiles.cs | 250 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/MsgGen.cs | 261 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/WixBuildTools.MsgGen.csproj | 22 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/Xsd/messages.xsd | 101 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/build/WixBuildTools.MsgGen.targets | 102 | ||||
-rw-r--r-- | src/WixBuildTools.MsgGen/buildCrossTargeting/WixBuildTools.MsgGen.targets | 6 |
7 files changed, 750 insertions, 0 deletions
diff --git a/src/WixBuildTools.MsgGen/AssemblyInfo.cs b/src/WixBuildTools.MsgGen/AssemblyInfo.cs new file mode 100644 index 00000000..378adbf0 --- /dev/null +++ b/src/WixBuildTools.MsgGen/AssemblyInfo.cs | |||
@@ -0,0 +1,8 @@ | |||
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 | using System.Reflection; | ||
4 | |||
5 | // General Information about an assembly is controlled through the following | ||
6 | // set of attributes. Change these attribute values to modify the information | ||
7 | // associated with an assembly. | ||
8 | [assembly: AssemblyCulture("")] | ||
diff --git a/src/WixBuildTools.MsgGen/GenerateMessageFiles.cs b/src/WixBuildTools.MsgGen/GenerateMessageFiles.cs new file mode 100644 index 00000000..6f51dbf9 --- /dev/null +++ b/src/WixBuildTools.MsgGen/GenerateMessageFiles.cs | |||
@@ -0,0 +1,250 @@ | |||
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 WixBuildTools.MsgGen | ||
4 | { | ||
5 | using System; | ||
6 | using System.CodeDom; | ||
7 | using System.Collections; | ||
8 | using System.Globalization; | ||
9 | using System.Reflection; | ||
10 | using System.Resources; | ||
11 | using System.Xml; | ||
12 | |||
13 | /// <summary> | ||
14 | /// Message files generation class. | ||
15 | /// </summary> | ||
16 | public class GenerateMessageFiles | ||
17 | { | ||
18 | /// <summary> | ||
19 | /// Generate the message files. | ||
20 | /// </summary> | ||
21 | /// <param name="messagesDoc">Input Xml document containing message definitions.</param> | ||
22 | /// <param name="codeCompileUnit">CodeDom container.</param> | ||
23 | /// <param name="resourceWriter">Writer for default resource file.</param> | ||
24 | public static void Generate(XmlDocument messagesDoc, CodeCompileUnit codeCompileUnit, ResourceWriter resourceWriter) | ||
25 | { | ||
26 | Hashtable usedNumbers = new Hashtable(); | ||
27 | |||
28 | if (null == messagesDoc) | ||
29 | { | ||
30 | throw new ArgumentNullException("messagesDoc"); | ||
31 | } | ||
32 | |||
33 | if (null == codeCompileUnit) | ||
34 | { | ||
35 | throw new ArgumentNullException("codeCompileUnit"); | ||
36 | } | ||
37 | |||
38 | if (null == resourceWriter) | ||
39 | { | ||
40 | throw new ArgumentNullException("resourceWriter"); | ||
41 | } | ||
42 | |||
43 | string namespaceAttr = messagesDoc.DocumentElement.GetAttribute("Namespace"); | ||
44 | string resourcesAttr = messagesDoc.DocumentElement.GetAttribute("Resources"); | ||
45 | |||
46 | // namespace | ||
47 | CodeNamespace messagesNamespace = new CodeNamespace(namespaceAttr); | ||
48 | codeCompileUnit.Namespaces.Add(messagesNamespace); | ||
49 | |||
50 | // imports | ||
51 | messagesNamespace.Imports.Add(new CodeNamespaceImport("System")); | ||
52 | messagesNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); | ||
53 | messagesNamespace.Imports.Add(new CodeNamespaceImport("System.Resources")); | ||
54 | if (namespaceAttr != "WixToolset.Data") | ||
55 | { | ||
56 | messagesNamespace.Imports.Add(new CodeNamespaceImport("WixToolset.Data")); | ||
57 | } | ||
58 | |||
59 | foreach (XmlElement classElement in messagesDoc.DocumentElement.ChildNodes) | ||
60 | { | ||
61 | string className = classElement.GetAttribute("Name"); | ||
62 | string baseContainerName = classElement.GetAttribute("BaseContainerName"); | ||
63 | string containerName = classElement.GetAttribute("ContainerName"); | ||
64 | string messageLevel = classElement.GetAttribute("Level"); | ||
65 | |||
66 | // message container class | ||
67 | messagesNamespace.Types.Add(CreateContainer(namespaceAttr, baseContainerName, containerName, messageLevel, resourcesAttr)); | ||
68 | |||
69 | // class | ||
70 | CodeTypeDeclaration messagesClass = new CodeTypeDeclaration(className); | ||
71 | messagesClass.TypeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed; | ||
72 | messagesNamespace.Types.Add(messagesClass); | ||
73 | |||
74 | // private constructor (needed since all methods in this class are static) | ||
75 | CodeConstructor constructor = new CodeConstructor(); | ||
76 | constructor.Attributes = MemberAttributes.Private; | ||
77 | constructor.ReturnType = null; | ||
78 | messagesClass.Members.Add(constructor); | ||
79 | |||
80 | // messages | ||
81 | foreach (XmlElement messageElement in classElement.ChildNodes) | ||
82 | { | ||
83 | int number; | ||
84 | string id = messageElement.GetAttribute("Id"); | ||
85 | string numberString = messageElement.GetAttribute("Number"); | ||
86 | bool sourceLineNumbers = true; | ||
87 | |||
88 | // determine the message number (and ensure it was set properly) | ||
89 | if (0 < numberString.Length) | ||
90 | { | ||
91 | number = Convert.ToInt32(numberString, CultureInfo.InvariantCulture); | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | throw new ApplicationException(String.Format("Message number must be assigned for {0} '{1}'.", containerName, id)); | ||
96 | } | ||
97 | |||
98 | // check for message number collisions | ||
99 | if (usedNumbers.Contains(number)) | ||
100 | { | ||
101 | throw new ApplicationException(String.Format("Collision detected between two or more messages with number '{0}'.", number)); | ||
102 | } | ||
103 | |||
104 | usedNumbers.Add(number, null); | ||
105 | |||
106 | if ("no" == messageElement.GetAttribute("SourceLineNumbers")) | ||
107 | { | ||
108 | sourceLineNumbers = false; | ||
109 | } | ||
110 | |||
111 | int instanceCount = 0; | ||
112 | foreach (XmlElement instanceElement in messageElement.ChildNodes) | ||
113 | { | ||
114 | string formatString = instanceElement.InnerText.Trim(); | ||
115 | string resourceName = String.Concat(className, "_", id, "_", (++instanceCount).ToString()); | ||
116 | |||
117 | // create a resource | ||
118 | resourceWriter.AddResource(resourceName, formatString); | ||
119 | |||
120 | // create method | ||
121 | CodeMemberMethod method = new CodeMemberMethod(); | ||
122 | method.ReturnType = new CodeTypeReference(baseContainerName); | ||
123 | method.Attributes = MemberAttributes.Public | MemberAttributes.Static; | ||
124 | messagesClass.Members.Add(method); | ||
125 | |||
126 | // method name | ||
127 | method.Name = id; | ||
128 | |||
129 | // return statement | ||
130 | CodeMethodReturnStatement stmt = new CodeMethodReturnStatement(); | ||
131 | method.Statements.Add(stmt); | ||
132 | |||
133 | // return statement expression | ||
134 | CodeObjectCreateExpression expr = new CodeObjectCreateExpression(); | ||
135 | stmt.Expression = expr; | ||
136 | |||
137 | // new struct | ||
138 | expr.CreateType = new CodeTypeReference(containerName); | ||
139 | |||
140 | // optionally have sourceLineNumbers as the first parameter | ||
141 | if (sourceLineNumbers) | ||
142 | { | ||
143 | // sourceLineNumbers parameter | ||
144 | expr.Parameters.Add(new CodeArgumentReferenceExpression("sourceLineNumbers")); | ||
145 | } | ||
146 | else | ||
147 | { | ||
148 | expr.Parameters.Add(new CodePrimitiveExpression(null)); | ||
149 | } | ||
150 | |||
151 | // message number parameter | ||
152 | expr.Parameters.Add(new CodePrimitiveExpression(number)); | ||
153 | |||
154 | // resource name parameter | ||
155 | expr.Parameters.Add(new CodePrimitiveExpression(resourceName)); | ||
156 | |||
157 | // optionally have sourceLineNumbers as the first parameter | ||
158 | if (sourceLineNumbers) | ||
159 | { | ||
160 | method.Parameters.Add(new CodeParameterDeclarationExpression("SourceLineNumber", "sourceLineNumbers")); | ||
161 | } | ||
162 | |||
163 | foreach (XmlNode parameterNode in instanceElement.ChildNodes) | ||
164 | { | ||
165 | XmlElement parameterElement; | ||
166 | |||
167 | if (null != (parameterElement = parameterNode as XmlElement)) | ||
168 | { | ||
169 | string type = parameterElement.GetAttribute("Type"); | ||
170 | string name = parameterElement.GetAttribute("Name"); | ||
171 | |||
172 | // method parameter | ||
173 | method.Parameters.Add(new CodeParameterDeclarationExpression(type, name)); | ||
174 | |||
175 | // String.Format parameter | ||
176 | expr.Parameters.Add(new CodeArgumentReferenceExpression(name)); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /// <summary> | ||
185 | /// Create message container class. | ||
186 | /// </summary> | ||
187 | /// <param name="namespaceName">Namespace to use for resources stream.</param> | ||
188 | /// <param name="baseContainerName">Name of the base message container class.</param> | ||
189 | /// <param name="containerName">Name of the message container class.</param> | ||
190 | /// <param name="messageLevel">Message level of for the message.</param> | ||
191 | /// <param name="resourcesName">Name of the resources stream (will get namespace prepended).</param> | ||
192 | /// <returns>Message container class CodeDom object.</returns> | ||
193 | private static CodeTypeDeclaration CreateContainer(string namespaceName, string baseContainerName, string containerName, string messageLevel, string resourcesName) | ||
194 | { | ||
195 | CodeTypeDeclaration messageContainer = new CodeTypeDeclaration(); | ||
196 | |||
197 | messageContainer.Name = containerName; | ||
198 | messageContainer.BaseTypes.Add(new CodeTypeReference(baseContainerName)); | ||
199 | |||
200 | // constructor | ||
201 | CodeConstructor constructor = new CodeConstructor(); | ||
202 | constructor.Attributes = MemberAttributes.Public; | ||
203 | constructor.ReturnType = null; | ||
204 | messageContainer.Members.Add(constructor); | ||
205 | |||
206 | CodeMemberField resourceManager = new CodeMemberField(); | ||
207 | resourceManager.Attributes = MemberAttributes.Private | MemberAttributes.Static; | ||
208 | resourceManager.Name = "resourceManager"; | ||
209 | resourceManager.Type = new CodeTypeReference("ResourceManager"); | ||
210 | resourceManager.InitExpression = new CodeObjectCreateExpression("ResourceManager", new CodeSnippetExpression(String.Format("\"{0}.{1}\"", namespaceName, resourcesName)), new CodeSnippetExpression("Assembly.GetExecutingAssembly()")); | ||
211 | messageContainer.Members.Add(resourceManager); | ||
212 | |||
213 | // constructor parameters | ||
214 | constructor.Parameters.Add(new CodeParameterDeclarationExpression("SourceLineNumber", "sourceLineNumbers")); | ||
215 | constructor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "id")); | ||
216 | constructor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "resourceName")); | ||
217 | CodeParameterDeclarationExpression messageArgsParam = new CodeParameterDeclarationExpression("params object[]", "messageArgs"); | ||
218 | constructor.Parameters.Add(messageArgsParam); | ||
219 | |||
220 | constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("sourceLineNumbers")); | ||
221 | constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("id")); | ||
222 | constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("resourceName")); | ||
223 | constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("messageArgs")); | ||
224 | |||
225 | // assign base.Level if messageLevel is specified | ||
226 | if (!String.IsNullOrEmpty(messageLevel)) | ||
227 | { | ||
228 | CodePropertyReferenceExpression levelReference = new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), "Level"); | ||
229 | CodeFieldReferenceExpression messageLevelField = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("MessageLevel"), messageLevel); | ||
230 | constructor.Statements.Add(new CodeAssignStatement(levelReference, messageLevelField)); | ||
231 | } | ||
232 | |||
233 | // Assign base.ResourceManager property | ||
234 | CodePropertyReferenceExpression baseResourceManagerReference = new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), "ResourceManager"); | ||
235 | CodeFieldReferenceExpression resourceManagerField = new CodeFieldReferenceExpression(null, "resourceManager"); | ||
236 | constructor.Statements.Add(new CodeAssignStatement(baseResourceManagerReference, resourceManagerField)); | ||
237 | |||
238 | //CodeMemberProperty resourceManagerProperty = new CodeMemberProperty(); | ||
239 | //resourceManagerProperty.Attributes = MemberAttributes.Public | MemberAttributes.Override; | ||
240 | //resourceManagerProperty.Name = "ResourceManager"; | ||
241 | //resourceManagerProperty.Type = new CodeTypeReference("ResourceManager"); | ||
242 | //CodeFieldReferenceExpression resourceManagerReference = new CodeFieldReferenceExpression(); | ||
243 | //resourceManagerReference.FieldName = "resourceManager"; | ||
244 | //resourceManagerProperty.GetStatements.Add(new CodeMethodReturnStatement(resourceManagerReference)); | ||
245 | //messageContainer.Members.Add(resourceManagerProperty); | ||
246 | |||
247 | return messageContainer; | ||
248 | } | ||
249 | } | ||
250 | } | ||
diff --git a/src/WixBuildTools.MsgGen/MsgGen.cs b/src/WixBuildTools.MsgGen/MsgGen.cs new file mode 100644 index 00000000..ff4a4a90 --- /dev/null +++ b/src/WixBuildTools.MsgGen/MsgGen.cs | |||
@@ -0,0 +1,261 @@ | |||
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 WixBuildTools.MsgGen | ||
4 | { | ||
5 | using Microsoft.CSharp; | ||
6 | using System; | ||
7 | using System.CodeDom; | ||
8 | using System.CodeDom.Compiler; | ||
9 | using System.Collections; | ||
10 | using System.IO; | ||
11 | using System.Reflection; | ||
12 | using System.Resources; | ||
13 | using System.Runtime.InteropServices; | ||
14 | using System.Xml; | ||
15 | using System.Xml.Schema; | ||
16 | |||
17 | /// <summary> | ||
18 | /// The main entry point for MsgGen. | ||
19 | /// </summary> | ||
20 | public class MsgGen | ||
21 | { | ||
22 | /// <summary> | ||
23 | /// The main entry point for MsgGen. | ||
24 | /// </summary> | ||
25 | /// <param name="args">Commandline arguments for the application.</param> | ||
26 | /// <returns>Returns the application error code.</returns> | ||
27 | [STAThread] | ||
28 | public static int Main(string[] args) | ||
29 | { | ||
30 | try | ||
31 | { | ||
32 | MsgGenMain msgGen = new MsgGenMain(args); | ||
33 | } | ||
34 | catch (Exception e) | ||
35 | { | ||
36 | Console.WriteLine("MsgGen.exe : fatal error MSGG0000: {0}\r\n\r\nStack Trace:\r\n{1}", e.Message, e.StackTrace); | ||
37 | if (e is NullReferenceException || e is SEHException) | ||
38 | { | ||
39 | throw; | ||
40 | } | ||
41 | return 2; | ||
42 | } | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | /// <summary> | ||
48 | /// Main class for MsgGen. | ||
49 | /// </summary> | ||
50 | private class MsgGenMain | ||
51 | { | ||
52 | private bool showLogo; | ||
53 | private bool showHelp; | ||
54 | |||
55 | private string sourceFile; | ||
56 | private string destClassFile; | ||
57 | private string destResourcesFile; | ||
58 | |||
59 | /// <summary> | ||
60 | /// Main method for the MsgGen application within the MsgGenMain class. | ||
61 | /// </summary> | ||
62 | /// <param name="args">Commandline arguments to the application.</param> | ||
63 | public MsgGenMain(string[] args) | ||
64 | { | ||
65 | this.showLogo = true; | ||
66 | this.showHelp = false; | ||
67 | |||
68 | this.sourceFile = null; | ||
69 | this.destClassFile = null; | ||
70 | this.destResourcesFile = null; | ||
71 | |||
72 | // parse the command line | ||
73 | this.ParseCommandLine(args); | ||
74 | |||
75 | if (null == this.sourceFile || null == this.destClassFile) | ||
76 | { | ||
77 | this.showHelp = true; | ||
78 | } | ||
79 | if (null == this.destResourcesFile) | ||
80 | { | ||
81 | this.destResourcesFile = Path.ChangeExtension(this.destClassFile, ".resources"); | ||
82 | } | ||
83 | |||
84 | // get the assemblies | ||
85 | Assembly msgGenAssembly = Assembly.GetExecutingAssembly(); | ||
86 | |||
87 | if (this.showLogo) | ||
88 | { | ||
89 | Console.WriteLine("Microsoft (R) Message Generation Tool version {0}", msgGenAssembly.GetName().Version.ToString()); | ||
90 | Console.WriteLine("Copyright (C) Microsoft Corporation 2004. All rights reserved."); | ||
91 | Console.WriteLine(); | ||
92 | } | ||
93 | if (this.showHelp) | ||
94 | { | ||
95 | Console.WriteLine(" usage: MsgGen.exe [-?] [-nologo] sourceFile destClassFile [destResourcesFile]"); | ||
96 | Console.WriteLine(); | ||
97 | Console.WriteLine(" -? this help information"); | ||
98 | Console.WriteLine(); | ||
99 | Console.WriteLine("For more information see: http://wix.sourceforge.net"); | ||
100 | return; // exit | ||
101 | } | ||
102 | |||
103 | // load the schema | ||
104 | XmlReader reader = null; | ||
105 | XmlSchemaCollection schemaCollection = null; | ||
106 | try | ||
107 | { | ||
108 | reader = new XmlTextReader(msgGenAssembly.GetManifestResourceStream("WixBuildTools.MsgGen.Xsd.messages.xsd")); | ||
109 | schemaCollection = new XmlSchemaCollection(); | ||
110 | schemaCollection.Add("http://schemas.microsoft.com/genmsgs/2004/07/messages", reader); | ||
111 | } | ||
112 | finally | ||
113 | { | ||
114 | reader.Close(); | ||
115 | } | ||
116 | |||
117 | // load the source file and process it | ||
118 | using (StreamReader sr = new StreamReader(this.sourceFile)) | ||
119 | { | ||
120 | XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.None); | ||
121 | XmlValidatingReader validatingReader = new XmlValidatingReader(sr.BaseStream, XmlNodeType.Document, context); | ||
122 | validatingReader.Schemas.Add(schemaCollection); | ||
123 | |||
124 | XmlDocument errorsDoc = new XmlDocument(); | ||
125 | errorsDoc.Load(validatingReader); | ||
126 | |||
127 | CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); | ||
128 | |||
129 | using (ResourceWriter resourceWriter = new ResourceWriter(this.destResourcesFile)) | ||
130 | { | ||
131 | GenerateMessageFiles.Generate(errorsDoc, codeCompileUnit, resourceWriter); | ||
132 | |||
133 | GenerateCSharpCode(codeCompileUnit, this.destClassFile); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /// <summary> | ||
139 | /// Generate the actual C# code. | ||
140 | /// </summary> | ||
141 | /// <param name="codeCompileUnit">The code DOM.</param> | ||
142 | /// <param name="destClassFile">Destination C# source file.</param> | ||
143 | public static void GenerateCSharpCode(CodeCompileUnit codeCompileUnit, string destClassFile) | ||
144 | { | ||
145 | // generate the code with the C# code provider | ||
146 | CSharpCodeProvider provider = new CSharpCodeProvider(); | ||
147 | |||
148 | // obtain an ICodeGenerator from the CodeDomProvider class | ||
149 | ICodeGenerator gen = provider.CreateGenerator(); | ||
150 | |||
151 | // create a TextWriter to a StreamWriter to the output file | ||
152 | using (StreamWriter sw = new StreamWriter(destClassFile)) | ||
153 | { | ||
154 | using (IndentedTextWriter tw = new IndentedTextWriter(sw, " ")) | ||
155 | { | ||
156 | CodeGeneratorOptions options = new CodeGeneratorOptions(); | ||
157 | |||
158 | // code generation options | ||
159 | options.BlankLinesBetweenMembers = true; | ||
160 | options.BracingStyle = "C"; | ||
161 | |||
162 | // generate source code using the code generator | ||
163 | gen.GenerateCodeFromCompileUnit(codeCompileUnit, tw, options); | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | /// <summary> | ||
169 | /// Parse the commandline arguments. | ||
170 | /// </summary> | ||
171 | /// <param name="args">Commandline arguments.</param> | ||
172 | private void ParseCommandLine(string[] args) | ||
173 | { | ||
174 | for (int i = 0; i < args.Length; ++i) | ||
175 | { | ||
176 | string arg = args[i]; | ||
177 | if (null == arg || "" == arg) // skip blank arguments | ||
178 | { | ||
179 | continue; | ||
180 | } | ||
181 | |||
182 | if ('-' == arg[0] || '/' == arg[0]) | ||
183 | { | ||
184 | string parameter = arg.Substring(1); | ||
185 | if ("nologo" == parameter) | ||
186 | { | ||
187 | this.showLogo = false; | ||
188 | } | ||
189 | else if ("?" == parameter || "help" == parameter) | ||
190 | { | ||
191 | this.showHelp = true; | ||
192 | } | ||
193 | } | ||
194 | else if ('@' == arg[0]) | ||
195 | { | ||
196 | using (StreamReader reader = new StreamReader(arg.Substring(1))) | ||
197 | { | ||
198 | string line; | ||
199 | ArrayList newArgs = new ArrayList(); | ||
200 | |||
201 | while (null != (line = reader.ReadLine())) | ||
202 | { | ||
203 | string newArg = ""; | ||
204 | bool betweenQuotes = false; | ||
205 | for (int j = 0; j < line.Length; ++j) | ||
206 | { | ||
207 | // skip whitespace | ||
208 | if (!betweenQuotes && (' ' == line[j] || '\t' == line[j])) | ||
209 | { | ||
210 | if ("" != newArg) | ||
211 | { | ||
212 | newArgs.Add(newArg); | ||
213 | newArg = null; | ||
214 | } | ||
215 | |||
216 | continue; | ||
217 | } | ||
218 | |||
219 | // if we're escaping a quote | ||
220 | if ('\\' == line[j] && '"' == line[j]) | ||
221 | { | ||
222 | ++j; | ||
223 | } | ||
224 | else if ('"' == line[j]) // if we've hit a new quote | ||
225 | { | ||
226 | betweenQuotes = !betweenQuotes; | ||
227 | continue; | ||
228 | } | ||
229 | |||
230 | newArg = String.Concat(newArg, line[j]); | ||
231 | } | ||
232 | if ("" != newArg) | ||
233 | { | ||
234 | newArgs.Add(newArg); | ||
235 | } | ||
236 | } | ||
237 | string[] ar = (string[])newArgs.ToArray(typeof(string)); | ||
238 | this.ParseCommandLine(ar); | ||
239 | } | ||
240 | } | ||
241 | else if (null == this.sourceFile) | ||
242 | { | ||
243 | this.sourceFile = arg; | ||
244 | } | ||
245 | else if (null == this.destClassFile) | ||
246 | { | ||
247 | this.destClassFile = arg; | ||
248 | } | ||
249 | else if (null == this.destResourcesFile) | ||
250 | { | ||
251 | this.destResourcesFile = arg; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | throw new ArgumentException(String.Format("Unknown argument '{0}'.", arg)); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | } | ||
diff --git a/src/WixBuildTools.MsgGen/WixBuildTools.MsgGen.csproj b/src/WixBuildTools.MsgGen/WixBuildTools.MsgGen.csproj new file mode 100644 index 00000000..7d7da64c --- /dev/null +++ b/src/WixBuildTools.MsgGen/WixBuildTools.MsgGen.csproj | |||
@@ -0,0 +1,22 @@ | |||
1 | <Project Sdk="Microsoft.NET.Sdk"> | ||
2 | |||
3 | <PropertyGroup> | ||
4 | <OutputType>Exe</OutputType> | ||
5 | <TargetFramework>net461</TargetFramework> | ||
6 | <IsTool>true</IsTool> | ||
7 | </PropertyGroup> | ||
8 | |||
9 | <ItemGroup> | ||
10 | <Content Include="build\WixBuildTools.MsgGen.targets" PackagePath="build\" /> | ||
11 | <Content Include="buildCrossTargeting\WixBuildTools.MsgGen.targets" PackagePath="buildCrossTargeting\" /> | ||
12 | </ItemGroup> | ||
13 | |||
14 | <ItemGroup> | ||
15 | <EmbeddedResource Include="Xsd\messages.xsd" /> | ||
16 | </ItemGroup> | ||
17 | |||
18 | <ItemGroup> | ||
19 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.0.37-beta" PrivateAssets="all" /> | ||
20 | </ItemGroup> | ||
21 | |||
22 | </Project> | ||
diff --git a/src/WixBuildTools.MsgGen/Xsd/messages.xsd b/src/WixBuildTools.MsgGen/Xsd/messages.xsd new file mode 100644 index 00000000..fd086502 --- /dev/null +++ b/src/WixBuildTools.MsgGen/Xsd/messages.xsd | |||
@@ -0,0 +1,101 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" | ||
6 | targetNamespace="http://schemas.microsoft.com/genmsgs/2004/07/messages" | ||
7 | xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages"> | ||
8 | <xs:annotation> | ||
9 | <xs:documentation> | ||
10 | Schema for describing any kind of messages. | ||
11 | </xs:documentation> | ||
12 | </xs:annotation> | ||
13 | |||
14 | <xs:element name="Messages"> | ||
15 | <xs:complexType> | ||
16 | <xs:sequence maxOccurs="unbounded"> | ||
17 | <xs:element ref="Class"/> | ||
18 | </xs:sequence> | ||
19 | <xs:attribute name="Namespace" type="xs:string" use="required"> | ||
20 | <xs:annotation><xs:documentation>Namespace of the generated class.</xs:documentation></xs:annotation> | ||
21 | </xs:attribute> | ||
22 | <xs:attribute name="Resources" type="xs:string" use="required"> | ||
23 | <xs:annotation><xs:documentation>Resources stream for messages. Will get namespace prepended to it.</xs:documentation></xs:annotation> | ||
24 | </xs:attribute> | ||
25 | </xs:complexType> | ||
26 | </xs:element> | ||
27 | |||
28 | <xs:element name="Class"> | ||
29 | <xs:complexType> | ||
30 | <xs:sequence minOccurs="0" maxOccurs="unbounded"> | ||
31 | <xs:element ref="Message"/> | ||
32 | </xs:sequence> | ||
33 | <xs:attribute name="Name" type="xs:string" use="required"> | ||
34 | <xs:annotation><xs:documentation>Name of the generated class.</xs:documentation></xs:annotation> | ||
35 | </xs:attribute> | ||
36 | <xs:attribute name="ContainerName" type="xs:string" use="required"> | ||
37 | <xs:annotation><xs:documentation>Name of the generated container class.</xs:documentation></xs:annotation> | ||
38 | </xs:attribute> | ||
39 | <xs:attribute name="BaseContainerName" type="xs:string" use="required"> | ||
40 | <xs:annotation><xs:documentation>Name of the base container class.</xs:documentation></xs:annotation> | ||
41 | </xs:attribute> | ||
42 | <xs:attribute name="Level" type="MessageLevelType"> | ||
43 | <xs:annotation><xs:documentation>Optional message level for this container class and derivative classes.</xs:documentation></xs:annotation> | ||
44 | </xs:attribute> | ||
45 | </xs:complexType> | ||
46 | </xs:element> | ||
47 | |||
48 | <xs:element name="Message"> | ||
49 | <xs:complexType> | ||
50 | <xs:sequence maxOccurs="unbounded"> | ||
51 | <xs:element ref="Instance"/> | ||
52 | </xs:sequence> | ||
53 | <xs:attribute name="Id" type="xs:string" use="required"> | ||
54 | <xs:annotation><xs:documentation>Name of the message type.</xs:documentation></xs:annotation> | ||
55 | </xs:attribute> | ||
56 | <xs:attribute name="Number" type="xs:integer" use="required"> | ||
57 | <xs:annotation><xs:documentation>Override the number for this message type.</xs:documentation></xs:annotation> | ||
58 | </xs:attribute> | ||
59 | <xs:attribute name="SourceLineNumbers" type="YesNoType"> | ||
60 | <xs:annotation><xs:documentation>Associate SourceLineNumbers with this message. The default value is "yes".</xs:documentation></xs:annotation> | ||
61 | </xs:attribute> | ||
62 | </xs:complexType> | ||
63 | </xs:element> | ||
64 | |||
65 | <xs:element name="Instance"> | ||
66 | <xs:complexType mixed="true"> | ||
67 | <xs:sequence minOccurs="0" maxOccurs="unbounded"> | ||
68 | <xs:element ref="Parameter"/> | ||
69 | </xs:sequence> | ||
70 | </xs:complexType> | ||
71 | </xs:element> | ||
72 | |||
73 | <xs:element name="Parameter"> | ||
74 | <xs:complexType> | ||
75 | <xs:attribute name="Type" type="xs:string" use="required"> | ||
76 | <xs:annotation><xs:documentation>Type of the parameter.</xs:documentation></xs:annotation> | ||
77 | </xs:attribute> | ||
78 | <xs:attribute name="Name" type="xs:string" use="required"> | ||
79 | <xs:annotation><xs:documentation>Name of the parameter.</xs:documentation></xs:annotation> | ||
80 | </xs:attribute> | ||
81 | </xs:complexType> | ||
82 | </xs:element> | ||
83 | |||
84 | <xs:simpleType name="YesNoType"> | ||
85 | <xs:annotation><xs:documentation>Values of this type will either be "yes" or "no".</xs:documentation></xs:annotation> | ||
86 | <xs:restriction base="xs:NMTOKEN"> | ||
87 | <xs:enumeration value="no"/> | ||
88 | <xs:enumeration value="yes"/> | ||
89 | </xs:restriction> | ||
90 | </xs:simpleType> | ||
91 | |||
92 | <xs:simpleType name="MessageLevelType"> | ||
93 | <xs:annotation><xs:documentation>The message level for this message which corresponds to the WixToolset.MessageLevel enumeration.</xs:documentation></xs:annotation> | ||
94 | <xs:restriction base="xs:NMTOKEN"> | ||
95 | <xs:enumeration value="Verbose"/> | ||
96 | <xs:enumeration value="Information"/> | ||
97 | <xs:enumeration value="Warning"/> | ||
98 | <xs:enumeration value="Error"/> | ||
99 | </xs:restriction> | ||
100 | </xs:simpleType> | ||
101 | </xs:schema> | ||
diff --git a/src/WixBuildTools.MsgGen/build/WixBuildTools.MsgGen.targets b/src/WixBuildTools.MsgGen/build/WixBuildTools.MsgGen.targets new file mode 100644 index 00000000..dfa7bcbe --- /dev/null +++ b/src/WixBuildTools.MsgGen/build/WixBuildTools.MsgGen.targets | |||
@@ -0,0 +1,102 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> | ||
5 | <PropertyGroup> | ||
6 | <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> | ||
7 | </PropertyGroup> | ||
8 | |||
9 | <ItemGroup> | ||
10 | <!--Provide support for setting type (BuildAction) from VS--> | ||
11 | <AvailableItemName Include="MsgGenSource" /> | ||
12 | </ItemGroup> | ||
13 | |||
14 | <PropertyGroup> | ||
15 | <MsgGenPath Condition=" '$(MsgGenPath)'=='' ">$(MSBuildThisFileDirectory)..\tools\</MsgGenPath> | ||
16 | </PropertyGroup> | ||
17 | |||
18 | <!-- | ||
19 | ================================================================================================ | ||
20 | MsgGen | ||
21 | |||
22 | Generates a .cs class file and a .resx file from an XML file. | ||
23 | |||
24 | [IN] | ||
25 | @(MsgGenSource) - The items to run through the MsgGen tool. | ||
26 | |||
27 | [OUT] | ||
28 | $(IntermediateOutputPath)%(Filename).cs - The generated .cs files to include in the compilation. | ||
29 | $(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName) - The generated .resources file to embed in the assembly. | ||
30 | ================================================================================================ | ||
31 | --> | ||
32 | <PropertyGroup> | ||
33 | <MsgGenDependsOn> | ||
34 | PrepareMsgGen | ||
35 | </MsgGenDependsOn> | ||
36 | <PrepareResourcesDependsOn> | ||
37 | MsgGen; | ||
38 | $(PrepareResourcesDependsOn) | ||
39 | </PrepareResourcesDependsOn> | ||
40 | </PropertyGroup> | ||
41 | <Target | ||
42 | Name="MsgGen" | ||
43 | BeforeTargets="PrepareResources" | ||
44 | DependsOnTargets="$(MsgGenDependsOn)" | ||
45 | Condition=" '@(MsgGenSource)' != '' " | ||
46 | Inputs="@(MsgGenSource)" | ||
47 | Outputs="$(IntermediateOutputPath)%(MsgGenSource.Filename).cs; | ||
48 | $(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName)"> | ||
49 | |||
50 | <Exec Command=""$(MsgGenPath)WixBuildTools.MsgGen.exe" -nologo "%(MsgGenSource.FullPath)" "$(MsgGenCsFile)" "$(MsgGenResourcesFile)"" | ||
51 | Outputs="$(MsgGenCsFile);$(MsgGenResourcesFile)" /> | ||
52 | |||
53 | <ItemGroup> | ||
54 | <!-- This will tell MSBuild to clean up the .cs and .resources file during a Clean build --> | ||
55 | <FileWrites Include="$(MsgGenCsFile);$(MsgGenResourcesFile)" /> | ||
56 | </ItemGroup> | ||
57 | </Target> | ||
58 | |||
59 | <!-- | ||
60 | ================================================================================================ | ||
61 | PrepareMsgGen | ||
62 | |||
63 | Creates properties and Include items for MsgGen. This must be separate from the MsgGen target | ||
64 | to workaround an MSBuild bug: AdditionalMetadata is ignored when the target is up-to-date. | ||
65 | |||
66 | ================================================================================================ | ||
67 | --> | ||
68 | <Target | ||
69 | Name="PrepareMsgGen" | ||
70 | Condition=" '@(MsgGenSource)' != '' "> | ||
71 | |||
72 | <CreateProperty Value="$(IntermediateOutputPath)%(MsgGenSource.Filename).cs"> | ||
73 | <Output TaskParameter="Value" PropertyName="MsgGenCsFile" /> | ||
74 | </CreateProperty> | ||
75 | |||
76 | <CreateProperty | ||
77 | Value="$(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName)" | ||
78 | Condition=" '%(MsgGenSource.ResourcesLogicalName)' != '' "> | ||
79 | |||
80 | <Output TaskParameter="Value" PropertyName="MsgGenResourcesFile" /> | ||
81 | </CreateProperty> | ||
82 | |||
83 | <!-- Add the generated .cs file to the list of source files to compile --> | ||
84 | <CreateItem | ||
85 | Include="$(MsgGenCsFile)" | ||
86 | AdditionalMetadata="Link=%(MsgGenCsFile.Filename)%(MsgGenCsFile.Extension)"> | ||
87 | |||
88 | <Output TaskParameter="Include" ItemName="Compile" /> | ||
89 | </CreateItem> | ||
90 | |||
91 | <!-- Add the generated .resources file to the list of resources to embed --> | ||
92 | <CreateItem | ||
93 | Include="$(MsgGenResourcesFile)" | ||
94 | AdditionalMetadata="Link=%(MsgGenResourcesFile.Filename)%(MsgGenResourcesFile.Extension); | ||
95 | LogicalName=%(MsgGenSource.ResourcesLogicalName)" | ||
96 | Condition=" '$(MsgGenResourcesFile)' != '' "> | ||
97 | |||
98 | <Output TaskParameter="Include" ItemName="EmbeddedResource" /> | ||
99 | </CreateItem> | ||
100 | </Target> | ||
101 | |||
102 | </Project> | ||
diff --git a/src/WixBuildTools.MsgGen/buildCrossTargeting/WixBuildTools.MsgGen.targets b/src/WixBuildTools.MsgGen/buildCrossTargeting/WixBuildTools.MsgGen.targets new file mode 100644 index 00000000..a3985af5 --- /dev/null +++ b/src/WixBuildTools.MsgGen/buildCrossTargeting/WixBuildTools.MsgGen.targets | |||
@@ -0,0 +1,6 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> | ||
5 | <Import Project="..\build\WixBuildTools.MsgGen.targets" /> | ||
6 | </Project> | ||