Пример #1
0
        public bool TryPreparePage(ContentObject page)
        {
            if (page.FrontMatter != null && !Scripts.TryRunFrontMatter(page.FrontMatter, page))
            {
                return(false);
            }

            if (page.Script != null && TryEvaluate(page))
            {
                // If page is discarded, skip it
                if (page.Discard)
                {
                    return(false);
                }

                var pendingPageProcessors = new OrderedList <IContentProcessor>();
                return(TryProcessPage(page, BeforeLoadingProcessors.OfType <IContentProcessor>(), pendingPageProcessors, false));
            }

            return(false);
        }
Пример #2
0
        private static async Task <ContentObject> LoadPageScript(SiteObject site, Stream stream, FileEntry file)
        {
            // Read the stream
            var reader  = new StreamReader(stream);
            var content = await reader.ReadToEndAsync();

            // Early dispose the stream
            stream.Dispose();

            ContentObject page = null;

            // Parse the page, using front-matter mode
            var scriptInstance = site.Scripts.ParseScript(content, file.FullName, ScriptMode.FrontMatterAndContent);

            if (!scriptInstance.HasErrors)
            {
                page = new ContentObject(site, file, scriptInstance);

                var evalClock = Stopwatch.StartNew();
                if (site.Content.TryPreparePage(page))
                {
                    evalClock.Stop();

                    // Update statistics
                    var contentStat = site.Statistics.GetContentStat(page);

                    contentStat.EvaluateTime += evalClock.Elapsed;

                    // Update the summary of the page
                    evalClock.Restart();
                    SummaryHelper.UpdateSummary(page);
                    evalClock.Stop();

                    // Update statistics
                    contentStat.SummaryTime += evalClock.Elapsed;
                }
            }

            return(page);
        }
Пример #3
0
        private void RunPage(ContentObject page)
        {
            // Update statistics
            var evalClock   = Stopwatch.StartNew();
            var contentStat = Site.Statistics.GetContentStat(page);

            if (page.Script != null && TryRunPageWithScript(page))
            {
                page.InitializeAfterRun();

                // If page is discarded, skip it
                if (page.Discard)
                {
                    return;
                }
            }

            var pendingPageProcessors = new OrderedList <IContentProcessor>();

            TryProcessPage(page, ContentProcessingStage.Running, AfterRunningProcessors, pendingPageProcessors, false);

            contentStat.RunningTime += evalClock.Elapsed;
        }
Пример #4
0
 public PageContentDependency(ContentObject page)
 {
     Page = page ?? throw new ArgumentNullException(nameof(page));
 }
Пример #5
0
        private bool TryProcessPage(ContentObject page, IEnumerable <IContentProcessor> pageProcessors, OrderedList <IContentProcessor> pendingPageProcessors, bool copyOutput)
        {
            // If page is discarded, skip it
            if (page.Discard)
            {
                return(false);
            }

            // By default working on all processors
            // Order is important!
            pendingPageProcessors.AddRange(pageProcessors);
            bool hasBeenProcessed = true;
            bool breakProcessing  = false;

            // We process the page going through all IContentProcessor from the end of the list
            // (more priority) to the beginning of the list (less priority).
            // An IContentProcessor can transform the page to another type of content
            // that could then be processed by another IContentProcessor
            // But we make sure that a processor cannot process a page more than one time
            // to avoid an infinite loop
            var clock = Stopwatch.StartNew();

            while (hasBeenProcessed && !breakProcessing && !page.Discard)
            {
                hasBeenProcessed = false;
                for (int i = pendingPageProcessors.Count - 1; i >= 0; i--)
                {
                    var processor = pendingPageProcessors[i];

                    // Note that page.ContentType can be changed by a processor
                    // while processing a page
                    clock.Restart();
                    try
                    {
                        var result = processor.TryProcess(page);

                        if (result != ContentResult.None)
                        {
                            // Update statistics per plugin
                            var statistics = Site.Statistics;
                            var stat       = statistics.GetPluginStat(processor);
                            stat.PageCount++;
                            stat.ContentProcessTime += clock.Elapsed;

                            hasBeenProcessed = true;
                            pendingPageProcessors.RemoveAt(i);
                            breakProcessing = result == ContentResult.Break;
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Site.Error(ex, $"Error while processing {page.Path}.");
                        breakProcessing  = true;
                        hasBeenProcessed = true;
                        break;
                    }
                }
            }
            pendingPageProcessors.Clear();

            // Copy only if the file are marked as include
            if (copyOutput && !breakProcessing && !page.Discard)
            {
                Site.Content.TryCopyContentToOutput(page, page.GetDestinationPath());
            }

            return(true);
        }
Пример #6
0
        private async Task <ContentObject> LoadContent(FileEntry file)
        {
            ContentObject page   = null;
            var           buffer = new byte[16];

            var clock  = Stopwatch.StartNew();
            var stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);

            try
            {
                var count = await stream.ReadAsync(buffer, 0, buffer.Length);

                // Rewind to 0
                stream.Position = 0;

                bool hasFrontMatter = false;
                bool isBinary       = false;

                int startFrontMatter = 0;

                // Does it start with UTF8 BOM? If yes, skip it
                // EF BB BF
                if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
                {
                    startFrontMatter = 3;
                }

                // TODO: avoid the chars alloc
                var charBuffer = Encoding.UTF8.GetChars(buffer, startFrontMatter, buffer.Length - startFrontMatter);
                foreach (var frontParser in Scripts.FrontMatterParsers)
                {
                    if (frontParser.CanHandle(charBuffer))
                    {
                        for (int i = startFrontMatter + 3; i < count; i++)
                        {
                            if (buffer[i] == 0)
                            {
                                isBinary = true;
                                break;
                            }
                        }

                        if (!isBinary)
                        {
                            hasFrontMatter = true;
                        }

                        break;
                    }
                }

                if (hasFrontMatter)
                {
                    page = await LoadPageScript(Site, stream, file);

                    stream = null;
                }
                else
                {
                    page = new ContentObject(Site, file);
                }
            }
            finally
            {
                // Dispose stream used
                stream?.Dispose();
            }

            clock.Stop();
            Site.Statistics.GetContentStat(page).LoadingParsingTime += clock.Elapsed;

            return(page);
        }
Пример #7
0
        public bool TryCopyContentToOutput(ContentObject fromFile, UPath outputPath)
        {
            if (fromFile == null)
            {
                throw new ArgumentNullException(nameof(fromFile));
            }
            outputPath.AssertAbsolute();

            var clock = Stopwatch.StartNew();

            var outputFile = new FileEntry(Site.OutputFileSystem, outputPath);
            var outputDir  = outputFile.Directory;

            if (outputDir == null)
            {
                throw new ArgumentException("Output directory cannot be empty", nameof(outputPath));
            }
            TrackDestination(outputFile, fromFile.SourceFile);

            var stat = Site.Statistics.GetContentStat(fromFile);

            CreateDirectory(outputDir);

            try
            {
                // If the file has a content, we will use this instead
                if (fromFile.Content != null)
                {
                    if (Site.CanTrace())
                    {
                        Site.Trace($"Write file [{outputFile}]");
                    }

                    using (var writer = new StreamWriter(outputFile.Open(FileMode.Create, FileAccess.Write)))
                    {
                        writer.Write(fromFile.Content);
                        writer.Flush();

                        // Update statistics
                        stat.Static       = false;
                        stat.OutputBytes += writer.BaseStream.Length;
                    }
                }
                // If the source file is not newer than the destination file, don't overwrite it
                else if (fromFile.SourceFile != null && (!outputFile.Exists || (fromFile.ModifiedTime > outputFile.LastWriteTime)))
                {
                    if (Site.CanTrace())
                    {
                        Site.Trace($"Write file [{outputFile}]");
                    }

                    // If the output file is readonly, make sure that it is not readonly before overwriting
                    if (outputFile.Exists && (outputFile.Attributes & FileAttributes.ReadOnly) != 0)
                    {
                        outputFile.Attributes = outputFile.Attributes & ~FileAttributes.ReadOnly;
                    }

                    fromFile.SourceFile.CopyTo(outputFile, true);

                    // Don't copy readonly attributes for output folder
                    outputFile.Attributes = fromFile.SourceFile.Attributes & ~FileAttributes.ReadOnly;

                    // Update statistics
                    stat.Static       = true;
                    stat.OutputBytes += fromFile.Length;
                }
            }
            catch (Exception ex)
            {
                Site.Error(fromFile.SourceFile != null
                    ? $"Unable to copy file [{fromFile.SourceFile}] to [{outputFile}]. Reason:{ex.GetReason()}"
                    : $"Unable to copy file to [{outputFile}]. Reason:{ex.GetReason()}");
                return(false);
            }
            finally
            {
                stat.OutputTime += clock.Elapsed;
            }

            return(true);
        }
Пример #8
0
 private bool TryRunPageWithScript(ContentObject page)
 {
     page.ScriptObjectLocal ??= new ScriptObject();
     return(Site.Scripts.TryEvaluatePage(page, page.Script, page.SourceFile.Path, page));
 }
Пример #9
0
        private async Task <ContentObject> LoadContent(FileEntry file)
        {
            ContentObject page   = null;
            var           buffer = new byte[16];

            var clock  = Stopwatch.StartNew();
            var stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

            try
            {
                var count = await stream.ReadAsync(buffer, 0, buffer.Length);

                // Rewind to 0
                stream.Position = 0;

                bool hasFrontMatter = false;
                bool isBinary       = false;

                int startFrontMatter = 0;

                // Does it start with UTF8 BOM? If yes, skip it
                // EF BB BF
                if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF)
                {
                    startFrontMatter = 3;
                }

                // TODO: avoid the chars alloc
                var charBuffer = Encoding.UTF8.GetChars(buffer, startFrontMatter, buffer.Length - startFrontMatter);
                foreach (var frontParser in Scripts.FrontMatterParsers)
                {
                    if (frontParser.CanHandle(charBuffer))
                    {
                        for (int i = startFrontMatter + 3; i < count; i++)
                        {
                            if (buffer[i] == 0)
                            {
                                isBinary = true;
                                break;
                            }
                        }

                        if (!isBinary)
                        {
                            hasFrontMatter = true;
                        }

                        break;
                    }
                }

                // Run pre-content (e.g AttributesPlugin)
                ScriptObject preContent = null;
                foreach (var preLoadingContentProcessor in BeforeLoadingContentProcessors)
                {
                    preLoadingContentProcessor(file.Path, ref preContent);
                }

                if (hasFrontMatter)
                {
                    page = await LoadPageScript(Site, stream, file, preContent);

                    stream = null;
                }
                else
                {
                    page = new FileContentObject(Site, file, preContent: preContent);

                    //// Run pre-processing on static content as well
                    //var pendingPageProcessors = new OrderedList<IContentProcessor>();
                    //TryProcessPage(page, ContentProcessingStage.AfterLoading, AfterLoadingProcessors, pendingPageProcessors, false);
                }

                // Initialize the page loaded
                page?.Initialize();
            }
            finally
            {
                // Dispose stream used
                stream?.Dispose();
            }

            clock.Stop();
            Site.Statistics.GetContentStat(page).LoadingParsingTime += clock.Elapsed;

            return(page);
        }