2016-02-02 10:04:50 -08:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Runtime.InteropServices ;
namespace Microsoft.DotNet.Cli.Build.Framework
{
public class BuildContext
{
private IDictionary < string , BuildTargetResult > _completedTargets = new Dictionary < string , BuildTargetResult > ( StringComparer . OrdinalIgnoreCase ) ;
public static readonly string DefaultTarget = "Default" ;
private int _maxTargetLen ;
private Stack < string > _targetStack = new Stack < string > ( ) ;
public IDictionary < string , BuildTarget > Targets { get ; }
public IDictionary < string , object > Properties = new Dictionary < string , object > ( ) ;
public string BuildDirectory { get ; }
public object this [ string name ]
{
get { return Properties . ContainsKey ( name ) ? Properties [ name ] : null ; }
set { Properties [ name ] = value ; }
}
public BuildContext ( IDictionary < string , BuildTarget > targets , string buildDirectory )
{
Targets = targets ;
BuildDirectory = buildDirectory ;
_maxTargetLen = targets . Values . Select ( t = > t . Name . Length ) . Max ( ) ;
}
2016-02-15 10:07:39 -08:00
public T Get < T > ( string name ) = > ( T ) this [ name ] ;
2016-02-02 10:04:50 -08:00
public BuildTargetResult RunTarget ( string name ) = > RunTarget ( name , force : false ) ;
public BuildTargetResult RunTarget ( string name , bool force )
{
BuildTarget target ;
if ( ! Targets . TryGetValue ( name , out target ) )
{
2016-02-19 17:00:41 -08:00
throw new UndefinedTargetException ( $"Undefined target: {name}" ) ;
}
if ( ! EvaluateTargetConditions ( target ) )
{
Reporter . Verbose . WriteLine ( $"Skipping, Target Conditions not met: {target.Name}" ) ;
return new BuildTargetResult ( target , success : true ) ;
2016-02-02 10:04:50 -08:00
}
// Check if it's been completed
BuildTargetResult result ;
if ( ! force & & _completedTargets . TryGetValue ( name , out result ) )
{
Reporter . Verbose . WriteLine ( $"Skipping completed target: {target.Name}" ) ;
return result ;
}
// It hasn't, or we're forcing, so run it
result = ExecTarget ( target ) ;
_completedTargets [ target . Name ] = result ;
return result ;
}
public void Verbose ( string message )
{
Reporter . Output . WriteLine ( "trace" . White ( ) + $": {message}" ) ;
}
public void Info ( string message )
{
Reporter . Output . WriteLine ( "info " . Green ( ) + $": {message}" ) ;
}
public void Warn ( string message )
{
Reporter . Output . WriteLine ( "warn " . Yellow ( ) + $": {message}" ) ;
}
public void Error ( string message )
{
Reporter . Error . WriteLine ( "error" . Red ( ) . Bold ( ) + $": {message}" ) ;
}
2016-02-19 17:00:41 -08:00
private bool EvaluateTargetConditions ( BuildTarget target )
{
if ( target = = null )
{
throw new ArgumentNullException ( "target" ) ;
}
if ( target . Conditions = = null )
{
return true ;
}
foreach ( var condition in target . Conditions )
{
if ( ! condition ( ) )
{
return false ;
}
}
return true ;
}
2016-02-02 10:04:50 -08:00
private BuildTargetResult ExecTarget ( BuildTarget target )
{
2016-02-18 11:39:36 -08:00
if ( target = = null )
{
throw new ArgumentNullException ( "target" ) ;
}
2016-02-02 10:04:50 -08:00
var sectionName = $"{target.Name.PadRight(_maxTargetLen + 2).Yellow()} ({target.Source.White()})" ;
BuildReporter . BeginSection ( "TARGET" , sectionName ) ;
BuildTargetResult result ;
// Run the dependencies
var dependencyResults = new Dictionary < string , BuildTargetResult > ( ) ;
var failedDependencyResult = RunDependencies ( target , dependencyResults ) ;
if ( failedDependencyResult ! = null )
{
result = failedDependencyResult ;
}
else if ( target . Body ! = null )
{
try
{
result = target . Body ( new BuildTargetContext ( this , target , dependencyResults ) ) ;
}
catch ( Exception ex )
{
result = new BuildTargetResult ( target , success : false , exception : ex ) ;
}
}
else
{
result = new BuildTargetResult ( target , success : true ) ;
}
BuildReporter . EndSection ( "TARGET" , sectionName , result . Success ) ;
return result ;
}
private BuildTargetResult RunDependencies ( BuildTarget target , Dictionary < string , BuildTargetResult > dependencyResults )
{
BuildTargetResult result = null ;
foreach ( var dependency in target . Dependencies )
{
result = RunTarget ( dependency ) ;
dependencyResults [ dependency ] = result ;
if ( ! result . Success )
{
return result ;
}
}
return null ;
}
}
}