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-10-13 14:31:29 -07:00
using System.Collections.Generic ;
2015-10-06 10:46:43 -07:00
using System.IO ;
2015-12-02 23:32:27 -08:00
using System.Linq ;
2015-10-06 10:46:43 -07:00
using Microsoft.Dnx.Runtime.Common.CommandLine ;
using Microsoft.DotNet.Cli.Utils ;
2015-11-27 16:19:54 -08:00
using Microsoft.DotNet.ProjectModel ;
using Microsoft.DotNet.ProjectModel.Compilation ;
2015-11-29 00:14:30 -08:00
using Microsoft.DotNet.ProjectModel.Graph ;
2015-10-13 14:31:29 -07:00
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-12-02 23:32:27 -08:00
NuGetFramework nugetframework = null ;
if ( framework . HasValue ( ) )
2015-10-15 12:56:07 -07:00
{
2015-12-02 23:32:27 -08:00
nugetframework = NuGetFramework . Parse ( framework . Value ( ) ) ;
if ( nugetframework . IsUnsupported )
{
Reporter . Output . WriteLine ( $"Unsupported framework {framework.Value()}." . Red ( ) ) ;
return 1 ;
}
2015-10-15 12:56:07 -07:00
}
2015-11-29 00:14:30 -08:00
// TODO: Remove this once xplat publish is enabled.
if ( ! runtime . HasValue ( ) )
2015-10-15 12:56:07 -07:00
{
2015-11-29 00:14:30 -08:00
runtime . Values . Add ( RuntimeIdentifier . Current ) ;
2015-10-15 12:56:07 -07:00
}
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-12-02 23:32:27 -08:00
var projectContexts = ProjectContext . CreateContextForEachTarget ( path ) ;
projectContexts = GetMatchingProjectContexts ( projectContexts , nugetframework , runtime . Value ( ) ) ;
2015-11-29 00:14:30 -08:00
2015-12-02 23:32:27 -08:00
if ( projectContexts . Count ( ) = = 0 )
2015-11-29 00:14:30 -08:00
{
string errMsg = $"'{project.Value}' cannot be published" ;
2015-12-02 23:32:27 -08:00
if ( framework . HasValue ( ) | | runtime . HasValue ( ) )
2015-11-29 00:14:30 -08:00
{
errMsg + = $" for '{framework.Value()}' '{runtime.Value()}'" ;
}
Reporter . Output . WriteLine ( errMsg . Red ( ) ) ;
return 1 ;
}
int result = 0 ;
2015-12-02 23:32:27 -08:00
foreach ( var projectContext in projectContexts )
2015-11-29 00:14:30 -08:00
{
2015-12-02 23:32:27 -08:00
result + = Publish ( projectContext , output . Value ( ) , configuration . Value ( ) ? ? Constants . DefaultConfiguration ) ;
2015-11-29 00:14:30 -08:00
}
return result ;
2015-10-06 10:46:43 -07:00
} ) ;
try
{
return app . Execute ( args ) ;
}
2015-10-18 02:06:15 -07:00
catch ( Exception ex )
2015-10-06 10:46:43 -07:00
{
2015-10-20 01:43:37 -07:00
#if DEBUG
Console . Error . WriteLine ( ex ) ;
#else
2015-10-06 10:46:43 -07:00
Console . Error . WriteLine ( ex . Message ) ;
2015-10-20 01:43:37 -07:00
#endif
2015-10-06 10:46:43 -07:00
return 1 ;
}
}
2015-10-15 12:56:07 -07:00
private static bool CheckArg ( CommandOption argument )
2015-10-06 10:46:43 -07:00
{
if ( ! argument . HasValue ( ) )
{
2015-10-15 12:56:07 -07:00
Reporter . Error . WriteLine ( $"Missing required argument: {argument.LongName.Red().Bold()}" ) ;
return false ;
2015-10-06 10:46:43 -07:00
}
2015-10-15 12:56:07 -07:00
return true ;
2015-10-06 10:46:43 -07:00
}
2015-12-02 23:32:27 -08:00
// return the matching framework/runtime ProjectContext.
// if 'nugetframework' or 'runtime' is null or empty then it matches with any.
2015-12-03 13:17:17 -08:00
private static IEnumerable < ProjectContext > GetMatchingProjectContexts ( IEnumerable < ProjectContext > contexts , NuGetFramework framework , string runtimeIdentifier )
2015-11-30 18:04:50 -08:00
{
2015-12-02 23:32:27 -08:00
var matchingContexts = contexts . Where ( context = >
2015-11-30 18:04:50 -08:00
{
2015-12-02 23:32:27 -08:00
if ( context . TargetFramework = = null | | string . IsNullOrEmpty ( context . RuntimeIdentifier ) )
2015-11-30 18:04:50 -08:00
{
return false ;
}
2015-12-02 23:32:27 -08:00
if ( string . IsNullOrEmpty ( runtimeIdentifier ) | | runtimeIdentifier . Equals ( context . RuntimeIdentifier ) )
2015-11-30 18:04:50 -08:00
{
2015-12-02 23:32:27 -08:00
if ( framework = = null | | framework . Equals ( context . TargetFramework ) )
2015-11-30 18:04:50 -08:00
{
return true ;
}
}
return false ;
} ) ;
2015-12-02 23:32:27 -08:00
return matchingContexts ;
2015-11-29 00:14:30 -08:00
}
2015-12-02 23:32:27 -08:00
/// <summary>
/// Publish the project for given 'framework (ex - dnxcore50)' and 'runtimeID (ex - win7-x64)'
/// </summary>
/// <param name="context">project that is to be published</param>
/// <param name="outputPath">Location of published files</param>
/// <param name="configuration">Debug or Release</param>
/// <returns>Return 0 if successful else return non-zero</returns>
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-11-01 16:21:10 -08:00
Reporter . Output . WriteLine ( $"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}" ) ;
2015-10-13 14:31:29 -07:00
2015-10-22 04:34:01 -07:00
var options = context . ProjectFile . GetCompilerOptions ( context . TargetFramework , configuration ) ;
2015-10-18 00:35:56 -07:00
// 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 (
2015-10-15 12:56:07 -07:00
context . ProjectFile . ProjectDirectory ,
Constants . BinDirectoryName ,
2015-10-13 14:31:29 -07:00
configuration ,
context . TargetFramework . GetTwoDigitShortFolderName ( ) ,
2015-10-24 03:59:39 -07:00
context . RuntimeIdentifier ) ;
2015-10-06 10:46:43 -07:00
}
2015-10-18 00:35:56 -07:00
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)
2015-12-02 23:32:27 -08:00
var result = Command . Create ( "dotnet-compile" ,
2015-11-30 12:17:41 -08:00
$"--framework \" { context . TargetFramework . DotNetFrameworkName } \ " " +
$"--output \" { outputPath } \ " " +
$"--configuration \" { configuration } \ " " +
"--no-host " +
$"\" { context . ProjectFile . ProjectDirectory } \ "" )
2015-10-06 10:46:43 -07:00
. ForwardStdErr ( )
. ForwardStdOut ( )
2015-10-21 03:11:27 -07:00
. Execute ( ) ;
2015-10-18 00:35:56 -07:00
2015-10-06 10:46:43 -07:00
if ( result . ExitCode ! = 0 )
{
return result . ExitCode ;
}
2015-10-13 14:31:29 -07:00
// Use a library exporter to collect publish assets
var exporter = context . CreateExporter ( configuration ) ;
2015-10-18 00:35:56 -07:00
2015-10-13 14:31:29 -07:00
foreach ( var export in exporter . GetAllExports ( ) )
2015-10-06 10:46:43 -07:00
{
2015-11-01 05:40:19 -08:00
// Skip copying project references
if ( export . Library is ProjectDescription )
{
continue ;
}
2015-11-01 16:21:10 -08:00
Reporter . Verbose . 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-11-30 12:26:53 -08:00
// Publish a host if this is an application
if ( options . EmitEntryPoint . GetValueOrDefault ( ) )
{
Reporter . Verbose . WriteLine ( $"Making {context.ProjectFile.Name.Cyan()} runnable ..." ) ;
PublishHost ( context , outputPath ) ;
}
2015-10-16 15:30:28 -07:00
Reporter . Output . WriteLine ( $"Published to {outputPath}" . Green ( ) . Bold ( ) ) ;
return 0 ;
}
2015-10-21 15:21:14 -07:00
private static int PublishHost ( ProjectContext context , string outputPath )
2015-10-16 15:30:28 -07:00
{
2015-10-20 04:35:40 -07:00
if ( context . TargetFramework . IsDesktop ( ) )
{
return 0 ;
}
2015-10-16 15:30:28 -07:00
2015-10-21 15:21:14 -07:00
var hostPath = Path . Combine ( AppContext . BaseDirectory , Constants . HostExecutableName ) ;
2015-11-01 05:40:19 -08:00
if ( ! File . Exists ( hostPath ) )
2015-10-28 14:35:29 -07:00
{
2015-10-21 15:21:14 -07:00
Reporter . Error . WriteLine ( $"Cannot find {Constants.HostExecutableName} in the dotnet directory." . Red ( ) ) ;
2015-10-28 14:35:29 -07:00
return 1 ;
}
2015-10-16 15:30:28 -07:00
var outputExe = Path . Combine ( outputPath , context . ProjectFile . Name + Constants . ExeSuffix ) ;
2015-10-13 14:31:29 -07:00
2015-10-21 15:21:14 -07:00
// Copy the host
File . Copy ( hostPath , outputExe , overwrite : true ) ;
2015-11-30 12:17:41 -08:00
2015-10-06 10:46:43 -07:00
return 0 ;
}
2015-10-13 14:31:29 -07:00
2015-10-21 15:21:14 -07:00
private static void PublishFiles ( IEnumerable < LibraryAsset > files , string outputPath )
2015-10-13 14:31:29 -07:00
{
foreach ( var file in files )
{
2015-10-21 15:21:14 -07:00
File . Copy ( file . ResolvedPath , Path . Combine ( outputPath , Path . GetFileName ( file . ResolvedPath ) ) , overwrite : true ) ;
2015-10-13 14:31:29 -07:00
}
}
2015-10-06 10:46:43 -07:00
}
}