//-- Protected interface /// Constructor to be called by derived classes. protected BuildTranslation(BuildGraph buildGraph) { if (buildGraph == null) { throw new ArgumentNullException("buildGraph"); } ModuleName = ""; BuildNode = new BuildNode(this); BuildGraph = buildGraph; BuildGraph.Add(this); }
private void WriteDepsCacheFile(FileStream depsCacheFileStream, BuildNode buildNode) { string depsCacheString = DependencyCache.CreateDepsCacheString( buildNode.Translation, m_buildOptions.FileDecider); QRFileStream.WriteAllText(depsCacheFileStream, depsCacheString); }
private bool RequiresBuild(BuildNode buildNode, string previousBuildNodeState) { // No need to check if the file exists, because it has been opened-or-created // prior to this function call. // Load a string representation of the previous state of files on disk. // If the deps cache does not exist, then return true to indicate we must build. if (String.IsNullOrEmpty(previousBuildNodeState)) { return true; } // Create a string representation of the current state of files on disk. string currentBuildNodeState = DependencyCache.CreateDepsCacheString( buildNode.Translation, m_buildOptions.FileDecider); // Compare previous and current state. bool filesChanged = (previousBuildNodeState != currentBuildNodeState); return filesChanged; }
private bool PropagateDependenciesFromImplicitInputs(BuildNode buildNode) { bool implicitDependenciesReady = true; // Create BuildFiles for ImplicitInputs and update Dependencies/Consumers. foreach (string path in buildNode.Translation.ImplicitInputs) { BuildFile buildFile = m_buildGraph.CreateOrGetBuildFile(path); if (buildFile.BuildNode != null) { buildNode.Dependencies.Add(buildFile.BuildNode); buildFile.BuildNode.Consumers.Add(buildNode); buildFile.Consumers.Add(buildNode); if (!buildFile.BuildNode.Status.Executed()) { implicitDependenciesReady = false; } if (!m_requiredNodes.Contains(buildFile.BuildNode)) { m_requiredNodes.Add(buildFile.BuildNode); bool generatorReady = AllDependenciesExecuted(buildFile.BuildNode); if (generatorReady) { m_runList.Enqueue(buildFile.BuildNode); m_runSet.Add(buildFile.BuildNode); } } } } return implicitDependenciesReady; }
private void NotifyBuildNodeCompletion(BuildNode buildNode) { foreach (BuildNode consumer in buildNode.Consumers) { // Skip consumers that aren't part of this build. if (!m_requiredNodes.Contains(consumer)) { continue; } bool consumerReady = AllDependenciesExecuted(consumer); if (consumerReady) { m_runList.Enqueue(consumer); m_runSet.Add(consumer); } else { continue; } } }
/// Executes the Translation associated with buildNode, if all dependencies /// are up-to-date. This includes explicit and implicit IOs. private BuildStatus ExecuteOneBuildNode(BuildNode buildNode) { // depsCache file opened for exclusive access here. using (FileStream depsCacheFileStream = new FileStream(buildNode.Translation.DepsCacheFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { if (!buildNode.Translation.RequiresImplicitInputs) { string prevDepsCacheFileContents = QRFileStream.ReadAllText(depsCacheFileStream); bool requiresBuild = RequiresBuild(buildNode, prevDepsCacheFileContents); if (!requiresBuild) { // success! we can early-exit return BuildStatus.TranslationUpToDate; } // Ensure explicit inputs exist prior to execution. // This must be done here since Translation.Execute() is not expected to do the checks. bool explicitInputsExist = FilesExist(buildNode.Translation.ExplicitInputs); if (!explicitInputsExist) { // failed. some input does not exist return BuildStatus.InputsDoNotExist; } // fall through to Execute() } else { // buildNode.Translation.RequiresImplicitInputs if (!buildNode.ImplicitInputsUpToDate) { string prevDepsCacheFileContents = QRFileStream.ReadAllText(depsCacheFileStream); bool requiresBuild = RequiresBuild(buildNode, prevDepsCacheFileContents); if (!requiresBuild) { // success! we can early-exit return BuildStatus.TranslationUpToDate; } // Ensure explicit inputs exist prior to execution. // This must be done here since Translation.Execute() is not expected to do the checks. bool explicitInputsExist = FilesExist(buildNode.Translation.ExplicitInputs); if (!explicitInputsExist) { // failed. some input does not exist return BuildStatus.InputsDoNotExist; } // Since all explicit inputs exist, we can update the implicit IOs. bool updateImplicitInputsSucceeded = buildNode.Translation.UpdateImplicitInputs(); if (!updateImplicitInputsSucceeded) { return BuildStatus.ExecuteFailed; } return BuildStatus.ImplicitInputsComputed; } else { // buildNode.ImplicitInputsUpToDate // Ensure explicit inputs exist prior to execution. // This must be done here since Translation.Execute() is not expected to do the checks. bool explicitInputsExist = FilesExist(buildNode.Translation.ExplicitInputs); if (!explicitInputsExist) { // failed. some input does not exist return BuildStatus.InputsDoNotExist; } // Ensure inputs exist prior to execution. // This must be done here since Translation.Execute() is not expected to do the checks. bool implicitInputsExist = FilesExist(buildNode.Translation.ImplicitInputs); if (!implicitInputsExist) { // failed. some input does not exist return BuildStatus.InputsDoNotExist; } // fall through to Execute() } } bool executeSucceeded = false; try { executeSucceeded = buildNode.Translation.Execute(); } catch (Exception) { // TODO: log the error } if (!executeSucceeded) { // Clear the deps cache, so this failed node must execute on the next build. return BuildStatus.ExecuteFailed; } // success. WriteDepsCacheFile(depsCacheFileStream, buildNode); return BuildStatus.ExecuteSucceeded; } }
private bool AllDependenciesExecuted(BuildNode buildNode) { foreach (BuildNode dependency in buildNode.Dependencies) { if (!m_requiredNodes.Contains(dependency)) { continue; } if (!dependency.Status.Executed()) { return false; } } return true; }