Fornax icon indicating copy to clipboard operation
Fornax copied to clipboard

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

Open MangelMaxime opened this issue 1 year ago • 1 comments

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

MangelMaxime avatar Jul 26 '22 20:07 MangelMaxime