Add resource satelite assembly generation
This commit is contained in:
parent
aebc89683e
commit
93158dc1be
20 changed files with 930 additions and 111 deletions
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public static class AnsiColorExtensions
|
||||
internal static class AnsiColorExtensions
|
||||
{
|
||||
public static string Black(this string text)
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ using NuGet.Frameworks;
|
|||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public class Command
|
||||
internal class Command
|
||||
{
|
||||
private readonly Process _process;
|
||||
private readonly StreamForwarder _stdOut;
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.IO;
|
|||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
public struct CommandResult
|
||||
internal struct CommandResult
|
||||
{
|
||||
public static readonly CommandResult Empty = new CommandResult();
|
||||
|
||||
|
|
439
src/Microsoft.DotNet.Compiler.Common/CultureInfoCache.cs
Normal file
439
src/Microsoft.DotNet.Compiler.Common/CultureInfoCache.cs
Normal file
|
@ -0,0 +1,439 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Compiler.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a list of known culture names that can be used to create a <see cref="System.Globalization.CultureInfo"/>.
|
||||
/// </summary>
|
||||
internal static class CultureInfoCache
|
||||
{
|
||||
/// <summary>
|
||||
/// This list of known cultures was generated by CultureInfoGenerator using .NET Framework 4.6 RC or later on
|
||||
/// Microsoft Windows NT 6.2.9200.0.
|
||||
/// As new versions of .NET Framework and Windows are released, this list should be regenerated to ensure it
|
||||
/// contains the latest culture names.
|
||||
/// </summary>
|
||||
public static readonly HashSet<string> KnownCultureNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"",
|
||||
"af",
|
||||
"af-ZA",
|
||||
"am",
|
||||
"am-ET",
|
||||
"ar",
|
||||
"ar-AE",
|
||||
"ar-BH",
|
||||
"ar-DZ",
|
||||
"ar-EG",
|
||||
"ar-IQ",
|
||||
"ar-JO",
|
||||
"ar-KW",
|
||||
"ar-LB",
|
||||
"ar-LY",
|
||||
"ar-MA",
|
||||
"ar-OM",
|
||||
"ar-QA",
|
||||
"ar-SA",
|
||||
"ar-SY",
|
||||
"ar-TN",
|
||||
"ar-YE",
|
||||
"arn",
|
||||
"arn-CL",
|
||||
"as",
|
||||
"as-IN",
|
||||
"az",
|
||||
"az-Cyrl",
|
||||
"az-Cyrl-AZ",
|
||||
"az-Latn",
|
||||
"az-Latn-AZ",
|
||||
"ba",
|
||||
"ba-RU",
|
||||
"be",
|
||||
"be-BY",
|
||||
"bg",
|
||||
"bg-BG",
|
||||
"bn",
|
||||
"bn-BD",
|
||||
"bn-IN",
|
||||
"bo",
|
||||
"bo-CN",
|
||||
"br",
|
||||
"br-FR",
|
||||
"bs",
|
||||
"bs-Cyrl",
|
||||
"bs-Cyrl-BA",
|
||||
"bs-Latn",
|
||||
"bs-Latn-BA",
|
||||
"ca",
|
||||
"ca-ES",
|
||||
"ca-ES-valencia",
|
||||
"chr",
|
||||
"chr-Cher",
|
||||
"chr-Cher-US",
|
||||
"co",
|
||||
"co-FR",
|
||||
"cs",
|
||||
"cs-CZ",
|
||||
"cy",
|
||||
"cy-GB",
|
||||
"da",
|
||||
"da-DK",
|
||||
"de",
|
||||
"de-AT",
|
||||
"de-CH",
|
||||
"de-DE",
|
||||
"de-LI",
|
||||
"de-LU",
|
||||
"dsb",
|
||||
"dsb-DE",
|
||||
"dv",
|
||||
"dv-MV",
|
||||
"el",
|
||||
"el-GR",
|
||||
"en",
|
||||
"en-029",
|
||||
"en-AU",
|
||||
"en-BZ",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-HK",
|
||||
"en-IE",
|
||||
"en-IN",
|
||||
"en-JM",
|
||||
"en-MY",
|
||||
"en-NZ",
|
||||
"en-PH",
|
||||
"en-SG",
|
||||
"en-TT",
|
||||
"en-US",
|
||||
"en-ZA",
|
||||
"en-ZW",
|
||||
"es",
|
||||
"es-419",
|
||||
"es-AR",
|
||||
"es-BO",
|
||||
"es-CL",
|
||||
"es-CO",
|
||||
"es-CR",
|
||||
"es-DO",
|
||||
"es-EC",
|
||||
"es-ES",
|
||||
"es-GT",
|
||||
"es-HN",
|
||||
"es-MX",
|
||||
"es-NI",
|
||||
"es-PA",
|
||||
"es-PE",
|
||||
"es-PR",
|
||||
"es-PY",
|
||||
"es-SV",
|
||||
"es-US",
|
||||
"es-UY",
|
||||
"es-VE",
|
||||
"et",
|
||||
"et-EE",
|
||||
"eu",
|
||||
"eu-ES",
|
||||
"fa",
|
||||
"fa-IR",
|
||||
"ff",
|
||||
"ff-Latn",
|
||||
"ff-Latn-SN",
|
||||
"fi",
|
||||
"fi-FI",
|
||||
"fil",
|
||||
"fil-PH",
|
||||
"fo",
|
||||
"fo-FO",
|
||||
"fr",
|
||||
"fr-BE",
|
||||
"fr-CA",
|
||||
"fr-CD",
|
||||
"fr-CH",
|
||||
"fr-CI",
|
||||
"fr-CM",
|
||||
"fr-FR",
|
||||
"fr-HT",
|
||||
"fr-LU",
|
||||
"fr-MA",
|
||||
"fr-MC",
|
||||
"fr-ML",
|
||||
"fr-RE",
|
||||
"fr-SN",
|
||||
"fy",
|
||||
"fy-NL",
|
||||
"ga",
|
||||
"ga-IE",
|
||||
"gd",
|
||||
"gd-GB",
|
||||
"gl",
|
||||
"gl-ES",
|
||||
"gn",
|
||||
"gn-PY",
|
||||
"gsw",
|
||||
"gsw-FR",
|
||||
"gu",
|
||||
"gu-IN",
|
||||
"ha",
|
||||
"ha-Latn",
|
||||
"ha-Latn-NG",
|
||||
"haw",
|
||||
"haw-US",
|
||||
"he",
|
||||
"he-IL",
|
||||
"hi",
|
||||
"hi-IN",
|
||||
"hr",
|
||||
"hr-BA",
|
||||
"hr-HR",
|
||||
"hsb",
|
||||
"hsb-DE",
|
||||
"hu",
|
||||
"hu-HU",
|
||||
"hy",
|
||||
"hy-AM",
|
||||
"id",
|
||||
"id-ID",
|
||||
"ig",
|
||||
"ig-NG",
|
||||
"ii",
|
||||
"ii-CN",
|
||||
"is",
|
||||
"is-IS",
|
||||
"it",
|
||||
"it-CH",
|
||||
"it-IT",
|
||||
"iu",
|
||||
"iu-Cans",
|
||||
"iu-Cans-CA",
|
||||
"iu-Latn",
|
||||
"iu-Latn-CA",
|
||||
"ja",
|
||||
"ja-JP",
|
||||
"jv",
|
||||
"jv-Latn",
|
||||
"jv-Latn-ID",
|
||||
"ka",
|
||||
"ka-GE",
|
||||
"kk",
|
||||
"kk-KZ",
|
||||
"kl",
|
||||
"kl-GL",
|
||||
"km",
|
||||
"km-KH",
|
||||
"kn",
|
||||
"kn-IN",
|
||||
"ko",
|
||||
"ko-KR",
|
||||
"kok",
|
||||
"kok-IN",
|
||||
"ku",
|
||||
"ku-Arab",
|
||||
"ku-Arab-IQ",
|
||||
"ky",
|
||||
"ky-KG",
|
||||
"lb",
|
||||
"lb-LU",
|
||||
"lo",
|
||||
"lo-LA",
|
||||
"lt",
|
||||
"lt-LT",
|
||||
"lv",
|
||||
"lv-LV",
|
||||
"mg",
|
||||
"mg-MG",
|
||||
"mi",
|
||||
"mi-NZ",
|
||||
"mk",
|
||||
"mk-MK",
|
||||
"ml",
|
||||
"ml-IN",
|
||||
"mn",
|
||||
"mn-Cyrl",
|
||||
"mn-MN",
|
||||
"mn-Mong",
|
||||
"mn-Mong-CN",
|
||||
"mn-Mong-MN",
|
||||
"moh",
|
||||
"moh-CA",
|
||||
"mr",
|
||||
"mr-IN",
|
||||
"ms",
|
||||
"ms-BN",
|
||||
"ms-MY",
|
||||
"mt",
|
||||
"mt-MT",
|
||||
"my",
|
||||
"my-MM",
|
||||
"nb",
|
||||
"nb-NO",
|
||||
"ne",
|
||||
"ne-IN",
|
||||
"ne-NP",
|
||||
"nl",
|
||||
"nl-BE",
|
||||
"nl-NL",
|
||||
"nn",
|
||||
"nn-NO",
|
||||
"no",
|
||||
"nqo",
|
||||
"nqo-GN",
|
||||
"nso",
|
||||
"nso-ZA",
|
||||
"oc",
|
||||
"oc-FR",
|
||||
"om",
|
||||
"om-ET",
|
||||
"or",
|
||||
"or-IN",
|
||||
"pa",
|
||||
"pa-Arab",
|
||||
"pa-Arab-PK",
|
||||
"pa-IN",
|
||||
"pl",
|
||||
"pl-PL",
|
||||
"prs",
|
||||
"prs-AF",
|
||||
"ps",
|
||||
"ps-AF",
|
||||
"pt",
|
||||
"pt-AO",
|
||||
"pt-BR",
|
||||
"pt-PT",
|
||||
"qut",
|
||||
"qut-GT",
|
||||
"quz",
|
||||
"quz-BO",
|
||||
"quz-EC",
|
||||
"quz-PE",
|
||||
"rm",
|
||||
"rm-CH",
|
||||
"ro",
|
||||
"ro-MD",
|
||||
"ro-RO",
|
||||
"ru",
|
||||
"ru-RU",
|
||||
"rw",
|
||||
"rw-RW",
|
||||
"sa",
|
||||
"sa-IN",
|
||||
"sah",
|
||||
"sah-RU",
|
||||
"sd",
|
||||
"sd-Arab",
|
||||
"sd-Arab-PK",
|
||||
"se",
|
||||
"se-FI",
|
||||
"se-NO",
|
||||
"se-SE",
|
||||
"si",
|
||||
"si-LK",
|
||||
"sk",
|
||||
"sk-SK",
|
||||
"sl",
|
||||
"sl-SI",
|
||||
"sma",
|
||||
"sma-NO",
|
||||
"sma-SE",
|
||||
"smj",
|
||||
"smj-NO",
|
||||
"smj-SE",
|
||||
"smn",
|
||||
"smn-FI",
|
||||
"sms",
|
||||
"sms-FI",
|
||||
"sn",
|
||||
"sn-Latn",
|
||||
"sn-Latn-ZW",
|
||||
"so",
|
||||
"so-SO",
|
||||
"sq",
|
||||
"sq-AL",
|
||||
"sr",
|
||||
"sr-Cyrl",
|
||||
"sr-Cyrl-BA",
|
||||
"sr-Cyrl-CS",
|
||||
"sr-Cyrl-ME",
|
||||
"sr-Cyrl-RS",
|
||||
"sr-Latn",
|
||||
"sr-Latn-BA",
|
||||
"sr-Latn-CS",
|
||||
"sr-Latn-ME",
|
||||
"sr-Latn-RS",
|
||||
"st",
|
||||
"st-ZA",
|
||||
"sv",
|
||||
"sv-FI",
|
||||
"sv-SE",
|
||||
"sw",
|
||||
"sw-KE",
|
||||
"syr",
|
||||
"syr-SY",
|
||||
"ta",
|
||||
"ta-IN",
|
||||
"ta-LK",
|
||||
"te",
|
||||
"te-IN",
|
||||
"tg",
|
||||
"tg-Cyrl",
|
||||
"tg-Cyrl-TJ",
|
||||
"th",
|
||||
"th-TH",
|
||||
"ti",
|
||||
"ti-ER",
|
||||
"ti-ET",
|
||||
"tk",
|
||||
"tk-TM",
|
||||
"tn",
|
||||
"tn-BW",
|
||||
"tn-ZA",
|
||||
"tr",
|
||||
"tr-TR",
|
||||
"ts",
|
||||
"ts-ZA",
|
||||
"tt",
|
||||
"tt-RU",
|
||||
"tzm",
|
||||
"tzm-Latn",
|
||||
"tzm-Latn-DZ",
|
||||
"tzm-Tfng",
|
||||
"tzm-Tfng-MA",
|
||||
"ug",
|
||||
"ug-CN",
|
||||
"uk",
|
||||
"uk-UA",
|
||||
"ur",
|
||||
"ur-IN",
|
||||
"ur-PK",
|
||||
"uz",
|
||||
"uz-Cyrl",
|
||||
"uz-Cyrl-UZ",
|
||||
"uz-Latn",
|
||||
"uz-Latn-UZ",
|
||||
"vi",
|
||||
"vi-VN",
|
||||
"wo",
|
||||
"wo-SN",
|
||||
"xh",
|
||||
"xh-ZA",
|
||||
"yo",
|
||||
"yo-NG",
|
||||
"zgh",
|
||||
"zgh-Tfng",
|
||||
"zgh-Tfng-MA",
|
||||
"zh",
|
||||
"zh-CN",
|
||||
"zh-Hans",
|
||||
"zh-Hant",
|
||||
"zh-HK",
|
||||
"zh-MO",
|
||||
"zh-SG",
|
||||
"zh-TW",
|
||||
"zu",
|
||||
"zu-ZA",
|
||||
"zh-CHS",
|
||||
"zh-CHT"
|
||||
};
|
||||
}
|
||||
}
|
79
src/Microsoft.DotNet.Compiler.Common/ResourceUtility.cs
Normal file
79
src/Microsoft.DotNet.Compiler.Common/ResourceUtility.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Compiler.Common
|
||||
{
|
||||
public static class ResourceUtility
|
||||
{
|
||||
public static string GetResourceName(string projectFolder, string resourcePath)
|
||||
{
|
||||
// If the file is outside of the project folder, we are assuming it is directly in the root
|
||||
// otherwise, keep the folders that are inside the project
|
||||
return PathUtility.IsChildOfDirectory(projectFolder, resourcePath) ?
|
||||
PathUtility.GetRelativePath(projectFolder, resourcePath) :
|
||||
Path.GetFileName(resourcePath);
|
||||
}
|
||||
|
||||
public static bool IsResourceFile(string fileName)
|
||||
{
|
||||
var ext = Path.GetExtension(fileName);
|
||||
|
||||
return
|
||||
IsResxFile(fileName) ||
|
||||
string.Equals(ext, ".restext", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(ext, ".resources", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsResxFile(string fileName)
|
||||
{
|
||||
var ext = Path.GetExtension(fileName);
|
||||
|
||||
return string.Equals(ext, ".resx", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetResourcesForCulture(string cultureName, IList<string> resources)
|
||||
{
|
||||
var resourcesByCultureName = resources
|
||||
.GroupBy(GetResourceCultureName, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (string.Equals(cultureName, "neutral", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
cultureName = string.Empty;
|
||||
}
|
||||
|
||||
return resourcesByCultureName
|
||||
.SingleOrDefault(grouping => string.Equals(grouping.Key, cultureName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static string GetResourceCultureName(string res)
|
||||
{
|
||||
var ext = Path.GetExtension(res);
|
||||
|
||||
if (IsResourceFile(res))
|
||||
{
|
||||
var resourceBaseName = Path.GetFileNameWithoutExtension(Path.GetFileName(res));
|
||||
var cultureName = Path.GetExtension(resourceBaseName);
|
||||
if (string.IsNullOrEmpty(cultureName) || cultureName.Length < 3)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Path.Extension adds a . to the file extension name; example - ".resources". Removing the "." with Substring
|
||||
cultureName = cultureName.Substring(1);
|
||||
|
||||
if (CultureInfoCache.KnownCultureNames.Contains(cultureName))
|
||||
{
|
||||
return cultureName;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,11 @@
|
|||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.CommandLine": "0.1.0-*",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*"
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-*"
|
||||
},
|
||||
},
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
|
|
|
@ -13,8 +13,8 @@ using Microsoft.DotNet.Cli.Compiler.Common;
|
|||
using Microsoft.DotNet.Tools.Common;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Compilation;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
|
@ -380,6 +380,11 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
var success = result.ExitCode == 0;
|
||||
|
||||
if (success)
|
||||
{
|
||||
success &= GenerateResourceAssemblies(context.ProjectFile, dependencies, outputPath, configuration);
|
||||
}
|
||||
|
||||
if (success && !noHost && compilationOptions.EmitEntryPoint.GetValueOrDefault())
|
||||
{
|
||||
var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { RuntimeIdentifier.Current });
|
||||
|
@ -628,52 +633,38 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
private static bool AddResources(Project project, List<string> compilerArgs, string intermediateOutputPath)
|
||||
{
|
||||
string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory);
|
||||
|
||||
foreach (var resourceFile in project.Files.ResourceFiles)
|
||||
{
|
||||
string resourceName = null;
|
||||
string rootNamespace = null;
|
||||
|
||||
var resourcePath = resourceFile.Key;
|
||||
|
||||
if (string.IsNullOrEmpty(resourceFile.Value))
|
||||
if (!string.IsNullOrEmpty(ResourceUtility.GetResourceCultureName(resourcePath)))
|
||||
{
|
||||
// No logical name, so use the file name
|
||||
resourceName = ResourcePathUtility.GetResourceName(root, resourcePath);
|
||||
rootNamespace = project.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceName = CreateCSharpManifestResourceName.EnsureResourceExtension(resourceFile.Value, resourcePath);
|
||||
rootNamespace = null;
|
||||
// Include only "neutral" resources into main assembly
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = CreateCSharpManifestResourceName.CreateManifestName(resourceName, rootNamespace);
|
||||
var name = GetResourceFileMetadataName(project, resourceFile);
|
||||
|
||||
var fileName = resourcePath;
|
||||
|
||||
if (ResourcePathUtility.IsResxResourceFile(fileName))
|
||||
if (ResourceUtility.IsResxFile(fileName))
|
||||
{
|
||||
var ext = Path.GetExtension(fileName);
|
||||
// {file}.resx -> {file}.resources
|
||||
var resourcesFile = Path.Combine(intermediateOutputPath, name);
|
||||
|
||||
if (string.Equals(ext, ".resx", StringComparison.OrdinalIgnoreCase))
|
||||
var result = Command.Create("dotnet-resgen", $"\"{fileName}\" -o \"{resourcesFile}\"")
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
// {file}.resx -> {file}.resources
|
||||
var resourcesFile = Path.Combine(intermediateOutputPath, name);
|
||||
|
||||
var result = Command.Create("dotnet-resgen", $"\"{fileName}\" \"{resourcesFile}\"")
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use this as the resource name instead
|
||||
fileName = resourcesFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use this as the resource name instead
|
||||
fileName = resourcesFile;
|
||||
}
|
||||
|
||||
compilerArgs.Add($"--resource:\"{fileName}\",{name}");
|
||||
|
@ -682,6 +673,71 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
return true;
|
||||
}
|
||||
|
||||
private static string GetResourceFileMetadataName(Project project, KeyValuePair<string, string> resourceFile)
|
||||
{
|
||||
string resourceName = null;
|
||||
string rootNamespace = null;
|
||||
|
||||
string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory);
|
||||
string resourcePath = resourceFile.Key;
|
||||
if (string.IsNullOrEmpty(resourceFile.Value))
|
||||
{
|
||||
// No logical name, so use the file name
|
||||
resourceName = ResourceUtility.GetResourceName(root, resourcePath);
|
||||
rootNamespace = project.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceName = ResourceManifestName.EnsureResourceExtension(resourceFile.Value, resourcePath);
|
||||
rootNamespace = null;
|
||||
}
|
||||
|
||||
var name = ResourceManifestName.CreateManifestName(resourceName, rootNamespace);
|
||||
return name;
|
||||
}
|
||||
|
||||
private static bool GenerateResourceAssemblies(Project project, List<LibraryExport> dependencies, string outputPath, string configuration)
|
||||
{
|
||||
var references = dependencies.SelectMany(libraryExport => libraryExport.CompilationAssemblies);
|
||||
|
||||
foreach (var resourceFileGroup in project.Files.ResourceFiles.GroupBy(file => ResourceUtility.GetResourceCultureName(file.Key)))
|
||||
{
|
||||
var culture = resourceFileGroup.Key;
|
||||
if (!string.IsNullOrEmpty(culture))
|
||||
{
|
||||
var resourceOutputPath = Path.Combine(outputPath, culture);
|
||||
|
||||
if (!Directory.Exists(resourceOutputPath))
|
||||
{
|
||||
Directory.CreateDirectory(resourceOutputPath);
|
||||
}
|
||||
|
||||
var resourceOuputFile = Path.Combine(resourceOutputPath, project.Name + ".resources.dll");
|
||||
|
||||
var arguments = new List<string>();
|
||||
arguments.AddRange(references.Select(r => $"-r \"{r.ResolvedPath}\""));
|
||||
arguments.Add($"-o \"{resourceOuputFile}\"");
|
||||
arguments.Add($"-c {culture}");
|
||||
|
||||
foreach (var resourceFile in resourceFileGroup)
|
||||
{
|
||||
var metadataName = GetResourceFileMetadataName(project, resourceFile);
|
||||
arguments.Add($"\"{resourceFile.Key}\",{metadataName}");
|
||||
}
|
||||
|
||||
var result = Command.Create("dotnet-resgen", arguments)
|
||||
.ForwardStdErr()
|
||||
.ForwardStdOut()
|
||||
.Execute();
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ISet<ProjectDescription> Sort(Dictionary<string, ProjectDescription> projects)
|
||||
{
|
||||
var outputs = new HashSet<ProjectDescription>();
|
||||
|
|
|
@ -5,10 +5,11 @@ using System;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
internal static class CreateCSharpManifestResourceName
|
||||
internal static class ResourceManifestName
|
||||
{
|
||||
// Original source: https://raw.githubusercontent.com/Microsoft/msbuild/82177a50da735cc0443ac10fa490d69368403d71/src/XMakeTasks/CreateCSharpManifestResourceName.cs
|
||||
|
||||
|
@ -32,7 +33,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
// This is different from the msbuild task: we always append extensions because otherwise,
|
||||
// the emitted resource doesn't have an extension and it is not the same as in the classic
|
||||
// C# assembly
|
||||
if (ResourcePathUtility.IsResxResourceFile(fileName))
|
||||
if (ResourceUtility.IsResourceFile(fileName))
|
||||
{
|
||||
name.Append(Path.Combine(path, Path.GetFileNameWithoutExtension(fileName)));
|
||||
name.Append(".resources");
|
||||
|
@ -103,8 +104,9 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
return id.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a folder subname into identifier
|
||||
/// Make a folder subname into identifier
|
||||
/// </summary>
|
||||
private static string MakeValidSubFolderIdentifier(string subName)
|
||||
{
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
internal static class ResourcePathUtility
|
||||
{
|
||||
public static string GetResourceName(string projectFolder, string resourcePath)
|
||||
{
|
||||
// If the file is outside of the project folder, we are assuming it is directly in the root
|
||||
// otherwise, keep the folders that are inside the project
|
||||
return PathUtility.IsChildOfDirectory(projectFolder, resourcePath) ?
|
||||
PathUtility.GetRelativePath(projectFolder, resourcePath) :
|
||||
Path.GetFileName(resourcePath);
|
||||
}
|
||||
|
||||
public static bool IsResxResourceFile(string fileName)
|
||||
{
|
||||
var ext = Path.GetExtension(fileName);
|
||||
|
||||
return
|
||||
string.Equals(ext, ".resx", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(ext, ".restext", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(ext, ".resources", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
"System.Reflection.Metadata": "1.1.0",
|
||||
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using System.Text;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet;
|
||||
|
@ -19,6 +18,7 @@ using Microsoft.DotNet.ProjectModel.Files;
|
|||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.DotNet.Cli.Compiler.Common;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
|
@ -142,6 +142,21 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, outputName);
|
||||
|
||||
var resourceCultures = context.ProjectFile.Files.ResourceFiles
|
||||
.Select(resourceFile => ResourceUtility.GetResourceCultureName(resourceFile.Key))
|
||||
.Distinct();
|
||||
|
||||
foreach (var culture in resourceCultures)
|
||||
{
|
||||
if (string.IsNullOrEmpty(culture))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resourceFilePath = Path.Combine(culture, $"{project.Name}.resources.dll");
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, resourceFilePath);
|
||||
}
|
||||
|
||||
// REVIEW: Do we keep making symbols packages?
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.pdb");
|
||||
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.mdb");
|
||||
|
@ -304,7 +319,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
string outputPath,
|
||||
string filePath)
|
||||
{
|
||||
var targetPath = Path.Combine("lib", context.TargetFramework.GetTwoDigitShortFolderName(), Path.GetFileName(filePath));
|
||||
var targetPath = Path.Combine("lib", context.TargetFramework.GetTwoDigitShortFolderName(), filePath);
|
||||
var sourcePath = Path.Combine(outputPath, filePath);
|
||||
|
||||
if (!File.Exists(sourcePath))
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
"dependencies": {
|
||||
"NETStandard.Library": "1.0.0-rc2-23608",
|
||||
"System.IO.Compression.ZipFile": "4.0.1-rc2-23608",
|
||||
"Microsoft.NETCore.Targets.DNXCore": "5.0.0-beta-23511",
|
||||
|
||||
"System.Linq": "4.0.1-rc2-23608",
|
||||
|
||||
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
|
@ -23,5 +21,12 @@
|
|||
},
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"scripts": {
|
||||
"postcompile": [
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.dll\"",
|
||||
"../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.pdb\""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
|
@ -17,53 +15,91 @@ namespace Microsoft.DotNet.Tools.Resgen
|
|||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
var app = new CommandLineApplication();
|
||||
var app = new CommandLineApplication(false);
|
||||
app.Name = "resgen";
|
||||
app.FullName = "Resource compiler";
|
||||
app.Description = "Microsoft (R) .NET Resource Generator";
|
||||
app.HelpOption("-h|--help");
|
||||
|
||||
var inputFile = app.Argument("<input>", "The .resx file to transform");
|
||||
var outputFile = app.Argument("<output>", "The .resources file to produce");
|
||||
var ouputFile = app.Option("-o", "Output file name", CommandOptionType.SingleValue);
|
||||
var culture = app.Option("-c", "Ouput assembly culture", CommandOptionType.SingleValue);
|
||||
var references = app.Option("-r", "Compilation references", CommandOptionType.MultipleValue);
|
||||
var inputFiles = app.Argument("<input>", "Input files", true);
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
WriteResourcesFileIfNotEmpty(inputFile.Value, outputFile.Value);
|
||||
if (!inputFiles.Values.Any())
|
||||
{
|
||||
Reporter.Error.WriteLine("No input files specified");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var intputResourceFiles = inputFiles.Values.Select(ParseInputFile).ToArray();
|
||||
var outputResourceFile = ResourceFile.Create(ouputFile.Value());
|
||||
|
||||
switch (outputResourceFile.Type)
|
||||
{
|
||||
case ResourceFileType.Dll:
|
||||
using (var outputStream = outputResourceFile.File.Create())
|
||||
{
|
||||
ResourceAssemblyGenerator.Generate(intputResourceFiles,
|
||||
outputStream,
|
||||
Path.GetFileNameWithoutExtension(outputResourceFile.File.Name),
|
||||
culture.Value(),
|
||||
references.Values.ToArray()
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ResourceFileType.Resources:
|
||||
using (var outputStream = outputResourceFile.File.Create())
|
||||
{
|
||||
if (intputResourceFiles.Length > 1)
|
||||
{
|
||||
Reporter.Error.WriteLine("Only one input file required when generating .resource output");
|
||||
return 1;
|
||||
}
|
||||
ResourcesFileGenerator.Generate(intputResourceFiles.Single().Resource, outputStream);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Reporter.Error.WriteLine("Resx output type not supported");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return app.Execute(args);
|
||||
}
|
||||
|
||||
private static void WriteResourcesFileIfNotEmpty(string resxFilePath, string outputFile)
|
||||
{
|
||||
using (var fs = File.OpenRead(resxFilePath))
|
||||
using (var outfs = File.Create(outputFile))
|
||||
try
|
||||
{
|
||||
var document = XDocument.Load(fs);
|
||||
|
||||
var data = document.Root.Elements("data");
|
||||
|
||||
if (data.Any())
|
||||
{
|
||||
WriteResourcesFile(outfs, data);
|
||||
}
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Reporter.Error.WriteLine(ex.ToString());
|
||||
#else
|
||||
Reporter.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteResourcesFile(Stream outfs, IEnumerable<XElement> data)
|
||||
private static ResourceSource ParseInputFile(string arg)
|
||||
{
|
||||
var rw = new ResourceWriter(outfs);
|
||||
|
||||
foreach (var e in data)
|
||||
var seperatorIndex = arg.IndexOf(',');
|
||||
string name = null;
|
||||
string metadataName = null;
|
||||
if (seperatorIndex > 0)
|
||||
{
|
||||
var name = e.Attribute("name").Value;
|
||||
var value = e.Element("value").Value;
|
||||
|
||||
rw.AddResource(name, value);
|
||||
name = arg.Substring(0, seperatorIndex);
|
||||
metadataName = arg.Substring(seperatorIndex + 1);
|
||||
}
|
||||
|
||||
rw.Generate();
|
||||
else
|
||||
{
|
||||
name = arg;
|
||||
metadataName = arg;
|
||||
}
|
||||
return new ResourceSource(ResourceFile.Create(name), metadataName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal class ResourceAssemblyGenerator
|
||||
{
|
||||
public static void Generate(ResourceSource[] sourceFiles, Stream outputStream, string asemblyName, string culture, string[] references)
|
||||
{
|
||||
if (sourceFiles == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sourceFiles));
|
||||
}
|
||||
|
||||
if (outputStream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(outputStream));
|
||||
}
|
||||
|
||||
if (!sourceFiles.Any())
|
||||
{
|
||||
throw new InvalidOperationException("No source files specified");
|
||||
}
|
||||
|
||||
var resourceDescriptions = new List<ResourceDescription>();
|
||||
foreach (var resourceInputFile in sourceFiles)
|
||||
{
|
||||
if (resourceInputFile.Resource.Type == ResourceFileType.Resx)
|
||||
{
|
||||
resourceDescriptions.Add(new ResourceDescription(
|
||||
resourceInputFile.MetadataName,
|
||||
() => GenerateResources(resourceInputFile.Resource), true));
|
||||
|
||||
}
|
||||
else if (resourceInputFile.Resource.Type == ResourceFileType.Resources)
|
||||
{
|
||||
resourceDescriptions.Add(new ResourceDescription(resourceInputFile.Resource.File.Name, () => resourceInputFile.Resource.File.OpenRead(), true));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Generation of resource assemblies from dll not supported");
|
||||
}
|
||||
}
|
||||
|
||||
var compilationOptions = new CSharpCompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary);
|
||||
var compilation = CSharpCompilation.Create(asemblyName,
|
||||
references: references.Select(reference => MetadataReference.CreateFromFile(reference)),
|
||||
options: compilationOptions);
|
||||
|
||||
if (!string.IsNullOrEmpty(culture))
|
||||
{
|
||||
compilation = compilation.AddSyntaxTrees(new[]
|
||||
{
|
||||
CSharpSyntaxTree.ParseText($"[assembly:System.Reflection.AssemblyCultureAttribute(\"{culture}\")]")
|
||||
});
|
||||
}
|
||||
|
||||
var result = compilation.Emit(outputStream, manifestResources: resourceDescriptions);
|
||||
if (!result.Success)
|
||||
{
|
||||
foreach (var diagnostic in result.Diagnostics)
|
||||
{
|
||||
Reporter.Error.WriteLine(diagnostic.ToString());
|
||||
}
|
||||
throw new InvalidOperationException("Error occured while emiting assembly");
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream GenerateResources(ResourceFile resourceFile)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
ResourcesFileGenerator.Generate(resourceFile, stream);
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
44
src/Microsoft.DotNet.Tools.Resgen/ResourceFile.cs
Normal file
44
src/Microsoft.DotNet.Tools.Resgen/ResourceFile.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal struct ResourceFile
|
||||
{
|
||||
public ResourceFile(FileInfo file, ResourceFileType type)
|
||||
{
|
||||
File = file;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public FileInfo File { get; }
|
||||
|
||||
public ResourceFileType Type { get; }
|
||||
|
||||
public static ResourceFile Create(string fileName)
|
||||
{
|
||||
var fileInfo = new FileInfo(fileName);
|
||||
|
||||
ResourceFileType type;
|
||||
switch (fileInfo.Extension.ToLowerInvariant())
|
||||
{
|
||||
case ".resx":
|
||||
type = ResourceFileType.Resx;
|
||||
break;
|
||||
case ".resources":
|
||||
type = ResourceFileType.Resources;
|
||||
break;
|
||||
case ".dll":
|
||||
type = ResourceFileType.Dll;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported resource file");
|
||||
}
|
||||
|
||||
return new ResourceFile(fileInfo, type);
|
||||
}
|
||||
}
|
||||
}
|
12
src/Microsoft.DotNet.Tools.Resgen/ResourceFileType.cs
Normal file
12
src/Microsoft.DotNet.Tools.Resgen/ResourceFileType.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal enum ResourceFileType
|
||||
{
|
||||
Resx,
|
||||
Resources,
|
||||
Dll
|
||||
}
|
||||
}
|
18
src/Microsoft.DotNet.Tools.Resgen/ResourceSource.cs
Normal file
18
src/Microsoft.DotNet.Tools.Resgen/ResourceSource.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal struct ResourceSource
|
||||
{
|
||||
public ResourceSource(ResourceFile resource, string metadataName)
|
||||
{
|
||||
Resource = resource;
|
||||
MetadataName = metadataName;
|
||||
}
|
||||
|
||||
public ResourceFile Resource { get; }
|
||||
|
||||
public string MetadataName { get; }
|
||||
}
|
||||
}
|
37
src/Microsoft.DotNet.Tools.Resgen/ResourcesFileGenerator.cs
Normal file
37
src/Microsoft.DotNet.Tools.Resgen/ResourcesFileGenerator.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Resgen
|
||||
{
|
||||
internal class ResourcesFileGenerator
|
||||
{
|
||||
public static void Generate(ResourceFile sourceFile, Stream outputStream)
|
||||
{
|
||||
if (outputStream == null) throw new ArgumentNullException(nameof(outputStream));
|
||||
using (var input = sourceFile.File.OpenRead())
|
||||
{
|
||||
var document = XDocument.Load(input);
|
||||
var data = document.Root.Elements("data");
|
||||
if (data.Any())
|
||||
{
|
||||
var rw = new ResourceWriter(outputStream);
|
||||
|
||||
foreach (var e in data)
|
||||
{
|
||||
var name = e.Attribute("name").Value;
|
||||
var value = e.Element("value").Value;
|
||||
rw.AddResource(name, value);
|
||||
}
|
||||
|
||||
rw.Generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
"System.Xml.XDocument": "4.0.11-rc2-23608",
|
||||
"System.Resources.ReaderWriter": "4.0.0-rc2-23608",
|
||||
|
||||
"Microsoft.CodeAnalysis.CSharp": "1.1.1",
|
||||
"Microsoft.DotNet.Cli.Utils": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-*"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0.23107" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.23107</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>482b1045-a1fa-4063-a0d9-a8107a91a016</ProjectGuid>
|
||||
<RootNamespace>Microsoft.Extensions.DependencyModel</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
Loading…
Reference in a new issue