/// <summary> /// Ensures that the sources of an <see cref="Asset"/> exist. /// </summary> /// <param name="result">The <see cref="AssetCompilerResult"/> in which to output log of potential errors.</param> /// <param name="assetItem">The asset to check.</param> /// <returns><c>true</c> if the source file exists, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">Any of the argument is <c>null</c>.</exception> private static bool EnsureSourcesExist(AssetCompilerResult result, AssetItem assetItem) { if (result == null) { throw new ArgumentNullException(nameof(result)); } if (assetItem == null) { throw new ArgumentNullException(nameof(assetItem)); } var collector = new SourceFilesCollector(); var sourceMembers = collector.GetSourceMembers(assetItem.Asset); foreach (var member in sourceMembers) { if (string.IsNullOrEmpty(member.Value)) { result.Error($"Source is null for Asset [{assetItem}] in property [{member.Key}]"); return(false); } // Get absolute path of asset source on disk var assetDirectory = assetItem.FullPath.GetParent(); var assetSource = UPath.Combine(assetDirectory, member.Value); // Ensure the file exists if (!File.Exists(assetSource)) { result.Error($"Unable to find the source file '{assetSource}' for Asset [{assetItem}]"); return(false); } } return(true); }
/// <summary> /// Compile the required build step necessary to produce the desired output item. /// </summary> /// <param name="context">The context.</param> /// <param name="compilationResult">The compilation result.</param> /// <param name="assetItem">The asset item.</param> public ListBuildStep CompileItem(AssetCompilerContext context, AssetCompilerResult compilationResult, AssetItem assetItem) { // First try to find an asset compiler for this particular asset. IAssetCompiler compiler; try { compiler = compilerRegistry.GetCompiler(assetItem.Asset.GetType(), compilationContext); } catch (Exception ex) { compilationResult.Error($"Cannot find a compiler for asset [{assetItem.Id}] from path [{assetItem.Location}]", ex); return(null); } if (compiler == null) { return(null); } // Second we are compiling the asset (generating a build step) try { var resultPerAssetType = compiler.Prepare(context, assetItem); // Raise the AssetCompiled event. AssetCompiled?.Invoke(this, new AssetCompiledArgs(assetItem, resultPerAssetType)); // TODO: See if this can be unified with PackageBuilder.BuildStepProcessed var assetFullPath = assetItem.FullPath.ToWindowsPath(); foreach (var message in resultPerAssetType.Messages) { var assetMessage = AssetLogMessage.From(null, assetItem.ToReference(), message, assetFullPath); // Forward log messages to compilationResult compilationResult.Log(assetMessage); // Forward log messages to build step logger resultPerAssetType.BuildSteps.Logger.Log(assetMessage); } // Make the build step fail if there was an error during compiling (only when we are compiling the build steps of an asset) if (resultPerAssetType.BuildSteps is AssetBuildStep && resultPerAssetType.BuildSteps.Logger.HasErrors) { resultPerAssetType.BuildSteps.Add(new CommandBuildStep(new FailedCommand(assetItem.Location))); } // TODO: Big review of the log infrastructure of CompilerApp & BuildEngine! // Assign module string to all command build steps SetAssetLogger(resultPerAssetType.BuildSteps, assetItem.Package, assetItem.ToReference(), assetItem.FullPath.ToWindowsPath()); foreach (var buildStep in resultPerAssetType.BuildSteps) { buildStep.Priority = latestPriority++; } // Add the item result build steps the item list result build steps return(resultPerAssetType.BuildSteps); } catch (Exception ex) { compilationResult.Error($"Unexpected exception while compiling asset [{assetItem.Id}] from path [{assetItem.Location}]", ex); return(null); } }
private void Prepare(AssetCompilerResult finalResult, AssetCompilerContext context, AssetItem assetItem, [NotNull] Type compilationContext, HashSet <BuildAssetNode> visitedItems, Dictionary <AssetId, BuildStep> compiledItems, BuildStep parentBuildStep = null, BuildDependencyType dependencyType = BuildDependencyType.Runtime) { if (compilationContext == null) { throw new ArgumentNullException(nameof(compilationContext)); } var assetNode = BuildDependencyManager.FindOrCreateNode(assetItem, compilationContext); compiledItems.TryGetValue(assetNode.AssetItem.Id, out var assetBuildSteps); // Prevent re-entrancy in the same node if (visitedItems.Add(assetNode)) { assetNode.Analyze(context); // Invoke the compiler to prepare the build step for this asset if the dependency needs to compile it (Runtime or CompileContent) if ((dependencyType & ~BuildDependencyType.CompileAsset) != 0 && assetBuildSteps == null) { var mainCompiler = BuildDependencyManager.AssetCompilerRegistry.GetCompiler(assetItem.Asset.GetType(), assetNode.CompilationContext); if (mainCompiler == null) { return; } var compilerResult = mainCompiler.Prepare(context, assetItem); if ((dependencyType & BuildDependencyType.Runtime) == BuildDependencyType.Runtime && compilerResult.HasErrors) //allow Runtime dependencies to fail { assetBuildSteps = new ErrorBuildStep(assetItem, compilerResult.Messages); } else { assetBuildSteps = compilerResult.BuildSteps; compiledItems.Add(assetNode.AssetItem.Id, assetBuildSteps); // Copy the log to the final result (note: this does not copy or forward the build steps) compilerResult.CopyTo(finalResult); if (compilerResult.HasErrors) { finalResult.Error($"Failed to prepare asset {assetItem.Location}"); return; } } // Add the resulting build steps to the final finalResult.BuildSteps.Add(assetBuildSteps); AssetCompiled?.Invoke(this, new AssetCompiledArgs(assetItem, compilerResult)); } // Go through the dependencies of the node and prepare them as well foreach (var reference in assetNode.References) { var target = reference.Target; Prepare(finalResult, context, target.AssetItem, target.CompilationContext, visitedItems, compiledItems, assetBuildSteps, reference.DependencyType); if (finalResult.HasErrors) { return; } } // If we didn't prepare any build step for this asset let's exit here. if (assetBuildSteps == null) { return; } } // Link the created build steps to their parent step. if (parentBuildStep != null && assetBuildSteps != null && (dependencyType & BuildDependencyType.CompileContent) == BuildDependencyType.CompileContent) //only if content is required Content.Load { BuildStep.LinkBuildSteps(assetBuildSteps, parentBuildStep); } }