dotnet-installer/build_projects/Microsoft.DotNet.Cli.Build.Framework/BuildSetup.cs
2016-05-16 14:55:15 -05:00

168 lines
5.5 KiB
C#

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()
let targetAttribute = m.GetCustomAttribute<TargetAttribute>()
let conditionalAttributes = m.GetCustomAttributes<TargetConditionAttribute>(false)
where targetAttribute != null
select CreateTarget(m, targetAttribute, conditionalAttributes);
}
private static BuildTarget CreateTarget(
MethodInfo methodInfo,
TargetAttribute targetAttribute,
IEnumerable<TargetConditionAttribute> targetConditionAttributes)
{
var name = targetAttribute.Name ?? methodInfo.Name;
var conditions = ExtractTargetConditionsFromAttributes(targetConditionAttributes);
return new BuildTarget(
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();
}
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;
}
}
}
}