Search code examples
visual-studiotemplatest4pre-build-event

TexTransform cli and the copyright symbol


After following the guidance found here, I've implemented a pre-build process designed to dynamical update assembly copyright.

The template for the copyright is

<#@ template language="C#" #>
<#@ output extension=".cs" #>
using System;
using System.Reflection;

[assembly: AssemblyCopyright("Copyright © <#=DateTime.Now.Year#>")]

If I save the file in VS, the resulting file (and compiled assembly) correctly contains the copyright symbol (©). When done as a part of the pre-build calling TextTransform.exe (in this case v12.0), the resulting file contains '?' instead. I get the same results specifying encoding="us-ascii" When the encoding is set to any of the utf variants, it comes out as '�'. Modifying the template to use \u00A9 gives the same results when the assembly is compiled.

I'm aware I can work on incorporating code generation in the solution build process, but this adds a burden on new hires (and new environment setup; we do a lot of development in VMs) insuring the appropriate SDKs are installed. It's also requires manual intervention for every project using the template (our group does a lot of different projects in a year with many of them requiring multi-year on-going maintenance). The process also forces a regeneration for every build (the pre-build event generates to a temp file and compares for differences before attempting to overwrite). And finally, the results from this path seem to be the same as with the pre-build event.

What other options am I missing?


Solution

  • To specifically answer my question: At least one other option I was missing involved writing a custom utility to generate the cs file for me. This code writes out the file with the correct copyright mark only if it's actually different or doesn't yet exist.

    I've implemented it as a console app targeting the version 4 framework written using VS2015.

    namespace GenerateAssemblyCopyright
    {
      class Program
      {
        const string _fileName = "AssemblyCopyright.cs";
        static void Main(string[] args)
        {
          if (args.Length == 0 || !Directory.Exists(args[0]))
            throw new InvalidOperationException("Must supply path for assembly copyright file");
    
          var acPath = Path.Combine(args[0], _fileName);
          var potentialOutput = $@"using System;
    using System.Reflection;
    
    [assembly: AssemblyCopyright(""Copyright © {DateTime.Now.Year}"")]";
          var exitingOutput = string.Empty;
    
          if (File.Exists(acPath))
          {
            using (var sr = new StreamReader(acPath, true))
            {
              exitingOutput = sr.ReadToEnd();
            }
          }
    
          if (!exitingOutput.Equals(potentialOutput))
          {
            using (var sw = new StreamWriter(acPath, false, Encoding.UTF8))
            {
              sw.Write(potentialOutput);
            }
          }
        }
      }
    }
    

    I copy the resulting exe into the solution directory and define a pre-build event on the first project in the solution.

    :: set the correct path to the the GenerateCopyright app
    set "generateExe=$(SolutionDir)GenerateAssemblyCopyright.exe"
    
    "%generateExe%" "$(SolutionDir)\"
    

    One thing to note: Even though the $(SolutionDir) already includes a trailing backslash (), an additional backslash is necessary to prevent turning the last quote into an escaped quote when passed in as a part of the exe args.