6d8b622451
Make Attribute properties immutable PR Feedback, bugfixes PR Feedback
168 lines
5.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|