using System; using System.Collections.Generic; using UnityEditor.Build.Pipeline.Injector; using UnityEditor.Build.Pipeline.Interfaces; using UnityEditor.Build.Pipeline.Utilities; using UnityEditor.Build.Profiler; using UnityEditor.Build.Reporting; namespace UnityEditor.Build.Pipeline { /// /// Basic static class containing default implementations for BuildTask validation and running. /// public static class BuildTasksRunner { /// /// Basic run implementation that takes a set of tasks, a context, and runs returning the build results. /// , , and /// /// The set of build tasks to run. /// The build context to use for this run. /// Return code with status information about success or failure causes. public static ReturnCode Run(IList pipeline, IBuildContext context) { // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (pipeline == null) { BuildLogger.LogException(new ArgumentNullException("pipeline")); return ReturnCode.Exception; } // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (context == null) { BuildLogger.LogException(new ArgumentNullException("context")); return ReturnCode.Exception; } IProgressTracker tracker; if (context.TryGetContextObject(out tracker)) tracker.TaskCount = pipeline.Count; context.TryGetContextObject(out IBuildLogger logger); foreach (IBuildTask task in pipeline) { { try { if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable())) return ReturnCode.Canceled; ContextInjector.Inject(context, task); ReturnCode result; using (logger.ScopedStep(LogLevel.Info, task.GetType().Name)) result = task.Run(); if (result < ReturnCode.Success) return result; ContextInjector.Extract(context, task); } catch (Exception e) { BuildLogger.LogError("Build Task {0} failed with exception:\n{1}\n{2}", task.GetType().Name, e.Message, e.StackTrace); return ReturnCode.Exception; } } } if (tracker is IDisposable disposable) disposable.Dispose(); return ReturnCode.Success; } /// /// Run implementation with task profiler that takes a set of tasks, a context, runs returning the build results and prints out the profiler details. /// , , and /// /// The set of build tasks to run. /// The build context to use for this run. /// Return code with status information about success or failure causes. internal static ReturnCode RunProfiled(IList pipeline, IBuildContext context) { // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (pipeline == null) { BuildLogger.LogException(new ArgumentNullException("pipeline")); return ReturnCode.Exception; } // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (context == null) { BuildLogger.LogException(new ArgumentNullException("context")); return ReturnCode.Exception; } var profiler = new BuildProfiler(pipeline.Count + 1); profiler.Start(pipeline.Count, "TotalTime"); int count = 0; IProgressTracker tracker; if (context.TryGetContextObject(out tracker)) tracker.TaskCount = pipeline.Count; foreach (IBuildTask task in pipeline) { try { if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable())) { profiler.Stop(pipeline.Count); profiler.Print(); return ReturnCode.Canceled; } ContextInjector.Inject(context, task); profiler.Start(count, task.GetType().Name); var result = task.Run(); profiler.Stop(count++); if (result < ReturnCode.Success) { profiler.Stop(pipeline.Count); profiler.Print(); return result; } ContextInjector.Extract(context, task); } catch (Exception e) { BuildLogger.LogException(e); profiler.Stop(count); profiler.Print(); return ReturnCode.Exception; } } profiler.Stop(pipeline.Count); profiler.Print(); return ReturnCode.Success; } /// /// Basic validate implementation that takes a set of tasks, a context, and does checks to ensure the task requirements are all satisfied. /// , , and /// /// The set of build tasks to run. /// The build context to use for this run. /// Return code with status information about success or failure causes. public static ReturnCode Validate(IList pipeline, IBuildContext context) { //// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code //if (pipeline == null) //{ // BuildLogger.LogException(new ArgumentNullException("pipeline")); // return ReturnCode.Exception; //} //// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code //if (context == null) //{ // BuildLogger.LogException(new ArgumentNullException("context")); // return ReturnCode.Exception; //} //var requiredTypes = new HashSet(); //foreach (IBuildTask task in pipeline) // requiredTypes.UnionWith(task.RequiredContextTypes); //var missingTypes = new List(); //foreach (Type requiredType in requiredTypes) //{ // if (!context.ContainsContextObject(requiredType)) // missingTypes.Add(requiredType.Name); //} //if (missingTypes.Count > 0) //{ // BuildLogger.LogError("Missing required object types to run build pipeline:\n{0}", string.Join(", ", missingTypes.ToArray())); // return ReturnCode.MissingRequiredObjects; //} return ReturnCode.Success; } } }