2015-11-16 11:21:57 -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 ;
2015-11-01 16:21:10 -08:00
using System.Collections.Generic ;
2015-10-06 02:19:27 -07:00
using System.Linq ;
2016-04-22 14:20:50 -05:00
using System.Text ;
2015-10-06 10:46:43 -07:00
using Microsoft.DotNet.Cli.Utils ;
2016-06-06 15:41:14 -07:00
using Microsoft.DotNet.Configurer ;
2016-08-09 11:05:00 -07:00
using Microsoft.DotNet.PlatformAbstractions ;
2016-11-16 15:49:25 -08:00
using Microsoft.DotNet.Tools.Add ;
2016-01-30 21:47:50 -08:00
using Microsoft.DotNet.Tools.Build ;
2016-10-27 18:46:43 -07:00
using Microsoft.DotNet.Tools.Clean ;
2016-02-04 12:41:50 -08:00
using Microsoft.DotNet.Tools.Help ;
2016-09-22 19:11:08 -05:00
using Microsoft.DotNet.Tools.Migrate ;
using Microsoft.DotNet.Tools.MSBuild ;
2016-01-30 21:47:50 -08:00
using Microsoft.DotNet.Tools.New ;
2016-08-27 15:57:14 -07:00
using Microsoft.DotNet.Tools.NuGet ;
2016-10-27 18:46:43 -07:00
using Microsoft.DotNet.Tools.Pack ;
2016-01-30 21:47:50 -08:00
using Microsoft.DotNet.Tools.Publish ;
2016-11-29 09:44:39 -08:00
using Microsoft.DotNet.Tools.Remove ;
2016-02-18 01:09:23 -08:00
using Microsoft.DotNet.Tools.Restore ;
2016-10-27 18:46:43 -07:00
using Microsoft.DotNet.Tools.RestoreProjectJson ;
2016-01-30 21:47:50 -08:00
using Microsoft.DotNet.Tools.Run ;
2016-04-14 23:33:41 -05:00
using Microsoft.DotNet.Tools.Test ;
2016-09-19 23:29:26 +05:30
using Microsoft.DotNet.Tools.VSTest ;
2016-04-14 23:33:41 -05:00
using NuGet.Frameworks ;
2015-10-03 11:34:08 -07:00
namespace Microsoft.DotNet.Cli
{
public class Program
{
2016-04-14 23:33:41 -05:00
private static Dictionary < string , Func < string [ ] , int > > s_builtIns = new Dictionary < string , Func < string [ ] , int > >
{
2016-11-29 09:44:39 -08:00
["add"] = ( new AddCommand ( ) ) . Run ,
2016-04-14 23:33:41 -05:00
["build"] = BuildCommand . Run ,
2016-10-27 18:46:43 -07:00
["clean"] = CleanCommand . Run ,
2016-04-14 23:33:41 -05:00
["help"] = HelpCommand . Run ,
2016-10-27 18:46:43 -07:00
["migrate"] = MigrateCommand . Run ,
["msbuild"] = MSBuildCommand . Run ,
2016-04-14 23:33:41 -05:00
["new"] = NewCommand . Run ,
2016-08-10 10:50:18 -07:00
["nuget"] = NuGetCommand . Run ,
2016-04-14 23:33:41 -05:00
["pack"] = PackCommand . Run ,
["publish"] = PublishCommand . Run ,
2016-11-29 09:44:39 -08:00
["remove"] = ( new RemoveCommand ( ) ) . Run ,
2016-04-14 23:33:41 -05:00
["restore"] = RestoreCommand . Run ,
2016-10-27 18:46:43 -07:00
["restore-projectjson"] = RestoreProjectJsonCommand . Run ,
2016-04-14 23:33:41 -05:00
["run"] = RunCommand . Run ,
2016-06-17 16:16:09 -07:00
["test"] = TestCommand . Run ,
2016-09-19 23:29:26 +05:30
["vstest"] = VSTestCommand . Run ,
2016-04-14 23:33:41 -05:00
} ;
2015-10-03 11:34:08 -07:00
public static int Main ( string [ ] args )
{
2015-11-28 00:28:45 -08:00
DebugHelper . HandleDebugSwitch ( ref args ) ;
2016-04-25 11:29:29 -07:00
2016-04-22 12:23:26 -07:00
new MulticoreJitActivator ( ) . TryActivateMulticoreJit ( ) ;
2016-04-25 11:29:29 -07:00
2016-04-27 16:04:26 -07:00
if ( Env . GetEnvironmentVariableAsBool ( "DOTNET_CLI_CAPTURE_TIMING" , false ) )
{
PerfTrace . Enabled = true ;
}
2016-04-22 14:20:50 -05:00
InitializeProcess ( ) ;
2016-01-06 02:27:16 -08:00
try
{
2016-04-27 16:04:26 -07:00
using ( PerfTrace . Current . CaptureTiming ( ) )
{
2016-06-22 15:17:54 -07:00
return ProcessArgs ( args ) ;
2016-04-27 16:04:26 -07:00
}
2016-01-06 02:27:16 -08:00
}
2016-04-12 16:44:34 -07:00
catch ( GracefulException e )
2016-01-06 02:27:16 -08:00
{
2016-04-29 15:46:16 -05:00
Reporter . Error . WriteLine ( CommandContext . IsVerbose ( ) ? e . ToString ( ) . Red ( ) . Bold ( ) : e . Message . Red ( ) . Bold ( ) ) ;
2016-04-28 17:49:04 -07:00
2016-01-06 02:27:16 -08:00
return 1 ;
}
2016-09-09 08:49:22 -05:00
catch ( Exception ex )
{
#if DEBUG
Reporter . Error . WriteLine ( ex . ToString ( ) ) ;
#else
if ( Reporter . IsVerbose )
{
Reporter . Error . WriteLine ( ex . ToString ( ) ) ;
}
else
{
Reporter . Error . WriteLine ( ex . Message ) ;
}
#endif
return 1 ;
}
2016-04-27 16:04:26 -07:00
finally
{
if ( PerfTrace . Enabled )
{
Reporter . Output . WriteLine ( "Performance Summary:" ) ;
PerfTraceOutput . Print ( Reporter . Output , PerfTrace . GetEvents ( ) ) ;
}
}
2016-01-06 02:27:16 -08:00
}
2016-06-22 15:17:54 -07:00
internal static int ProcessArgs ( string [ ] args , ITelemetry telemetryClient = null )
2016-01-06 02:27:16 -08:00
{
2015-11-01 16:21:10 -08:00
// CommandLineApplication is a bit restrictive, so we parse things ourselves here. Individual apps should use CLA.
2016-01-06 02:27:16 -08:00
2016-02-05 12:55:09 -08:00
bool? verbose = null ;
2016-01-06 02:27:16 -08:00
var success = true ;
2015-11-01 16:21:10 -08:00
var command = string . Empty ;
var lastArg = 0 ;
2016-06-22 15:17:54 -07:00
using ( INuGetCacheSentinel nugetCacheSentinel = new NuGetCacheSentinel ( ) )
2015-10-08 14:49:39 -07:00
{
2016-06-22 15:17:54 -07:00
for ( ; lastArg < args . Length ; lastArg + + )
2015-12-18 16:39:43 -08:00
{
2016-06-22 15:17:54 -07:00
if ( IsArg ( args [ lastArg ] , "v" , "verbose" ) )
{
verbose = true ;
}
else if ( IsArg ( args [ lastArg ] , "version" ) )
{
PrintVersion ( ) ;
return 0 ;
}
else if ( IsArg ( args [ lastArg ] , "info" ) )
{
PrintInfo ( ) ;
return 0 ;
}
else if ( IsArg ( args [ lastArg ] , "h" , "help" ) )
{
HelpCommand . PrintHelp ( ) ;
return 0 ;
}
else if ( args [ lastArg ] . StartsWith ( "-" ) )
{
Reporter . Error . WriteLine ( $"Unknown option: {args[lastArg]}" ) ;
success = false ;
}
else
{
ConfigureDotNetForFirstTimeUse ( nugetCacheSentinel ) ;
// It's the command, and we're done!
command = args [ lastArg ] ;
break ;
}
2015-12-18 16:39:43 -08:00
}
2016-06-22 15:17:54 -07:00
if ( ! success )
2015-11-16 17:39:03 -08:00
{
2016-02-04 12:41:50 -08:00
HelpCommand . PrintHelp ( ) ;
2016-06-22 15:17:54 -07:00
return 1 ;
2015-10-08 14:49:39 -07:00
}
2016-06-22 15:17:54 -07:00
if ( telemetryClient = = null )
2015-10-08 14:49:39 -07:00
{
2016-06-22 15:17:54 -07:00
telemetryClient = new Telemetry ( nugetCacheSentinel ) ;
2015-10-08 14:49:39 -07:00
}
}
2015-11-01 16:21:10 -08:00
var appArgs = ( lastArg + 1 ) > = args . Length ? Enumerable . Empty < string > ( ) : args . Skip ( lastArg + 1 ) . ToArray ( ) ;
2016-02-05 12:55:09 -08:00
if ( verbose . HasValue )
{
Environment . SetEnvironmentVariable ( CommandContext . Variables . Verbose , verbose . ToString ( ) ) ;
2016-04-27 16:04:26 -07:00
Console . WriteLine ( $"Telemetry is: {(telemetryClient.Enabled ? " Enabled " : " Disabled ")}" ) ;
2016-02-05 12:55:09 -08:00
}
2016-02-04 12:41:50 -08:00
if ( string . IsNullOrEmpty ( command ) )
2015-10-08 14:49:39 -07:00
{
2016-02-04 12:41:50 -08:00
command = "help" ;
2015-11-01 16:21:10 -08:00
}
2016-04-27 17:28:44 -07:00
telemetryClient . TrackEvent ( command , null , null ) ;
2016-04-22 15:01:56 -07:00
int exitCode ;
2016-01-30 21:47:50 -08:00
Func < string [ ] , int > builtIn ;
2016-04-14 23:33:41 -05:00
if ( s_builtIns . TryGetValue ( command , out builtIn ) )
2016-01-30 21:47:50 -08:00
{
2016-03-25 13:15:36 -07:00
exitCode = builtIn ( appArgs . ToArray ( ) ) ;
}
else
{
2016-10-03 21:40:24 -07:00
CommandResult result = Command . Create (
"dotnet-" + command ,
appArgs ,
FrameworkConstants . CommonFrameworks . NetStandardApp15 )
2016-03-25 13:15:36 -07:00
. Execute ( ) ;
exitCode = result . ExitCode ;
2016-01-30 21:47:50 -08:00
}
2016-03-25 13:15:36 -07:00
return exitCode ;
2015-11-01 16:21:10 -08:00
}
2016-06-22 15:17:54 -07:00
private static void ConfigureDotNetForFirstTimeUse ( INuGetCacheSentinel nugetCacheSentinel )
2016-06-09 20:52:49 -07:00
{
2016-06-10 13:02:48 -07:00
using ( PerfTrace . Current . CaptureTiming ( ) )
2016-06-09 20:52:49 -07:00
{
2016-06-10 13:02:48 -07:00
using ( var nugetPackagesArchiver = new NuGetPackagesArchiver ( ) )
{
2016-06-22 15:17:54 -07:00
var environmentProvider = new EnvironmentProvider ( ) ;
2016-11-28 00:46:26 -08:00
var commandFactory = new DotNetCommandFactory ( alwaysRunOutOfProc : true ) ;
2016-06-22 15:17:54 -07:00
var nugetCachePrimer =
new NuGetCachePrimer ( commandFactory , nugetPackagesArchiver , nugetCacheSentinel ) ;
var dotnetConfigurer = new DotnetFirstTimeUseConfigurer (
nugetCachePrimer ,
nugetCacheSentinel ,
environmentProvider ) ;
dotnetConfigurer . Configure ( ) ;
2016-06-10 13:02:48 -07:00
}
}
2016-06-09 20:52:49 -07:00
}
2016-04-27 16:04:26 -07:00
2016-04-22 14:20:50 -05:00
private static void InitializeProcess ( )
{
// by default, .NET Core doesn't have all code pages needed for Console apps.
// see the .NET Core Notes in https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx
Encoding . RegisterProvider ( CodePagesEncodingProvider . Instance ) ;
}
2016-04-14 23:33:41 -05:00
internal static bool TryGetBuiltInCommand ( string commandName , out Func < string [ ] , int > builtInCommand )
{
return s_builtIns . TryGetValue ( commandName , out builtInCommand ) ;
}
2016-03-28 17:17:21 -07:00
private static void PrintVersion ( )
2016-03-24 15:36:58 -05:00
{
2016-03-25 13:15:36 -07:00
Reporter . Output . WriteLine ( Product . Version ) ;
2016-03-24 15:36:58 -05:00
}
private static void PrintInfo ( )
2015-12-18 16:39:43 -08:00
{
2016-02-04 12:41:50 -08:00
HelpCommand . PrintVersionHeader ( ) ;
2015-12-18 16:39:43 -08:00
2016-09-29 18:16:26 -05:00
DotnetVersionFile versionFile = DotnetFiles . VersionFileObject ;
var commitSha = versionFile . CommitSha ? ? "N/A" ;
2016-02-18 01:09:23 -08:00
Reporter . Output . WriteLine ( ) ;
Reporter . Output . WriteLine ( "Product Information:" ) ;
2016-05-04 18:02:52 +00:00
Reporter . Output . WriteLine ( $" Version: {Product.Version}" ) ;
Reporter . Output . WriteLine ( $" Commit SHA-1 hash: {commitSha}" ) ;
2016-02-18 01:09:23 -08:00
Reporter . Output . WriteLine ( ) ;
2015-12-18 16:39:43 -08:00
Reporter . Output . WriteLine ( "Runtime Environment:" ) ;
2016-04-28 16:30:32 -07:00
Reporter . Output . WriteLine ( $" OS Name: {RuntimeEnvironment.OperatingSystem}" ) ;
Reporter . Output . WriteLine ( $" OS Version: {RuntimeEnvironment.OperatingSystemVersion}" ) ;
Reporter . Output . WriteLine ( $" OS Platform: {RuntimeEnvironment.OperatingSystemPlatform}" ) ;
2016-09-30 12:00:37 -05:00
Reporter . Output . WriteLine ( $" RID: {GetDisplayRid(versionFile)}" ) ;
2016-11-20 10:24:01 -08:00
Reporter . Output . WriteLine ( $" Base Path: {ApplicationEnvironment.ApplicationBasePath}" ) ;
2015-12-18 16:39:43 -08:00
}
private static bool IsArg ( string candidate , string longName )
{
return IsArg ( candidate , shortName : null , longName : longName ) ;
2015-10-08 14:49:39 -07:00
}
2015-11-01 16:21:10 -08:00
private static bool IsArg ( string candidate , string shortName , string longName )
2015-10-08 14:49:39 -07:00
{
2015-12-18 16:39:43 -08:00
return ( shortName ! = null & & candidate . Equals ( "-" + shortName ) ) | | ( longName ! = null & & candidate . Equals ( "--" + longName ) ) ;
2015-10-06 02:19:27 -07:00
}
2016-04-22 15:01:56 -07:00
2016-09-30 12:00:37 -05:00
private static string GetDisplayRid ( DotnetVersionFile versionFile )
2016-02-18 01:09:23 -08:00
{
2016-09-30 12:00:37 -05:00
FrameworkDependencyFile fxDepsFile = new FrameworkDependencyFile ( ) ;
2016-04-22 15:01:56 -07:00
2016-09-30 12:00:37 -05:00
string currentRid = RuntimeEnvironment . GetRuntimeIdentifier ( ) ;
2016-04-22 15:01:56 -07:00
2016-09-30 12:00:37 -05:00
// if the current RID isn't supported by the shared framework, display the RID the CLI was
// built with instead, so the user knows which RID they should put in their "runtimes" section.
return fxDepsFile . IsRuntimeSupported ( currentRid ) ?
currentRid :
versionFile . BuildRid ;
2016-02-18 01:09:23 -08:00
}
2015-10-03 11:34:08 -07:00
}
}