Skip to content

The first time a file content changes the new loaded information are not provided to the generator #115

Open
@MangelMaxime

Description

@MangelMaxime

Describe the bug

To Reproduce
Steps to reproduce the behaviour:

  1. Start dotnet fornax watch
  2. Wait for the first generation
  3. Change the content of one of the file
  4. See that the new generated file still have the old content
  5. Change the content of one of the file
  6. See that the new generated file is now using the correct content
  7. Change the content of one of the file
  8. See that the new generated file is now using the correct content
  9. etc. (From now, the generation will always be correct)

Expected behaviour

The file should always used the last loaded information even on the first change.

Screenshots

First generation (all good)

Loader and generator have the same informations

==== POST LOADER =====
"---
layout: post
title: Some nice post title
author: k_cieslak
published: 2020-02-19
tags: [ 'F#', 'blog']
---
# Introduction

First
"
==== POST GENERATOR =====
"# Introduction

First
"
[22:10:56] '/home/mmangel/Workspaces/GitHub/MangelMaxime/mangelmaxime.github.io/_public/posts/first.html' generated in 58ms
Generation time: 00:00:04.6666586
[22:10:56] Watch mode started. Press any key to exit.
[22:10:56 INF] Smooth! Suave listener started in 32.428ms with binding 127.0.0.1:8080

Second generation (not good) : first time user update a file

Loader is using the new file content while the generator still received the old informations.

[22:11:11] Changes detected: /home/mmangel/Workspaces/GitHub/MangelMaxime/mangelmaxime.github.io/posts/first.md
==== POST LOADER =====
"---
layout: post
title: Some nice post title
author: k_cieslak
published: 2020-02-19
tags: [ 'F#', 'blog']
---
# Introduction

File is updated
"
==== POST GENERATOR =====
"# Introduction

First
"
[22:11:12] '/home/mmangel/Workspaces/GitHub/MangelMaxime/mangelmaxime.github.io/_public/posts/first.html' generated in 0ms
Generation time: 00:00:00.7931652

Third and more generation (all good)

Loader and generator have the same informations

[22:12:07] Changes detected: /home/mmangel/Workspaces/GitHub/MangelMaxime/mangelmaxime.github.io/posts/first.md
==== POST LOADER =====
"---
layout: post
title: Some nice post title
author: k_cieslak
published: 2020-02-19
tags: [ 'F#', 'blog']
---
# Introduction

File is updated 2
"
==== POST GENERATOR =====
"# Introduction

File is updated 2
"
[22:12:08] '/home/mmangel/Workspaces/GitHub/MangelMaxime/mangelmaxime.github.io/_public/posts/first.html' generated in 49ms
Generation time: 00:00:01.0151255

Could it be caused by a cache mechanism?

Postloader.fsx
#r "../_lib/Fornax.Core.dll"
#load "../.paket/load/main.group.fsx"
#load "../utils/Log.fsx"
#load "../utils/Helpers.fsx"

open System
open System.IO
open System.Diagnostics
open System.Threading.Tasks
open Legivel.Serialization
open Helpers

type Post =
    {
        relativeFile: string
        link : string
        title: string
        author: string option
        published: DateTime option
        tags: string list
        content: string
    }

type PostFrontMatter =
    {
        title: string
        author: string option
        published: DateTime option
        tags: string list
    }

let contentDir = "posts"

let private getLastModified (fileName: string) =
    async {
        let psi = ProcessStartInfo()
        psi.FileName <- "git"
        psi.Arguments <- $"--no-pager log -1 --format=%%ai \"%s{fileName}\""
        psi.RedirectStandardError <- true
        psi.RedirectStandardOutput <- true
        psi.CreateNoWindow <- true
        psi.WindowStyle <- ProcessWindowStyle.Hidden
        psi.UseShellExecute <- false

        use p = new Process()
        p.StartInfo <- psi
        p.Start() |> ignore

        let outTask =
            Task.WhenAll(
                [|
                    p.StandardOutput.ReadToEndAsync()
                    p.StandardError.ReadToEndAsync()
                |]
            )

        do! p.WaitForExitAsync() |> Async.AwaitTask
        let! result = outTask |> Async.AwaitTask

        if p.ExitCode = 0 then
            // File is not in the git repo
            if String.IsNullOrEmpty result[0] then
                return DateTime.Now
            else
                return DateTime.Parse(result[0])
        else
            Log.error $"Failed to get last modified information %s{result[1]}"
            return DateTime.Now
    }
    |> Async.RunSynchronously


let private loadFile (rootDir: string) (absolutePath: string) =
    let text = File.ReadAllText absolutePath

    printfn "==== POST LOADER ====="
    printfn "%A" text

    let relativePath =
        Path.relativePath rootDir absolutePath

    let lines = text.Replace("\r\n", "\n").Split("\n")

    let x = getLastModified absolutePath

    let firstLine = Array.tryHead lines

    if firstLine <> Some "---" then
        Log.error $"File '%s{relativePath}' does not have a front matter"
        None

    else
        let lines = lines |> Array.skip 1

        let frontMatterLines =
            lines
            |> Array.takeWhile (fun line -> line <> "---")

        let markdownContent =
            lines
            |> Array.skip (frontMatterLines.Length + 1)
            |> String.concat "\n"

        let frontMatterContent = frontMatterLines |> String.concat "\n"

        let frontMatterResult =
            Deserialize<PostFrontMatter> frontMatterContent
            |> List.head

        match frontMatterResult with
        | Error error ->
            Log.error $"Error parsing front matter in file '%s{relativePath}': %A{error}"
            None

        | Success frontMatter ->
            if not (frontMatter.Warn.IsEmpty) then
                for warning in frontMatter.Warn do
                    Log.warn $"Warning in file '%s{relativePath}': %A{warning}"

            let link =
                Path.ChangeExtension(relativePath, "html")

            {
                relativeFile = relativePath
                link = link
                title = ""
                author = None
                published = frontMatter.Data.published
                tags = frontMatter.Data.tags
                content = markdownContent
            }
            |> Some

let loader (projectRoot: string) (siteContent: SiteContents) =
    let postsPath = Path.Combine(projectRoot, contentDir)
    let options = EnumerationOptions(RecurseSubdirectories = true)
    let files = Directory.GetFiles(postsPath, "*", options)

    files
    |> Array.filter (fun n -> n.EndsWith ".md")
    |> Array.map (loadFile projectRoot)
    // Only keep the valid post to avoid to propagate errors
    |> Array.filter Option.isSome
    |> Array.map Option.get
    |> Array.iter siteContent.Add

    siteContent
Postloader.fsx
#r "../_lib/Fornax.Core.dll"
#load "layout.fsx"

open Giraffe.ViewEngine

let generate (ctx: SiteContents) (_projectRoot: string) (page: string) =

    let postOpt =
        ctx.TryGetValues<PostLoader.Post>()
        |> Option.defaultValue Seq.empty
        |> Seq.tryFind (fun post -> post.relativeFile = page)

    match postOpt with
    | None ->
        let error =
            {
                Path = page
                Message = $"Post %s{page} not found in the context"
                Phase = Generating
            }

        ctx.AddError error

        Layout.generationErrorPage ctx

    | Some post ->

        printfn "==== POST GENERATOR ====="
        printfn "%A" post.content
        div [] [ str post.content ] |> Layout.mainPage ctx

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions