Skip to content

Commit 3c36762

Browse files
committed
[Csproj] Add support for texttemplates that use Host.SetFileExtension instead of output extension tags.
* Add dictionary helper GetOrAdd that will only create the new items on demand instead of having to create them at the function call site
1 parent f3e7be5 commit 3c36762

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

Sharpmake.Generators/VisualStudio/Csproj.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2170,7 +2170,7 @@ List<string> skipFiles
21702170
bool runtimeTemplate = project.AdditionalRuntimeTemplates.Contains(ttFile);
21712171
string expectedExtension =
21722172
runtimeTemplate ? ".cs" :
2173-
Util.GetTextTemplateDirectiveParam(Path.Combine(_projectPath, ttFile), "output", "extension") ?? ".cs";
2173+
Util.GetTextTemplateOutputExtension(Path.Combine(_projectPath, ttFile)) ?? ".cs";
21742174
if (!expectedExtension.StartsWith(".", StringComparison.Ordinal))
21752175
expectedExtension = "." + expectedExtension;
21762176
string fileNameWithoutExtension = ttFile.Substring(0, ttFile.Length - TTExtension.Length);

Sharpmake/Util.cs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,24 @@ public static int GetDeterministicHashCode(this string str)
9898
}
9999
}
100100

101+
static readonly Dictionary<string, Regex> _ttDirectiveRegexes = new Dictionary<string, Regex>();
102+
private static string GetTextTemplateDirectiveParam(string[] templateText, string directive, string paramName)
103+
{
104+
Regex regex = _ttDirectiveRegexes.GetValueOrAdd($"{directive}+{paramName}", () =>
105+
new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?<paramValue>.*?)"".*?#>", RegexOptions.Compiled)
106+
);
107+
108+
foreach (var line in templateText)
109+
{
110+
Match m = regex.Match(line);
111+
Group g = m.Groups["paramValue"];
112+
if (g != null && g.Success)
113+
return g.Value;
114+
}
115+
116+
return null;
117+
}
118+
101119
/// <summary>
102120
/// Finds the first occurrence of directive and returns the
103121
/// requested param value. Ex:
@@ -107,14 +125,33 @@ public static int GetDeterministicHashCode(this string str)
107125
/// and return ".txt"
108126
/// </summary>
109127
public static string GetTextTemplateDirectiveParam(string filePath, string directive, string paramName)
128+
{
129+
return GetTextTemplateDirectiveParam(File.ReadAllLines(filePath), directive, paramName);
130+
}
131+
132+
/// <summary>
133+
/// Finds the output type of a template, looking for both the directive form and the Host.SetFileExtension form
134+
/// will match:
135+
/// <#@ output extension=".txt" #>
136+
/// or
137+
/// Host.SetFileExtension(".txt")
138+
/// and return ".txt"
139+
/// </summary>
140+
///
141+
static readonly Regex _ttFileExtensionRegex = new Regex(@"Host.SetFileExtension\(""(?<paramValue>.*?)""\)", RegexOptions.Compiled);
142+
public static string GetTextTemplateOutputExtension(string filePath)
110143
{
111144
string[] templateText = File.ReadAllLines(filePath);
112145

113-
Regex regex = new Regex(@"<#@\s*?" + directive + @"\s+?.*?" + paramName + @"=""(?<paramValue>.*?)"".*?#>");
146+
var output = Util.GetTextTemplateDirectiveParam(templateText, "output", "extension");
147+
if (output != null)
148+
return output;
149+
150+
// alternatively look for host.SetFileExtension
114151

115152
foreach (var line in templateText)
116153
{
117-
Match m = regex.Match(line);
154+
Match m = _ttFileExtensionRegex.Match(line);
118155
Group g = m.Groups["paramValue"];
119156
if (g != null && g.Success)
120157
return g.Value;
@@ -1481,6 +1518,28 @@ public static Value GetValueOrAdd<Key, Value>(this IDictionary<Key, Value> dicti
14811518
return addValue;
14821519
}
14831520

1521+
/// <summary>
1522+
/// Extension GetValueOrAdd gets the value at the given key or adds at the given key the value provided by the func argument
1523+
/// </summary>
1524+
/// <typeparam name="Key">Type of the key</typeparam>
1525+
/// <typeparam name="Value">Type of the value</typeparam>
1526+
/// <param name="dictionary">dictionary in which to search</param>
1527+
/// <param name="key">key of the value</param>
1528+
/// <param name="addValueFunc">functon to create the new value</param>
1529+
/// <returns>the value at the given key (created or not in this call)</returns>
1530+
public static Value GetValueOrAdd<Key, Value>(this IDictionary<Key, Value> dictionary, Key key, Func<Value> addValueFunc)
1531+
{
1532+
Value value;
1533+
if (dictionary.TryGetValue(key, out value) == false)
1534+
{
1535+
value = addValueFunc();
1536+
dictionary.Add(key, value);
1537+
}
1538+
1539+
return value;
1540+
}
1541+
1542+
14841543
public static Value AddOrUpdateValue<Key, Value>(this IDictionary<Key, Value> dictionary, Key key, Value newValue, Func<Key, Value, Value, Value> update)
14851544
{
14861545
Value currentValue;

0 commit comments

Comments
 (0)