Esempio n. 1
0
        // The function that runs on the thread
        private void _thread_func(bool rebuild)
        {
            Stopwatch      _timer  = new Stopwatch();
            PipelineLogger _logger = new PipelineLogger(Engine);

            Results.Reset();

            // Create the content stream
            var cStream = new ContentStream();

            // Iterate over the tasks
            while (!Manager.ShouldStop && Manager.GetTaskItem(out BuildEvent current))
            {
                // Report start
                Engine.Logger.ItemStart(current);
                _timer.Restart();
                _logger.UseEvent(current);
                Results.UseItem(current);

                // Check the source file exists
                if (current.InputTime == BuildEvent.ERROR_TIME)
                {
                    Engine.Logger.ItemFailed(current, "Could not find the source file for the item");
                    continue;
                }

                // Check for the requested importer and processor
                if (!_importers.ContainsKey(current.ImporterName))
                {
                    if (Engine.StageCache.Importers.ContainsKey(current.ImporterName))
                    {
                        _importers.Add(current.ImporterName, new ImporterInstance(Engine.StageCache.Importers[current.ImporterName]));
                    }
                    else
                    {
                        Engine.Logger.ItemFailed(current, "The item requested an importer type that does not exist");
                        continue;
                    }
                }
                if (!_processors.ContainsKey(current.ProcessorName))
                {
                    if (Engine.StageCache.Processors.ContainsKey(current.ProcessorName))
                    {
                        _processors.Add(current.ProcessorName, new ProcessorInstance(Engine.StageCache.Processors[current.ProcessorName]));
                    }
                    else
                    {
                        Engine.Logger.ItemFailed(current, "The item requested an processor type that does not exist");
                        continue;
                    }
                }
                var importer  = _importers[current.ImporterName];
                var processor = _processors[current.ProcessorName];

                // Validate stage compatibility
                if (!processor.Type.InputType.IsAssignableFrom(importer.Type.OutputType))
                {
                    Engine.Logger.ItemFailed(current, "The item specified incompatible stages");
                    continue;
                }

                // Compare the current and cached build events to see if we can skip the build
                //   If we are forcing a rebuild we have to build so we can skip the check
                bool compress =
                    (processor.Policy == CompressionPolicy.Always) ||
                    (processor.Policy == CompressionPolicy.ReleaseOnly && Engine.IsRelease) ||
                    (processor.Policy == CompressionPolicy.Default && Engine.Compress) ||
                    false;                     // policy is never, compress = false
                if (!rebuild)
                {
                    var cached = BuildEvent.FromCacheFile(Engine, current.Item);
                    if (!current.NeedsBuild(cached, processor, compress))
                    {
                        Engine.Logger.ItemSkipped(current);
                        Results.PassItem(cached.UCSize, true);
                        if (compress)
                        {
                            Results.UpdatePreviousItem(current.RealSize);                             // Update with the real (compressed) size of the data
                        }
                        continue;
                    }
                }

                // Early stop check
                if (Manager.ShouldStop)
                {
                    Engine.Logger.ItemFailed(current, "The build process was stopped while the item was being built");
                    break;
                }

                // Run the importer
                FileStream importStream = null;
                FileInfo   importInfo   = null;
                try
                {
                    importInfo   = new FileInfo(current.Paths.SourcePath);
                    importStream = importInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
                }
                catch (Exception e)
                {
                    Engine.Logger.ItemFailed(current, $"The item source file could not be opened, {e.Message}");
                    continue;
                }
                object importedData = null;
                try
                {
                    _logger.UpdateStageName(current.ImporterName);
                    ImporterContext ctx = new ImporterContext(this, _logger, importInfo);
                    importedData = importer.Instance.Import(importStream, ctx);
                    if (importedData == null)
                    {
                        Engine.Logger.ItemFailed(current, "The importer for the item did not produce any data");
                        continue;
                    }

                    // Save the dependencies to the event
                    if (ctx.Dependencies.Count > 0)
                    {
                        foreach (var ed in ctx.Dependencies)
                        {
                            current.ExternalDependencies.Add((ed, File.GetLastWriteTimeUtc(ed)));
                        }
                    }
                }
                catch (Exception e)
                {
                    int    pos = e.StackTrace.IndexOf(" at ");
                    string loc = e.StackTrace.Substring(pos + 4).Split('\n')[0];
                    Engine.Logger.ItemFailed(current, $"Unhandled exception in importer, {e.Message} ({e.GetType().Name})\n Source: {loc}");
                    if (e.InnerException != null)
                    {
                        Engine.Logger.ItemFailed(current, $"Inner Exception ({e.InnerException.GetType().Name}): {e.InnerException.Message}");
                    }
                    continue;
                }
                finally
                {
                    importStream.Dispose();
                }

                // Early stop check
                if (Manager.ShouldStop)
                {
                    Engine.Logger.ItemFailed(current, "The build process was stopped while the item was being built");
                    break;
                }

                // Run the processor
                Engine.Logger.ItemContinue(current, BuildLogger.ContinueStage.Processing);
                object processedData = null;
                try
                {
                    _logger.UpdateStageName(current.ProcessorName);
                    ProcessorContext ctx = new ProcessorContext(this, _logger, importInfo);
                    processor.UpdateFields(Engine, current);
                    processedData = processor.Instance.Process(importedData, ctx);
                    if (processedData == null)
                    {
                        Engine.Logger.ItemFailed(current, "The processor for the item did not produce any data");
                        continue;
                    }
                }
                catch (Exception e)
                {
                    int    pos = e.StackTrace.IndexOf(" at ");
                    string loc = e.StackTrace.Substring(pos + 4).Split('\n')[0];
                    Engine.Logger.ItemFailed(current, $"Unhandled exception in processor, {e.Message} ({e.GetType().Name})\n Source: {loc}");
                    if (e.InnerException != null)
                    {
                        Engine.Logger.ItemFailed(current, $"Inner Exception ({e.InnerException.GetType().Name}): {e.InnerException.Message}");
                    }
                    continue;
                }

                // Early stop check
                if (Manager.ShouldStop)
                {
                    Engine.Logger.ItemFailed(current, "The build process was stopped while the item was being built");
                    break;
                }

                // Delete the output and cache files
                try
                {
                    if (File.Exists(current.Paths.OutputPath))
                    {
                        File.Delete(current.Paths.OutputPath);
                    }
                    if (File.Exists(current.CachePath))
                    {
                        File.Delete(current.CachePath);
                    }
                }
                catch
                {
                    Engine.Logger.ItemFailed(current, "Could not delete the output file to rebuild the item");
                    continue;
                }

                // Run the writer
                Engine.Logger.ItemContinue(current, BuildLogger.ContinueStage.Writing);
                try
                {
                    _logger.UpdateStageName(processor.Type.WriterType.Name);
                    uint lastRealSize = cStream.Reset(current.Paths.OutputPath, compress);
                    if (lastRealSize != 0)
                    {
                        Results.UpdatePreviousItem(lastRealSize);
                    }
                    WriterContext ctx = new WriterContext(this, _logger, importInfo);
                    processor.WriterInstance.Write(processedData, cStream, ctx);
                    cStream.Flush();
                }
                catch (Exception e)
                {
                    int    pos = e.StackTrace.IndexOf(" at ");
                    string loc = e.StackTrace.Substring(pos + 4).Split('\n')[0];
                    Engine.Logger.ItemFailed(current, $"Unhandled exception in writer, {e.Message} ({e.GetType().Name})\n Source: {loc}");
                    if (e.InnerException != null)
                    {
                        Engine.Logger.ItemFailed(current, $"Inner Exception ({e.InnerException.GetType().Name}): {e.InnerException.Message}");
                    }
                    continue;
                }

                // Save the cache
                current.SaveCache(Engine, cStream.OutputSize, compress);

                // Report end
                Engine.Logger.ItemFinished(current, _timer.Elapsed);
                Results.PassItem(cStream.OutputSize, false);
            }

            // Wait for the final output to be complete
            uint realsize = cStream.Reset(null, false);

            if (realsize != 0)
            {
                Results.UpdatePreviousItem(realsize);
            }
            Results.UseItem(null);             // In the case that the last item fails
        }