2016-02-02 18:04:50 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Runtime.CompilerServices ;
namespace Microsoft.DotNet.Cli.Build.Framework
{
public class BuildSetup
{
private Dictionary < string , BuildTarget > _targets = new Dictionary < string , BuildTarget > ( ) ;
public IList < TargetOverride > _overrides = new List < TargetOverride > ( ) ;
public string ProductName { get ; }
public BuildSetup ( string productName )
{
ProductName = productName ;
}
public static BuildSetup Create ( string productName )
{
return new BuildSetup ( productName ) ;
}
public BuildSetup UseTargets ( IEnumerable < BuildTarget > targets )
{
foreach ( var target in targets )
{
BuildTarget previousTarget ;
if ( _targets . TryGetValue ( target . Name , out previousTarget ) )
{
_overrides . Add ( new TargetOverride ( target . Name , previousTarget . Source , target . Source ) ) ;
}
_targets [ target . Name ] = target ;
}
return this ;
}
public BuildSetup UseAllTargetsFromAssembly < T > ( )
{
var asm = typeof ( T ) . GetTypeInfo ( ) . Assembly ;
return UseTargets ( asm . GetExportedTypes ( ) . SelectMany ( t = > CollectTargets ( t ) ) ) ;
}
public BuildSetup UseTargetsFrom < T > ( )
{
return UseTargets ( CollectTargets ( typeof ( T ) ) ) ;
}
public int Run ( string [ ] args )
{
var targets = new [ ] { BuildContext . DefaultTarget } ;
if ( args . Length > 0 )
{
targets = args ;
}
Reporter . Output . WriteBanner ( $"Building {ProductName}" ) ;
if ( _overrides . Any ( ) )
{
foreach ( var targetOverride in _overrides )
{
Reporter . Verbose . WriteLine ( $"Target {targetOverride.Name} from {targetOverride.OriginalSource} was overridden in {targetOverride.OverrideSource}" . Black ( ) ) ;
}
}
var context = new BuildContext ( _targets , Directory . GetCurrentDirectory ( ) ) ;
BuildTargetResult result = null ;
try
{
foreach ( var target in targets )
{
result = context . RunTarget ( target ) ;
if ( ! result . Success )
{
break ;
}
}
}
catch ( Exception ex )
{
Reporter . Error . WriteLine ( ex . ToString ( ) . Red ( ) ) ;
return 1 ;
}
if ( result ! = null & & ! result . Success )
{
Reporter . Error . WriteLine ( $"Build failed: {result.ErrorMessage}" . Red ( ) ) ;
return 1 ;
}
else
{
Reporter . Output . WriteLine ( "Build succeeded" . Green ( ) ) ;
return 0 ;
}
}
private static IEnumerable < BuildTarget > CollectTargets ( Type typ )
{
return from m in typ . GetMethods ( )
2016-02-20 01:00:41 +00:00
let targetAttribute = m . GetCustomAttribute < TargetAttribute > ( )
let conditionalAttributes = m . GetCustomAttributes < TargetConditionAttribute > ( false )
where targetAttribute ! = null
select CreateTarget ( m , targetAttribute , conditionalAttributes ) ;
2016-02-02 18:04:50 +00:00
}
2016-02-20 01:00:41 +00:00
private static BuildTarget CreateTarget (
MethodInfo methodInfo ,
TargetAttribute targetAttribute ,
IEnumerable < TargetConditionAttribute > targetConditionAttributes )
2016-02-02 18:04:50 +00:00
{
2016-02-20 01:00:41 +00:00
var name = targetAttribute . Name ? ? methodInfo . Name ;
var conditions = ExtractTargetConditionsFromAttributes ( targetConditionAttributes ) ;
2016-02-02 18:04:50 +00:00
return new BuildTarget (
2016-02-20 01:00:41 +00:00
name ,
$"{methodInfo.DeclaringType.FullName}.{methodInfo.Name}" ,
targetAttribute . Dependencies ,
conditions ,
( Func < BuildTargetContext , BuildTargetResult > ) methodInfo . CreateDelegate ( typeof ( Func < BuildTargetContext , BuildTargetResult > ) ) ) ;
}
private static IEnumerable < Func < bool > > ExtractTargetConditionsFromAttributes (
IEnumerable < TargetConditionAttribute > targetConditionAttributes )
{
if ( targetConditionAttributes = = null | | targetConditionAttributes . Count ( ) = = 0 )
{
return Enumerable . Empty < Func < bool > > ( ) ;
}
return targetConditionAttributes
. Select < TargetConditionAttribute , Func < bool > > ( c = > c . EvaluateCondition )
. ToArray ( ) ;
2016-02-02 18:04:50 +00:00
}
private string GenerateSourceString ( string file , int? line , string member )
{
if ( ! string . IsNullOrEmpty ( file ) & & line ! = null )
{
return $"{file}:{line}" ;
}
else if ( ! string . IsNullOrEmpty ( member ) )
{
return member ;
}
return string . Empty ;
}
public class TargetOverride
{
public string Name { get ; }
public string OriginalSource { get ; }
public string OverrideSource { get ; }
public TargetOverride ( string name , string originalSource , string overrideSource )
{
Name = name ;
OriginalSource = originalSource ;
OverrideSource = overrideSource ;
}
}
}
}