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 _targets = new Dictionary(); public IList _overrides = new List(); public string ProductName { get; } public BuildSetup(string productName) { ProductName = productName; } public static BuildSetup Create(string productName) { return new BuildSetup(productName); } public BuildSetup UseTargets(IEnumerable 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() { var asm = typeof(T).GetTypeInfo().Assembly; return UseTargets(asm.GetExportedTypes().SelectMany(t => CollectTargets(t))); } public BuildSetup UseTargetsFrom() { 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 CollectTargets(Type typ) { return from m in typ.GetMethods() let targetAttribute = m.GetCustomAttribute() let conditionalAttributes = m.GetCustomAttributes(false) where targetAttribute != null select CreateTarget(m, targetAttribute, conditionalAttributes); } private static BuildTarget CreateTarget( MethodInfo methodInfo, TargetAttribute targetAttribute, IEnumerable targetConditionAttributes) { var name = targetAttribute.Name ?? methodInfo.Name; var conditions = ExtractTargetConditionsFromAttributes(targetConditionAttributes); return new BuildTarget( name, $"{methodInfo.DeclaringType.FullName}.{methodInfo.Name}", targetAttribute.Dependencies, conditions, (Func)methodInfo.CreateDelegate(typeof(Func))); } private static IEnumerable> ExtractTargetConditionsFromAttributes( IEnumerable targetConditionAttributes) { if (targetConditionAttributes == null || targetConditionAttributes.Count() == 0) { return Enumerable.Empty>(); } return targetConditionAttributes .Select>(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; } } } }