summaryrefslogtreecommitdiff
path: root/src/internal/MessagesToMessages/Program.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 16:36:39 -0700
committerRob Mensching <rob@firegiant.com>2021-04-22 16:50:15 -0700
commit6a24996a2e831cfe402398af65b31fb1ecd575a9 (patch)
treee377370df4bc7901745c6b5f50268fa665edb3f8 /src/internal/MessagesToMessages/Program.cs
parent2587a8b46b705d53156f5cd1bd866f855049081d (diff)
downloadwix-6a24996a2e831cfe402398af65b31fb1ecd575a9.tar.gz
wix-6a24996a2e831cfe402398af65b31fb1ecd575a9.tar.bz2
wix-6a24996a2e831cfe402398af65b31fb1ecd575a9.zip
Move WixBuildTools into internal
Diffstat (limited to 'src/internal/MessagesToMessages/Program.cs')
-rw-r--r--src/internal/MessagesToMessages/Program.cs261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/internal/MessagesToMessages/Program.cs b/src/internal/MessagesToMessages/Program.cs
new file mode 100644
index 00000000..2d5a3777
--- /dev/null
+++ b/src/internal/MessagesToMessages/Program.cs
@@ -0,0 +1,261 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Xml.Linq;
7
8namespace MessagesToMessages
9{
10 class Program
11 {
12 static readonly XNamespace ns = "http://schemas.microsoft.com/genmsgs/2004/07/messages";
13 static readonly XName ClassDefinition = ns + "Class";
14 static readonly XName MessageDefinition = ns + "Message";
15 static readonly XName InstanceDefinition = ns + "Instance";
16 static readonly XName ParameterDefinition = ns + "Parameter";
17 static readonly XName Id = "Id";
18 static readonly XName Level = "Level";
19 static readonly XName Number = "Number";
20 static readonly XName SourceLineNumbers = "SourceLineNumbers";
21 static readonly XName Type = "Type";
22 static readonly XName Name = "Name";
23
24 static void Main(string[] args)
25 {
26 if (args.Length == 0)
27 {
28 return;
29 }
30 else if (args.Length < 2)
31 {
32 Console.WriteLine("Need to specify output folder as well.");
33 }
34 else if (!Directory.Exists(args[1]))
35 {
36 Console.WriteLine("Output folder does not exist: {0}", args[1]);
37 }
38
39 var messages = ReadXml(Path.GetFullPath(args[0]));
40
41 foreach (var m in messages.GroupBy(m => m.Level))
42 {
43 var className = m.First().ClassName;
44 var result = GenerateCs(className, m.Key, m);
45
46 var path = Path.Combine(args[1], className + ".cs");
47 File.WriteAllText(path, result);
48 }
49 }
50
51 private static IEnumerable<Message> ReadXml(string inputPath)
52 {
53 var doc = XDocument.Load(inputPath);
54
55 foreach (var xClass in doc.Root.Descendants(ClassDefinition))
56 {
57 var name = xClass.Attribute(Name)?.Value;
58 var level = xClass.Attribute(Level)?.Value;
59
60 if (String.IsNullOrEmpty(name))
61 {
62 name = level + "Messages";
63 }
64 if (String.IsNullOrEmpty(level))
65 {
66 if (name.EndsWith("Errors", StringComparison.InvariantCultureIgnoreCase))
67 {
68 level = "Error";
69 }
70 else if (name.EndsWith("Verboses", StringComparison.InvariantCultureIgnoreCase))
71 {
72 level = "Verbose";
73 }
74 else if (name.EndsWith("Warnings", StringComparison.InvariantCultureIgnoreCase))
75 {
76 level = "Warning";
77 }
78 }
79
80 var unique = new HashSet<string>();
81 var lastNumber = 0;
82 foreach (var xMessage in xClass.Elements(MessageDefinition))
83 {
84 var id = xMessage.Attribute(Id).Value;
85
86 if (!unique.Add(id))
87 {
88 Console.WriteLine("Duplicated message: {0}", id);
89 }
90
91 if (!Int32.TryParse(xMessage.Attribute(Number)?.Value, out var number))
92 {
93 number = lastNumber;
94 }
95 lastNumber = number + 1;
96
97 var sln = xMessage.Attribute(SourceLineNumbers)?.Value != "no";
98
99 var suffix = 0;
100 foreach (var xInstance in xMessage.Elements(InstanceDefinition))
101 {
102 var value = xInstance.Value.Trim();
103
104 var parameters = xInstance.Elements(ParameterDefinition).Select(ReadParameter).ToList();
105
106 yield return new Message { Id = id, ClassName = name, Level = level, Number = number, Parameters = parameters, SourceLineNumbers = sln, Value = value, Suffix = suffix == 0 ? String.Empty : suffix.ToString() };
107
108 ++suffix;
109 }
110 }
111 }
112 }
113
114 private static Parameter ReadParameter(XElement element)
115 {
116 var name = element.Attribute(Name)?.Value;
117 var type = element.Attribute(Type)?.Value ?? "string";
118
119 if (type.StartsWith("System."))
120 {
121 type = type.Substring(7);
122 }
123
124 switch (type)
125 {
126 case "String":
127 type = "string";
128 break;
129
130 case "Int32":
131 type = "int";
132 break;
133
134 case "Int64":
135 type = "long";
136 break;
137 }
138
139 return new Parameter { Name = name, Type = type };
140 }
141
142 private static string GenerateCs(string className, string level, IEnumerable<Message> messages)
143 {
144 var header = String.Join(Environment.NewLine,
145 "// 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.",
146 "",
147 "namespace WixToolset.Data",
148 "{",
149 " using System;",
150 " using System.Resources;",
151 "",
152 " public static class {0}",
153 " {");
154
155 var messageFormat = String.Join(Environment.NewLine,
156 " public static Message {0}({1})",
157 " {{",
158 " return Message({4}, Ids.{0}, \"{3}\"{2});",
159 " }}",
160 "");
161
162
163 var endMessagesFormat = String.Join(Environment.NewLine,
164 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)",
165 " {{",
166 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, format, args);",
167 " }}",
168 "",
169 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)",
170 " {{",
171 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, resourceManager, resourceName, args);",
172 " }}",
173 "",
174 " public enum Ids",
175 " {{");
176
177 var idEnumFormat =
178 " {0} = {1},";
179 var footer = String.Join(Environment.NewLine,
180 " }",
181 " }",
182 "}",
183 "");
184
185 var sb = new StringBuilder();
186
187 sb.AppendLine(header.Replace("{0}", className));
188
189 foreach (var message in messages.OrderBy(m => m.Id))
190 {
191 var paramsWithTypes = String.Join(", ", message.Parameters.Select(p => $"{p.Type} {p.Name}"));
192 var paramsWithoutTypes = String.Join(", ", message.Parameters.Select(p => p.Name));
193
194 if (message.SourceLineNumbers)
195 {
196 paramsWithTypes = String.IsNullOrEmpty(paramsWithTypes)
197 ? "SourceLineNumber sourceLineNumbers"
198 : "SourceLineNumber sourceLineNumbers, " + paramsWithTypes;
199 }
200
201 if (!String.IsNullOrEmpty(paramsWithoutTypes))
202 {
203 paramsWithoutTypes = ", " + paramsWithoutTypes;
204 }
205
206 sb.AppendFormat(messageFormat, message.Id, paramsWithTypes, paramsWithoutTypes, ToCSharpString(message.Value), message.SourceLineNumbers ? "sourceLineNumbers" : "null");
207
208 sb.AppendLine();
209 }
210
211 sb.AppendFormat(endMessagesFormat, level);
212 sb.AppendLine();
213
214 var unique = new HashSet<int>();
215 foreach (var message in messages.OrderBy(m => m.Number))
216 {
217 if (unique.Add(message.Number))
218 {
219 sb.AppendFormat(idEnumFormat, message.Id, message.Number);
220 sb.AppendLine();
221 }
222 }
223
224 sb.Append(footer);
225
226 return sb.ToString();
227 }
228
229 private static string ToCSharpString(string value)
230 {
231 return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t");
232 }
233
234 private class Message
235 {
236 public string Id { get; set; }
237
238 public string Suffix { get; set; }
239
240 public string ClassName { get; set; }
241
242 public string Level { get; set; }
243
244 public int Number { get; set; }
245
246 public bool SourceLineNumbers { get; set; }
247
248 public string Value { get; set; }
249
250 public IEnumerable<Parameter> Parameters { get; set; }
251 }
252
253
254 private class Parameter
255 {
256 public string Name { get; set; }
257
258 public string Type { get; set; }
259 }
260 }
261}