diff --git a/.gitignore b/.gitignore index c19742c237..143c3c0a90 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,4 @@ gen .profile.ps1 #VS Code files -/.vscode +.vscode diff --git a/build.psm1 b/build.psm1 index a87ccd54ac..bfaddc1961 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1276,22 +1276,17 @@ function Start-ResGen [CmdletBinding()] param() - Get-ChildItem $PSScriptRoot/src -Directory | ? { - Get-ChildItem (Join-Path $_.FullName 'resources') -ErrorAction SilentlyContinue} | % { - $_. Name} | % { + # Add .NET CLI tools to PATH + Find-Dotnet - $module = $_ - Get-ChildItem "$PSScriptRoot/src/$module/resources" -Filter '*.resx' | % { - $className = $_.Name.Replace('.resx', '') - $xml = [xml](Get-Content -raw $_.FullName) - - $fileName = $className - $genSource = Get-StronglyTypeCsFileForResx -xml $xml -ModuleName $module -ClassName $className - $outPath = "$PSScriptRoot/src/$module/gen/$fileName.cs" - Write-Verbose "ResGen for $outPath" - New-Item -Type Directory -ErrorAction SilentlyContinue (Split-Path $outPath) > $null - Set-Content -Encoding Ascii -Path $outPath -Value $genSource - } + Push-Location "$PSScriptRoot/src/ResGen" + try + { + Start-NativeExecution { dotnet run } | Write-Verbose + } + finally + { + Pop-Location } } @@ -1576,129 +1571,6 @@ function script:Start-NativeExecution([scriptblock]$sb) } } -function script:Get-StronglyTypeCsFileForResx -{ - param($xml, $ModuleName, $ClassName) - - # Example - # - # $ClassName = Full.Name.Of.The.ClassFoo - # $shortClassName = ClassFoo - # $namespaceName = Full.Name.Of.The - - $shortClassName = $ClassName - $namespaceName = $null - - $lastIndexOfDot = $className.LastIndexOf(".") - if ($lastIndexOfDot -ne -1) - { - $namespaceName = $className.Substring(0, $lastIndexOfDot) - $shortClassName = $className.Substring($lastIndexOfDot + 1) - } - -$banner = @' -//------------------------------------------------------------------------------ -// -// This code was generated by a Start-ResGen funciton from build.psm1. -// To add or remove a member, edit your .ResX file then rerun Start-ResGen. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -{0} -'@ - -$namespace = @' -namespace {0} {{ -{1} -}} -'@ - -$body = @' -using System; -using System.Reflection; - -/// -/// A strongly-typed resource class, for looking up localized strings, etc. -/// -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] -[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] -[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - -internal class {0} {{ - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal {0}() {{ - }} - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager {{ - get {{ - if (object.ReferenceEquals(resourceMan, null)) {{ - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("{1}.resources.{3}", typeof({0}).GetTypeInfo().Assembly); - resourceMan = temp; - }} - return resourceMan; - }} - }} - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture {{ - get {{ - return resourceCulture; - }} - set {{ - resourceCulture = value; - }} - }} - {2} -}} -'@ - - $entry = @' - - /// - /// Looks up a localized string similar to {1} - /// - internal static string {0} {{ - get {{ - return ResourceManager.GetString("{0}", resourceCulture); - }} - }} -'@ - $entries = $xml.root.data | % { - if ($_) { - $val = $_.value.Replace("`n", "`n ///") - $name = $_.name.Replace(' ', '_') - $entry -f $name,$val - } - } | Out-String - - $bodyCode = $body -f $shortClassName,$ModuleName,$entries,$ClassName - - if ($NamespaceName) - { - $bodyCode = $namespace -f $NamespaceName, $bodyCode - } - - $resultCode = $banner -f $bodyCode - - return $resultCode -replace "`r`n?|`n","`r`n" -} - # Builds coming out of this project can have version number as 'a.b.c' OR 'a.b.c-d-f' # This function converts the above version into major.minor[.build[.revision]] format function Get-PackageVersionAsMajorMinorBuildRevision diff --git a/src/ResGen/Program.cs b/src/ResGen/Program.cs new file mode 100644 index 0000000000..fe7524c8de --- /dev/null +++ b/src/ResGen/Program.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml.Linq; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + // we are assuming resgen is run with 'dotnet run' + // so we can use relative paths + foreach (string folder in Directory.EnumerateDirectories("..")) + { + string moduleName = Path.GetFileName(folder); + string resourcePath = Path.Combine(folder, "resources"); + if (Directory.Exists(resourcePath)) + { + string genFolder = Path.Combine(folder, "gen"); + if (!Directory.Exists(genFolder)) + { + Directory.CreateDirectory(genFolder); + } + + foreach (string resxPath in Directory.EnumerateFiles(resourcePath, "*.resx")) + { + string className = Path.GetFileNameWithoutExtension(resxPath); + string sourceCode = GetStronglyTypeCsFileForResx(resxPath, moduleName, className); + string outPath = Path.Combine(genFolder, className + ".cs"); + Console.WriteLine("ResGen for " + outPath); + File.WriteAllText(outPath, sourceCode); + } + } + } + } + + private static string GetStronglyTypeCsFileForResx(string xmlPath, string moduleName, string className) + { + // Example + // + // className = Full.Name.Of.The.ClassFoo + // shortClassName = ClassFoo + // namespaceName = Full.Name.Of.The + + string shortClassName = className; + string namespaceName = null; + int lastIndexOfDot = className.LastIndexOf('.'); + if (lastIndexOfDot != -1) + { + namespaceName = className.Substring(0, lastIndexOfDot); + shortClassName = className.Substring(lastIndexOfDot + 1); + } + + var entries = new StringBuilder(); + XElement root = XElement.Parse(File.ReadAllText(xmlPath)); + foreach (var data in root.Elements("data")) + { + string value = data.Value.Replace("\n", "\n ///"); + string name = data.Attribute("name").Value.Replace(' ', '_'); + entries.AppendFormat(ENTRY, name, value); + } + + string bodyCode = string.Format(BODY, shortClassName, moduleName, entries.ToString(), className); + if (namespaceName != null) + { + bodyCode = string.Format(NAMESPACE, namespaceName, bodyCode); + } + + string resultCode = string.Format(BANNER, bodyCode).Replace("\r\n?|\n", "\r\n"); + return resultCode; + } + + private static readonly string BANNER = @" +//------------------------------------------------------------------------------ +// +// This code was generated by a dotnet run from src\ResGen folder. +// To add or remove a member, edit your .resx file then rerun src\ResGen. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +{0} +"; + + private static readonly string NAMESPACE = @" +namespace {0} {{ +{1} +}} +"; + private static readonly string BODY = @" +using System; +using System.Reflection; + +/// +/// A strongly-typed resource class, for looking up localized strings, etc. +/// +[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""System.Resources.Tools.StronglyTypedResourceBuilder"", ""4.0.0.0"")] +[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] +[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + +internal class {0} {{ + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(""Microsoft.Performance"", ""CA1811:AvoidUncalledPrivateCode"")] + internal {0}() {{ + }} + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager {{ + get {{ + if (object.ReferenceEquals(resourceMan, null)) {{ + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(""{1}.resources.{3}"", typeof({0}).GetTypeInfo().Assembly); + resourceMan = temp; + }} + return resourceMan; + }} + }} + + /// + /// Overrides the current threads CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture {{ + get {{ + return resourceCulture; + }} + set {{ + resourceCulture = value; + }} + }} + {2} +}} +"; + + private static readonly string ENTRY = @" + + /// + /// Looks up a localized string similar to {1} + /// + internal static string {0} {{ + get {{ + return ResourceManager.GetString(""{0}"", resourceCulture); + }} + }} +"; + + } +} diff --git a/src/ResGen/project.json b/src/ResGen/project.json new file mode 100644 index 0000000000..0dea62d8e4 --- /dev/null +++ b/src/ResGen/project.json @@ -0,0 +1,28 @@ +{ + "name": "resgen", + "version": "1.0.0-*", + "description": "Generates C# typed bindings for .resx files", + + "buildOptions": { + "emitEntryPoint": true + }, + + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": "1.0.0", + "System.Xml.XDocument": "4.0.11" + } + } + }, + + "runtimes": { + "ubuntu.14.04-x64": { }, + "debian.8-x64": { }, + "centos.7-x64": { }, + "win7-x64": { }, + "win81-x64": { }, + "win10-x64": { }, + "osx.10.11-x64": { } + } +}