Refactor ScriptExecutor, add test cases for scriptexecutor.
Add TargetFramework and FullTargetFramework to compile and publish script variables. Add ProjectLocal Command Resolution Strategy. Fixup ArgumentEscaper to not always quote things. Fixes #1216 Fixes #1016 Fixes #982
This commit is contained in:
parent
dbc9032202
commit
c1e28ae921
21 changed files with 421 additions and 164 deletions
|
@ -13,10 +13,5 @@
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"dnxcore50": { }
|
"dnxcore50": { }
|
||||||
},
|
|
||||||
|
|
||||||
"scripts": {
|
|
||||||
"prepublish" : ["echo prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"],
|
|
||||||
"postpublish" : ["echo postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
TestAssets/TestProjects/TestAppWithScripts/Program.cs
Normal file
17
TestAssets/TestProjects/TestAppWithScripts/Program.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
|
||||||
|
namespace TestApp
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello World");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj
Normal file
20
TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>58808bbc-371e-47d6-a3d0-4902145eda4e</ProjectGuid>
|
||||||
|
<RootNamespace>TestApp</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>
|
|
@ -0,0 +1,2 @@
|
||||||
|
@echo off
|
||||||
|
echo %*
|
1
TestAssets/TestProjects/TestAppWithScripts/echoscript.sh
Normal file
1
TestAssets/TestProjects/TestAppWithScripts/echoscript.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
echo $@
|
22
TestAssets/TestProjects/TestAppWithScripts/project.json
Normal file
22
TestAssets/TestProjects/TestAppWithScripts/project.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"version": "1.0.0-*",
|
||||||
|
"compilationOptions": {
|
||||||
|
"emitEntryPoint": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"NETStandard.Library": "1.0.0-rc2-23811"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frameworks": {
|
||||||
|
"dnxcore50": { }
|
||||||
|
},
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"prepublish" : ["echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"],
|
||||||
|
"postpublish" : ["echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"],
|
||||||
|
|
||||||
|
"precompile" : ["echoscript precompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"],
|
||||||
|
"postcompile" : ["echoscript postcompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,8 +86,10 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
var quoted = ShouldSurroundWithQuotes(arg);
|
var needsQuotes = ShouldSurroundWithQuotes(arg);
|
||||||
if (quoted) sb.Append("\"");
|
var isQuoted = needsQuotes || IsSurroundedWithQuotes(arg);
|
||||||
|
|
||||||
|
if (needsQuotes) sb.Append("\"");
|
||||||
|
|
||||||
for (int i = 0; i < arg.Length; ++i)
|
for (int i = 0; i < arg.Length; ++i)
|
||||||
{
|
{
|
||||||
|
@ -101,13 +103,21 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape any backslashes at the end of the arg
|
// Escape any backslashes at the end of the arg
|
||||||
|
// when the argument is also quoted.
|
||||||
// This ensures the outside quote is interpreted as
|
// This ensures the outside quote is interpreted as
|
||||||
// an argument delimiter
|
// an argument delimiter
|
||||||
if (i == arg.Length)
|
if (i == arg.Length && isQuoted)
|
||||||
{
|
{
|
||||||
sb.Append('\\', 2 * backslashCount);
|
sb.Append('\\', 2 * backslashCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At then end of the arg, which isn't quoted,
|
||||||
|
// just add the backslashes, no need to escape
|
||||||
|
else if (i == arg.Length)
|
||||||
|
{
|
||||||
|
sb.Append('\\', backslashCount);
|
||||||
|
}
|
||||||
|
|
||||||
// Escape any preceding backslashes and the quote
|
// Escape any preceding backslashes and the quote
|
||||||
else if (arg[i] == '"')
|
else if (arg[i] == '"')
|
||||||
{
|
{
|
||||||
|
@ -123,7 +133,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quoted) sb.Append("\"");
|
if (needsQuotes) sb.Append("\"");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
@ -149,22 +159,14 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
if (quoted) sb.Append("^\"");
|
if (quoted) sb.Append("^\"");
|
||||||
|
|
||||||
|
// Prepend every character with ^
|
||||||
|
// This is harmless when passing through cmd
|
||||||
|
// and ensures cmd metacharacters are not interpreted
|
||||||
|
// as such
|
||||||
foreach (var character in argument)
|
foreach (var character in argument)
|
||||||
{
|
{
|
||||||
|
sb.Append("^");
|
||||||
if (character == '"')
|
sb.Append(character);
|
||||||
{
|
|
||||||
|
|
||||||
sb.Append('^');
|
|
||||||
sb.Append('"');
|
|
||||||
sb.Append('^');
|
|
||||||
sb.Append(character);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.Append("^");
|
|
||||||
sb.Append(character);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quoted) sb.Append("^\"");
|
if (quoted) sb.Append("^\"");
|
||||||
|
@ -172,35 +174,27 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepare as single argument to
|
|
||||||
/// roundtrip properly through cmd.
|
|
||||||
///
|
|
||||||
/// This prefixes every character with the '^' character to force cmd to
|
|
||||||
/// interpret the argument string literally. An alternative option would
|
|
||||||
/// be to do this only for cmd metacharacters.
|
|
||||||
///
|
|
||||||
/// See here for more info:
|
|
||||||
/// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal static bool ShouldSurroundWithQuotes(string argument)
|
internal static bool ShouldSurroundWithQuotes(string argument)
|
||||||
{
|
{
|
||||||
// Don't quote already quoted strings
|
// Don't quote already quoted strings
|
||||||
if (argument.StartsWith("\"", StringComparison.Ordinal) &&
|
if (IsSurroundedWithQuotes(argument))
|
||||||
argument.EndsWith("\"", StringComparison.Ordinal))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only quote if whitespace exists in the string
|
// Only quote if whitespace exists in the string
|
||||||
if (argument.Contains(" ") || argument.Contains("\t") || argument.Contains("\n"))
|
return ArgumentContainsWhitespace(argument);
|
||||||
{
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
internal static bool IsSurroundedWithQuotes(string argument)
|
||||||
|
{
|
||||||
|
return argument.StartsWith("\"", StringComparison.Ordinal) &&
|
||||||
|
argument.EndsWith("\"", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool ArgumentContainsWhitespace(string argument)
|
||||||
|
{
|
||||||
|
return argument.Contains(" ") || argument.Contains("\t") || argument.Contains("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using NuGet.Frameworks;
|
using NuGet.Frameworks;
|
||||||
|
using Microsoft.DotNet.ProjectModel;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli.Utils
|
namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
|
@ -40,9 +41,9 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
ResolutionStrategy = commandSpec.ResolutionStrategy;
|
ResolutionStrategy = commandSpec.ResolutionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Command CreateDotNet(string commandName, IEnumerable<string> args, NuGetFramework framework = null, bool useComSpec = false)
|
public static Command CreateDotNet(string commandName, IEnumerable<string> args, NuGetFramework framework = null)
|
||||||
{
|
{
|
||||||
return Create("dotnet", new[] { commandName }.Concat(args), framework, useComSpec);
|
return Create("dotnet", new[] { commandName }.Concat(args), framework);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -55,9 +56,23 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
/// <param name="args"></param>
|
/// <param name="args"></param>
|
||||||
/// <param name="framework"></param>
|
/// <param name="framework"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Command Create(string commandName, IEnumerable<string> args, NuGetFramework framework = null, bool useComSpec = false)
|
public static Command Create(string commandName, IEnumerable<string> args, NuGetFramework framework = null)
|
||||||
{
|
{
|
||||||
var commandSpec = CommandResolver.TryResolveCommandSpec(commandName, args, framework, useComSpec);
|
var commandSpec = CommandResolver.TryResolveCommandSpec(commandName, args, framework);
|
||||||
|
|
||||||
|
if (commandSpec == null)
|
||||||
|
{
|
||||||
|
throw new CommandUnknownException(commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = new Command(commandSpec);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Command CreateForScript(string commandName, IEnumerable<string> args, Project project, string[] inferredExtensionList)
|
||||||
|
{
|
||||||
|
var commandSpec = CommandResolver.TryResolveScriptCommandSpec(commandName, args, project, inferredExtensionList);
|
||||||
|
|
||||||
if (commandSpec == null)
|
if (commandSpec == null)
|
||||||
{
|
{
|
||||||
|
@ -197,6 +212,8 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
public string CommandName => _process.StartInfo.FileName;
|
public string CommandName => _process.StartInfo.FileName;
|
||||||
|
|
||||||
|
public string CommandArgs => _process.StartInfo.Arguments;
|
||||||
|
|
||||||
private string FormatProcessInfo(ProcessStartInfo info)
|
private string FormatProcessInfo(ProcessStartInfo info)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(info.Arguments))
|
if (string.IsNullOrWhiteSpace(info.Arguments))
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
//command loaded from the same directory as the executing assembly
|
//command loaded from the same directory as the executing assembly
|
||||||
BaseDirectory,
|
BaseDirectory,
|
||||||
|
|
||||||
|
//command loaded from the same directory as a project.json file
|
||||||
|
ProjectLocal,
|
||||||
|
|
||||||
//command loaded from path
|
//command loaded from path
|
||||||
Path,
|
Path,
|
||||||
|
|
||||||
|
|
|
@ -13,52 +13,60 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
internal static class CommandResolver
|
internal static class CommandResolver
|
||||||
{
|
{
|
||||||
public static CommandSpec TryResolveCommandSpec(string commandName, IEnumerable<string> args, NuGetFramework framework = null, bool useComSpec = false)
|
public static CommandSpec TryResolveCommandSpec(string commandName, IEnumerable<string> args, NuGetFramework framework = null)
|
||||||
{
|
{
|
||||||
return ResolveFromRootedCommand(commandName, args, useComSpec) ??
|
return ResolveFromRootedCommand(commandName, args) ??
|
||||||
ResolveFromProjectDependencies(commandName, args, framework, useComSpec) ??
|
ResolveFromProjectDependencies(commandName, args, framework) ??
|
||||||
ResolveFromProjectTools(commandName, args, useComSpec) ??
|
ResolveFromProjectTools(commandName, args) ??
|
||||||
ResolveFromAppBase(commandName, args, useComSpec) ??
|
ResolveFromAppBase(commandName, args) ??
|
||||||
ResolveFromPath(commandName, args, useComSpec);
|
ResolveFromPath(commandName, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandSpec TryResolveScriptCommandSpec(string commandName, IEnumerable<string> args, Project project, string[] inferredExtensionList)
|
||||||
|
{
|
||||||
|
return ResolveFromRootedCommand(commandName, args) ??
|
||||||
|
ResolveFromProjectPath(commandName, args, project, inferredExtensionList) ??
|
||||||
|
ResolveFromAppBase(commandName, args) ??
|
||||||
|
ResolveFromPath(commandName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec ResolveFromPath(string commandName, IEnumerable<string> args, bool useComSpec = false)
|
private static CommandSpec ResolveFromPath(string commandName, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
var commandPath = Env.GetCommandPath(commandName);
|
var commandPath = Env.GetCommandPath(commandName);
|
||||||
return commandPath == null
|
return commandPath == null
|
||||||
? null
|
? null
|
||||||
: CreateCommandSpecPreferringExe(commandName, args, commandPath, CommandResolutionStrategy.Path, useComSpec);
|
: CreateCommandSpecPreferringExe(commandName, args, commandPath, CommandResolutionStrategy.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec ResolveFromAppBase(string commandName, IEnumerable<string> args, bool useComSpec = false)
|
private static CommandSpec ResolveFromAppBase(string commandName, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
var commandPath = Env.GetCommandPathFromAppBase(PlatformServices.Default.Application.ApplicationBasePath, commandName);
|
var commandPath = Env.GetCommandPathFromRootPath(PlatformServices.Default.Application.ApplicationBasePath, commandName);
|
||||||
return commandPath == null
|
return commandPath == null
|
||||||
? null
|
? null
|
||||||
: CreateCommandSpecPreferringExe(commandName, args, commandPath, CommandResolutionStrategy.BaseDirectory, useComSpec);
|
: CreateCommandSpecPreferringExe(commandName, args, commandPath, CommandResolutionStrategy.BaseDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CommandSpec ResolveFromProjectPath(string commandName, IEnumerable<string> args, Project project, string[] inferredExtensionList)
|
||||||
|
{
|
||||||
|
var commandPath = Env.GetCommandPathFromRootPath(project.ProjectDirectory, commandName, inferredExtensionList);
|
||||||
|
return commandPath == null
|
||||||
|
? null
|
||||||
|
: CreateCommandSpecPreferringExe(commandName, args, commandPath, CommandResolutionStrategy.ProjectLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec ResolveFromRootedCommand(string commandName, IEnumerable<string> args, bool useComSpec = false)
|
private static CommandSpec ResolveFromRootedCommand(string commandName, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
if (Path.IsPathRooted(commandName))
|
if (Path.IsPathRooted(commandName))
|
||||||
{
|
{
|
||||||
if (useComSpec)
|
var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args);
|
||||||
{
|
return new CommandSpec(commandName, escapedArgs, CommandResolutionStrategy.Path);
|
||||||
return CreateComSpecCommandSpec(commandName, args, CommandResolutionStrategy.Path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args);
|
|
||||||
return new CommandSpec(commandName, escapedArgs, CommandResolutionStrategy.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandSpec ResolveFromProjectDependencies(string commandName, IEnumerable<string> args,
|
public static CommandSpec ResolveFromProjectDependencies(string commandName, IEnumerable<string> args,
|
||||||
NuGetFramework framework, bool useComSpec = false)
|
NuGetFramework framework)
|
||||||
{
|
{
|
||||||
if (framework == null) return null;
|
if (framework == null) return null;
|
||||||
|
|
||||||
|
@ -72,7 +80,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
var depsPath = projectContext.GetOutputPaths(Constants.DefaultConfiguration).RuntimeFiles.Deps;
|
var depsPath = projectContext.GetOutputPaths(Constants.DefaultConfiguration).RuntimeFiles.Deps;
|
||||||
|
|
||||||
return ConfigureCommandFromPackage(commandName, args, commandPackage, projectContext, depsPath, useComSpec);
|
return ConfigureCommandFromPackage(commandName, args, commandPackage, projectContext, depsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProjectContext GetProjectContext(NuGetFramework framework)
|
private static ProjectContext GetProjectContext(NuGetFramework framework)
|
||||||
|
@ -101,7 +109,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
e == FileNameSuffixes.DotNet.DynamicLib));
|
e == FileNameSuffixes.DotNet.DynamicLib));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandSpec ResolveFromProjectTools(string commandName, IEnumerable<string> args, bool useComSpec = false)
|
public static CommandSpec ResolveFromProjectTools(string commandName, IEnumerable<string> args)
|
||||||
{
|
{
|
||||||
var context = GetProjectContext(FrameworkConstants.CommonFrameworks.DnxCore50);
|
var context = GetProjectContext(FrameworkConstants.CommonFrameworks.DnxCore50);
|
||||||
|
|
||||||
|
@ -147,7 +155,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec ConfigureCommandFromPackage(string commandName, IEnumerable<string> args,
|
private static CommandSpec ConfigureCommandFromPackage(string commandName, IEnumerable<string> args,
|
||||||
PackageDescription commandPackage, ProjectContext projectContext, string depsPath = null, bool useComSpec = false)
|
PackageDescription commandPackage, ProjectContext projectContext, string depsPath = null)
|
||||||
{
|
{
|
||||||
var files = commandPackage.Library.Files;
|
var files = commandPackage.Library.Files;
|
||||||
|
|
||||||
|
@ -157,11 +165,11 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
var packageDir = Path.Combine(packageRoot, packagePath);
|
var packageDir = Path.Combine(packageRoot, packagePath);
|
||||||
|
|
||||||
return ConfigureCommandFromPackage(commandName, args, files, packageDir, depsPath, useComSpec);
|
return ConfigureCommandFromPackage(commandName, args, files, packageDir, depsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec ConfigureCommandFromPackage(string commandName, IEnumerable<string> args,
|
private static CommandSpec ConfigureCommandFromPackage(string commandName, IEnumerable<string> args,
|
||||||
IEnumerable<string> files, string packageDir, string depsPath = null, bool useComSpec = false)
|
IEnumerable<string> files, string packageDir, string depsPath = null)
|
||||||
{
|
{
|
||||||
var fileName = string.Empty;
|
var fileName = string.Empty;
|
||||||
|
|
||||||
|
@ -192,24 +200,18 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
fileName = Path.Combine(packageDir, commandPath);
|
fileName = Path.Combine(packageDir, commandPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useComSpec)
|
var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args);
|
||||||
{
|
return new CommandSpec(fileName, escapedArgs, CommandResolutionStrategy.NugetPackage);
|
||||||
return CreateComSpecCommandSpec(fileName, args, CommandResolutionStrategy.NugetPackage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args);
|
|
||||||
return new CommandSpec(fileName, escapedArgs, CommandResolutionStrategy.NugetPackage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec CreateCommandSpecPreferringExe(
|
private static CommandSpec CreateCommandSpecPreferringExe(
|
||||||
string commandName,
|
string commandName,
|
||||||
IEnumerable<string> args,
|
IEnumerable<string> args,
|
||||||
string commandPath,
|
string commandPath,
|
||||||
CommandResolutionStrategy resolutionStrategy,
|
CommandResolutionStrategy resolutionStrategy)
|
||||||
bool useComSpec = false)
|
|
||||||
{
|
{
|
||||||
|
var useComSpec = false;
|
||||||
|
|
||||||
if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows &&
|
if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows &&
|
||||||
Path.GetExtension(commandPath).Equals(".cmd", StringComparison.OrdinalIgnoreCase))
|
Path.GetExtension(commandPath).Equals(".cmd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -228,7 +230,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
if (useComSpec)
|
if (useComSpec)
|
||||||
{
|
{
|
||||||
return CreateComSpecCommandSpec(commandPath, args, resolutionStrategy);
|
return CreateCmdCommandSpec(commandPath, args, resolutionStrategy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -237,14 +239,14 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommandSpec CreateComSpecCommandSpec(
|
private static CommandSpec CreateCmdCommandSpec(
|
||||||
string command,
|
string command,
|
||||||
IEnumerable<string> args,
|
IEnumerable<string> args,
|
||||||
CommandResolutionStrategy resolutionStrategy)
|
CommandResolutionStrategy resolutionStrategy)
|
||||||
{
|
{
|
||||||
// To prevent Command Not Found, comspec gets passed in as
|
|
||||||
// the command already in some cases
|
|
||||||
var comSpec = Environment.GetEnvironmentVariable("ComSpec");
|
var comSpec = Environment.GetEnvironmentVariable("ComSpec");
|
||||||
|
|
||||||
|
// Handle the case where ComSpec is already the command
|
||||||
if (command.Equals(comSpec, StringComparison.OrdinalIgnoreCase))
|
if (command.Equals(comSpec, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
command = args.FirstOrDefault();
|
command = args.FirstOrDefault();
|
||||||
|
|
|
@ -66,14 +66,14 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
return commandPath;
|
return commandPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetCommandPathFromAppBase(string appBase, string commandName, params string[] extensions)
|
public static string GetCommandPathFromRootPath(string rootPath, string commandName, params string[] extensions)
|
||||||
{
|
{
|
||||||
if (!extensions.Any())
|
if (!extensions.Any())
|
||||||
{
|
{
|
||||||
extensions = Env.ExecutableExtensions.ToArray();
|
extensions = Env.ExecutableExtensions.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var commandPath = extensions.Select(e => Path.Combine(appBase, commandName + e))
|
var commandPath = extensions.Select(e => Path.Combine(rootPath, commandName + e))
|
||||||
.FirstOrDefault(File.Exists);
|
.FirstOrDefault(File.Exists);
|
||||||
|
|
||||||
return commandPath;
|
return commandPath;
|
||||||
|
|
|
@ -17,82 +17,47 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
public static ICommand CreateCommandForScript(Project project, string scriptCommandLine, Func<string, string> getVariable)
|
public static ICommand CreateCommandForScript(Project project, string scriptCommandLine, Func<string, string> getVariable)
|
||||||
{
|
{
|
||||||
// Preserve quotation marks around arguments since command is about to be passed to a shell. May need
|
var scriptArguments = ParseScriptArguments(project, scriptCommandLine, getVariable);
|
||||||
// the quotes to ensure the shell groups arguments correctly.
|
if (scriptArguments == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"ScriptExecutor: failed to parse script \"{scriptCommandLine}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
var inferredExtensions = DetermineInferredScriptExtensions();
|
||||||
|
|
||||||
|
return Command
|
||||||
|
.CreateForScript(scriptArguments.First(), scriptArguments.Skip(1), project, inferredExtensions)
|
||||||
|
.WorkingDirectory(project.ProjectDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> ParseScriptArguments(Project project, string scriptCommandLine, Func<string, string> getVariable)
|
||||||
|
{
|
||||||
var scriptArguments = CommandGrammar.Process(
|
var scriptArguments = CommandGrammar.Process(
|
||||||
scriptCommandLine,
|
scriptCommandLine,
|
||||||
GetScriptVariable(project, getVariable),
|
GetScriptVariable(project, getVariable),
|
||||||
preserveSurroundingQuotes: true);
|
preserveSurroundingQuotes: false);
|
||||||
|
|
||||||
// Ensure the array won't be empty and the elements won't be null or empty strings.
|
|
||||||
scriptArguments = scriptArguments.Where(argument => !string.IsNullOrEmpty(argument)).ToArray();
|
scriptArguments = scriptArguments.Where(argument => !string.IsNullOrEmpty(argument)).ToArray();
|
||||||
if (scriptArguments.Length == 0)
|
if (scriptArguments.Length == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var useComSpec = false;
|
return scriptArguments;
|
||||||
|
}
|
||||||
|
|
||||||
if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows)
|
private static string[] DetermineInferredScriptExtensions()
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
// Only forward slashes are used in script blocks. Replace with backslashes to correctly
|
return new string[] { "", ".cmd" };
|
||||||
// locate the script. The directory separator is platform-specific.
|
|
||||||
scriptArguments[0] = scriptArguments[0].Replace(
|
|
||||||
Path.AltDirectorySeparatorChar,
|
|
||||||
Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
// Command-lines on Windows are executed via "cmd /S /C" in order to support batch files, &&,
|
|
||||||
// built-in commands like echo, et cetera. /S allows quoting the command as well as the arguments.
|
|
||||||
// ComSpec is Windows-specific, and contains the full path to cmd.exe
|
|
||||||
var comSpec = Environment.GetEnvironmentVariable("ComSpec");
|
|
||||||
if (!string.IsNullOrEmpty(comSpec))
|
|
||||||
{
|
|
||||||
useComSpec = true;
|
|
||||||
|
|
||||||
scriptArguments = new string[] { comSpec }
|
|
||||||
.Concat(scriptArguments)
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Special-case a script name that, perhaps with added .sh, matches an existing file.
|
return new string[] { "", ".sh" };
|
||||||
var surroundWithQuotes = false;
|
|
||||||
var scriptCandidate = scriptArguments[0];
|
|
||||||
if (scriptCandidate.StartsWith("\"", StringComparison.Ordinal) &&
|
|
||||||
scriptCandidate.EndsWith("\"", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
// Strip surrounding quotes; they were required in project.json to keep the script name
|
|
||||||
// together but confuse File.Exists() e.g. "My Script", lacking ./ prefix and .sh suffix.
|
|
||||||
surroundWithQuotes = true;
|
|
||||||
scriptCandidate = scriptCandidate.Substring(1, scriptCandidate.Length - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptCandidate.EndsWith(".sh", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
scriptCandidate = scriptCandidate + ".sh";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(Path.Combine(project.ProjectDirectory, scriptCandidate)))
|
|
||||||
{
|
|
||||||
// scriptCandidate may be a path relative to the project root. If so, likely will not be found
|
|
||||||
// in the $PATH; add ./ to let bash know where to look.
|
|
||||||
var prefix = Path.IsPathRooted(scriptCandidate) ? string.Empty : "./";
|
|
||||||
var quote = surroundWithQuotes ? "\"" : string.Empty;
|
|
||||||
scriptArguments[0] = $"{ quote }{ prefix }{ scriptCandidate }{ quote }";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always use /usr/bin/env bash -c in order to support redirection and so on; similar to Windows case.
|
|
||||||
// Unlike Windows, must escape quotation marks within the newly-quoted string.
|
|
||||||
scriptArguments = new[] { "/usr/bin/env", "bash", "-c", "\"" }
|
|
||||||
.Concat(scriptArguments.Select(argument => argument.Replace("\"", "\\\"")))
|
|
||||||
.Concat(new[] { "\"" })
|
|
||||||
.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Command.Create(scriptArguments.FirstOrDefault(), scriptArguments.Skip(1), useComSpec: useComSpec)
|
|
||||||
.WorkingDirectory(project.ProjectDirectory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Func<string, string> WrapVariableDictionary(IDictionary<string, string> contextVariables)
|
private static Func<string, string> WrapVariableDictionary(IDictionary<string, string> contextVariables)
|
||||||
{
|
{
|
||||||
return key =>
|
return key =>
|
||||||
|
|
|
@ -135,7 +135,8 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
// Run pre-compile event
|
// Run pre-compile event
|
||||||
var contextVariables = new Dictionary<string, string>()
|
var contextVariables = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName },
|
{ "compile:TargetFramework", context.TargetFramework.GetShortFolderName() },
|
||||||
|
{ "compile:FullTargetFramework", context.TargetFramework.DotNetFrameworkName },
|
||||||
{ "compile:Configuration", args.ConfigValue },
|
{ "compile:Configuration", args.ConfigValue },
|
||||||
{ "compile:OutputFile", outputName },
|
{ "compile:OutputFile", outputName },
|
||||||
{ "compile:OutputDir", outputPath.TrimEnd('\\', '/') },
|
{ "compile:OutputDir", outputPath.TrimEnd('\\', '/') },
|
||||||
|
|
|
@ -96,7 +96,8 @@ namespace Microsoft.DotNet.Tools.Publish
|
||||||
{ "publish:ProjectPath", context.ProjectDirectory },
|
{ "publish:ProjectPath", context.ProjectDirectory },
|
||||||
{ "publish:Configuration", configuration },
|
{ "publish:Configuration", configuration },
|
||||||
{ "publish:OutputPath", outputPath },
|
{ "publish:OutputPath", outputPath },
|
||||||
{ "publish:Framework", context.TargetFramework.Framework },
|
{ "publish:TargetFramework", context.TargetFramework.GetShortFolderName() },
|
||||||
|
{ "publish:FullTargetFramework", context.TargetFramework.DotNetFrameworkName },
|
||||||
{ "publish:Runtime", context.RuntimeIdentifier },
|
{ "publish:Runtime", context.RuntimeIdentifier },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -94,16 +94,12 @@ namespace Microsoft.DotNet.Tests.ArgumentForwarding
|
||||||
[InlineData("\"abc\"\t\td\te")]
|
[InlineData("\"abc\"\t\td\te")]
|
||||||
[InlineData(@"a\\b d""e f""g h")]
|
[InlineData(@"a\\b d""e f""g h")]
|
||||||
[InlineData(@"\ \\ \\\")]
|
[InlineData(@"\ \\ \\\")]
|
||||||
[InlineData(@"a\""b c d")]
|
|
||||||
[InlineData(@"a\\""b c d")]
|
[InlineData(@"a\\""b c d")]
|
||||||
[InlineData(@"a\\\""b c d")]
|
|
||||||
[InlineData(@"a\\\\""b c d")]
|
[InlineData(@"a\\\\""b c d")]
|
||||||
[InlineData(@"a\\\\""b c d")]
|
[InlineData(@"a\\\\""b c d")]
|
||||||
[InlineData(@"a\\\\""b c"" d e")]
|
[InlineData(@"a\\\\""b c"" d e")]
|
||||||
[InlineData(@"a""b c""d e""f g""h i""j k""l")]
|
[InlineData(@"a""b c""d e""f g""h i""j k""l")]
|
||||||
[InlineData(@"a b c""def")]
|
[InlineData(@"a b c""def")]
|
||||||
[InlineData(@"""\a\"" \\""\\\ b c")]
|
|
||||||
[InlineData(@"a\""b \\ cd ""\e f\"" \\""\\\")]
|
|
||||||
public void TestArgumentForwardingCmd(string testUserArgument)
|
public void TestArgumentForwardingCmd(string testUserArgument)
|
||||||
{
|
{
|
||||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
@ -153,6 +149,29 @@ namespace Microsoft.DotNet.Tests.ArgumentForwarding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(@"a\""b c d")]
|
||||||
|
[InlineData(@"a\\\""b c d")]
|
||||||
|
[InlineData(@"""\a\"" \\""\\\ b c")]
|
||||||
|
[InlineData(@"a\""b \\ cd ""\e f\"" \\""\\\")]
|
||||||
|
public void TestArgumentForwardingCmdFailsWithUnbalancedQuote(string testArgString)
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Baseline Argument Evaluation via Reflector
|
||||||
|
// This does not need to be different for cmd because
|
||||||
|
// it only establishes what the string[] args should be
|
||||||
|
var rawEvaluatedArgument = RawEvaluateArgumentString(testArgString);
|
||||||
|
|
||||||
|
// Escape and Re-Evaluate the rawEvaluatedArgument
|
||||||
|
var escapedEvaluatedRawArgument = EscapeAndEvaluateArgumentStringCmd(rawEvaluatedArgument);
|
||||||
|
|
||||||
|
rawEvaluatedArgument.Length.Should().NotBe(escapedEvaluatedRawArgument.Length);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// EscapeAndEvaluateArgumentString returns a representation of string[] args
|
/// EscapeAndEvaluateArgumentString returns a representation of string[] args
|
||||||
/// when rawEvaluatedArgument is passed as an argument to a process using
|
/// when rawEvaluatedArgument is passed as an argument to a process using
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
||||||
if (!Path.IsPathRooted(_command))
|
if (!Path.IsPathRooted(_command))
|
||||||
{
|
{
|
||||||
_command = Env.GetCommandPath(_command) ??
|
_command = Env.GetCommandPath(_command) ??
|
||||||
Env.GetCommandPathFromAppBase(AppContext.BaseDirectory, _command);
|
Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Executing - {_command} {args}");
|
Console.WriteLine($"Executing - {_command} {args}");
|
||||||
|
@ -43,7 +43,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
||||||
Console.WriteLine($"Executing (Captured Output) - {_command} {args}");
|
Console.WriteLine($"Executing (Captured Output) - {_command} {args}");
|
||||||
|
|
||||||
var commandPath = Env.GetCommandPath(_command, ".exe", ".cmd", "") ??
|
var commandPath = Env.GetCommandPath(_command, ".exe", ".cmd", "") ??
|
||||||
Env.GetCommandPathFromAppBase(AppContext.BaseDirectory, _command, ".exe", ".cmd", "");
|
Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command, ".exe", ".cmd", "");
|
||||||
|
|
||||||
var stdOut = new StreamForwarder();
|
var stdOut = new StreamForwarder();
|
||||||
var stdErr = new StreamForwarder();
|
var stdErr = new StreamForwarder();
|
||||||
|
|
155
test/ScriptExecutorTests/ScriptExecutorTests.cs
Normal file
155
test/ScriptExecutorTests/ScriptExecutorTests.cs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Microsoft.DotNet.ProjectModel;
|
||||||
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Xunit;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli.Utils.ScriptExecutorTests
|
||||||
|
{
|
||||||
|
public class ScriptExecutorTests : TestBase
|
||||||
|
{
|
||||||
|
private static readonly string s_testProjectRoot = Path.Combine(AppContext.BaseDirectory, "TestAssets/TestProjects");
|
||||||
|
|
||||||
|
private TempDirectory _root;
|
||||||
|
|
||||||
|
public ScriptExecutorTests()
|
||||||
|
{
|
||||||
|
_root = Temp.CreateDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Project_Local_Script_is_Resolved()
|
||||||
|
{
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
CreateTestFile("some.script", binTestProjectPath);
|
||||||
|
var scriptCommandLine = "some.script";
|
||||||
|
|
||||||
|
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
|
||||||
|
command.Should().NotBeNull();
|
||||||
|
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Nonexistent_Project_Local_Script_is_not_Resolved()
|
||||||
|
{
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
var scriptCommandLine = "nonexistent.script";
|
||||||
|
|
||||||
|
Action action = () => ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
action.ShouldThrow<CommandUnknownException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Extension_Inference_in_Resolution_for_Project_Local_Scripts()
|
||||||
|
{
|
||||||
|
var extensionList = new string[] {".cmd", ".sh"};
|
||||||
|
|
||||||
|
var expectedExtension = default(string);
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
expectedExtension = ".cmd";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expectedExtension = ".sh";
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
foreach (var extension in extensionList)
|
||||||
|
{
|
||||||
|
CreateTestFile("uniquescriptname" + extension, binTestProjectPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't include extension
|
||||||
|
var scriptCommandLine = "uniquescriptname";
|
||||||
|
|
||||||
|
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
|
||||||
|
command.Should().NotBeNull();
|
||||||
|
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||||
|
command.CommandArgs.Should().Contain(scriptCommandLine + expectedExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Script_Exe_Files_Dont_Use_Cmd_or_Sh()
|
||||||
|
{
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
CreateTestFile("some.exe", binTestProjectPath);
|
||||||
|
var scriptCommandLine = "some.exe";
|
||||||
|
|
||||||
|
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
|
||||||
|
command.Should().NotBeNull();
|
||||||
|
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||||
|
|
||||||
|
Path.GetFileName(command.CommandName).Should().NotBe("cmd.exe");
|
||||||
|
Path.GetFileName(command.CommandName).Should().NotBe("sh");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Script_Cmd_Files_Use_CmdExe()
|
||||||
|
{
|
||||||
|
if (! RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
CreateTestFile("some.cmd", binTestProjectPath);
|
||||||
|
var scriptCommandLine = "some.cmd";
|
||||||
|
|
||||||
|
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
|
||||||
|
command.Should().NotBeNull();
|
||||||
|
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||||
|
|
||||||
|
Path.GetFileName(command.CommandName).Should().Be("cmd.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_Script_Builtins_Fail()
|
||||||
|
{
|
||||||
|
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||||
|
var binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||||
|
|
||||||
|
var project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("dnxcore50")).ProjectFile;
|
||||||
|
|
||||||
|
var scriptCommandLine = "echo";
|
||||||
|
|
||||||
|
Action action = () => ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||||
|
action.ShouldThrow<CommandUnknownException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateTestFile(string filename, string directory)
|
||||||
|
{
|
||||||
|
string path = Path.Combine(directory, filename);
|
||||||
|
File.WriteAllText(path, "echo hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
test/ScriptExecutorTests/ScriptExecutorTests.xproj
Normal file
19
test/ScriptExecutorTests/ScriptExecutorTests.xproj
Normal file
|
@ -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>833ffee1-7eed-4f51-8dfd-946d48833333</ProjectGuid>
|
||||||
|
<RootNamespace>Microsoft.DotNet.Cli.Utils.ScriptExecutorTests</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>
|
26
test/ScriptExecutorTests/project.json
Normal file
26
test/ScriptExecutorTests/project.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"version": "1.0.0-*",
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"NETStandard.Library": "1.0.0-rc2-23805",
|
||||||
|
|
||||||
|
"Microsoft.DotNet.ProjectModel": { "target": "project" },
|
||||||
|
"Microsoft.DotNet.Cli.Utils": { "target": "project" },
|
||||||
|
"Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" },
|
||||||
|
|
||||||
|
"xunit": "2.1.0",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-48273-16"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net45+win8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"content": [
|
||||||
|
"../../TestAssets/TestProjects/TestApp/**/*"
|
||||||
|
],
|
||||||
|
|
||||||
|
"testRunner": "xunit"
|
||||||
|
}
|
|
@ -214,18 +214,15 @@ namespace Microsoft.DotNet.Tools.Publish.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[ActiveIssue(982)]
|
|
||||||
public void PublishScriptsRun()
|
public void PublishScriptsRun()
|
||||||
{
|
{
|
||||||
// create unique directories in the 'temp' folder
|
// create unique directories in the 'temp' folder
|
||||||
var root = Temp.CreateDirectory();
|
var root = Temp.CreateDirectory();
|
||||||
|
|
||||||
var testAppDir = root.CreateDirectory("TestApp");
|
var testAppDir = root.CreateDirectory("TestAppWithScripts");
|
||||||
var testLibDir = root.CreateDirectory("TestLibrary");
|
|
||||||
|
|
||||||
//copy projects to the temp dir
|
//copy projects to the temp dir
|
||||||
CopyProjectToTempDir(Path.Combine(_testProjectsRoot, "TestApp"), testAppDir);
|
CopyProjectToTempDir(Path.Combine(_testProjectsRoot, "TestAppWithScripts"), testAppDir);
|
||||||
CopyProjectToTempDir(Path.Combine(_testProjectsRoot, "TestLibrary"), testLibDir);
|
|
||||||
|
|
||||||
// run publish
|
// run publish
|
||||||
var testProject = GetProjectPath(testAppDir);
|
var testProject = GetProjectPath(testAppDir);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
"content": [
|
"content": [
|
||||||
"../../TestAssets/TestProjects/TestApp/**/*",
|
"../../TestAssets/TestProjects/TestApp/**/*",
|
||||||
|
"../../TestAssets/TestProjects/TestAppWithScripts/**/*",
|
||||||
"../../TestAssets/TestProjects/TestLibrary/**/*",
|
"../../TestAssets/TestProjects/TestLibrary/**/*",
|
||||||
"../../TestAssets/TestProjects/CompileFail/**/*",
|
"../../TestAssets/TestProjects/CompileFail/**/*",
|
||||||
"../../TestAssets/TestProjects/TestBindingRedirectGeneration/**/*",
|
"../../TestAssets/TestProjects/TestBindingRedirectGeneration/**/*",
|
||||||
|
|
Loading…
Reference in a new issue