2015-10-06 10:46:43 -07:00
using System ;
2015-10-13 14:31:29 -07:00
using System.Collections.Generic ;
2015-10-06 10:46:43 -07:00
using System.IO ;
2015-10-13 14:31:29 -07:00
using System.Linq ;
2015-10-06 10:46:43 -07:00
using Microsoft.Dnx.Runtime.Common.CommandLine ;
using Microsoft.DotNet.Cli.Utils ;
2015-10-13 14:31:29 -07:00
using Microsoft.Extensions.ProjectModel ;
using NuGet.Frameworks ;
2015-10-06 10:46:43 -07:00
2015-10-07 14:39:36 -07:00
namespace Microsoft.DotNet.Tools.Publish
2015-10-06 10:46:43 -07:00
{
public class Program
{
public static int Main ( string [ ] args )
{
2015-10-13 14:31:29 -07:00
DebugHelper . HandleDebugSwitch ( ref args ) ;
2015-10-06 10:46:43 -07:00
var app = new CommandLineApplication ( ) ;
app . Name = "dotnet publish" ;
app . FullName = ".NET Publisher" ;
app . Description = "Publisher for the .NET Platform" ;
app . HelpOption ( "-h|--help" ) ;
var framework = app . Option ( "-f|--framework <FRAMEWORK>" , "Target framework to compile for" , CommandOptionType . SingleValue ) ;
var runtime = app . Option ( "-r|--runtime <RUNTIME_IDENTIFIER>" , "Target runtime to publish for" , CommandOptionType . SingleValue ) ;
var output = app . Option ( "-o|--output <OUTPUT_PATH>" , "Path in which to publish the app" , CommandOptionType . SingleValue ) ;
2015-10-13 14:31:29 -07:00
var configuration = app . Option ( "-c|--configuration <CONFIGURATION>" , "Configuration under which to build" , CommandOptionType . SingleValue ) ;
var project = app . Argument ( "<PROJECT>" , "The project to publish, defaults to the current directory. Can be a path to a project.json or a project directory" ) ;
2015-10-06 10:46:43 -07:00
app . OnExecute ( ( ) = >
{
2015-10-13 14:31:29 -07:00
CheckArg ( framework ) ;
CheckArg ( runtime ) ;
2015-10-06 10:46:43 -07:00
// Locate the project and get the name and full path
var path = project . Value ;
if ( string . IsNullOrEmpty ( path ) )
{
path = Directory . GetCurrentDirectory ( ) ;
}
2015-10-13 14:31:29 -07:00
// Load project context and publish it
var context = ProjectContext . Create ( path , NuGetFramework . Parse ( framework . Value ( ) ) , new [ ] { runtime . Value ( ) } ) ;
return Publish ( context , output . Value ( ) , configuration . Value ( ) ? ? Constants . DefaultConfiguration ) ;
2015-10-06 10:46:43 -07:00
} ) ;
try
{
return app . Execute ( args ) ;
}
catch ( OperationCanceledException ex )
{
Console . Error . WriteLine ( ex . Message ) ;
return 1 ;
}
}
2015-10-13 14:31:29 -07:00
private static void CheckArg ( CommandOption argument )
2015-10-06 10:46:43 -07:00
{
if ( ! argument . HasValue ( ) )
{
// TODO: GROOOOOOSS
2015-10-13 14:31:29 -07:00
throw new OperationCanceledException ( $"Missing required argument: {argument.LongName}" ) ;
2015-10-06 10:46:43 -07:00
}
}
2015-10-13 14:31:29 -07:00
private static int Publish ( ProjectContext context , string outputPath , string configuration )
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
Reporter . Output . WriteLine ( $"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier}" ) ;
// Hackily generate the output path
2015-10-06 10:46:43 -07:00
if ( string . IsNullOrEmpty ( outputPath ) )
{
2015-10-13 14:31:29 -07:00
outputPath = Path . Combine (
context . Project . ProjectDirectory ,
"bin" ,
configuration ,
context . TargetFramework . GetTwoDigitShortFolderName ( ) ,
"publish" ) ;
2015-10-06 10:46:43 -07:00
}
if ( ! Directory . Exists ( outputPath ) )
{
Directory . CreateDirectory ( outputPath ) ;
}
2015-10-13 14:31:29 -07:00
// Compile the project (and transitively, all it's dependencies)
var result = Command . Create ( "dotnet-compile" , $"--framework {context.TargetFramework.DotNetFrameworkName} {context.Project.ProjectDirectory}" )
2015-10-06 10:46:43 -07:00
. ForwardStdErr ( )
. ForwardStdOut ( )
. RunAsync ( )
. Result ;
if ( result . ExitCode ! = 0 )
{
Console . Error . WriteLine ( "Compilation failed!" ) ;
return result . ExitCode ;
}
2015-10-13 14:31:29 -07:00
// Use a library exporter to collect publish assets
var exporter = context . CreateExporter ( configuration ) ;
foreach ( var export in exporter . GetAllExports ( ) )
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
Reporter . Output . WriteLine ( $"Publishing {export.Library.Identity.ToString().Green().Bold()} ..." ) ;
2015-10-06 10:46:43 -07:00
2015-10-13 14:31:29 -07:00
PublishFiles ( export . RuntimeAssemblies , outputPath ) ;
PublishFiles ( export . NativeLibraries , outputPath ) ;
2015-10-06 10:46:43 -07:00
}
2015-10-13 14:31:29 -07:00
// Publishing for windows, TODO(anurse): Publish for Mac/Linux/etc.
2015-10-06 10:46:43 -07:00
// CoreConsole should be there...
var coreConsole = Path . Combine ( outputPath , Constants . CoreConsoleName ) ;
if ( ! File . Exists ( coreConsole ) )
{
Console . Error . WriteLine ( $"Unable to find {Constants.CoreConsoleName} at {coreConsole}. You must have an explicit dependency on Microsoft.NETCore.ConsoleHost (for now ;))" ) ;
return 1 ;
}
2015-10-13 14:31:29 -07:00
// Use the 'command' field to generate the name
var outputExe = Path . Combine ( outputPath , context . Project . Name + ".exe" ) ;
2015-10-06 10:46:43 -07:00
if ( File . Exists ( outputExe ) )
{
File . Delete ( outputExe ) ;
}
File . Move ( coreConsole , outputExe ) ;
2015-10-13 14:31:29 -07:00
// Check if the a command name is specified, and rename the necessary files
if ( context . Project . Commands . Count = = 1 )
{
var commandName = context . Project . Commands . Single ( ) . Key ;
// Move coreconsole and the matching dll
var renamedExe = Path . Combine ( outputPath , commandName + ".exe" ) ;
var renamedDll = Path . ChangeExtension ( renamedExe , ".dll" ) ;
if ( File . Exists ( renamedExe ) )
{
File . Delete ( renamedExe ) ;
}
File . Move ( outputExe , renamedExe ) ;
File . Move ( Path . ChangeExtension ( outputExe , ".dll" ) , renamedDll ) ;
outputExe = Path . Combine ( outputPath , commandName + ".exe" ) ;
}
2015-10-06 10:46:43 -07:00
Console . Error . WriteLine ( $"Published to {outputExe}" ) ;
return 0 ;
}
2015-10-13 14:31:29 -07:00
private static void PublishFiles ( IEnumerable < string > files , string outputPath )
{
foreach ( var file in files )
{
File . Copy ( file , Path . Combine ( outputPath , Path . GetFileName ( file ) ) , overwrite : true ) ;
}
}
2015-10-06 10:46:43 -07:00
}
}