Made changes to compilation and other things
- Added basic support for embedded resources (resx files are next!) - Print out exit code from executed command (makes debugging easier) - Fixed dnvm2.cmd to avoid putting things on the user path - Fixed up propagation of exit codes
This commit is contained in:
parent
dc46d3e23e
commit
6ba4781c4f
7 changed files with 493 additions and 20 deletions
|
@ -1533,12 +1533,12 @@ function dnvm-use {
|
||||||
_WriteOut "Removing all runtimes from process PATH"
|
_WriteOut "Removing all runtimes from process PATH"
|
||||||
Set-Path (Change-Path $env:Path "" ($RuntimeDirs))
|
Set-Path (Change-Path $env:Path "" ($RuntimeDirs))
|
||||||
|
|
||||||
if ($Persistent) {
|
#if ($Persistent) {
|
||||||
_WriteOut "Removing all runtimes from user PATH"
|
# _WriteOut "Removing all runtimes from user PATH"
|
||||||
$userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
|
# $userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
|
||||||
$userPath = Change-Path $userPath "" ($RuntimeDirs)
|
# $userPath = Change-Path $userPath "" ($RuntimeDirs)
|
||||||
[Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User)
|
# [Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User)
|
||||||
}
|
#}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1553,12 +1553,12 @@ function dnvm-use {
|
||||||
_WriteOut "Adding $runtimeBin to process PATH"
|
_WriteOut "Adding $runtimeBin to process PATH"
|
||||||
Set-Path (Change-Path $env:Path $runtimeBin ($RuntimeDirs))
|
Set-Path (Change-Path $env:Path $runtimeBin ($RuntimeDirs))
|
||||||
|
|
||||||
if ($Persistent) {
|
#if ($Persistent) {
|
||||||
_WriteOut "Adding $runtimeBin to user PATH"
|
# _WriteOut "Adding $runtimeBin to user PATH"
|
||||||
$userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
|
# $userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
|
||||||
$userPath = Change-Path $userPath $runtimeBin ($RuntimeDirs)
|
# $userPath = Change-Path $userPath $runtimeBin ($RuntimeDirs)
|
||||||
[Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User)
|
# [Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User)
|
||||||
}
|
#}
|
||||||
}
|
}
|
||||||
|
|
||||||
<#
|
<#
|
||||||
|
@ -1682,10 +1682,10 @@ function dnvm-setup {
|
||||||
Set-Path (Change-Path $env:PATH $Destination $PathsToRemove)
|
Set-Path (Change-Path $env:PATH $Destination $PathsToRemove)
|
||||||
|
|
||||||
if(!$SkipUserEnvironmentInstall) {
|
if(!$SkipUserEnvironmentInstall) {
|
||||||
_WriteOut "Adding $Destination to User PATH"
|
#_WriteOut "Adding $Destination to User PATH"
|
||||||
$userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
|
#$userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
|
||||||
$userPath = Change-Path $userPath $Destination $PathsToRemove
|
#$userPath = Change-Path $userPath $Destination $PathsToRemove
|
||||||
[Environment]::SetEnvironmentVariable("PATH", $userPath, "User")
|
#[Environment]::SetEnvironmentVariable("PATH", $userPath, "User")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Now the HomeEnvVar
|
# Now the HomeEnvVar
|
||||||
|
|
|
@ -137,6 +137,10 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
var exitCode = await _processTcs.Task;
|
var exitCode = await _processTcs.Task;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Console.WriteLine($"> {_process.StartInfo.FileName} {_process.StartInfo.Arguments} exited with {exitCode}.");
|
||||||
|
#endif
|
||||||
|
|
||||||
return new CommandResult(
|
return new CommandResult(
|
||||||
exitCode,
|
exitCode,
|
||||||
_stdOutCapture?.GetStringBuilder()?.ToString(),
|
_stdOutCapture?.GetStringBuilder()?.ToString(),
|
||||||
|
|
202
src/Microsoft.DotNet.Cli.Utils/PathUtility.cs
Normal file
202
src/Microsoft.DotNet.Cli.Utils/PathUtility.cs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tools.Common
|
||||||
|
{
|
||||||
|
internal static class PathUtility
|
||||||
|
{
|
||||||
|
public static bool IsPlaceholderFile(string path)
|
||||||
|
{
|
||||||
|
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsChildOfDirectory(string dir, string candidate)
|
||||||
|
{
|
||||||
|
if (dir == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(dir));
|
||||||
|
}
|
||||||
|
if (candidate == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(candidate));
|
||||||
|
}
|
||||||
|
dir = Path.GetFullPath(dir);
|
||||||
|
dir = EnsureTrailingSlash(dir);
|
||||||
|
candidate = Path.GetFullPath(candidate);
|
||||||
|
return candidate.StartsWith(dir, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EnsureTrailingSlash(string path)
|
||||||
|
{
|
||||||
|
return EnsureTrailingCharacter(path, Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EnsureTrailingForwardSlash(string path)
|
||||||
|
{
|
||||||
|
return EnsureTrailingCharacter(path, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EnsureTrailingCharacter(string path, char trailingCharacter)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the path is empty, we want to return the original string instead of a single trailing character.
|
||||||
|
if (path.Length == 0 || path[path.Length - 1] == trailingCharacter)
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path + trailingCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnsureParentDirectory(string filePath)
|
||||||
|
{
|
||||||
|
string directory = Path.GetDirectoryName(filePath);
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns path2 relative to path1, with Path.DirectorySeparatorChar as separator
|
||||||
|
/// </summary>
|
||||||
|
public static string GetRelativePath(string path1, string path2)
|
||||||
|
{
|
||||||
|
return GetRelativePath(path1, path2, Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns path2 relative to path1, with given path separator
|
||||||
|
/// </summary>
|
||||||
|
public static string GetRelativePath(string path1, string path2, char separator)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path1))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Path must have a value", nameof(path1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(path2))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Path must have a value", nameof(path2));
|
||||||
|
}
|
||||||
|
|
||||||
|
StringComparison compare;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
compare = StringComparison.OrdinalIgnoreCase;
|
||||||
|
// check if paths are on the same volume
|
||||||
|
if (!string.Equals(Path.GetPathRoot(path1), Path.GetPathRoot(path2)))
|
||||||
|
{
|
||||||
|
// on different volumes, "relative" path is just path2
|
||||||
|
return path2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compare = StringComparison.Ordinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
var path1Segments = path1.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
var path2Segments = path2.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
// if path1 does not end with / it is assumed the end is not a directory
|
||||||
|
// we will assume that is isn't a directory by ignoring the last split
|
||||||
|
var len1 = path1Segments.Length - 1;
|
||||||
|
var len2 = path2Segments.Length;
|
||||||
|
|
||||||
|
// find largest common absolute path between both paths
|
||||||
|
var min = Math.Min(len1, len2);
|
||||||
|
while (min > index)
|
||||||
|
{
|
||||||
|
if (!string.Equals(path1Segments[index], path2Segments[index], compare))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Handle scenarios where folder and file have same name (only if os supports same name for file and directory)
|
||||||
|
// e.g. /file/name /file/name/app
|
||||||
|
else if ((len1 == index && len2 > index + 1) || (len1 > index && len2 == index + 1))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = "";
|
||||||
|
|
||||||
|
// check if path2 ends with a non-directory separator and if path1 has the same non-directory at the end
|
||||||
|
if (len1 + 1 == len2 && !string.IsNullOrEmpty(path1Segments[index]) &&
|
||||||
|
string.Equals(path1Segments[index], path2Segments[index], compare))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = index; len1 > i; ++i)
|
||||||
|
{
|
||||||
|
path += ".." + separator;
|
||||||
|
}
|
||||||
|
for (var i = index; len2 - 1 > i; ++i)
|
||||||
|
{
|
||||||
|
path += path2Segments[i] + separator;
|
||||||
|
}
|
||||||
|
// if path2 doesn't end with an empty string it means it ended with a non-directory name, so we add it back
|
||||||
|
if (!string.IsNullOrEmpty(path2Segments[len2 - 1]))
|
||||||
|
{
|
||||||
|
path += path2Segments[len2 - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetAbsolutePath(string basePath, string relativePath)
|
||||||
|
{
|
||||||
|
if (basePath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relativePath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(relativePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri resultUri = new Uri(new Uri(basePath), new Uri(relativePath, UriKind.Relative));
|
||||||
|
return resultUri.LocalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDirectoryName(string path)
|
||||||
|
{
|
||||||
|
path = path.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
|
return path.Substring(Path.GetDirectoryName(path).Length).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPathWithForwardSlashes(string path)
|
||||||
|
{
|
||||||
|
return path.Replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPathWithBackSlashes(string path)
|
||||||
|
{
|
||||||
|
return path.Replace('/', '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPathWithDirectorySeparator(string path)
|
||||||
|
{
|
||||||
|
if (Path.DirectorySeparatorChar == '/')
|
||||||
|
{
|
||||||
|
return GetPathWithForwardSlashes(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetPathWithBackSlashes(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
DebugHelper.HandleDebugSwitch(ref args);
|
DebugHelper.HandleDebugSwitch(ref args);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
|
||||||
return result.ExitCode;
|
return result.ExitCode;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.Execute(args);
|
return app.Execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Command RunCsc(string cscArgs)
|
private static Command RunCsc(string cscArgs)
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Microsoft.DotNet.Tools.Common;
|
||||||
using Microsoft.Extensions.ProjectModel;
|
using Microsoft.Extensions.ProjectModel;
|
||||||
using Microsoft.Extensions.ProjectModel.Compilation;
|
using Microsoft.Extensions.ProjectModel.Compilation;
|
||||||
using NuGet.Frameworks;
|
using NuGet.Frameworks;
|
||||||
|
@ -162,7 +163,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
"-nologo",
|
"-nologo",
|
||||||
$"-out:\"{outputName}\""
|
$"-out:\"{outputName}\""
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!bootstrappingWithMono)
|
if (!bootstrappingWithMono)
|
||||||
{
|
{
|
||||||
// Default suppressions, some versions of mono don't support these
|
// Default suppressions, some versions of mono don't support these
|
||||||
|
@ -183,6 +184,8 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
// Add project source files
|
// Add project source files
|
||||||
compilerArgs.AddRange(context.ProjectFile.Files.SourceFiles);
|
compilerArgs.AddRange(context.ProjectFile.Files.SourceFiles);
|
||||||
|
|
||||||
|
AddResources(context.ProjectFile, compilerArgs);
|
||||||
|
|
||||||
// TODO: Read this from the project
|
// TODO: Read this from the project
|
||||||
const string compiler = "csc";
|
const string compiler = "csc";
|
||||||
|
|
||||||
|
@ -200,11 +203,48 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
if (result.ExitCode == 0)
|
if (result.ExitCode == 0)
|
||||||
{
|
{
|
||||||
Reporter.Output.WriteLine($"Compiled to {outputPath} successfully!".Green().Bold());
|
Reporter.Output.WriteLine($"Compiled to {outputPath} successfully!".Green().Bold());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AddResources(Project project, List<string> compilerArgs)
|
||||||
|
{
|
||||||
|
string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory);
|
||||||
|
|
||||||
|
foreach (var resourceFile in project.Files.ResourceFiles)
|
||||||
|
{
|
||||||
|
string resourceName = null;
|
||||||
|
string rootNamespace = null;
|
||||||
|
|
||||||
|
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
|
||||||
|
resourceName = ResourcePathUtility.GetResourceName(root, resourcePath);
|
||||||
|
rootNamespace = project.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resourceName = CreateCSharpManifestResourceName.EnsureResourceExtension(resourceFile.Value, resourcePath);
|
||||||
|
rootNamespace = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = CreateCSharpManifestResourceName.CreateManifestName(resourceName, rootNamespace);
|
||||||
|
var fileName = resourcePath;
|
||||||
|
|
||||||
|
compilerArgs.Add($"-resource:\"{fileName}\",{name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ISet<ProjectDescription> Sort(Dictionary<string, ProjectDescription> projects)
|
private static ISet<ProjectDescription> Sort(Dictionary<string, ProjectDescription> projects)
|
||||||
{
|
{
|
||||||
var outputs = new HashSet<ProjectDescription>();
|
var outputs = new HashSet<ProjectDescription>();
|
||||||
|
@ -279,7 +319,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
{
|
{
|
||||||
cscArgs.Add("-debug:portable");
|
cscArgs.Add("-debug:portable");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: OSS signing
|
// TODO: OSS signing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tools.Compiler
|
||||||
|
{
|
||||||
|
internal static class CreateCSharpManifestResourceName
|
||||||
|
{
|
||||||
|
// Original source: https://raw.githubusercontent.com/Microsoft/msbuild/82177a50da735cc0443ac10fa490d69368403d71/src/XMakeTasks/CreateCSharpManifestResourceName.cs
|
||||||
|
|
||||||
|
public static string CreateManifestName(string fileName, string rootNamespace)
|
||||||
|
{
|
||||||
|
var name = new StringBuilder();
|
||||||
|
|
||||||
|
// Differences from the msbuild task:
|
||||||
|
// - we do not include the name of the first class (if any) for binary resources or source code
|
||||||
|
// - culture info is ignored
|
||||||
|
|
||||||
|
if (rootNamespace != null && rootNamespace.Length > 0)
|
||||||
|
{
|
||||||
|
name.Append(rootNamespace).Append(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace spaces in the directory name with underscores.
|
||||||
|
// Note that spaces in the file name itself are preserved.
|
||||||
|
var path = MakeValidIdentifier(Path.GetDirectoryName(fileName));
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
name.Append(Path.Combine(path, Path.GetFileNameWithoutExtension(fileName)));
|
||||||
|
name.Append(".resources");
|
||||||
|
name.Replace(Path.DirectorySeparatorChar, '.');
|
||||||
|
name.Replace(Path.AltDirectorySeparatorChar, '.');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name.Append(Path.Combine(path, Path.GetFileName(fileName)));
|
||||||
|
name.Replace(Path.DirectorySeparatorChar, '.');
|
||||||
|
name.Replace(Path.AltDirectorySeparatorChar, '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The code below the same is same as here: https://raw.githubusercontent.com/Microsoft/msbuild/41b137cd8805079af7792995e044521d62fcb005/src/XMakeTasks/CreateManifestResourceName.cs
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is provided for compatibility with MsBuild which used to convert parts of resource names into
|
||||||
|
/// valid identifiers
|
||||||
|
/// </summary>
|
||||||
|
private static string MakeValidIdentifier(string name)
|
||||||
|
{
|
||||||
|
var id = new StringBuilder(name.Length);
|
||||||
|
|
||||||
|
// split the name into folder names
|
||||||
|
var subNames = name.Split(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
|
||||||
|
|
||||||
|
// convert every folder name
|
||||||
|
id.Append(MakeValidFolderIdentifier(subNames[0]));
|
||||||
|
|
||||||
|
for (int i = 1; i < subNames.Length; i++)
|
||||||
|
{
|
||||||
|
id.Append('.');
|
||||||
|
id.Append(MakeValidFolderIdentifier(subNames[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Make a folder name into an identifier
|
||||||
|
/// </summary>
|
||||||
|
private static string MakeValidFolderIdentifier(string name)
|
||||||
|
{
|
||||||
|
// give string length to avoid reallocations; +1 since the resulting string may be one char longer than the
|
||||||
|
// original - if the name is a single underscore we add another underscore to it
|
||||||
|
var id = new StringBuilder(name.Length + 1);
|
||||||
|
|
||||||
|
// split folder name into subnames separated by '.', if any
|
||||||
|
var subNames = name.Split(new char[] { '.' });
|
||||||
|
|
||||||
|
// convert each subname separately
|
||||||
|
id.Append(MakeValidSubFolderIdentifier(subNames[0]));
|
||||||
|
|
||||||
|
for (int i = 1; i < subNames.Length; i++)
|
||||||
|
{
|
||||||
|
id.Append('.');
|
||||||
|
id.Append(MakeValidSubFolderIdentifier(subNames[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// folder name cannot be a single underscore - add another underscore to it
|
||||||
|
if (id.ToString() == "_")
|
||||||
|
{
|
||||||
|
id.Append('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
return id.ToString();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Make a folder subname into identifier
|
||||||
|
/// </summary>
|
||||||
|
private static string MakeValidSubFolderIdentifier(string subName)
|
||||||
|
{
|
||||||
|
if (subName.Length == 0)
|
||||||
|
{
|
||||||
|
return subName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// give string length to avoid reallocations; +1 since the resulting string may be one char longer than the
|
||||||
|
// original - if the first character is an invalid first identifier character but a valid subsequent one,
|
||||||
|
// we prepend an underscore to it.
|
||||||
|
var id = new StringBuilder(subName.Length + 1);
|
||||||
|
|
||||||
|
// the first character has stronger restrictions than the rest
|
||||||
|
if (!IsValidIdFirstChar(subName[0]))
|
||||||
|
{
|
||||||
|
// if the first character is not even a valid subsequent character, replace it with an underscore
|
||||||
|
if (!IsValidIdChar(subName[0]))
|
||||||
|
{
|
||||||
|
id.Append('_');
|
||||||
|
}
|
||||||
|
// if it is a valid subsequent character, prepend an underscore to it
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id.Append('_');
|
||||||
|
id.Append(subName[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id.Append(subName[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the rest of the subname
|
||||||
|
for (int i = 1; i < subName.Length; i++)
|
||||||
|
{
|
||||||
|
if (!IsValidIdChar(subName[i]))
|
||||||
|
{
|
||||||
|
id.Append('_');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id.Append(subName[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the character a valid first identifier character?
|
||||||
|
/// </summary>
|
||||||
|
private static bool IsValidIdFirstChar(char c)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
char.IsLetter(c) ||
|
||||||
|
CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the character a valid identifier character?
|
||||||
|
/// </summary>
|
||||||
|
private static bool IsValidIdChar(char c)
|
||||||
|
{
|
||||||
|
var cat = CharUnicodeInfo.GetUnicodeCategory(c);
|
||||||
|
|
||||||
|
return
|
||||||
|
char.IsLetterOrDigit(c) ||
|
||||||
|
cat == UnicodeCategory.ConnectorPunctuation ||
|
||||||
|
cat == UnicodeCategory.NonSpacingMark ||
|
||||||
|
cat == UnicodeCategory.SpacingCombiningMark ||
|
||||||
|
cat == UnicodeCategory.EnclosingMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EnsureResourceExtension(string logicalName, string resourceFilePath)
|
||||||
|
{
|
||||||
|
string resourceExtension = Path.GetExtension(resourceFilePath);
|
||||||
|
if (!string.IsNullOrEmpty(resourceExtension))
|
||||||
|
{
|
||||||
|
if (!logicalName.EndsWith(resourceExtension, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
logicalName += resourceExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logicalName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue