2016-01-06 02:27:16 -08:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Runtime.InteropServices ;
using Microsoft.DotNet.ProjectModel ;
using Microsoft.DotNet.ProjectModel.Graph ;
2016-02-03 10:57:25 -08:00
using Microsoft.Extensions.PlatformAbstractions ;
2016-02-10 16:13:30 -08:00
using NuGet.Frameworks ;
2016-01-06 02:27:16 -08:00
using NuGet.Packaging ;
namespace Microsoft.DotNet.Cli.Utils
{
internal static class CommandResolver
{
2016-03-01 21:15:07 -08:00
public static CommandSpec TryResolveCommandSpec (
string commandName ,
IEnumerable < string > args ,
NuGetFramework framework = null ,
string configuration = Constants . DefaultConfiguration ,
string outputPath = null )
2016-01-06 02:27:16 -08:00
{
2016-02-09 15:30:04 -08:00
return ResolveFromRootedCommand ( commandName , args ) ? ?
2016-03-01 21:15:07 -08:00
ResolveFromProjectDependencies ( commandName , args , framework , configuration , outputPath ) ? ?
2016-02-09 15:30:04 -08:00
ResolveFromProjectTools ( commandName , args ) ? ?
ResolveFromAppBase ( commandName , args ) ? ?
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 ) ;
2016-01-06 02:27:16 -08:00
}
2016-02-05 18:55:15 -08:00
2016-01-06 02:27:16 -08:00
2016-02-09 15:30:04 -08:00
private static CommandSpec ResolveFromPath ( string commandName , IEnumerable < string > args )
2016-01-06 02:27:16 -08:00
{
var commandPath = Env . GetCommandPath ( commandName ) ;
2016-01-27 20:35:43 -08:00
return commandPath = = null
? null
2016-02-09 15:30:04 -08:00
: CreateCommandSpecPreferringExe ( commandName , args , commandPath , CommandResolutionStrategy . Path ) ;
2016-01-11 14:54:02 -08:00
}
2016-01-06 02:27:16 -08:00
2016-02-09 15:30:04 -08:00
private static CommandSpec ResolveFromAppBase ( string commandName , IEnumerable < string > args )
{
var commandPath = Env . GetCommandPathFromRootPath ( PlatformServices . Default . Application . ApplicationBasePath , commandName ) ;
return commandPath = = null
? null
: CreateCommandSpecPreferringExe ( commandName , args , commandPath , CommandResolutionStrategy . BaseDirectory ) ;
}
private static CommandSpec ResolveFromProjectPath ( string commandName , IEnumerable < string > args , Project project , string [ ] inferredExtensionList )
2016-01-11 14:54:02 -08:00
{
2016-02-09 15:30:04 -08:00
var commandPath = Env . GetCommandPathFromRootPath ( project . ProjectDirectory , commandName , inferredExtensionList ) ;
2016-01-27 20:35:43 -08:00
return commandPath = = null
? null
2016-02-09 15:30:04 -08:00
: CreateCommandSpecPreferringExe ( commandName , args , commandPath , CommandResolutionStrategy . ProjectLocal ) ;
2016-01-06 02:27:16 -08:00
}
2016-02-09 15:30:04 -08:00
private static CommandSpec ResolveFromRootedCommand ( string commandName , IEnumerable < string > args )
2016-01-06 02:27:16 -08:00
{
if ( Path . IsPathRooted ( commandName ) )
{
2016-02-09 15:30:04 -08:00
var escapedArgs = ArgumentEscaper . EscapeAndConcatenateArgArrayForProcessStart ( args ) ;
return new CommandSpec ( commandName , escapedArgs , CommandResolutionStrategy . Path ) ;
2016-01-06 02:27:16 -08:00
}
return null ;
}
2016-02-05 18:55:15 -08:00
public static CommandSpec ResolveFromProjectDependencies (
2016-03-01 21:15:07 -08:00
string commandName ,
IEnumerable < string > args ,
NuGetFramework framework ,
string configuration ,
string outputPath )
2016-01-06 02:27:16 -08:00
{
if ( framework = = null ) return null ;
var projectContext = GetProjectContext ( framework ) ;
if ( projectContext = = null ) return null ;
var commandPackage = GetCommandPackage ( projectContext , commandName ) ;
if ( commandPackage = = null ) return null ;
2016-03-01 21:15:07 -08:00
var depsPath = projectContext . GetOutputPaths ( configuration , outputPath : outputPath ) . RuntimeFiles . Deps ;
2016-01-06 02:27:16 -08:00
2016-02-09 15:30:04 -08:00
return ConfigureCommandFromPackage ( commandName , args , commandPackage , projectContext , depsPath ) ;
2016-01-06 02:27:16 -08:00
}
private static ProjectContext GetProjectContext ( NuGetFramework framework )
{
var projectRootPath = Directory . GetCurrentDirectory ( ) ;
if ( ! File . Exists ( Path . Combine ( projectRootPath , Project . FileName ) ) )
{
return null ;
}
2016-02-03 10:57:25 -08:00
var projectContext = ProjectContext . Create ( projectRootPath , framework , PlatformServices . Default . Runtime . GetAllCandidateRuntimeIdentifiers ( ) ) ;
2016-01-06 02:27:16 -08:00
return projectContext ;
}
private static PackageDescription GetCommandPackage ( ProjectContext projectContext , string commandName )
{
return projectContext . LibraryManager . GetLibraries ( )
2016-01-27 20:35:43 -08:00
. Where ( l = > l . GetType ( ) = = typeof ( PackageDescription ) )
2016-01-06 02:27:16 -08:00
. Select ( l = > l as PackageDescription )
. FirstOrDefault ( p = > p . Library . Files
. Select ( Path . GetFileName )
. Where ( f = > Path . GetFileNameWithoutExtension ( f ) = = commandName )
. Select ( Path . GetExtension )
. Any ( e = > Env . ExecutableExtensions . Contains ( e ) | |
e = = FileNameSuffixes . DotNet . DynamicLib ) ) ;
}
2016-02-09 15:30:04 -08:00
public static CommandSpec ResolveFromProjectTools ( string commandName , IEnumerable < string > args )
2016-01-06 02:27:16 -08:00
{
var context = GetProjectContext ( FrameworkConstants . CommonFrameworks . DnxCore50 ) ;
if ( context = = null )
{
return null ;
}
var commandLibrary = context . ProjectFile . Tools
. FirstOrDefault ( l = > l . Name = = commandName ) ;
if ( commandLibrary = = default ( LibraryRange ) )
{
return null ;
}
var lockPath = Path . Combine ( context . ProjectDirectory , "artifacts" , "Tools" , commandName ,
"project.lock.json" ) ;
if ( ! File . Exists ( lockPath ) )
{
return null ;
}
var lockFile = LockFileReader . Read ( lockPath ) ;
var lib = lockFile . PackageLibraries . FirstOrDefault ( l = > l . Name = = commandName ) ;
var packageDir = new VersionFolderPathResolver ( context . PackagesDirectory )
. GetInstallPath ( lib . Name , lib . Version ) ;
return Directory . Exists ( packageDir )
? ConfigureCommandFromPackage ( commandName , args , lib . Files , packageDir )
: null ;
}
2016-01-22 14:03:40 -08:00
private static CommandSpec ConfigureCommandFromPackage ( string commandName , IEnumerable < string > args , string packageDir )
2016-01-06 02:27:16 -08:00
{
var commandPackage = new PackageFolderReader ( packageDir ) ;
var files = commandPackage . GetFiles ( ) ;
return ConfigureCommandFromPackage ( commandName , args , files , packageDir ) ;
}
2016-01-22 14:03:40 -08:00
private static CommandSpec ConfigureCommandFromPackage ( string commandName , IEnumerable < string > args ,
2016-02-09 15:30:04 -08:00
PackageDescription commandPackage , ProjectContext projectContext , string depsPath = null )
2016-01-06 02:27:16 -08:00
{
var files = commandPackage . Library . Files ;
var packageRoot = projectContext . PackagesDirectory ;
var packagePath = commandPackage . Path ;
var packageDir = Path . Combine ( packageRoot , packagePath ) ;
2016-02-09 15:30:04 -08:00
return ConfigureCommandFromPackage ( commandName , args , files , packageDir , depsPath ) ;
2016-01-06 02:27:16 -08:00
}
2016-01-22 14:03:40 -08:00
private static CommandSpec ConfigureCommandFromPackage ( string commandName , IEnumerable < string > args ,
2016-02-09 15:30:04 -08:00
IEnumerable < string > files , string packageDir , string depsPath = null )
2016-01-06 02:27:16 -08:00
{
var fileName = string . Empty ;
var commandPath = files
. FirstOrDefault ( f = > Env . ExecutableExtensions . Contains ( Path . GetExtension ( f ) ) ) ;
if ( commandPath = = null )
{
var dllPath = files
. Where ( f = > Path . GetFileName ( f ) = = commandName + FileNameSuffixes . DotNet . DynamicLib )
. Select ( f = > Path . Combine ( packageDir , f ) )
. FirstOrDefault ( ) ;
2016-01-09 23:33:22 -08:00
fileName = CoreHost . HostExePath ;
2016-01-06 02:27:16 -08:00
2016-01-22 14:03:40 -08:00
var additionalArgs = new List < string > ( ) ;
additionalArgs . Add ( dllPath ) ;
2016-01-11 00:14:14 -08:00
2016-01-06 02:27:16 -08:00
if ( depsPath ! = null )
{
2016-01-28 18:12:28 -08:00
additionalArgs . Add ( $"--depsfile:{depsPath}" ) ;
2016-01-06 02:27:16 -08:00
}
2016-01-22 14:03:40 -08:00
args = additionalArgs . Concat ( args ) ;
2016-01-06 02:27:16 -08:00
}
else
{
fileName = Path . Combine ( packageDir , commandPath ) ;
}
2016-02-09 15:30:04 -08:00
var escapedArgs = ArgumentEscaper . EscapeAndConcatenateArgArrayForProcessStart ( args ) ;
return new CommandSpec ( fileName , escapedArgs , CommandResolutionStrategy . NugetPackage ) ;
2016-01-06 02:27:16 -08:00
}
2016-01-11 14:54:02 -08:00
2016-01-22 14:03:40 -08:00
private static CommandSpec CreateCommandSpecPreferringExe (
2016-01-27 20:35:43 -08:00
string commandName ,
IEnumerable < string > args ,
2016-01-22 14:03:40 -08:00
string commandPath ,
2016-02-09 15:30:04 -08:00
CommandResolutionStrategy resolutionStrategy )
2016-01-11 14:54:02 -08:00
{
2016-02-09 15:30:04 -08:00
var useComSpec = false ;
2016-02-10 16:13:30 -08:00
if ( PlatformServices . Default . Runtime . OperatingSystemPlatform = = Platform . Windows & &
2016-01-11 14:54:02 -08:00
Path . GetExtension ( commandPath ) . Equals ( ".cmd" , StringComparison . OrdinalIgnoreCase ) )
{
var preferredCommandPath = Env . GetCommandPath ( commandName , ".exe" ) ;
2016-01-22 14:03:40 -08:00
// Use cmd if we can't find an exe
if ( preferredCommandPath = = null )
2016-01-11 14:54:02 -08:00
{
2016-01-27 20:35:43 -08:00
useComSpec = true ;
2016-01-11 14:54:02 -08:00
}
2016-01-22 14:03:40 -08:00
else
{
commandPath = preferredCommandPath ;
}
}
if ( useComSpec )
{
2016-02-09 15:30:04 -08:00
return CreateCmdCommandSpec ( commandPath , args , resolutionStrategy ) ;
2016-01-22 14:03:40 -08:00
}
else
{
2016-01-22 16:31:35 -08:00
var escapedArgs = ArgumentEscaper . EscapeAndConcatenateArgArrayForProcessStart ( args ) ;
2016-01-22 14:03:40 -08:00
return new CommandSpec ( commandPath , escapedArgs , resolutionStrategy ) ;
2016-01-11 14:54:02 -08:00
}
2016-01-22 14:03:40 -08:00
}
2016-02-09 15:30:04 -08:00
private static CommandSpec CreateCmdCommandSpec (
2016-01-27 20:35:43 -08:00
string command ,
IEnumerable < string > args ,
2016-01-22 14:03:40 -08:00
CommandResolutionStrategy resolutionStrategy )
{
var comSpec = Environment . GetEnvironmentVariable ( "ComSpec" ) ;
2016-02-09 15:30:04 -08:00
// Handle the case where ComSpec is already the command
2016-01-22 14:03:40 -08:00
if ( command . Equals ( comSpec , StringComparison . OrdinalIgnoreCase ) )
{
command = args . FirstOrDefault ( ) ;
args = args . Skip ( 1 ) ;
}
2016-01-22 15:37:37 -08:00
var cmdEscapedArgs = ArgumentEscaper . EscapeAndConcatenateArgArrayForCmdProcessStart ( args ) ;
2016-01-22 03:59:04 -08:00
if ( ArgumentEscaper . ShouldSurroundWithQuotes ( command ) )
{
command = $"\" { command } \ "" ;
}
var escapedArgString = $"/s /c \" { command } { cmdEscapedArgs } \ "" ;
2016-01-22 14:03:40 -08:00
return new CommandSpec ( comSpec , escapedArgString , resolutionStrategy ) ;
2016-01-11 14:54:02 -08:00
}
2016-01-06 02:27:16 -08:00
}
}
2016-01-22 14:03:40 -08:00