From 22f5fcad95efac197a07b53c47761199579a7e13 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 11 Jan 2024 13:32:22 -0500 Subject: [PATCH 1/7] Add C# 9 to langversion helper --- .../Mono.TextTemplating.CodeCompilation/CSharpLangVersion.cs | 1 + .../CSharpLangVersionHelper.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersion.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersion.cs index 36b3c00..91343e2 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersion.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersion.cs @@ -22,5 +22,6 @@ enum CSharpLangVersion v10_0, v11_0, v12_0, + v13_0, Latest = 1024 // make sure value doesn't change as we add new C# versions } diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs index 0339575..c1f755b 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs @@ -48,6 +48,7 @@ public static bool IsLangVersionArg (string arg) => //https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history public static CSharpLangVersion FromNetCoreSdkVersion (SemVersion sdkVersion) => sdkVersion switch { + { Major: 9 } => CSharpLangVersion.v13_0, { Major: 8 } => CSharpLangVersion.v12_0, { Major: 7 } => CSharpLangVersion.v11_0, { Major: 6 } => CSharpLangVersion.v10_0, @@ -73,6 +74,7 @@ public static CSharpLangVersion FromNetCoreSdkVersion (SemVersion sdkVersion) CSharpLangVersion.v10_0 => "10.0", CSharpLangVersion.v11_0 => "11.0", CSharpLangVersion.v12_0 => "12.0", + CSharpLangVersion.v13_0 => "13.0", CSharpLangVersion.Latest => "latest", _ => throw new ArgumentException ($"Not a valid value: '{version}'", nameof (version)) }; From db044b13d7ec67b787ad641edcf9ee4e2c409dce Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 11 Jan 2024 13:35:25 -0500 Subject: [PATCH 2/7] Fix relative pragmas in build-time preprocessing --- .../TextTransformProcessor.cs | 5 ++-- .../Mono.TextTemplating/TemplateSettings.cs | 6 +++++ .../TemplatingEngine.CodeGeneration.cs | 25 ++++++++++++------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Mono.TextTemplating.Build/TextTransformProcessor.cs b/Mono.TextTemplating.Build/TextTransformProcessor.cs index e0eb29b..3854cd2 100644 --- a/Mono.TextTemplating.Build/TextTransformProcessor.cs +++ b/Mono.TextTemplating.Build/TextTransformProcessor.cs @@ -80,6 +80,9 @@ public static bool Process (TaskLoggingHelper taskLog, TemplateBuildState previo var pt = LoadTemplate (generator, inputFile, out var inputContent); TemplateSettings settings = TemplatingEngine.GetSettings (generator, pt); + settings.RelativeLinePragmas = true; + settings.RelativeLinePragmasBaseDirectory = Path.GetDirectoryName (preprocess.OutputFile); + settings.CodeGenerationOptions.UseRemotingCallContext = buildState.PreprocessTargetRuntimeIdentifier == ".NETFramework"; // FIXME: make these configurable, take relative path into account @@ -208,8 +211,6 @@ static MSBuildTemplateGenerator CreateGenerator (TemplateBuildState buildState) } } - generator.UseRelativeLinePragmas = true; - return generator; } diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs index 769285f..7e69276 100644 --- a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs +++ b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs @@ -69,6 +69,12 @@ public TemplateSettings () public string GetFullName () => string.IsNullOrEmpty (Namespace) ? Name : Namespace + "." + Name; internal CodeGenerationOptions CodeGenerationOptions { get; } = new CodeGenerationOptions (); + + /// + /// Base directory for calculation of relative line pragmas. + /// Internal until we clean up the settings API. + /// + internal string RelativeLinePragmasBaseDirectory { get; set; } } public class CustomDirective diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs index 2fdcf8f..b618f99 100644 --- a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs +++ b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs @@ -63,7 +63,16 @@ public static CodeCompileUnit GenerateCompileUnit (ITextTemplatingEngineHost hos static void GenerateTransformMethod (CodeTypeDeclaration templateType, TemplateSettings settings, ParsedTemplate pt, string templateFile, bool isOverride) { - string baseDirectory = Path.GetDirectoryName (templateFile); + string pragmasRelativeToDirectory = null; + + if (settings.RelativeLinePragmas) { + if (!string.IsNullOrEmpty (settings.RelativeLinePragmasBaseDirectory)) { + pragmasRelativeToDirectory = Path.GetFullPath (settings.RelativeLinePragmasBaseDirectory); + } + if (pragmasRelativeToDirectory is null && templateFile is not null) { + pragmasRelativeToDirectory = Path.GetDirectoryName (Path.GetFullPath (templateFile)); + } + } var transformMeth = Declare.Method ("TransformText").Returns ().AsVirtual (); @@ -87,16 +96,14 @@ static void GenerateTransformMethod (CodeTypeDeclaration templateType, TemplateS CodeStatement st = null; CodeLinePragma location = null; if (!settings.NoLinePragmas) { - var f = seg.StartLocation.FileName ?? templateFile; - if (!string.IsNullOrEmpty (f)) { - // FIXME: we need to know where the output file will be to make this work properly - if (settings.RelativeLinePragmas) { - f = FileUtil.AbsoluteToRelativePath (baseDirectory, f); - } else { - f = Path.GetFullPath (f); + var filename = seg.StartLocation.FileName ?? templateFile; + if (!string.IsNullOrEmpty (filename)) { + filename = Path.GetFullPath (filename); + if (pragmasRelativeToDirectory is not null) { + filename = FileUtil.AbsoluteToRelativePath (pragmasRelativeToDirectory, filename); } } - location = new CodeLinePragma (f, seg.StartLocation.Line); + location = new CodeLinePragma (filename, seg.StartLocation.Line); } switch (seg.Type) { case SegmentType.Block: From a11f6f9451b5f9c529908a0733144f3d8eec016e Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 11 Jan 2024 13:41:23 -0500 Subject: [PATCH 3/7] Add project system XAML When using CPS project system, fixes transform on save and displays relevant item metadata in VS property window. --- .../Mono.TextTemplating.Build.csproj | 20 +++++----- Mono.TextTemplating.Build/T4.BuildTools.props | 29 ++++++++------ Mono.TextTemplating.Build/T4PropertyPage.xaml | 39 +++++++++++++++++++ .../T4PropertySchema.xaml | 23 +++++++++++ 4 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 Mono.TextTemplating.Build/T4PropertyPage.xaml create mode 100644 Mono.TextTemplating.Build/T4PropertySchema.xaml diff --git a/Mono.TextTemplating.Build/Mono.TextTemplating.Build.csproj b/Mono.TextTemplating.Build/Mono.TextTemplating.Build.csproj index df1e20f..c75dc30 100644 --- a/Mono.TextTemplating.Build/Mono.TextTemplating.Build.csproj +++ b/Mono.TextTemplating.Build/Mono.TextTemplating.Build.csproj @@ -1,4 +1,4 @@ - + net48;net6.0 @@ -14,15 +14,15 @@ readme.md - - - <_PackageFiles Include="T4.BuildTools.props" PackagePath="build\$(PackageId).props" Pack="true" /> - <_PackageFiles Include="T4.BuildTools.targets" PackagePath="build\$(PackageId).targets" Pack="true" /> - <_PackageFiles Include="multitargeting.props" PackagePath="buildMultiTargeting\$(PackageId).props" Pack="true" /> - <_PackageFiles Include="multitargeting.targets" PackagePath="buildMultiTargeting\$(PackageId).targets" Pack="true" /> - <_PackageFiles Include="T4.BuildTools.targets.buildschema.json" PackagePath="build\$(PackageId).targets.buildschema.json" Pack="true" /> - - + + + + + + + + + diff --git a/Mono.TextTemplating.Build/T4.BuildTools.props b/Mono.TextTemplating.Build/T4.BuildTools.props index b67947a..40c97a1 100644 --- a/Mono.TextTemplating.Build/T4.BuildTools.props +++ b/Mono.TextTemplating.Build/T4.BuildTools.props @@ -1,11 +1,6 @@ - - false - true - - + - False @@ -24,18 +19,30 @@ False - + + + + - MSBuild:TransformAll + MSBuild:TransformTemplates - MSBuild:TransformAll + MSBuild:TransformTemplates - + - + + Project + + + File;BrowseObject + + \ No newline at end of file diff --git a/Mono.TextTemplating.Build/T4PropertyPage.xaml b/Mono.TextTemplating.Build/T4PropertyPage.xaml new file mode 100644 index 0000000..96f7258 --- /dev/null +++ b/Mono.TextTemplating.Build/T4PropertyPage.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mono.TextTemplating.Build/T4PropertySchema.xaml b/Mono.TextTemplating.Build/T4PropertySchema.xaml new file mode 100644 index 0000000..38d9b76 --- /dev/null +++ b/Mono.TextTemplating.Build/T4PropertySchema.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + From c79ba9c3fecd3c4ee794dc2131972a96c69dcf14 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 11 Jan 2024 13:50:35 -0500 Subject: [PATCH 4/7] Output dependency information from TextTransform task Output items for templates and preprocessed templates now have InputFIle and Dependencies metadata. --- .../T4.BuildTools.targets.buildschema.json | 12 ++++++++++++ Mono.TextTemplating.Build/TextTransform.cs | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json b/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json index eee551f..3da1ce1 100644 --- a/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json +++ b/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json @@ -79,6 +79,18 @@ "description": "Overrides the output filename for a T4 template. Note that Visual Studio does not respect this.", "type": "file" } + }, + { + "$appliesTo": [ "GeneratedTemplates", "PreprocessedTemplates" ], + "InputFile": { + "description": "The original template file that generated this file", + "type": "file" + }, + "Dependencies": { + "description": "The files that the template depends on", + "type": "file", + "isList": true + } } ], "properties": { diff --git a/Mono.TextTemplating.Build/TextTransform.cs b/Mono.TextTemplating.Build/TextTransform.cs index 32558e4..79a4e02 100644 --- a/Mono.TextTemplating.Build/TextTransform.cs +++ b/Mono.TextTemplating.Build/TextTransform.cs @@ -135,14 +135,16 @@ public override bool Execute () if (buildState.TransformTemplates != null) { TransformTemplateOutput = new ITaskItem[buildState.TransformTemplates.Count]; for (int i = 0; i < buildState.TransformTemplates.Count; i++) { - TransformTemplateOutput[i] = new TaskItem (buildState.TransformTemplates[i].OutputFile); + var template = buildState.TransformTemplates[i]; + TransformTemplateOutput[i] = ConstructOutputItem (template.OutputFile, template.InputFile, template.Dependencies); } } if (buildState.PreprocessTemplates != null) { PreprocessedTemplateOutput = new ITaskItem[buildState.PreprocessTemplates.Count]; for (int i = 0; i < buildState.PreprocessTemplates.Count; i++) { - PreprocessedTemplateOutput[i] = new TaskItem (buildState.PreprocessTemplates[i].OutputFile); + var template = buildState.PreprocessTemplates[i]; + PreprocessedTemplateOutput[i] = ConstructOutputItem (template.OutputFile, template.InputFile, template.Dependencies); } } @@ -159,6 +161,18 @@ public override bool Execute () return success; } + static TaskItem ConstructOutputItem (string outputFile, string inputFile, List itemDependencies) + { + var item = new TaskItem (outputFile); + item.SetMetadata ("InputFile", inputFile); + + if (itemDependencies?.Count > 0) { + item.SetMetadata ("Dependencies", string.Join (";", itemDependencies)); + } + + return item; + } + bool AddParameters (TemplateBuildState buildState) { bool success = true; From e324d6b14a1d6e685473c3c8e4d2d3a8060eebee Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 11 Jan 2024 14:03:25 -0500 Subject: [PATCH 5/7] Clean up the msbuild schema --- .../T4.BuildTools.targets.buildschema.json | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json b/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json index 3da1ce1..cc8b4ad 100644 --- a/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json +++ b/Mono.TextTemplating.Build/T4.BuildTools.targets.buildschema.json @@ -18,7 +18,7 @@ } }, "T4Argument": { - "description": "T4 template argument, optionally scoped to a directive and/or directive processor. The value, processor and directive may be provided using the `Value, `Processor` and `Directive metadata, or encoded into the `Include` with the syntax `name=value`, `directive!name!value` or `processor!directive!name!value`.", + "description": "T4 template argument, optionally scoped to a directive and/or directive processor. The value, processor and directive may be provided using the `Value, `Processor` and `Directive metadata, or encoded into the `Include` with the format `name=value`, `directive!name!value` or `processor!directive!name!value`.", "includeDescription": "T4 argument name", "metadata": { "Value": "The T4 argument value. Overrides any value encoded in the `Include`.", @@ -55,15 +55,15 @@ "type": "file" }, "T4RequiredAssemblies": { - "description": "After running the TransformTemplates target, the assemblies that must be referenced to compile the preprocessed templates", + "description": "After running the `TransformTemplates` target, the assemblies that must be referenced to compile the preprocessed templates", "type": "file" }, "GeneratedTemplates": { - "description": "After running the TransformTemplates target, the output of all transformed templates", + "description": "After running the `TransformTemplates` target, the output of all transformed templates", "type": "file" }, "PreprocessedTemplates": { - "description": "After running the TransformTemplates target, the output of all preprocessed templates", + "description": "After running the `TransformTemplates` target, the output of all preprocessed templates", "type": "file" } }, @@ -105,20 +105,20 @@ "defaultValue": "true" }, "TransformFile": { - "description": "The T4 files to transform when running the Transform target", + "description": "The T4 files to transform when running the `Transform` target", "type": "file", "isList": true }, "BeforeTransform": { "description": "Targets to run before the T4 Transform target", "type": "target-name", - "deprecationMessage": "Use `BeforeTargets=\"TransformTemplatesCore\" for target ordering`", + "deprecationMessage": "Use `BeforeTargets=\"TransformTemplatesCore\"` for target ordering.", "isList": true }, "AfterTransform": { "description": "Targets to run after the T4 Transform target", "type": "target-name", - "deprecationMessage": "Use `AfterTargets=\"TransformTemplatesCore\" for target ordering`", + "deprecationMessage": "Use `AfterTargets=\"TransformTemplatesCore\"` for target ordering.", "isList": true }, "IncludeFolders": { @@ -134,20 +134,15 @@ "PreprocessTemplateDefaultNamespace": { "description": "Default namespace for preprocessed templates", "defaultValue": "$(RootNamespace)", - "deprecationMessage": "Legacy alternative to`$(T4DefaultNamespace)`" + "deprecationMessage": "Legacy alternative to `$(T4DefaultNamespace)`" }, "UseLegacyT4Preprocessing": { "description": "Place preprocessed templates beside the templates instead of dynamically injecting them into the build.", "type": "bool" }, "T4Arguments": { - "description": "Semicolon-separated list of values to convert to `@(T4Argument)` items. Intended to be used from command-line invocations only.", - "isList": true, - "type": { - "description": "Key-value pair", - "allowUnknownValues": true, - "values": {} - } + "description": "Used to pass arguments when invoking on the CLI. This is a semicolon-separated list and uses the same format as encoded `T4Argument` items: `name=value`, `directive!name!value` or `processor!directive!name!value`.", + "isList": true } }, "targets": { From 44a3f6eb76accd8f4486e875c26a7d12619db3c1 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Mon, 22 Jan 2024 21:52:01 -0500 Subject: [PATCH 6/7] Change mechanism for TFM support warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently when we tried to pack a TFM-specific file called _._ into buildTransitive to indicate that there were no targets for that TFM, NuGet arbitrarily decided to pack the targets file from a different TFM instead ¯\_(ツ)_/¯ Borrow the logic from https://github.com/dotnet/runtime/blob/bb74bb79db53eae474977a0928756a0db7fc6a3f/src/libraries/Microsoft.Extensions.Configuration.Binder/src/buildTransitive/Microsoft.Extensions.Configuration.Binder.targets#L17 as it's easier than overriding NuGet's weird pack behavior. Fixes #174 --- Mono.TextTemplating/Mono.TextTemplating.csproj | 5 +---- .../package/Mono.TextTemplating.targets | 14 +++++++++++++- Mono.TextTemplating/package/_._ | 0 3 files changed, 14 insertions(+), 5 deletions(-) delete mode 100644 Mono.TextTemplating/package/_._ diff --git a/Mono.TextTemplating/Mono.TextTemplating.csproj b/Mono.TextTemplating/Mono.TextTemplating.csproj index 25aab18..b1188a8 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.csproj +++ b/Mono.TextTemplating/Mono.TextTemplating.csproj @@ -24,10 +24,7 @@ - - - - + diff --git a/Mono.TextTemplating/package/Mono.TextTemplating.targets b/Mono.TextTemplating/package/Mono.TextTemplating.targets index 53f0035..2c9ce7e 100644 --- a/Mono.TextTemplating/package/Mono.TextTemplating.targets +++ b/Mono.TextTemplating/package/Mono.TextTemplating.targets @@ -1,6 +1,18 @@ - + + <_Mono_TextTemplating_Warn_Compat_Tfm + Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netcoreapp2.0')) AND + !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))"> + >net6.0 + <_Mono_TextTemplating_Warn_Compat_Tfm + Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net461')) AND + !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net462'))" + >net462 + + diff --git a/Mono.TextTemplating/package/_._ b/Mono.TextTemplating/package/_._ deleted file mode 100644 index e69de29..0000000 From 18ca3f21d61fe78f153c6054d0926d6c28205e25 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Mon, 22 Jan 2024 23:49:11 -0500 Subject: [PATCH 7/7] Fix relative pragma tests When relative pragmas are enabled, and includes already have relative path, and there is no base bath from which to calculate relative paths, use the existing relative path as-is. --- .../Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs index b618f99..72c7949 100644 --- a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs +++ b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.CodeGeneration.cs @@ -98,8 +98,10 @@ static void GenerateTransformMethod (CodeTypeDeclaration templateType, TemplateS if (!settings.NoLinePragmas) { var filename = seg.StartLocation.FileName ?? templateFile; if (!string.IsNullOrEmpty (filename)) { - filename = Path.GetFullPath (filename); - if (pragmasRelativeToDirectory is not null) { + if (!settings.RelativeLinePragmas) { + filename = Path.GetFileName (filename); + } else if (pragmasRelativeToDirectory is not null) { + filename = Path.GetFullPath (filename); filename = FileUtil.AbsoluteToRelativePath (pragmasRelativeToDirectory, filename); } }