ionide / Fornax

Scriptable static site generator using type safe F# DSL to define page templates.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

generate wrong path when a file within a folder with space

newbienewbie opened this issue · comments

Describe the bug

A post folder path that contains a space character (or non-ascii char) will cause an error of System.Collections.Generic.KeyNotFoundException

To Reproduce
Steps to reproduce the behaviour:

  1. Run fornax new
  2. create a markdown file with path of "posts/subdir/a sub folder with space/post3 with space and 你好.md" :
├─ posts/
│  └─ subdir/
│      └─ a sub folder with space/
|               └─ post3 with space and 你好.md
  1. Run fornax watch. Now we get an error :

An unexpected error happend: System.IO.DirectoryNotFoundException: Could not find a part of the path 'F:\Playground\Fornax\posts\subdir\a%20sub%20folder%20with%20space\post3%20with%20space%20and%20%E4%BD%A0%E5%A5%BD.md'.
at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks)
at System.IO.File.InternalReadAllText(String path, Encoding encoding)
at System.IO.File.ReadAllText(String path)
at FSI_0001.Config.postPredicate(String projectRoot, String page)
at FSI_0001.Config.config@37.Invoke(Tuple2 tupledArg) at Microsoft.FSharp.Collections.ListModule.TryFind[T](FSharpFunc2 predicate, FSharpList`1 list) in F:\workspace_work\1\s\src\fsharp\FSharp.Core\list.fs:line 391
at Generator.pickGenerator(Config cfg, SiteContents siteContent, String projectRoot, String page) in F:\Source Code Study\Fornax\src\Fornax\Generator.fs:line 302
at Generator.generate(FsiEvaluationSession fsi, Config cfg, SiteContents siteContent, String projectRoot, String page) in F:\Source Code Study\Fornax\src\Fornax\Generator.fs:line 333
at Generator.action@1-3(String projectRoot, FsiEvaluationSession fsi, Config config, SiteContents sc, String filePath) in F:\Source Code Study\Fornax\src\Fornax\Generator.fs:line 496
at Generator.generateFolder(String projectRoot, Boolean isWatch) in F:\Source Code Study\Fornax\src\Fornax\Generator.fs:line 495
at Fornax.guardedGenerate@226(String cwd, Unit unitVar0) in F:\Source Code Study\Fornax\src\Fornax\Fornax.fs:line 228

Expected behaviour

The static files will be generated and the HTTP server will run flawlessly.
Screenshots

image

Environment (please complete the following information):

  • OS: win10-x64, 10.0.19042
  • Ionide version: v5.7.3
  • VSCode version: 1.61.0
  • dotnet SDK version: 5.0.102
  • mono / .Net Framework version: -

Additional context

the relative function calculates the relative path by using the MakeRelativeUri method:

    let relative toPath fromPath =
        let toUri = Uri(toPath)
        let fromUri = Uri(fromPath)
        toUri.MakeRelativeUri(fromUri).OriginalString

However, when a directory path contains an space char, the result will not be decoded, and then causes an Exception of :

An unexpected error happend: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. System.Collections.Generic.KeyNotFoundException

Actually, this exception also occurs when having any directory that uses non-ascii encodings. For example, if we have a post with path of posts/subdir/中文 目录-带空格和非URL字符/post 带空格3.md, the relative funtion will return:

posts/subdir/%E4%B8%AD%E6%96%87%20%E7%9B%AE%E5%BD%95-%E5%B8%A6%E7%A9%BA%E6%A0%BC%E5%92%8C%E9%9D%9EURL%E5%AD%97%E7%AC%A6/post%20%E5%B8%A6%E7%A9%BA%E6%A0%BC3.md

And the above path will be passed to the generate function as a file path. However, the encoded url is not the original path.

A quick fix is to use the Path.GetRelativePath as below :

    let relative toPath fromPath =
        Path.GetRelativePath(toPath, fromPath).Replace("\\","/")