2016-02-02 10:04:50 -08:00
using Microsoft.DotNet.Cli.Build.Framework ;
using Microsoft.Extensions.PlatformAbstractions ;
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
2016-03-17 21:45:03 -07:00
using System.Linq ;
2016-02-02 10:04:50 -08:00
using System.Runtime.InteropServices ;
2016-02-18 11:39:36 -08:00
using System.Text ;
2016-02-02 10:04:50 -08:00
using static Microsoft . DotNet . Cli . Build . FS ;
using static Microsoft . DotNet . Cli . Build . Utils ;
using static Microsoft . DotNet . Cli . Build . Framework . BuildHelpers ;
2016-03-16 17:54:44 -07:00
using System.Text.RegularExpressions ;
2016-02-02 10:04:50 -08:00
namespace Microsoft.DotNet.Cli.Build
{
public class PrepareTargets
{
[Target(nameof(Init), nameof(RestorePackages))]
public static BuildTargetResult Prepare ( BuildTargetContext c ) = > c . Success ( ) ;
2016-02-19 17:00:41 -08:00
[Target(nameof(CheckPrereqCmakePresent), nameof(CheckPlatformDependencies))]
2016-02-18 11:39:36 -08:00
public static BuildTargetResult CheckPrereqs ( BuildTargetContext c ) = > c . Success ( ) ;
2016-03-07 14:52:41 -08:00
[Target(nameof(CheckCoreclrPlatformDependencies), nameof(CheckInstallerBuildPlatformDependencies))]
2016-02-19 17:00:41 -08:00
public static BuildTargetResult CheckPlatformDependencies ( BuildTargetContext c ) = > c . Success ( ) ;
2016-03-07 14:52:41 -08:00
[Target(nameof(CheckUbuntuCoreclrAndCoreFxDependencies), nameof(CheckCentOSCoreclrAndCoreFxDependencies))]
2016-02-19 17:00:41 -08:00
public static BuildTargetResult CheckCoreclrPlatformDependencies ( BuildTargetContext c ) = > c . Success ( ) ;
[Target(nameof(CheckUbuntuDebianPackageBuildDependencies))]
public static BuildTargetResult CheckInstallerBuildPlatformDependencies ( BuildTargetContext c ) = > c . Success ( ) ;
2016-02-02 10:04:50 -08:00
// All major targets will depend on this in order to ensure variables are set up right if they are run independently
2016-03-07 12:20:50 -08:00
[Target(nameof(GenerateVersions), nameof(CheckPrereqs), nameof(LocateStage0), nameof(ExpectedBuildArtifacts))]
2016-02-02 10:04:50 -08:00
public static BuildTargetResult Init ( BuildTargetContext c )
{
var runtimeInfo = PlatformServices . Default . Runtime ;
var configEnv = Environment . GetEnvironmentVariable ( "CONFIGURATION" ) ;
2016-02-15 09:42:17 -08:00
if ( string . IsNullOrEmpty ( configEnv ) )
2016-02-02 10:04:50 -08:00
{
configEnv = "Debug" ;
}
2016-02-15 09:42:17 -08:00
2016-02-02 10:04:50 -08:00
c . BuildContext [ "Configuration" ] = configEnv ;
2016-03-07 14:52:41 -08:00
c . BuildContext [ "Channel" ] = Environment . GetEnvironmentVariable ( "CHANNEL" ) ;
2016-02-02 10:04:50 -08:00
c . Info ( $"Building {c.BuildContext[" Configuration "]} to: {Dirs.Output}" ) ;
c . Info ( "Build Environment:" ) ;
c . Info ( $" Operating System: {runtimeInfo.OperatingSystem} {runtimeInfo.OperatingSystemVersion}" ) ;
c . Info ( $" Platform: {runtimeInfo.OperatingSystemPlatform}" ) ;
return c . Success ( ) ;
}
[Target]
public static BuildTargetResult GenerateVersions ( BuildTargetContext c )
{
var gitResult = Cmd ( "git" , "rev-list" , "--count" , "HEAD" )
. CaptureStdOut ( )
. Execute ( ) ;
gitResult . EnsureSuccessful ( ) ;
var commitCount = int . Parse ( gitResult . StdOut ) ;
gitResult = Cmd ( "git" , "rev-parse" , "HEAD" )
. CaptureStdOut ( )
. Execute ( ) ;
gitResult . EnsureSuccessful ( ) ;
var commitHash = gitResult . StdOut . Trim ( ) ;
var branchInfo = ReadBranchInfo ( c , Path . Combine ( c . BuildContext . BuildDirectory , "branchinfo.txt" ) ) ;
var buildVersion = new BuildVersion ( )
{
Major = int . Parse ( branchInfo [ "MAJOR_VERSION" ] ) ,
Minor = int . Parse ( branchInfo [ "MINOR_VERSION" ] ) ,
Patch = int . Parse ( branchInfo [ "PATCH_VERSION" ] ) ,
ReleaseSuffix = branchInfo [ "RELEASE_SUFFIX" ] ,
CommitCount = commitCount
} ;
c . BuildContext [ "BuildVersion" ] = buildVersion ;
c . BuildContext [ "CommitHash" ] = commitHash ;
2016-03-23 17:13:58 -07:00
c . BuildContext [ "SharedFrameworkNugetVersion" ] = GetVersionFromProjectJson ( Path . Combine ( Dirs . RepoRoot , "src" , "sharedframework" , "framework" , "project.json" ) ) ;
2016-02-02 10:04:50 -08:00
c . Info ( $"Building Version: {buildVersion.SimpleVersion} (NuGet Packages: {buildVersion.NuGetVersion})" ) ;
c . Info ( $"From Commit: {commitHash}" ) ;
return c . Success ( ) ;
}
[Target]
public static BuildTargetResult LocateStage0 ( BuildTargetContext c )
{
// We should have been run in the repo root, so locate the stage 0 relative to current directory
var stage0 = DotNetCli . Stage0 . BinPath ;
if ( ! Directory . Exists ( stage0 ) )
{
return c . Failed ( $"Stage 0 directory does not exist: {stage0}" ) ;
}
// Identify the version
2016-03-17 21:45:03 -07:00
string versionFile = Directory . GetFiles ( stage0 , ".version" , SearchOption . AllDirectories ) . FirstOrDefault ( ) ;
if ( string . IsNullOrEmpty ( versionFile ) )
{
throw new Exception ( $"'.version' file not found in '{stage0}' folder" ) ;
}
var version = File . ReadAllLines ( versionFile ) ;
2016-02-02 10:04:50 -08:00
c . Info ( $"Using Stage 0 Version: {version[1]}" ) ;
return c . Success ( ) ;
}
2016-03-07 12:20:50 -08:00
[Target]
public static BuildTargetResult ExpectedBuildArtifacts ( BuildTargetContext c )
{
var config = Environment . GetEnvironmentVariable ( "CONFIGURATION" ) ;
var versionBadgeName = $"{CurrentPlatform.Current}_{CurrentArchitecture.Current}_{config}_version_badge.svg" ;
c . BuildContext [ "VersionBadge" ] = Path . Combine ( Dirs . Output , versionBadgeName ) ;
2016-03-23 17:13:58 -07:00
var cliVersion = c . BuildContext . Get < BuildVersion > ( "BuildVersion" ) . NuGetVersion ;
var sharedFrameworkVersion = c . BuildContext . Get < string > ( "SharedFrameworkNugetVersion" ) ;
AddInstallerArtifactToContext ( c , "dotnet-sdk" , "Sdk" , cliVersion ) ;
AddInstallerArtifactToContext ( c , "dotnet-host" , "SharedHost" , cliVersion ) ;
AddInstallerArtifactToContext ( c , "dotnet-sharedframework" , "SharedFramework" , sharedFrameworkVersion ) ;
AddInstallerArtifactToContext ( c , "dotnet-dev" , "CombinedFrameworkSDKHost" , cliVersion ) ;
AddInstallerArtifactToContext ( c , "dotnet" , "CombinedFrameworkHost" , sharedFrameworkVersion ) ;
2016-03-07 12:20:50 -08:00
return c . Success ( ) ;
}
2016-02-02 10:04:50 -08:00
[Target]
public static BuildTargetResult CheckPackageCache ( BuildTargetContext c )
{
var ciBuild = string . Equals ( Environment . GetEnvironmentVariable ( "CI_BUILD" ) , "1" , StringComparison . Ordinal ) ;
if ( ciBuild )
{
// On CI, HOME is redirected under the repo, which gets deleted after every build.
// So make NUGET_PACKAGES outside of the repo.
var nugetPackages = Path . GetFullPath ( Path . Combine ( c . BuildContext . BuildDirectory , ".." , ".nuget" , "packages" ) ) ;
Environment . SetEnvironmentVariable ( "NUGET_PACKAGES" , nugetPackages ) ;
Dirs . NuGetPackages = nugetPackages ;
}
// Set the package cache location in NUGET_PACKAGES just to be safe
if ( string . IsNullOrEmpty ( Environment . GetEnvironmentVariable ( "NUGET_PACKAGES" ) ) )
{
Environment . SetEnvironmentVariable ( "NUGET_PACKAGES" , Dirs . NuGetPackages ) ;
}
CleanNuGetTempCache ( ) ;
// Determine cache expiration time
var cacheExpiration = 7 * 24 ; // cache expiration in hours
var cacheExpirationStr = Environment . GetEnvironmentVariable ( "NUGET_PACKAGES_CACHE_TIME_LIMIT" ) ;
if ( ! string . IsNullOrEmpty ( cacheExpirationStr ) )
{
cacheExpiration = int . Parse ( cacheExpirationStr ) ;
}
if ( ciBuild )
{
var cacheTimeFile = Path . Combine ( Dirs . NuGetPackages , "packageCacheTime.txt" ) ;
DateTime ? cacheTime = null ;
try
{
// Read the cache file
2016-02-15 09:42:17 -08:00
if ( File . Exists ( cacheTimeFile ) )
2016-02-02 10:04:50 -08:00
{
var content = File . ReadAllText ( cacheTimeFile ) ;
2016-02-15 09:42:17 -08:00
if ( ! string . IsNullOrEmpty ( content ) )
2016-02-02 10:04:50 -08:00
{
cacheTime = DateTime . ParseExact ( "O" , content , CultureInfo . InvariantCulture , DateTimeStyles . AssumeUniversal ) ;
}
}
}
2016-02-15 09:42:17 -08:00
catch ( Exception ex )
2016-02-02 10:04:50 -08:00
{
c . Warn ( $"Error reading NuGet cache time file, leaving the cache alone" ) ;
c . Warn ( $"Error Detail: {ex.ToString()}" ) ;
}
2016-02-15 09:42:17 -08:00
if ( cacheTime = = null | | ( cacheTime . Value . AddHours ( cacheExpiration ) < DateTime . UtcNow ) )
2016-02-02 10:04:50 -08:00
{
// Cache has expired or the status is unknown, clear it and write the file
c . Info ( "Clearing NuGet cache" ) ;
Rmdir ( Dirs . NuGetPackages ) ;
Mkdirp ( Dirs . NuGetPackages ) ;
File . WriteAllText ( cacheTimeFile , DateTime . UtcNow . ToString ( "O" ) ) ;
}
}
return c . Success ( ) ;
}
[Target(nameof(CheckPackageCache))]
public static BuildTargetResult RestorePackages ( BuildTargetContext c )
{
var dotnet = DotNetCli . Stage0 ;
2016-03-14 10:14:15 -07:00
dotnet . Restore ( "--verbosity" , "verbose" , "--disable-parallel" ) . WorkingDirectory ( Path . Combine ( c . BuildContext . BuildDirectory , "src" ) ) . Execute ( ) . EnsureSuccessful ( ) ;
dotnet . Restore ( "--verbosity" , "verbose" , "--disable-parallel" ) . WorkingDirectory ( Path . Combine ( c . BuildContext . BuildDirectory , "tools" ) ) . Execute ( ) . EnsureSuccessful ( ) ;
2016-02-02 10:04:50 -08:00
return c . Success ( ) ;
}
2016-02-18 11:39:36 -08:00
[Target]
2016-02-19 17:00:41 -08:00
[BuildPlatforms(BuildPlatform.Ubuntu)]
public static BuildTargetResult CheckUbuntuDebianPackageBuildDependencies ( BuildTargetContext c )
2016-02-18 11:39:36 -08:00
{
var messageBuilder = new StringBuilder ( ) ;
2016-02-23 15:27:03 -08:00
var aptDependencyUtility = new AptDependencyUtility ( ) ;
2016-02-18 11:39:36 -08:00
2016-02-23 15:27:03 -08:00
foreach ( var package in PackageDependencies . DebianPackageBuildDependencies )
2016-02-18 11:39:36 -08:00
{
2016-02-23 15:27:03 -08:00
if ( ! AptDependencyUtility . PackageIsInstalled ( package ) )
2016-02-18 11:39:36 -08:00
{
messageBuilder . Append ( $"Error: Debian package build dependency {package} missing." ) ;
messageBuilder . Append ( Environment . NewLine ) ;
messageBuilder . Append ( $"-> install with apt-get install {package}" ) ;
messageBuilder . Append ( Environment . NewLine ) ;
}
}
if ( messageBuilder . Length = = 0 )
{
return c . Success ( ) ;
}
else
{
return c . Failed ( messageBuilder . ToString ( ) ) ;
}
}
[Target]
2016-02-19 17:00:41 -08:00
[BuildPlatforms(BuildPlatform.Ubuntu)]
2016-02-23 15:27:03 -08:00
public static BuildTargetResult CheckUbuntuCoreclrAndCoreFxDependencies ( BuildTargetContext c )
2016-02-18 11:39:36 -08:00
{
var errorMessageBuilder = new StringBuilder ( ) ;
2016-02-23 15:27:03 -08:00
var stage0 = DotNetCli . Stage0 . BinPath ;
2016-02-18 11:39:36 -08:00
2016-02-23 15:27:03 -08:00
foreach ( var package in PackageDependencies . UbuntuCoreclrAndCoreFxDependencies )
2016-02-18 11:39:36 -08:00
{
2016-02-23 15:27:03 -08:00
if ( ! AptDependencyUtility . PackageIsInstalled ( package ) )
2016-02-18 11:39:36 -08:00
{
2016-02-19 17:00:41 -08:00
errorMessageBuilder . Append ( $"Error: Coreclr package dependency {package} missing." ) ;
errorMessageBuilder . Append ( Environment . NewLine ) ;
errorMessageBuilder . Append ( $"-> install with apt-get install {package}" ) ;
errorMessageBuilder . Append ( Environment . NewLine ) ;
}
2016-02-18 11:39:36 -08:00
}
2016-02-19 17:00:41 -08:00
if ( errorMessageBuilder . Length = = 0 )
2016-02-18 11:39:36 -08:00
{
2016-02-19 17:00:41 -08:00
return c . Success ( ) ;
}
else
{
return c . Failed ( errorMessageBuilder . ToString ( ) ) ;
2016-02-18 11:39:36 -08:00
}
2016-02-19 17:00:41 -08:00
}
[Target]
[BuildPlatforms(BuildPlatform.CentOS)]
2016-02-23 15:27:03 -08:00
public static BuildTargetResult CheckCentOSCoreclrAndCoreFxDependencies ( BuildTargetContext c )
2016-02-19 17:00:41 -08:00
{
var errorMessageBuilder = new StringBuilder ( ) ;
2016-03-07 14:52:41 -08:00
2016-02-23 15:27:03 -08:00
foreach ( var package in PackageDependencies . CentosCoreclrAndCoreFxDependencies )
2016-02-19 17:00:41 -08:00
{
2016-02-23 15:27:03 -08:00
if ( ! YumDependencyUtility . PackageIsInstalled ( package ) )
2016-02-18 11:39:36 -08:00
{
errorMessageBuilder . Append ( $"Error: Coreclr package dependency {package} missing." ) ;
errorMessageBuilder . Append ( Environment . NewLine ) ;
2016-02-19 17:00:41 -08:00
errorMessageBuilder . Append ( $"-> install with yum install {package}" ) ;
errorMessageBuilder . Append ( Environment . NewLine ) ;
2016-02-18 11:39:36 -08:00
}
}
if ( errorMessageBuilder . Length = = 0 )
{
return c . Success ( ) ;
}
else
{
return c . Failed ( errorMessageBuilder . ToString ( ) ) ;
}
}
[Target]
public static BuildTargetResult CheckPrereqCmakePresent ( BuildTargetContext c )
{
try
{
Command . Create ( "cmake" , "--version" )
. CaptureStdOut ( )
. CaptureStdErr ( )
. Execute ( ) ;
}
catch ( Exception ex )
{
string message = $ @ "Error running cmake: {ex.Message}
cmake is required to build the native host ' corehost ' ";
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
{
message + = Environment . NewLine + "Download it from https://www.cmake.org" ;
}
else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
{
message + = Environment . NewLine + "Ubuntu: 'sudo apt-get install cmake'" ;
}
else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) )
{
message + = Environment . NewLine + "OS X w/Homebrew: 'brew install cmake'" ;
}
return c . Failed ( message ) ;
}
return c . Success ( ) ;
}
2016-03-16 17:54:44 -07:00
private static string GetVersionFromProjectJson ( string pathToProjectJson )
{
Regex r = new Regex ( $"\" { Regex . Escape ( Monikers . SharedFrameworkName ) } \ "\\s*:\\s*\"(?'version'[^\"]*)\"" ) ;
foreach ( var line in File . ReadAllLines ( pathToProjectJson ) )
{
var m = r . Match ( line ) ;
if ( m . Success )
{
return m . Groups [ "version" ] . Value ;
}
}
throw new InvalidOperationException ( "Unable to match the version name from " + pathToProjectJson ) ;
}
2016-02-18 11:39:36 -08:00
private static bool AptPackageIsInstalled ( string packageName )
{
var result = Command . Create ( "dpkg" , "-s" , packageName )
. CaptureStdOut ( )
. CaptureStdErr ( )
2016-02-19 17:00:41 -08:00
. QuietBuildReporter ( )
2016-02-18 11:39:36 -08:00
. Execute ( ) ;
return result . ExitCode = = 0 ;
}
2016-02-02 10:04:50 -08:00
private static IDictionary < string , string > ReadBranchInfo ( BuildTargetContext c , string path )
{
var lines = File . ReadAllLines ( path ) ;
var dict = new Dictionary < string , string > ( ) ;
c . Verbose ( "Branch Info:" ) ;
2016-02-15 09:42:17 -08:00
foreach ( var line in lines )
2016-02-02 10:04:50 -08:00
{
2016-02-15 09:42:17 -08:00
if ( ! line . Trim ( ) . StartsWith ( "#" ) & & ! string . IsNullOrWhiteSpace ( line ) )
2016-02-02 10:04:50 -08:00
{
var splat = line . Split ( new [ ] { '=' } , 2 ) ;
dict [ splat [ 0 ] ] = splat [ 1 ] ;
c . Verbose ( $" {splat[0]} = {splat[1]}" ) ;
}
}
return dict ;
}
2016-03-08 13:39:41 -08:00
2016-03-23 17:13:58 -07:00
private static void AddInstallerArtifactToContext (
BuildTargetContext c ,
string artifactPrefix ,
string contextPrefix ,
string version )
2016-03-08 13:39:41 -08:00
{
2016-03-23 17:13:58 -07:00
var productName = Monikers . GetProductMoniker ( c , artifactPrefix , version ) ;
2016-03-08 13:39:41 -08:00
var extension = CurrentPlatform . IsWindows ? ".zip" : ".tar.gz" ;
c . BuildContext [ contextPrefix + "CompressedFile" ] = Path . Combine ( Dirs . Packages , productName + extension ) ;
string installer = "" ;
switch ( CurrentPlatform . Current )
{
case BuildPlatform . Windows :
installer = productName + ".exe" ;
break ;
case BuildPlatform . OSX :
installer = productName + ".pkg" ;
break ;
case BuildPlatform . Ubuntu :
installer = productName + ".deb" ;
break ;
default :
break ;
}
if ( ! string . IsNullOrEmpty ( installer ) )
{
c . BuildContext [ contextPrefix + "InstallerFile" ] = Path . Combine ( Dirs . Packages , installer ) ;
}
}
2016-02-02 10:04:50 -08:00
}
}