Skip to content

Commit f26e6c7

Browse files
committed
Fix building web templates in ASP.NET.
1 parent 1530b5f commit f26e6c7

File tree

2 files changed

+284
-0
lines changed

2 files changed

+284
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
From 399b294e6ebd3797513a22ab2213d5be512a162f Mon Sep 17 00:00:00 2001
2+
From: Chris Rummel <[email protected]>
3+
Date: Sun, 4 Apr 2021 20:04:41 -0500
4+
Subject: [PATCH 6/6] Add task for ASP.NET.
5+
6+
---
7+
.../src/GenerateFileFromTemplate.cs | 190 ++++++++++++++++++
8+
1 file changed, 190 insertions(+)
9+
create mode 100644 src/Microsoft.DotNet.Arcade.Sdk/src/GenerateFileFromTemplate.cs
10+
11+
diff --git a/src/Microsoft.DotNet.Arcade.Sdk/src/GenerateFileFromTemplate.cs b/src/Microsoft.DotNet.Arcade.Sdk/src/GenerateFileFromTemplate.cs
12+
new file mode 100644
13+
index 00000000..ef98d8fc
14+
--- /dev/null
15+
+++ b/src/Microsoft.DotNet.Arcade.Sdk/src/GenerateFileFromTemplate.cs
16+
@@ -0,0 +1,190 @@
17+
+// Copyright (c) .NET Foundation. All rights reserved.
18+
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
19+
+
20+
+using System;
21+
+using System.Collections.Generic;
22+
+using System.IO;
23+
+using System.Text;
24+
+using Microsoft.Build.Framework;
25+
+using Microsoft.Build.Utilities;
26+
+
27+
+namespace Microsoft.AspNetCore.BuildTools
28+
+{
29+
+ /// <summary>
30+
+ /// <para>
31+
+ /// Generates a new file at <see cref="OutputPath"/>.
32+
+ /// </para>
33+
+ /// <para>
34+
+ /// The <see cref="TemplateFile"/> can define variables for substitution using <see cref="Properties"/>.
35+
+ /// </para>
36+
+ /// <example>
37+
+ /// The input file might look like this:
38+
+ /// <code>
39+
+ /// 2 + 2 = ${Sum}
40+
+ /// </code>
41+
+ /// When the task is invoked like this, it will produce "2 + 2 = 4"
42+
+ /// <code>
43+
+ /// &lt;GenerateFileFromTemplate Properties="Sum=4;OtherValue=123;" ... &gt;
44+
+ /// </code>
45+
+ /// </example>
46+
+ /// </summary>
47+
+ public class GenerateFileFromTemplate : Task
48+
+ {
49+
+ /// <summary>
50+
+ /// The template file.
51+
+ /// Variable syntax: ${VarName}
52+
+ /// If your template file needs to output this format, you can escape the dollar sign with a backtick, e.g. `${NotReplaced}
53+
+ /// </summary>
54+
+ [Required]
55+
+ public string TemplateFile { get; set; }
56+
+
57+
+ /// <summary>
58+
+ /// The destination for the generated file.
59+
+ /// </summary>
60+
+ [Required]
61+
+ [Output]
62+
+ public string OutputPath { get; set; }
63+
+
64+
+ /// <summary>
65+
+ /// Key=value pairs of values
66+
+ /// </summary>
67+
+ [Required]
68+
+ public string[] Properties { get; set; }
69+
+
70+
+ public override bool Execute()
71+
+ {
72+
+ var outputPath = Path.GetFullPath(OutputPath.Replace('\\', '/'));
73+
+
74+
+ if (!File.Exists(TemplateFile))
75+
+ {
76+
+ Log.LogError($"File {TemplateFile} does not exist");
77+
+ return false;
78+
+ }
79+
+
80+
+ var values = MSBuildListSplitter.GetNamedProperties(Properties);
81+
+ var template = File.ReadAllText(TemplateFile);
82+
+
83+
+ var result = Replace(template, values);
84+
+ Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
85+
+ File.WriteAllText(outputPath, result);
86+
+
87+
+ return true;
88+
+ }
89+
+
90+
+ public string Replace(string template, IDictionary<string, string> values)
91+
+ {
92+
+ var sb = new StringBuilder();
93+
+ var varNameSb = new StringBuilder();
94+
+ var line = 1;
95+
+ for (var i = 0; i < template.Length; i++)
96+
+ {
97+
+ var ch = template[i];
98+
+ var nextCh = i + 1 >= template.Length
99+
+ ? '\0'
100+
+ : template[i + 1];
101+
+
102+
+ // count lines in the template file
103+
+ if (ch == '\n')
104+
+ {
105+
+ line++;
106+
+ }
107+
+
108+
+ if (ch == '`' && (nextCh == '$' || nextCh == '`'))
109+
+ {
110+
+ // skip the backtick for known escape characters
111+
+ i++;
112+
+ sb.Append(nextCh);
113+
+ continue;
114+
+ }
115+
+
116+
+ if (ch != '$' || nextCh != '{')
117+
+ {
118+
+ // variables begin with ${. Moving on.
119+
+ sb.Append(ch);
120+
+ continue;
121+
+ }
122+
+
123+
+ varNameSb.Clear();
124+
+ i += 2;
125+
+ for (; i < template.Length; i++)
126+
+ {
127+
+ ch = template[i];
128+
+ if (ch != '}')
129+
+ {
130+
+ varNameSb.Append(ch);
131+
+ }
132+
+ else
133+
+ {
134+
+ // Found the end of the variable substitution
135+
+ var varName = varNameSb.ToString();
136+
+ if (values.TryGetValue(varName, out var value))
137+
+ {
138+
+ sb.Append(value);
139+
+ }
140+
+ else
141+
+ {
142+
+ Log.LogWarning(null, null, null, TemplateFile,
143+
+ line, 0, 0, 0,
144+
+ message: $"No property value is available for '{varName}'");
145+
+ }
146+
+
147+
+ varNameSb.Clear();
148+
+ break;
149+
+ }
150+
+ }
151+
+
152+
+ if (varNameSb.Length > 0)
153+
+ {
154+
+ Log.LogWarning(null, null, null, TemplateFile,
155+
+ line, 0, 0, 0,
156+
+ message: "Expected closing bracket for variable placeholder. No substitution will be made.");
157+
+ sb.Append("${").Append(varNameSb.ToString());
158+
+ }
159+
+ }
160+
+
161+
+ return sb.ToString();
162+
+ }
163+
+ }
164+
+
165+
+ internal static class MSBuildListSplitter
166+
+ {
167+
+ public static IDictionary<string, string> GetNamedProperties(string input)
168+
+ {
169+
+ if (string.IsNullOrEmpty(input))
170+
+ {
171+
+ return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
172+
+ }
173+
+
174+
+ return GetNamedProperties(input.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
175+
+ }
176+
+
177+
+ public static IDictionary<string, string> GetNamedProperties(string[] input)
178+
+ {
179+
+ var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
180+
+ if (input == null)
181+
+ {
182+
+ return values;
183+
+ }
184+
+
185+
+ foreach (var item in input)
186+
+ {
187+
+ var splitIdx = item.IndexOf('=');
188+
+ if (splitIdx < 0)
189+
+ {
190+
+ continue;
191+
+ }
192+
+
193+
+ var key = item.Substring(0, splitIdx).Trim();
194+
+ if (string.IsNullOrEmpty(key))
195+
+ {
196+
+ continue;
197+
+ }
198+
+
199+
+ var value = item.Substring(splitIdx + 1);
200+
+ values[key] = value;
201+
+ }
202+
+
203+
+ return values;
204+
+ }
205+
+ }
206+
+}
207+
--
208+
2.18.0
209+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
From 42a4cb1b80128e87e014d91bbb349a8057e308e7 Mon Sep 17 00:00:00 2001
2+
From: Chris Rummel <[email protected]>
3+
Date: Sun, 4 Apr 2021 17:38:54 -0500
4+
Subject: [PATCH 20/20] Try to get templates to build
5+
6+
---
7+
src/ProjectTemplates/GenerateContent.targets | 2 ++
8+
.../Microsoft.DotNet.Web.Client.ItemTemplates.csproj | 1 +
9+
.../Web.ItemTemplates/Microsoft.DotNet.Web.ItemTemplates.csproj | 1 +
10+
.../Microsoft.DotNet.Web.ProjectTemplates.csproj | 1 +
11+
.../Microsoft.DotNet.Web.Spa.ProjectTemplates.csproj | 1 +
12+
5 files changed, 6 insertions(+)
13+
14+
diff --git a/src/ProjectTemplates/GenerateContent.targets b/src/ProjectTemplates/GenerateContent.targets
15+
index 0de73148b3..c748e69512 100644
16+
--- a/src/ProjectTemplates/GenerateContent.targets
17+
+++ b/src/ProjectTemplates/GenerateContent.targets
18+
@@ -1,4 +1,6 @@
19+
<Project>
20+
+ <UsingTask TaskName="Microsoft.AspNetCore.BuildTools.GenerateFileFromTemplate" AssemblyFile="$(ArcadeSdkBuildTasksAssembly)" />
21+
+
22+
<PropertyGroup>
23+
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
24+
25+
diff --git a/src/ProjectTemplates/Web.Client.ItemTemplates/Microsoft.DotNet.Web.Client.ItemTemplates.csproj b/src/ProjectTemplates/Web.Client.ItemTemplates/Microsoft.DotNet.Web.Client.ItemTemplates.csproj
26+
index 38c7fb6b62..55867f6524 100644
27+
--- a/src/ProjectTemplates/Web.Client.ItemTemplates/Microsoft.DotNet.Web.Client.ItemTemplates.csproj
28+
+++ b/src/ProjectTemplates/Web.Client.ItemTemplates/Microsoft.DotNet.Web.Client.ItemTemplates.csproj
29+
@@ -3,6 +3,7 @@
30+
<PropertyGroup>
31+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
32+
<Description>Web Client-Side File Templates for Microsoft Template Engine</Description>
33+
+ <ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
34+
</PropertyGroup>
35+
36+
</Project>
37+
diff --git a/src/ProjectTemplates/Web.ItemTemplates/Microsoft.DotNet.Web.ItemTemplates.csproj b/src/ProjectTemplates/Web.ItemTemplates/Microsoft.DotNet.Web.ItemTemplates.csproj
38+
index 20e88246ec..74305ab084 100644
39+
--- a/src/ProjectTemplates/Web.ItemTemplates/Microsoft.DotNet.Web.ItemTemplates.csproj
40+
+++ b/src/ProjectTemplates/Web.ItemTemplates/Microsoft.DotNet.Web.ItemTemplates.csproj
41+
@@ -3,6 +3,7 @@
42+
<PropertyGroup>
43+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
44+
<Description>Web File Templates for Microsoft Template Engine.</Description>
45+
+ <ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
46+
</PropertyGroup>
47+
48+
</Project>
49+
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
50+
index 5b39b0fd0d..ad935040a2 100644
51+
--- a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
52+
+++ b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
53+
@@ -5,6 +5,7 @@
54+
<PackageId>Microsoft.DotNet.Web.ProjectTemplates.$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion)</PackageId>
55+
<Description>ASP.NET Core Web Template Pack for Microsoft Template Engine</Description>
56+
<ComponentsWebAssemblyProjectsRoot>$(RepoRoot)src\Components\WebAssembly\</ComponentsWebAssemblyProjectsRoot>
57+
+ <ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
58+
</PropertyGroup>
59+
60+
<PropertyGroup>
61+
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/Microsoft.DotNet.Web.Spa.ProjectTemplates.csproj b/src/ProjectTemplates/Web.Spa.ProjectTemplates/Microsoft.DotNet.Web.Spa.ProjectTemplates.csproj
62+
index 62e1c07e7d..1d5f276ae0 100644
63+
--- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/Microsoft.DotNet.Web.Spa.ProjectTemplates.csproj
64+
+++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/Microsoft.DotNet.Web.Spa.ProjectTemplates.csproj
65+
@@ -7,6 +7,7 @@
66+
<PackageTags>$(PackageTags);spa</PackageTags>
67+
<!-- By default Pack will exclude files that start with '.', we want to include those files -->
68+
<NoDefaultExcludes>true</NoDefaultExcludes>
69+
+ <ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
70+
</PropertyGroup>
71+
72+
<PropertyGroup>
73+
--
74+
2.18.0
75+

0 commit comments

Comments
 (0)