-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Hello,
I encountered the following surprising (to me) behavior. Consider:
{-# LANGUAGE QuasiQuotes #-}
module Main (main)
import System.OsPath (OsPath, osp, (</>))
import System.Directory.Internal qualified as IDir
main :: IO ()
main = putStrLn . show =<< IDir.prependCurrentDirectory relOsPath
-- "a/rel/path "
relOsPath :: OsPath
relOsPath = [osp|a|] </> [osp|rel|] </> [osp|path |]This prints:
"/<root-path>/a/rel/path " -- unix
"/<root-path>/a/rel/path" -- windows
This is the latest directory-1.3.9.0 and filepath-1.5.4.0.
I discovered this when a property test expected a filename to be preserved after calling makeAbsolute (which calls prependCurrentDirectory). On unix this test passed, but on windows it failed because the generated path had its trailing whitespace stripped.
My question, is this expected? I don't understand windows paths well enough to know what's going on here. The docs mention that some applications will strip whitespace when actually saving files, but it's not clear to me what part of directory's API is doing this. I attempted to investigate this here, though I was not able to pinpoint an exact cause (I do not have a windows machine, so I am relying on github's CI).
The examples are essentially:
Rel: print "a/rel/path "
Rel normalise: print (OsP.normalise "a/rel/path ")
Rel simplify: print (Internal.simplify "a/rel/path ")
/ </> (root </> a/rel/path ): print ("/" </> ("root" </> "a/rel/path "))
/root </> a/rel/path : print (("/" </> "root") </> "a/rel/path ")
Abs: print "/a/rel/path "
Abs normalise: print (OsP.normalise "/a/rel/path ")
Abs simplify: print (Internal.simplify "/a/rel/path ")
Manual prepend: print ((</> "a/rel/path ") <$> Internal.getCurrentDirectoryInternal)
My prepend: print (myPrependCurrentDirectory "a/rel/path ")
Dir prepend: print (Internal.prependCurrentDirectory "a/rel/path ")
Abs: print (Dir.makeAbsolute "a/rel/path ")And the output is (with links to CI output, though they're probably not publicly available):
-- ubuntu: https://github.com/tbidne/dir-abs-whitespace/actions/runs/13776102934/job/38525559164
Rel: "a/rel/path "
Rel normalise: "a/rel/path "
Rel simplify: "a/rel/path "
/ </> (root </> a/rel/path ): "/root/a/rel/path "
/root </> a/rel/path : "/root/a/rel/path "
Abs: "/a/rel/path "
Abs normalise: "/a/rel/path "
Abs simplify: "/a/rel/path "
Manual prepend: "/home/runner/work/dir-abs-whitespace/dir-abs-whitespace/a/rel/path "
My prepend: "/home/runner/work/dir-abs-whitespace/dir-abs-whitespace/a/rel/path "
Dir prepend: "/home/runner/work/dir-abs-whitespace/dir-abs-whitespace/a/rel/path "
Abs: "/home/runner/work/dir-abs-whitespace/dir-abs-whitespace/a/rel/path "
-- windows: https://github.com/tbidne/dir-abs-whitespace/actions/runs/13776102934/job/38525559428
Rel: "a\rel\path "
Rel normalise: "a\rel\path "
Rel simplify: "a\rel\path "
/ </> (root </> a/rel/path ): "\root\a\rel\path "
/root </> a/rel/path : "\root\a\rel\path "
Abs: "\a\rel\path "
Abs normalise: "\a\rel\path "
Abs simplify: "\a\rel\path "
Manual prepend: "D:\a\dir-abs-whitespace\dir-abs-whitespace\a\rel\path "
My prepend: "D:\a\dir-abs-whitespace\dir-abs-whitespace\a\rel\path "
Dir prepend: "D:\a\dir-abs-whitespace\dir-abs-whitespace\a\rel\path"
Abs: "D:\a\dir-abs-whitespace\dir-abs-whitespace\a\rel\path"
Even more bizarre, the "My prepend" example is just directory's Internal.prependCurrentDirectory directly copied, so I'm not sure where the discrepancy is. This code for this is here.
Thanks!