Skip to content

Commit

Permalink
Merge pull request #286 from sandydoo/fix-case-hack
Browse files Browse the repository at this point in the history
nar: fix ordering of case-hacked paths on macOS
  • Loading branch information
domenkozar authored Oct 9, 2024
2 parents 247be71 + 67ea0d0 commit 9944d96
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 21 deletions.
5 changes: 1 addition & 4 deletions hnix-store-nar/src/System/Nix/Nar/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ data NarOptions = NarOptions {

defaultNarOptions :: NarOptions
defaultNarOptions = NarOptions {
optUseCaseHack =
if System.Info.os == "darwin"
then True
else False
optUseCaseHack = System.Info.os == "darwin"
}

caseHackSuffix :: Text
Expand Down
2 changes: 1 addition & 1 deletion hnix-store-nar/src/System/Nix/Nar/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ parseDirectory = do
conflictCount <- getFilePathConflictCount key
pure $
if conflictCount > 0 then
fName <> Nar.caseHackSuffix <> (Text.pack $ show conflictCount)
fName <> Nar.caseHackSuffix <> Text.pack (show conflictCount)
else
fName

Expand Down
40 changes: 24 additions & 16 deletions hnix-store-nar/src/System/Nix/Nar/Streamer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module System.Nix.Nar.Streamer

import Data.ByteString (ByteString)
import Data.Int (Int64)
import Data.Text (Text)
import qualified Data.Map.Strict as Map

import Control.Monad ( forM_
, when
Expand All @@ -23,7 +23,7 @@ import qualified Data.ByteString.Lazy as Bytes.Lazy
import qualified Data.Foldable
import qualified Data.List
import qualified Data.Serialize as Serial
import qualified Data.Text as T (pack, breakOn)
import qualified Data.Text as T (pack, unpack)
import qualified Data.Text.Encoding as TE (encodeUtf8)
import System.FilePath ((</>))

Expand Down Expand Up @@ -92,18 +92,24 @@ streamNarIOWithOptions opts effs basePath yield = do
isDir <- IO.liftIO $ Nar.narIsDir effs path
if isDir then do
fs <- IO.liftIO (Nar.narListDir effs path)
let entries =
foldr (\f acc ->
let
name =
if Nar.optUseCaseHack opts
then undoCaseHack f
else f
in
case Map.insertLookupWithKey (\_ n _ -> n) name f acc of
(Nothing, newMap) -> newMap
(Just conflict, _) -> error $ "File name collision between " ++ (path </> name) ++ " and " ++ (path </> conflict)
) Map.empty fs
yield $ strs ["type", "directory"]
forM_ (Data.List.sort fs) $ \f -> do
forM_ (Map.toAscList entries) $ \(unhacked, original) -> do
yield $ str "entry"
parens $ do
let fullName = path </> f
let serializedPath =
if Nar.optUseCaseHack opts then
filePathToBSWithCaseHack f
else
filePathToBS f
yield $ strs ["name", serializedPath, "node"]
parens $ go fullName
yield $ strs ["name", filePathToBS unhacked, "node"]
parens $ go (path </> original)
else do
isExec <- IO.liftIO $ Nar.narIsExec effs path
yield $ strs ["type", "regular"]
Expand Down Expand Up @@ -148,8 +154,10 @@ strs xs = Bytes.concat $ str <$> xs
filePathToBS :: FilePath -> ByteString
filePathToBS = TE.encodeUtf8 . T.pack

filePathToBSWithCaseHack :: FilePath -> ByteString
filePathToBSWithCaseHack = TE.encodeUtf8 . undoCaseHack . T.pack

undoCaseHack :: Text -> Text
undoCaseHack = fst . T.breakOn Nar.caseHackSuffix
undoCaseHack :: FilePath -> FilePath
undoCaseHack f =
case Data.List.findIndex (caseHackSuffix `Data.List.isPrefixOf`) (Data.List.tails f) of
Just index -> take index f
Nothing -> f
where
caseHackSuffix = T.unpack Nar.caseHackSuffix

0 comments on commit 9944d96

Please sign in to comment.