private PipelineBuildEvent LoadBuildEvent(string destFile, out string eventFilepath) { var contentPath = Path.ChangeExtension(PathHelper.GetRelativePath(OutputDirectory, destFile), PipelineBuildEvent.Extension); eventFilepath = Path.Combine(IntermediateDirectory, contentPath); return(PipelineBuildEvent.Load(eventFilepath)); }
public override TOutput BuildAndLoadAsset <TInput, TOutput>(ExternalReference <TInput> sourceAsset, string processorName, OpaqueDataDictionary processorParameters, string importerName) { var sourceFilepath = PathHelper.Normalize(sourceAsset.Filename); // The processorName can be null or empty. In this case the asset should // be imported but not processed. This is, for example, necessary to merge // animation files as described here: // http://blogs.msdn.com/b/shawnhar/archive/2010/06/18/merging-animation-files.aspx. bool processAsset = !string.IsNullOrEmpty(processorName); _manager.ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName); var buildEvent = new PipelineBuildEvent { SourceFile = sourceFilepath, Importer = importerName, Processor = processAsset ? processorName : null, Parameters = _manager.ValidateProcessorParameters(processorName, processorParameters), }; var processedObject = _manager.ProcessContent(buildEvent); // Record that we processed this dependent asset. _pipelineEvent.Dependencies.AddUnique(sourceFilepath); return((TOutput)processedObject); }
public PipelineBuildEvent BuildContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null) { sourceFilepath = PathHelper.Normalize(sourceFilepath); ResolveOutputFilepath(sourceFilepath, ref outputFilepath); // Resolve the importer name. if (string.IsNullOrEmpty(importerName)) { importerName = FindImporterByExtension(Path.GetExtension(sourceFilepath)); } // Resolve the processor name. if (string.IsNullOrEmpty(processorName)) { processorName = FindDefaultProcessor(importerName); } // Record what we're building and how. var contentEvent = new PipelineBuildEvent { SourceFile = PathHelper.Normalize(sourceFilepath), DestFile = outputFilepath, Importer = importerName, Processor = processorName, Parameters = ValidateProcessorParameters(processorName, processorParameters), }; // Load the previous content event if it exists. string eventFilepath; var cachedEvent = LoadBuildEvent(contentEvent.DestFile, out eventFilepath); BuildContent(contentEvent, cachedEvent, eventFilepath); return(contentEvent); }
public PipelineBuildEvent BuildContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null) { sourceFilepath = PathHelper.Normalize(sourceFilepath); ResolveOutputFilepath(sourceFilepath, ref outputFilepath); ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName); // Record what we're building and how. var contentEvent = new PipelineBuildEvent { SourceFile = sourceFilepath, DestFile = outputFilepath, Importer = importerName, Processor = processorName, Parameters = ValidateProcessorParameters(processorName, processorParameters), }; // Load the previous content event if it exists. string eventFilepath; var cachedEvent = LoadBuildEvent(contentEvent.DestFile, out eventFilepath); BuildContent(contentEvent, cachedEvent, eventFilepath); return(contentEvent); }
private void WriteXnb(object content, PipelineBuildEvent pipelineEvent) { // Make sure the output directory exists. var outputFileDir = Path.GetDirectoryName(pipelineEvent.DestFile); Directory.CreateDirectory(outputFileDir); if (_compiler == null) { _compiler = new ContentCompiler(); } var type = content.GetType(); var attrib = type.GetCustomAttribute <CompressedContentAttribute>(true); bool compress = attrib == null && CompressContent; // Write the XNB. using (var fs = new FileStream( pipelineEvent.DestFile, FileMode.Create, FileAccess.Write, FileShare.None)) _compiler.Compile(fs, content, Platform, Profile, compress, OutputDirectory, outputFileDir); // Store the last write time of the output XNB here // so we can verify it hasn't been tampered with. pipelineEvent.DestTime = File.GetLastWriteTime(pipelineEvent.DestFile); }
/// <summary> /// Determines whether the specified list contains a matching pipeline build event. /// </summary> /// <param name="pipelineBuildEvents">The list of pipeline build events.</param> /// <param name="importerName">The name of the content importer. Can be <see langword="null"/>.</param> /// <param name="processorName">The name of the content processor. Can be <see langword="null"/>.</param> /// <param name="processorParameters">The processor parameters. Can be <see langword="null"/>.</param> /// <returns> /// The matching pipeline build event, or <see langword="null"/>. /// </returns> private static PipelineBuildEvent FindMatchingEvent(List <PipelineBuildEvent> pipelineBuildEvents, string importerName, string processorName, OpaqueDataDictionary processorParameters) { foreach (var existingBuildEvent in pipelineBuildEvents) { if (existingBuildEvent.Importer == importerName && existingBuildEvent.Processor == processorName && PipelineBuildEvent.AreParametersEqual(existingBuildEvent.Parameters, processorParameters)) { return(existingBuildEvent); } } return(null); }
/// <summary> /// Stores the pipeline build event (in memory) if no matching event is found. /// </summary> /// <param name="pipelineEvent">The pipeline build event.</param> private void TrackPipelineBuildEvent(PipelineBuildEvent pipelineEvent) { List <PipelineBuildEvent> pipelineBuildEvents; if (!_pipelineBuildEvents.TryGetValue(pipelineEvent.SourceFile, out pipelineBuildEvents)) { pipelineBuildEvents = new List <PipelineBuildEvent>(); _pipelineBuildEvents.Add(pipelineEvent.SourceFile, pipelineBuildEvents); } if (FindMatchingEvent(pipelineBuildEvents, pipelineEvent.Importer, pipelineEvent.Processor, pipelineEvent.Parameters) == null) { pipelineBuildEvents.Add(pipelineEvent); } }
public override TOutput Convert <TInput, TOutput>( TInput input, string processorName, OpaqueDataDictionary processorParameters) { var processor = _manager.CreateProcessor(processorName, processorParameters); var buildEvent = new PipelineBuildEvent { Parameters = processorParameters }; var processContext = new PipelineProcessorContext(_manager, buildEvent); var processedObject = processor.Process(input, processContext); // Add its dependencies and built assets to ours. _pipelineEvent.Dependencies.AddRangeUnique(processContext._pipelineEvent.Dependencies); _pipelineEvent.BuildAsset.AddRangeUnique(processContext._pipelineEvent.BuildAsset); return((TOutput)processedObject); }
/// <summary> /// Determines whether the specified list contains a matching pipeline build event. /// </summary> /// <param name="pipelineBuildEvents">The list of pipeline build events.</param> /// <param name="destFile">Absolute path to the output file. Can be <see langword="null"/>.</param> /// <param name="importerName">The name of the content importer. Can be <see langword="null"/>.</param> /// <param name="processorName">The name of the content processor. Can be <see langword="null"/>.</param> /// <param name="processorParameters">The processor parameters. Can be <see langword="null"/>.</param> /// <returns> /// The matching pipeline build event, or <see langword="null"/>. /// </returns> private PipelineBuildEvent FindMatchingEvent(List <PipelineBuildEvent> pipelineBuildEvents, string destFile, string importerName, string processorName, OpaqueDataDictionary processorParameters) { foreach (var existingBuildEvent in pipelineBuildEvents) { if ((destFile == null || existingBuildEvent.DestFile.Equals(destFile)) && existingBuildEvent.Importer == importerName && existingBuildEvent.Processor == processorName) { var defaultValues = GetProcessorDefaultValues(processorName); if (PipelineBuildEvent.AreParametersEqual(existingBuildEvent.Parameters, processorParameters, defaultValues)) { return(existingBuildEvent); } } } return(null); }
public void RegisterContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null) { sourceFilepath = PathHelper.Normalize(sourceFilepath); ResolveOutputFilepath(sourceFilepath, ref outputFilepath); ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName); var contentEvent = new PipelineBuildEvent { SourceFile = sourceFilepath, DestFile = outputFilepath, Importer = importerName, Processor = processorName, Parameters = ValidateProcessorParameters(processorName, processorParameters), }; // Register pipeline build event. (Required to correctly resolve external dependencies.) TrackPipelineBuildEvent(contentEvent); }
private void WriteXnb(object content, PipelineBuildEvent pipelineEvent) { // Make sure the output directory exists. var outputFileDir = Path.GetDirectoryName(pipelineEvent.DestFile); Directory.CreateDirectory(outputFileDir); if (_compiler == null) { _compiler = new ContentCompiler(); } // Write the XNB. using (var stream = new FileStream(pipelineEvent.DestFile, FileMode.Create, FileAccess.Write, FileShare.None)) _compiler.Compile(stream, content, Platform, Profile, false, OutputDirectory, outputFileDir); // Store the last write time of the output XNB here // so we can verify it hasn't been tampered with. pipelineEvent.DestTime = File.GetLastWriteTime(pipelineEvent.DestFile); }
public override TOutput BuildAndLoadAsset <TInput, TOutput>(ExternalReference <TInput> sourceAsset, string processorName, OpaqueDataDictionary processorParameters, string importerName) { var sourceFilepath = PathHelper.Normalize(sourceAsset.Filename); _manager.ResolveImporterAndProcessor(sourceFilepath, ref importerName, ref processorName); var buildEvent = new PipelineBuildEvent { SourceFile = sourceFilepath, Importer = importerName, Processor = processorName, Parameters = _manager.ValidateProcessorParameters(processorName, processorParameters), }; var processedObject = _manager.ProcessContent(buildEvent); return((TOutput)processedObject); }
public bool NeedsRebuild(PipelineBuildEvent cachedEvent) { // If we have no previously cached build event then we cannot // be sure that the state hasn't changed... force a rebuild. if (cachedEvent == null) return true; // Verify that the last write time of the dest file matches // what we recorded when it was built. If it is different // that means someone modified it and we need to rebuild. var destWriteTime = File.GetLastWriteTime(DestFile); if (cachedEvent.DestTime != destWriteTime) return true; // If the source and dest files changed... this is always a rebuild. if (File.GetLastWriteTime(SourceFile) >= destWriteTime) return true; // Are any of the dependancy files newer than the dest file? foreach (var depFile in cachedEvent.Dependancies) { if (File.GetLastWriteTime(depFile) >= destWriteTime) return true; } // This shouldn't happen... but if the source or dest files changed // then force a rebuild. if (cachedEvent.SourceFile != SourceFile || cachedEvent.DestFile != DestFile) return true; // Did the importer change? // TODO: I need to test the assembly versions here! if (cachedEvent.Importer != Importer) return true; // Did the processor change? // TODO: I need to test the assembly versions here! if (cachedEvent.Processor != Processor) return true; // If the count of parameters is different then we have // to assume the results of processing are different. if (cachedEvent.Parameters.Count != Parameters.Count) return true; // Finally did any of the processor parameters change? foreach (var pair in cachedEvent.Parameters) { // If the key value doesn't exist... then rebuild. object value; if (!Parameters.TryGetValue(pair.Key, out value)) return true; // If the values are the same type and do not match... rebuild. if (value.GetType().IsInstanceOfType(pair.Value)) { if (!value.Equals(pair.Value)) return true; } else { var typeConverter = TypeDescriptor.GetConverter(value.GetType()); var converted = typeConverter.ConvertTo(value, pair.Value.GetType()); if (!converted.Equals(pair.Value)) return true; } } return false; }
public void BuildContent(PipelineBuildEvent pipelineEvent, PipelineBuildEvent cachedEvent, string eventFilepath) { if (!File.Exists(pipelineEvent.SourceFile)) { throw new PipelineException("The source file does not exist!"); } Logger.PushFile(pipelineEvent.SourceFile); var rebuild = pipelineEvent.NeedsRebuild(cachedEvent); if (!rebuild) { // While this asset doesn't need to be rebuilt the dependent assets might. foreach (var asset in cachedEvent.BuildAsset) { string assetEventFilepath; var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath); // If we cannot find the cached event for the dependancy // then we have to trigger a rebuild of the parent content. if (assetCachedEvent == null) { rebuild = true; break; } var depEvent = new PipelineBuildEvent { SourceFile = assetCachedEvent.SourceFile, DestFile = assetCachedEvent.DestFile, Importer = assetCachedEvent.Importer, Processor = assetCachedEvent.Processor, Parameters = assetCachedEvent.Parameters, }; // Give the asset a chance to rebuild. BuildContent(depEvent, assetCachedEvent, assetEventFilepath); } } // Do we need to rebuild? if (rebuild) { Logger.LogMessage("{0}", pipelineEvent.SourceFile); // Make sure we can find the importer and processor. var importer = CreateImporter(pipelineEvent.Importer); if (importer == null) { throw new PipelineException("Failed to create importer '{0}'", pipelineEvent.Importer); } var processor = CreateProcessor(pipelineEvent.Processor, pipelineEvent.Parameters); if (processor == null) { throw new PipelineException("Failed to create processor '{0}'", pipelineEvent.Processor); } // Try importing the content. object importedObject; try { var importContext = new PipelineImporterContext(this); importedObject = importer.Import(pipelineEvent.SourceFile, importContext); } catch (PipelineException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Importer '{0}' had unexpected failure!", pipelineEvent.Importer), inner); } // Make sure the input type is valid. if (!processor.InputType.IsAssignableFrom(importedObject.GetType())) { throw new PipelineException( string.Format("The type '{0}' cannot be processed by {1} as a {2}!", importedObject.GetType().FullName, pipelineEvent.Processor, processor.InputType.FullName)); } // Process the imported object. object processedObject; try { var processContext = new PipelineProcessorContext(this, pipelineEvent); processedObject = processor.Process(importedObject, processContext); } catch (PipelineException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Processor '{0}' had unexpected failure!", pipelineEvent.Processor), inner); } // Write the content to disk. WriteXnb(processedObject, pipelineEvent); // Store the new event into the intermediate folder. pipelineEvent.Save(eventFilepath); } else { Logger.LogMessage("Skipping {0}", pipelineEvent.SourceFile); } Logger.PopFile(); }
public void BuildContent(PipelineBuildEvent pipelineEvent, PipelineBuildEvent cachedEvent, string eventFilepath) { if (!File.Exists(pipelineEvent.SourceFile)) { throw new PipelineException("The source file '{0}' does not exist!", pipelineEvent.SourceFile); } Logger.PushFile(pipelineEvent.SourceFile); var rebuild = pipelineEvent.NeedsRebuild(cachedEvent); if (!rebuild) { // While this asset doesn't need to be rebuilt the dependent assets might. foreach (var asset in cachedEvent.BuildAsset) { string assetEventFilepath; var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath); // If we cannot find the cached event for the dependancy // then we have to trigger a rebuild of the parent content. if (assetCachedEvent == null) { rebuild = true; break; } var depEvent = new PipelineBuildEvent { SourceFile = assetCachedEvent.SourceFile, DestFile = assetCachedEvent.DestFile, Importer = assetCachedEvent.Importer, Processor = assetCachedEvent.Processor, Parameters = assetCachedEvent.Parameters, }; // Give the asset a chance to rebuild. BuildContent(depEvent, assetCachedEvent, assetEventFilepath); } } // Do we need to rebuild? if (rebuild) { Logger.LogMessage("{0}", pipelineEvent.SourceFile); // Import and process the content. var processedObject = ProcessContent(pipelineEvent); // Write the content to disk. WriteXnb(processedObject, pipelineEvent); // Store the new event into the intermediate folder. pipelineEvent.Save(eventFilepath); } else { Logger.LogMessage("Skipping {0}", pipelineEvent.SourceFile); } Logger.PopFile(); }
public bool NeedsRebuild(PipelineBuildEvent cachedEvent) { // If we have no previously cached build event then we cannot // be sure that the state hasn't changed... force a rebuild. if (cachedEvent == null) { return(true); } // Verify that the last write time of the dest file matches // what we recorded when it was built. If it is different // that means someone modified it and we need to rebuild. var destWriteTime = File.GetLastWriteTime(DestFile); if (cachedEvent.DestTime != destWriteTime) { return(true); } // If the source and dest files changed... this is always a rebuild. if (File.GetLastWriteTime(SourceFile) >= destWriteTime) { return(true); } // Are any of the dependancy files newer than the dest file? foreach (var depFile in cachedEvent.Dependancies) { if (File.GetLastWriteTime(depFile) >= destWriteTime) { return(true); } } // This shouldn't happen... but if the source or dest files changed // then force a rebuild. if (cachedEvent.SourceFile != SourceFile || cachedEvent.DestFile != DestFile) { return(true); } // Did the importer change? // TODO: I need to test the assembly versions here! if (cachedEvent.Importer != Importer) { return(true); } // Did the processor change? // TODO: I need to test the assembly versions here! if (cachedEvent.Processor != Processor) { return(true); } // If the count of parameters is different then we have // to assume the results of processing are different. if (cachedEvent.Parameters.Count != Parameters.Count) { return(true); } // Finally did any of the processor parameters change? foreach (var pair in cachedEvent.Parameters) { // If the key value doesn't exist... then rebuild. object value; if (!Parameters.TryGetValue(pair.Key, out value)) { return(true); } // If the values are the same type and do not match... rebuild. if (value.GetType().IsInstanceOfType(pair.Value)) { if (!value.Equals(pair.Value)) { return(true); } } else { var typeConverter = TypeDescriptor.GetConverter(value.GetType()); var converted = typeConverter.ConvertTo(value, pair.Value.GetType()); if (!converted.Equals(pair.Value)) { return(true); } } } return(false); }
public PipelineProcessorContext(PipelineManager manager, PipelineBuildEvent pipelineEvent) { _manager = manager; _pipelineEvent = pipelineEvent; }
public bool NeedsRebuild(PipelineManager manager, PipelineBuildEvent cachedEvent) { // If we have no previously cached build event then we cannot // be sure that the state hasn't changed... force a rebuild. if (cachedEvent == null) return true; // Verify that the last write time of the source file matches // what we recorded when it was built. If it is different // that means someone modified it and we need to rebuild. var sourceWriteTime = File.GetLastWriteTime(SourceFile); if (cachedEvent.SourceTime != sourceWriteTime) return true; // Do the same test for the dest file. var destWriteTime = File.GetLastWriteTime(DestFile); if (cachedEvent.DestTime != destWriteTime) return true; // If the source file is newer than the dest file // then it must have been updated and needs a rebuild. if (sourceWriteTime >= destWriteTime) return true; // Are any of the dependancy files newer than the dest file? foreach (var depFile in cachedEvent.Dependencies) { if (File.GetLastWriteTime(depFile) >= destWriteTime) return true; } // This shouldn't happen... but if the source or dest files changed // then force a rebuild. if (cachedEvent.SourceFile != SourceFile || cachedEvent.DestFile != DestFile) return true; // Did the importer assembly change? if (manager.GetImporterAssemblyTimestamp(cachedEvent.Importer) > cachedEvent.ImporterTime) return true; // Did the importer change? if (cachedEvent.Importer != Importer) return true; // Did the processor assembly change? if (manager.GetProcessorAssemblyTimestamp(cachedEvent.Processor) > cachedEvent.ProcessorTime) return true; // Did the processor change? if (cachedEvent.Processor != Processor) return true; // Did the parameters change? var defaultValues = manager.GetProcessorDefaultValues(Processor); if (!AreParametersEqual(cachedEvent.Parameters, Parameters, defaultValues)) return true; return false; }
private void WriteXnb(object content, PipelineBuildEvent pipelineEvent) { // Make sure the output directory exists. var outputFileDir = Path.GetDirectoryName(pipelineEvent.DestFile); Directory.CreateDirectory(outputFileDir); if (_compiler == null) _compiler = new ContentCompiler(); // Write the XNB. using (var stream = new FileStream(pipelineEvent.DestFile, FileMode.Create, FileAccess.Write, FileShare.None)) _compiler.Compile(stream, content, Platform, Profile, false, OutputDirectory, outputFileDir); // Store the last write time of the output XNB here // so we can verify it hasn't been tampered with. pipelineEvent.DestTime = File.GetLastWriteTime(pipelineEvent.DestFile); }
public void BuildContent(PipelineBuildEvent pipelineEvent, PipelineBuildEvent cachedEvent, string eventFilepath) { if (!File.Exists(pipelineEvent.SourceFile)) throw new PipelineException("The source file does not exist!"); Logger.PushFile(pipelineEvent.SourceFile); var rebuild = pipelineEvent.NeedsRebuild(cachedEvent); if (!rebuild) { // While this asset doesn't need to be rebuilt the dependent assets might. foreach (var asset in cachedEvent.BuildAsset) { string assetEventFilepath; var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath); // If we cannot find the cached event for the dependancy // then we have to trigger a rebuild of the parent content. if (assetCachedEvent == null) { rebuild = true; break; } var depEvent = new PipelineBuildEvent { SourceFile = assetCachedEvent.SourceFile, DestFile = assetCachedEvent.DestFile, Importer = assetCachedEvent.Importer, Processor = assetCachedEvent.Processor, Parameters = assetCachedEvent.Parameters, }; // Give the asset a chance to rebuild. BuildContent(depEvent, assetCachedEvent, assetEventFilepath); } } // Do we need to rebuild? if (rebuild) { Logger.LogMessage("{0}", pipelineEvent.SourceFile); // Make sure we can find the importer and processor. var importer = CreateImporter(pipelineEvent.Importer); if (importer == null) throw new PipelineException("Failed to create importer '{0}'", pipelineEvent.Importer); var processor = CreateProcessor(pipelineEvent.Processor, pipelineEvent.Parameters); if (processor == null) throw new PipelineException("Failed to create processor '{0}'", pipelineEvent.Processor); // Try importing the content. object importedObject; try { var importContext = new PipelineImporterContext(this); importedObject = importer.Import(pipelineEvent.SourceFile, importContext); } catch (PipelineException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Importer '{0}' had unexpected failure!", pipelineEvent.Importer), inner); } // Make sure the input type is valid. if (!processor.InputType.IsAssignableFrom(importedObject.GetType())) { throw new PipelineException( string.Format("The type '{0}' cannot be processed by {1} as a {2}!", importedObject.GetType().FullName, pipelineEvent.Processor, processor.InputType.FullName)); } // Process the imported object. object processedObject; try { var processContext = new PipelineProcessorContext(this, pipelineEvent); processedObject = processor.Process(importedObject, processContext); } catch (PipelineException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Processor '{0}' had unexpected failure!", pipelineEvent.Processor), inner); } // Write the content to disk. WriteXnb(processedObject, pipelineEvent); // Store the new event into the intermediate folder. pipelineEvent.Save(eventFilepath); } else { Logger.LogMessage("Skipping {0}", pipelineEvent.SourceFile); } Logger.PopFile(); }
public PipelineBuildEvent BuildContent(string sourceFilepath, string outputFilepath = null, string importerName = null, string processorName = null, OpaqueDataDictionary processorParameters = null) { sourceFilepath = PathHelper.Normalize(sourceFilepath); ResolveOutputFilepath(sourceFilepath, ref outputFilepath); // Resolve the importer name. if (string.IsNullOrEmpty(importerName)) importerName = FindImporterByExtension(Path.GetExtension(sourceFilepath)); // Resolve the processor name. if (string.IsNullOrEmpty(processorName)) processorName = FindDefaultProcessor(importerName); // Record what we're building and how. var contentEvent = new PipelineBuildEvent { SourceFile = PathHelper.Normalize(sourceFilepath), DestFile = outputFilepath, Importer = importerName, Processor = processorName, Parameters = ValidateProcessorParameters(processorName, processorParameters), }; // Load the previous content event if it exists. string eventFilepath; var cachedEvent = LoadBuildEvent(contentEvent.DestFile, out eventFilepath); BuildContent(contentEvent, cachedEvent, eventFilepath); return contentEvent; }
public bool NeedsRebuild(PipelineManager manager, PipelineBuildEvent cachedEvent) { // If we have no previously cached build event then we cannot // be sure that the state hasn't changed... force a rebuild. if (cachedEvent == null) { return(true); } // Verify that the last write time of the source file matches // what we recorded when it was built. If it is different // that means someone modified it and we need to rebuild. var sourceWriteTime = File.GetLastWriteTime(SourceFile); if (cachedEvent.SourceTime != sourceWriteTime) { return(true); } // Do the same test for the dest file. var destWriteTime = File.GetLastWriteTime(DestFile); if (cachedEvent.DestTime != destWriteTime) { return(true); } // If the source file is newer than the dest file // then it must have been updated and needs a rebuild. if (sourceWriteTime >= destWriteTime) { return(true); } // Are any of the dependancy files newer than the dest file? foreach (var depFile in cachedEvent.Dependencies) { if (File.GetLastWriteTime(depFile) >= destWriteTime) { return(true); } } // This shouldn't happen... but if the source or dest files changed // then force a rebuild. if (cachedEvent.SourceFile != SourceFile || cachedEvent.DestFile != DestFile) { return(true); } // Did the importer assembly change? if (manager.GetImporterAssemblyTimestamp(cachedEvent.Importer) > cachedEvent.ImporterTime) { return(true); } // Did the importer change? if (cachedEvent.Importer != Importer) { return(true); } // Did the processor assembly change? if (manager.GetProcessorAssemblyTimestamp(cachedEvent.Processor) > cachedEvent.ProcessorTime) { return(true); } // Did the processor change? if (cachedEvent.Processor != Processor) { return(true); } // Did the parameters change? var defaultValues = manager.GetProcessorDefaultValues(Processor); if (!AreParametersEqual(cachedEvent.Parameters, Parameters, defaultValues)) { return(true); } return(false); }
public object ProcessContent(PipelineBuildEvent pipelineEvent) { if (!File.Exists(pipelineEvent.SourceFile)) { throw new PipelineException("The source file '{0}' does not exist!", pipelineEvent.SourceFile); } // Store the last write time of the source file // so we can detect if it has been changed. pipelineEvent.SourceTime = File.GetLastWriteTime(pipelineEvent.SourceFile); // Make sure we can find the importer and processor. var importer = CreateImporter(pipelineEvent.Importer); if (importer == null) { throw new PipelineException("Failed to create importer '{0}'", pipelineEvent.Importer); } // Try importing the content. object importedObject; if (RethrowExceptions) { try { var importContext = new PipelineImporterContext(this); importedObject = importer.Import(pipelineEvent.SourceFile, importContext); } catch (PipelineException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Importer '{0}' had unexpected failure!", pipelineEvent.Importer), inner); } } else { var importContext = new PipelineImporterContext(this); importedObject = importer.Import(pipelineEvent.SourceFile, importContext); } // The pipelineEvent.Processor can be null or empty. In this case the // asset should be imported but not processed. if (string.IsNullOrEmpty(pipelineEvent.Processor)) { return(importedObject); } var processor = CreateProcessor(pipelineEvent.Processor, pipelineEvent.Parameters); if (processor == null) { throw new PipelineException("Failed to create processor '{0}'", pipelineEvent.Processor); } // Make sure the input type is valid. if (!processor.InputType.IsAssignableFrom(importedObject.GetType())) { throw new PipelineException( string.Format("The type '{0}' cannot be processed by {1} as a {2}!", importedObject.GetType().FullName, pipelineEvent.Processor, processor.InputType.FullName)); } // Process the imported object. object processedObject; if (RethrowExceptions) { try { var processContext = new PipelineProcessorContext(this, pipelineEvent); processedObject = processor.Process(importedObject, processContext); } catch (PipelineException) { throw; } catch (InvalidContentException) { throw; } catch (Exception inner) { throw new PipelineException(string.Format("Processor '{0}' had unexpected failure!", pipelineEvent.Processor), inner); } } else { var processContext = new PipelineProcessorContext(this, pipelineEvent); processedObject = processor.Process(importedObject, processContext); } return(processedObject); }
private void BuildContent(PipelineBuildEvent pipelineEvent, PipelineBuildEvent cachedEvent, string eventFilepath) { if (!File.Exists(pipelineEvent.SourceFile)) { Logger.LogMessage("{0}", pipelineEvent.SourceFile); throw new PipelineException("The source file '{0}' does not exist!", pipelineEvent.SourceFile); } Logger.PushFile(pipelineEvent.SourceFile); // Keep track of all build events. (Required to resolve automatic names "AssetName_n".) TrackPipelineBuildEvent(pipelineEvent); var rebuild = pipelineEvent.NeedsRebuild(this, cachedEvent); if (rebuild) { Logger.LogMessage("{0}", pipelineEvent.SourceFile); } else { Logger.LogMessage("Skipping {0}", pipelineEvent.SourceFile); } Logger.Indent(); try { if (!rebuild) { // While this asset doesn't need to be rebuilt the dependent assets might. foreach (var asset in cachedEvent.BuildAsset) { string assetEventFilepath; var assetCachedEvent = LoadBuildEvent(asset, out assetEventFilepath); // If we cannot find the cached event for the dependancy // then we have to trigger a rebuild of the parent content. if (assetCachedEvent == null) { rebuild = true; break; } var depEvent = new PipelineBuildEvent { SourceFile = assetCachedEvent.SourceFile, DestFile = assetCachedEvent.DestFile, Importer = assetCachedEvent.Importer, Processor = assetCachedEvent.Processor, Parameters = assetCachedEvent.Parameters, }; // Give the asset a chance to rebuild. BuildContent(depEvent, assetCachedEvent, assetEventFilepath); } } // Do we need to rebuild? if (rebuild) { // Import and process the content. var processedObject = ProcessContent(pipelineEvent); // Write the content to disk. WriteXnb(processedObject, pipelineEvent); // Store the timestamp of the DLLs containing the importer and processor. pipelineEvent.ImporterTime = GetImporterAssemblyTimestamp(pipelineEvent.Importer); pipelineEvent.ProcessorTime = GetProcessorAssemblyTimestamp(pipelineEvent.Processor); // Store the new event into the intermediate folder. pipelineEvent.Save(eventFilepath); } } finally { Logger.Unindent(); Logger.PopFile(); } }