From fc64db1f7307ac5501e4d4ed5f46a6ae55100485 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 18 Oct 2015 21:07:48 -0700 Subject: [PATCH] Support resx file embedding - Added resgen tool and takes .resx and makes .resources - Write .resources and .rsp to obj folder --- Microsoft.DotNet.Cli.sln | 7 +++ scripts/bootstrap | 4 ++ scripts/bootstrap.cmd | 8 +++ src/Microsoft.DotNet.Cli.Utils/Constants.cs | 1 + .../Program.cs | 56 +++++++++++++++---- .../Microsoft.DotNet.Tools.Resgen.xproj | 20 +++++++ src/Microsoft.DotNet.Tools.Resgen/Program.cs | 54 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 23 ++++++++ .../project.json | 32 +++++++++++ 9 files changed, 195 insertions(+), 10 deletions(-) create mode 100644 src/Microsoft.DotNet.Tools.Resgen/Microsoft.DotNet.Tools.Resgen.xproj create mode 100644 src/Microsoft.DotNet.Tools.Resgen/Program.cs create mode 100644 src/Microsoft.DotNet.Tools.Resgen/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.DotNet.Tools.Resgen/project.json diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 01ec8c7bf..33da15b58 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -36,6 +36,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dnxhost", "dnxhost", "{0773 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Compiler.Csc", "src\Microsoft.DotNet.Tools.Compiler.Csc\Microsoft.DotNet.Tools.Compiler.Csc.xproj", "{B559378C-FC03-45FA-893C-71784F28E0A2}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Resgen", "src\Microsoft.DotNet.Tools.Resgen\Microsoft.DotNet.Tools.Resgen.xproj", "{585FC6F6-48E0-4EA5-8015-0264614E97C0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -66,6 +68,10 @@ Global {B559378C-FC03-45FA-893C-71784F28E0A2}.Debug|Any CPU.Build.0 = Debug|Any CPU {B559378C-FC03-45FA-893C-71784F28E0A2}.Release|Any CPU.ActiveCfg = Release|Any CPU {B559378C-FC03-45FA-893C-71784F28E0A2}.Release|Any CPU.Build.0 = Release|Any CPU + {585FC6F6-48E0-4EA5-8015-0264614E97C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {585FC6F6-48E0-4EA5-8015-0264614E97C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {585FC6F6-48E0-4EA5-8015-0264614E97C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {585FC6F6-48E0-4EA5-8015-0264614E97C0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -78,5 +84,6 @@ Global {303677D5-7312-4C3F-BAEE-BEB1A9BD9FE6} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {07731125-77D7-4B83-B7B2-C865C6B8A6E8} = {13F8C30C-1011-459C-82B2-0ACDD73EDA18} {B559378C-FC03-45FA-893C-71784F28E0A2} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} + {585FC6F6-48E0-4EA5-8015-0264614E97C0} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} EndGlobalSection EndGlobal diff --git a/scripts/bootstrap b/scripts/bootstrap index 965b47bf6..69e756273 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -60,6 +60,8 @@ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi $STAGE0_PUBLISH --framework dnxcore50 --runtime $RID --output "$STAGE1_DIR" "$REPOROOT/src/Microsoft.DotNet.Tools.Compiler.Csc" rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi $STAGE0_PUBLISH --framework dnxcore50 --runtime $RID --output "$STAGE1_DIR" "$REPOROOT/src/Microsoft.DotNet.Tools.Publish" +rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi +$STAGE0_PUBLISH --framework dnxcore50 --runtime $RID --output "$STAGE1_DIR" "$REPOROOT/src/Microsoft.DotNet.Tools.Resgen" # Add stage1 to the path and use it to build stage2 export PATH=$STAGE1_DIR:$PATH @@ -73,3 +75,5 @@ dotnet publish --framework dnxcore50 --runtime $RID --output "$STAGE2_DIR" "$REP rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi dotnet publish --framework dnxcore50 --runtime $RID --output "$STAGE2_DIR" "$REPOROOT/src/Microsoft.DotNet.Tools.Publish" rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi +dotnet publish --framework dnxcore50 --runtime $RID --output "$STAGE2_DIR" "$REPOROOT/src/Microsoft.DotNet.Tools.Resgen" +rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi diff --git a/scripts/bootstrap.cmd b/scripts/bootstrap.cmd index 82d77aa36..8bedc0fe6 100644 --- a/scripts/bootstrap.cmd +++ b/scripts/bootstrap.cmd @@ -59,6 +59,10 @@ echo Building stage1 dotnet-publish.exe ... dotnet-publish --framework dnxcore50 --runtime %RID% --output "%STAGE1_DIR%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish" if errorlevel 1 goto fail +echo Building stage1 dotnet-publish.exe ... +dotnet-publish --framework dnxcore50 --runtime %RID% --output "%STAGE1_DIR%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen" +if errorlevel 1 goto fail + echo Re-building dotnet tools with the bootstrapped version REM This should move into a proper build script of some kind once we are bootstrapped set PATH=%STAGE1_DIR%;%PATH% @@ -85,6 +89,10 @@ echo Building stage2 dotnet-publish.exe ... dotnet publish --framework dnxcore50 --runtime %RID% --output "%STAGE2_DIR%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish" if errorlevel 1 goto fail +echo Building stage2 dotnet-publish.exe ... +dotnet publish --framework dnxcore50 --runtime %RID% --output "%STAGE2_DIR%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen" +if errorlevel 1 goto fail + echo Bootstrapped dotnet to %STAGE2_DIR% popd diff --git a/src/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Microsoft.DotNet.Cli.Utils/Constants.cs index c47537c58..3d86695ee 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -14,6 +14,7 @@ namespace Microsoft.DotNet.Cli.Utils public static readonly string CoreRunName = "corerun" + ExeSuffix; public static readonly string DefaultConfiguration = "Debug"; public static readonly string BinDirectoryName = "bin"; + public static readonly string ObjDirectoryName = "obj"; public static readonly string HostsPathEnvironmentVariable = "DOTNET_CLR_HOSTS_PATH"; public static readonly string CSCPathEnvironmentVariable = "DOTNET_CSC_PATH"; diff --git a/src/Microsoft.DotNet.Tools.Compiler/Program.cs b/src/Microsoft.DotNet.Tools.Compiler/Program.cs index 569c821af..2118bb7c5 100644 --- a/src/Microsoft.DotNet.Tools.Compiler/Program.cs +++ b/src/Microsoft.DotNet.Tools.Compiler/Program.cs @@ -145,11 +145,22 @@ namespace Microsoft.DotNet.Tools.Compiler context.TargetFramework.GetTwoDigitShortFolderName()); } + string intermediateOutputPath = Path.Combine( + context.ProjectFile.ProjectDirectory, + Constants.ObjDirectoryName, + configuration, + context.TargetFramework.GetTwoDigitShortFolderName()); + if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } + if (!Directory.Exists(intermediateOutputPath)) + { + Directory.CreateDirectory(intermediateOutputPath); + } + // Get compilation options var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var outputName = Path.Combine(outputPath, context.ProjectFile.Name + ".dll"); @@ -184,13 +195,16 @@ namespace Microsoft.DotNet.Tools.Compiler // Add project source files compilerArgs.AddRange(context.ProjectFile.Files.SourceFiles); - AddResources(context.ProjectFile, compilerArgs); + if (!AddResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) + { + return false; + } // TODO: Read this from the project const string compiler = "csc"; // Write RSP file - var rsp = Path.Combine(outputPath, $"dotnet-compile.{compiler}.rsp"); + var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{compiler}.rsp"); File.WriteAllLines(rsp, compilerArgs); var result = Command.Create($"dotnet-compile-{compiler}", $"\"{rsp}\"") @@ -202,14 +216,14 @@ namespace Microsoft.DotNet.Tools.Compiler if (result.ExitCode == 0) { - Reporter.Output.WriteLine($"Compiled to {outputPath} successfully!".Green().Bold()); + Reporter.Output.WriteLine($"Compiled {context.ProjectFile.Name} successfully!".Green().Bold()); return true; } return false; } - private static void AddResources(Project project, List compilerArgs) + private static bool AddResources(Project project, List compilerArgs, string intermediateOutputPath) { string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory); @@ -220,12 +234,6 @@ namespace Microsoft.DotNet.Tools.Compiler var resourcePath = resourceFile.Key; - if (ResourcePathUtility.IsResxResourceFile(resourcePath)) - { - // TODO: Handle resource files - continue; - } - if (string.IsNullOrEmpty(resourceFile.Value)) { // No logical name, so use the file name @@ -241,8 +249,36 @@ namespace Microsoft.DotNet.Tools.Compiler var name = CreateCSharpManifestResourceName.CreateManifestName(resourceName, rootNamespace); var fileName = resourcePath; + if (ResourcePathUtility.IsResxResourceFile(fileName)) + { + var ext = Path.GetExtension(fileName); + + if (string.Equals(ext, ".resx", StringComparison.OrdinalIgnoreCase)) + { + // {file}.resx -> {file}.resources + var resourcesFile = Path.Combine(intermediateOutputPath, name); + + var result = Command.Create("resgen", $"{fileName} {resourcesFile}") + .ForwardStdErr() + .ForwardStdOut() + .RunAsync() + .GetAwaiter() + .GetResult(); + + if (result.ExitCode != 0) + { + return false; + } + + // Use this as the resource name instead + fileName = resourcesFile; + } + } + compilerArgs.Add($"-resource:\"{fileName}\",{name}"); } + + return true; } private static ISet Sort(Dictionary projects) diff --git a/src/Microsoft.DotNet.Tools.Resgen/Microsoft.DotNet.Tools.Resgen.xproj b/src/Microsoft.DotNet.Tools.Resgen/Microsoft.DotNet.Tools.Resgen.xproj new file mode 100644 index 000000000..abf38884b --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Resgen/Microsoft.DotNet.Tools.Resgen.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 585fc6f6-48e0-4ea5-8015-0264614e97c0 + Microsoft.DotNet.Tools.Resgen + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + diff --git a/src/Microsoft.DotNet.Tools.Resgen/Program.cs b/src/Microsoft.DotNet.Tools.Resgen/Program.cs new file mode 100644 index 000000000..a1f5977cd --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Resgen/Program.cs @@ -0,0 +1,54 @@ +using System.IO; +using System.Resources; +using System.Xml.Linq; +using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Tools.Resgen +{ + public class Program + { + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + var app = new CommandLineApplication(); + app.Name = "resgen"; + app.FullName = "Resource compiler"; + app.Description = "Microsoft (R) .NET Resource Generator"; + app.HelpOption("-h|--help"); + + var inputFile = app.Argument("", "The .resx file to transform"); + var outputFile = app.Argument("", "The .resources file to produce"); + + app.OnExecute(() => + { + WriteResourcesFile(inputFile.Value, outputFile.Value); + return 0; + }); + + return app.Execute(args); + } + + private static void WriteResourcesFile(string resxFilePath, string outputFile) + { + using (var fs = File.OpenRead(resxFilePath)) + using (var outfs = File.Create(outputFile)) + { + var document = XDocument.Load(fs); + + var rw = new ResourceWriter(outfs); + + foreach (var e in document.Root.Elements("data")) + { + string name = e.Attribute("name").Value; + string value = e.Element("value").Value; + + rw.AddResource(name, value); + } + + rw.Generate(); + } + } + } +} diff --git a/src/Microsoft.DotNet.Tools.Resgen/Properties/AssemblyInfo.cs b/src/Microsoft.DotNet.Tools.Resgen/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d9209f331 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Resgen/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.DotNet.Tools.Resgen")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.DotNet.Tools.Resgen")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("585fc6f6-48e0-4ea5-8015-0264614e97c0")] diff --git a/src/Microsoft.DotNet.Tools.Resgen/project.json b/src/Microsoft.DotNet.Tools.Resgen/project.json new file mode 100644 index 000000000..777b338d4 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Resgen/project.json @@ -0,0 +1,32 @@ +{ + "name": "resgen", + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "commands": { + "resgen": "Microsoft.DotNet.Tools.Resgen" + }, + "dependencies": { + "Microsoft.NETCore.TestHost": "1.0.0-*", + "Microsoft.NETCore.Runtime": "1.0.1-*", + "System.Console": "4.0.0-*", + "System.Collections": "4.0.11-*", + "System.Linq": "4.0.1-*", + "System.Diagnostics.Process": "4.1.0-*", + "System.IO.FileSystem": "4.0.1-*", + "Microsoft.DotNet.Cli.Utils": { + "type": "build", + "version": "1.0.0-*" + }, + "Microsoft.Extensions.CommandLineUtils.Sources": { + "type": "build", + "version": "1.0.0-*" + }, + "System.Xml.XDocument": "4.0.11-*", + "System.Resources.ReaderWriter": "4.0.0-*" + }, + "frameworks": { + "dnxcore50": { } + } +}