예제 #1
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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);
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        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;
        }
예제 #14
0
        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();
        }
예제 #15
0
        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();
        }
예제 #16
0
        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);
        }
예제 #17
0
 public PipelineProcessorContext(PipelineManager manager, PipelineBuildEvent pipelineEvent)
 {
     _manager       = manager;
     _pipelineEvent = pipelineEvent;
 }
예제 #18
0
        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;
        }
예제 #19
0
        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);
        }
예제 #20
0
        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();
        }
예제 #21
0
        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);
        }
예제 #23
0
        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);
        }
예제 #24
0
        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();
            }
        }