2015-11-20 19:00:56 -08:00
// 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 ;
2017-03-21 13:46:08 -05:00
using Microsoft.Build.Evaluation ;
2017-06-23 10:47:09 -07:00
using Microsoft.Build.Exceptions ;
2015-11-20 19:00:56 -08:00
using Microsoft.DotNet.Cli.Utils ;
2017-06-01 21:25:06 -07:00
using Microsoft.DotNet.Tools ;
2016-10-27 18:46:43 -07:00
using Microsoft.DotNet.Tools.MSBuild ;
2017-05-25 18:47:59 -07:00
using Microsoft.DotNet.Tools.Run.LaunchSettings ;
2015-11-20 19:00:56 -08:00
namespace Microsoft.DotNet.Tools.Run
{
2016-01-30 21:47:50 -08:00
public partial class RunCommand
2015-11-20 19:00:56 -08:00
{
2017-04-12 16:03:45 -07:00
public string Configuration { get ; private set ; }
public string Framework { get ; private set ; }
public bool NoBuild { get ; private set ; }
public string Project { get ; private set ; }
public IReadOnlyCollection < string > Args { get ; private set ; }
2017-06-01 21:25:06 -07:00
public bool NoRestore { get ; private set ; }
2017-06-02 23:32:53 -07:00
public IEnumerable < string > RestoreArgs { get ; private set ; }
2015-11-20 19:00:56 -08:00
2016-05-12 10:24:57 -05:00
private List < string > _args ;
2017-03-21 13:46:08 -05:00
private bool ShouldBuild = > ! NoBuild ;
2016-04-25 13:53:02 -07:00
2017-05-25 18:47:59 -07:00
public string LaunchProfile { get ; private set ; }
public bool NoLaunchProfile { get ; private set ; }
2017-05-30 22:30:14 -07:00
private bool UseLaunchProfile = > ! NoLaunchProfile ;
2017-05-25 18:47:59 -07:00
2016-10-27 18:46:43 -07:00
public int Start ( )
2016-05-12 10:24:57 -05:00
{
2016-10-27 18:46:43 -07:00
Initialize ( ) ;
2017-03-21 13:46:08 -05:00
if ( ShouldBuild )
{
EnsureProjectIsBuilt ( ) ;
}
2016-10-27 18:46:43 -07:00
2017-06-23 10:47:09 -07:00
try
{
ICommand runCommand = GetRunCommand ( ) ;
int launchSettingsApplicationResult = ApplyLaunchProfileSettingsIfNeeded ( ref runCommand ) ;
if ( launchSettingsApplicationResult ! = 0 )
{
return launchSettingsApplicationResult ;
}
2017-05-30 22:42:24 -07:00
2017-06-23 10:47:09 -07:00
return runCommand
. Execute ( )
. ExitCode ;
}
catch ( InvalidProjectFileException e )
2017-05-30 22:42:24 -07:00
{
2017-06-23 10:47:09 -07:00
throw new GracefulException (
string . Format ( LocalizableStrings . RunCommandSpecifiecFileIsNotAValidProject , Project ) ,
e ) ;
2017-05-30 22:42:24 -07:00
}
2016-05-12 10:24:57 -05:00
}
2015-11-20 19:00:56 -08:00
2017-04-12 16:03:45 -07:00
public RunCommand ( string configuration ,
string framework ,
bool noBuild ,
string project ,
2017-05-25 18:47:59 -07:00
string launchProfile ,
bool noLaunchProfile ,
2017-06-01 21:25:06 -07:00
bool noRestore ,
2017-06-02 23:32:53 -07:00
IEnumerable < string > restoreArgs ,
2017-04-12 16:03:45 -07:00
IReadOnlyCollection < string > args )
{
Configuration = configuration ;
Framework = framework ;
NoBuild = noBuild ;
Project = project ;
2017-05-25 18:47:59 -07:00
LaunchProfile = launchProfile ;
NoLaunchProfile = noLaunchProfile ;
2017-04-12 16:03:45 -07:00
Args = args ;
2017-06-02 23:32:53 -07:00
RestoreArgs = restoreArgs ;
2017-06-01 21:25:06 -07:00
NoRestore = noRestore ;
2017-04-12 16:03:45 -07:00
}
public RunCommand MakeNewWithReplaced ( string configuration = null ,
string framework = null ,
bool? noBuild = null ,
string project = null ,
2017-05-25 18:47:59 -07:00
string launchProfile = null ,
bool? noLaunchProfile = null ,
2017-06-01 21:25:06 -07:00
bool? noRestore = null ,
2017-06-02 23:32:53 -07:00
IEnumerable < string > restoreArgs = null ,
2017-04-12 16:03:45 -07:00
IReadOnlyCollection < string > args = null )
{
return new RunCommand (
configuration ? ? this . Configuration ,
framework ? ? this . Framework ,
noBuild ? ? this . NoBuild ,
project ? ? this . Project ,
2017-05-25 18:47:59 -07:00
launchProfile ? ? this . LaunchProfile ,
noLaunchProfile ? ? this . NoLaunchProfile ,
2017-06-01 21:25:06 -07:00
noRestore ? ? this . NoRestore ,
2017-06-02 23:32:53 -07:00
restoreArgs ? ? this . RestoreArgs ,
2017-04-12 16:03:45 -07:00
args ? ? this . Args
) ;
}
2017-05-30 22:42:24 -07:00
private int ApplyLaunchProfileSettingsIfNeeded ( ref ICommand runCommand )
2017-05-30 22:30:14 -07:00
{
if ( UseLaunchProfile )
{
var buildPathContainer = File . Exists ( Project ) ? Path . GetDirectoryName ( Project ) : Project ;
var launchSettingsPath = Path . Combine ( buildPathContainer , "Properties" , "launchSettings.json" ) ;
if ( File . Exists ( launchSettingsPath ) )
{
Reporter . Output . WriteLine ( string . Format ( LocalizableStrings . UsingLaunchSettingsFromMessage , launchSettingsPath ) ) ;
string profileName = string . IsNullOrEmpty ( LaunchProfile ) ? LocalizableStrings . DefaultLaunchProfileDisplayName : LaunchProfile ;
try
{
var launchSettingsFileContents = File . ReadAllText ( launchSettingsPath ) ;
var applyResult = LaunchSettingsManager . TryApplyLaunchSettings ( launchSettingsFileContents , ref runCommand , LaunchProfile ) ;
if ( ! applyResult . Success )
{
//Error that the launch profile couldn't be applied
Reporter . Error . WriteLine ( string . Format ( LocalizableStrings . RunCommandExceptionCouldNotApplyLaunchSettings , profileName , applyResult . FailureReason ) . Bold ( ) . Red ( ) ) ;
}
}
catch ( IOException ex )
{
Reporter . Error . WriteLine ( string . Format ( LocalizableStrings . RunCommandExceptionCouldNotApplyLaunchSettings , profileName ) . Bold ( ) . Red ( ) ) ;
Reporter . Error . WriteLine ( ex . Message . Bold ( ) . Red ( ) ) ;
return - 1 ;
}
}
else if ( ! string . IsNullOrEmpty ( LaunchProfile ) )
{
//Error that the launch profile couldn't be found
Reporter . Error . WriteLine ( LocalizableStrings . RunCommandExceptionCouldNotLocateALaunchSettingsFile . Bold ( ) . Red ( ) ) ;
}
}
2017-05-30 22:42:24 -07:00
return 0 ;
2017-05-30 22:30:14 -07:00
}
2016-10-27 18:46:43 -07:00
private void EnsureProjectIsBuilt ( )
2015-11-20 19:00:56 -08:00
{
2016-10-27 18:46:43 -07:00
List < string > buildArgs = new List < string > ( ) ;
2017-03-21 13:46:08 -05:00
buildArgs . Add ( Project ) ;
2016-10-27 18:46:43 -07:00
buildArgs . Add ( "/nologo" ) ;
buildArgs . Add ( "/verbosity:quiet" ) ;
2017-06-02 23:32:53 -07:00
buildArgs . AddRange ( RestoreArgs ) ;
2015-11-20 19:00:56 -08:00
2017-06-13 00:04:25 -07:00
var buildResult =
new RestoringCommand ( buildArgs , RestoreArgs , new [ ] { Project } , NoRestore ) . Execute ( ) ;
2016-10-27 18:46:43 -07:00
if ( buildResult ! = 0 )
2015-11-20 19:00:56 -08:00
{
2016-10-27 18:46:43 -07:00
Reporter . Error . WriteLine ( ) ;
2016-11-19 11:45:46 -08:00
throw new GracefulException ( LocalizableStrings . RunCommandException ) ;
2015-11-20 19:00:56 -08:00
}
2015-11-23 16:31:27 -08:00
}
2016-10-27 18:46:43 -07:00
private ICommand GetRunCommand ( )
2015-11-23 16:31:27 -08:00
{
2017-02-07 15:14:43 -08:00
var globalProperties = new Dictionary < string , string >
2015-11-23 19:58:11 -08:00
{
2017-02-07 15:14:43 -08:00
{ Constants . MSBuildExtensionsPath , AppContext . BaseDirectory }
2016-10-27 18:46:43 -07:00
} ;
2015-11-20 19:00:56 -08:00
2016-10-27 18:46:43 -07:00
if ( ! string . IsNullOrWhiteSpace ( Configuration ) )
2015-11-20 19:00:56 -08:00
{
2017-02-07 15:14:43 -08:00
globalProperties . Add ( "Configuration" , Configuration ) ;
2015-11-20 19:00:56 -08:00
}
2016-10-27 18:46:43 -07:00
if ( ! string . IsNullOrWhiteSpace ( Framework ) )
2015-11-20 19:00:56 -08:00
{
2017-02-07 15:14:43 -08:00
globalProperties . Add ( "TargetFramework" , Framework ) ;
2015-11-20 19:00:56 -08:00
}
2017-03-21 13:46:08 -05:00
Project project = new Project ( Project , globalProperties , null ) ;
2016-10-27 18:46:43 -07:00
2017-03-21 13:46:08 -05:00
string runProgram = project . GetPropertyValue ( "RunCommand" ) ;
2016-10-27 18:46:43 -07:00
if ( string . IsNullOrEmpty ( runProgram ) )
2016-04-25 13:53:02 -07:00
{
2017-03-21 13:46:08 -05:00
ThrowUnableToRunError ( project ) ;
2016-04-25 13:53:02 -07:00
}
2017-03-21 13:46:08 -05:00
string runArguments = project . GetPropertyValue ( "RunArguments" ) ;
string runWorkingDirectory = project . GetPropertyValue ( "RunWorkingDirectory" ) ;
2016-04-25 13:53:02 -07:00
2016-10-27 18:46:43 -07:00
string fullArguments = runArguments ;
if ( _args . Any ( ) )
2015-11-20 19:00:56 -08:00
{
2016-10-27 18:46:43 -07:00
fullArguments + = " " + ArgumentEscaper . EscapeAndConcatenateArgArrayForProcessStart ( _args ) ;
2015-11-20 19:00:56 -08:00
}
2016-04-22 15:01:56 -07:00
2016-10-27 18:46:43 -07:00
CommandSpec commandSpec = new CommandSpec ( runProgram , fullArguments , CommandResolutionStrategy . None ) ;
2015-11-23 19:58:11 -08:00
2016-10-27 18:46:43 -07:00
return Command . Create ( commandSpec )
. WorkingDirectory ( runWorkingDirectory ) ;
}
2015-11-20 19:00:56 -08:00
2017-03-21 13:46:08 -05:00
private void ThrowUnableToRunError ( Project project )
{
string targetFrameworks = project . GetPropertyValue ( "TargetFrameworks" ) ;
if ( ! string . IsNullOrEmpty ( targetFrameworks ) )
{
string targetFramework = project . GetPropertyValue ( "TargetFramework" ) ;
if ( string . IsNullOrEmpty ( targetFramework ) )
{
var framework = "--framework" ;
throw new GracefulException ( LocalizableStrings . RunCommandExceptionUnableToRunSpecifyFramework , framework ) ;
}
}
string outputType = project . GetPropertyValue ( "OutputType" ) ;
throw new GracefulException (
string . Format (
LocalizableStrings . RunCommandExceptionUnableToRun ,
"dotnet run" ,
"OutputType" ,
outputType ) ) ;
}
2016-10-27 18:46:43 -07:00
private void Initialize ( )
{
if ( string . IsNullOrWhiteSpace ( Project ) )
2016-03-31 09:00:25 -07:00
{
2017-03-24 06:44:53 +01:00
Project = Directory . GetCurrentDirectory ( ) ;
}
if ( Directory . Exists ( Project ) )
{
Project = FindSingleProjectInDirectory ( Project ) ;
2015-11-20 19:00:56 -08:00
}
2016-10-27 18:46:43 -07:00
if ( Args = = null )
2016-03-15 11:50:14 -07:00
{
2016-10-27 18:46:43 -07:00
_args = new List < string > ( ) ;
2016-03-15 11:50:14 -07:00
}
else
{
2016-10-27 18:46:43 -07:00
_args = new List < string > ( Args ) ;
2016-05-12 10:24:57 -05:00
}
}
2017-03-24 06:44:53 +01:00
private static string FindSingleProjectInDirectory ( string directory )
{
string [ ] projectFiles = Directory . GetFiles ( directory , "*.*proj" ) ;
if ( projectFiles . Length = = 0 )
{
var project = "--project" ;
throw new GracefulException ( LocalizableStrings . RunCommandExceptionNoProjects , directory , project ) ;
}
else if ( projectFiles . Length > 1 )
{
throw new GracefulException ( LocalizableStrings . RunCommandExceptionMultipleProjects , directory ) ;
}
return projectFiles [ 0 ] ;
}
2015-11-20 19:00:56 -08:00
}
}