packages feed

nova-cache 0.11.1.0 → 0.11.1.1

raw patch · 5 files changed

+50/−5 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Changelog +## 0.11.1.1 - 2026-08-26++- **A symlink target with a separator serialises to its POSIX spelling on every platform.** Windows stores a symlink's reparse point with backslashes, so a target written `bin/tool` reads back `bin\tool`, and `getSymbolicLinkTarget` returned that verbatim into the NAR. NAR targets are host-independent byte strings in the POSIX spelling, so the archive of the same logical tree diverged between Windows and POSIX, and an unpack-then-recheck round-trip failed its on-disk hash comparison on Windows for any symlink whose target had more than one component. Both producers now normalise the separator to `/` when reading a target on Windows, where a backslash is only ever a separator and encodes as the single byte `0x5C` that no multi-byte UTF-8 sequence contains, so the byte-level replacement is exact. POSIX is untouched, where a backslash is a legitimate filename byte.+ ## 0.11.1.0 - 2026-08-26  - **The default executable answer on POSIX is the file's own owner-execute bit, matching upstream's dump.** `defaultExecBitResolver` (and so both producers before any custom resolver) read `getPermissions`, which answers from `access(2)`: what the calling process may do. Root read any execute bit as executable, ACLs counted, and a file the caller does not own answered by the caller's groups; upstream reads `st_mode & S_IXUSR`, a property of the file alone, and the flag lands in NAR bytes, so the divergence moved a hash exactly where the caller was unusual. The POSIX default now reads the mode bit directly; Windows keeps the extension answer, which is all the platform has.
README.md view
@@ -118,7 +118,7 @@ cabal test ``` -Optional extras: `--flag server` builds the cache server, and the public `nova-cache:xz`, `nova-cache:bzip2`, and `nova-cache:zstandard` sublibraries carry the bounded codecs (liblzma, libbz2, and libzstd are bundled - no system libraries needed) - consumers depend on them with `build-depends: nova-cache:xz` and the like. Requires GHC 9.14+ and cabal-install 3.10+.+Optional extras: `--flag server` builds the cache server, and the public `nova-cache:xz`, `nova-cache:bzip2`, and `nova-cache:zstandard` sublibraries carry the bounded codecs - consumers depend on them with `build-depends: nova-cache:xz` and the like. libbz2 and libzstd are bundled; liblzma comes from the `xz` package, which prefers a pkg-config system liblzma and falls back to its bundled `xz-clib` (pin `constraints: xz -system-xz` to force the bundled copy, as this repo's cabal.project does). Requires GHC 9.14+ and cabal-install 3.10+.  --- 
nova-cache.cabal view
@@ -4,7 +4,7 @@ -- 3.0 an in-package component name shadowed its external namesake -- (the hazard the zstandard library's name dodges, documented there). name:               nova-cache-version:            0.11.1.0+version:            0.11.1.1 synopsis:           Pure-first Nix binary cache protocol library description:   A pure-first library implementing the Nix binary cache protocol -
src/NovaCache/NAR.hs view
@@ -364,7 +364,7 @@ walkPath opts path = do   isSym <- pathIsSymbolicLink path   if isSym-    then NarSymlink <$> (osPathBytes =<< getSymbolicLinkTarget path)+    then NarSymlink <$> (symlinkTargetBytes =<< getSymbolicLinkTarget path)     else do       isDir <- doesDirectoryExist path       if isDir@@ -494,6 +494,26 @@     fail ("serialiseFromPath: undecodable name: " ++ show err) #endif +-- | A symlink target's NAR bytes.  Identical to 'osPathBytes' for a name,+-- except that on Windows the separator is normalised to @\/@: Windows+-- stores a reparse point with backslashes, so a target written @bin\/tool@+-- reads back @bin\\tool@, and a NAR target is the POSIX spelling on every+-- platform so the archive stays host-independent.  A backslash is only+-- ever a separator on Windows, never a filename byte, and it encodes as+-- the single byte @0x5C@ that no multi-byte UTF-8 sequence contains, so+-- the byte-level replacement is exact.  On POSIX a backslash is a+-- legitimate filename byte and is left untouched.+symlinkTargetBytes :: OsPath -> IO ByteString+#ifdef mingw32_HOST_OS+symlinkTargetBytes path = BS.map normalizeSeparator <$> osPathBytes path+  where+    normalizeSeparator b = if b == backslashByte then forwardSlashByte else b+    backslashByte = 0x5C+    forwardSlashByte = 0x2F+#else+symlinkTargetBytes = osPathBytes+#endif+ -- --------------------------------------------------------------------------- -- Streaming filesystem serialisation (IO boundary) -- ---------------------------------------------------------------------------@@ -633,7 +653,7 @@   isSym <- pathIsSymbolicLink path   if isSym     then do-      target <- osPathBytes =<< getSymbolicLinkTarget path+      target <- symlinkTargetBytes =<< getSymbolicLinkTarget path       pure [PieceBytes (buildNode (NarSymlink target))]     else do       isDir <- doesDirectoryExist path
test/Main.hs view
@@ -31,7 +31,7 @@ import qualified NovaCache.Store as Store import qualified NovaCache.StorePath as StorePath import qualified NovaCache.Validate as Validate-import System.Directory (createDirectory, getPermissions, getTemporaryDirectory, listDirectory, removeDirectoryRecursive, setOwnerExecutable, setPermissions)+import System.Directory (createDirectory, createFileLink, getPermissions, getTemporaryDirectory, listDirectory, removeDirectoryRecursive, setOwnerExecutable, setPermissions) import System.Exit (exitFailure, exitSuccess) import System.IO (hFlush, stdout) import qualified System.Info@@ -573,6 +573,27 @@             expected             (sort (map baseName planned))         pure (walkOk && planOk),+      -- A symlink target with a separator serialises to the POSIX+      -- spelling on every platform (nova-nix #112): Windows stores a+      -- reparse point with backslashes, so a target written bin/tool+      -- reads back bin\tool, and an unpack-then-recheck round-trip+      -- diverges from the archive unless the NAR boundary normalises+      -- it.  Both producers must agree with the forward-slash form.+      -- Guarded on symlink privilege, which a Windows runner without+      -- developer mode lacks.+      test "a separator-bearing symlink target serialises with forward slashes" $ do+        dir <- caseHackFixture "nova-cache-test-symlinksep"+        created <- try (createFileLink "bin/tool" (dir <> "/link")) :: IO (Either SomeException ())+        case created of+          Left _ -> removeDirectoryRecursive dir >> pure True+          Right () -> do+            let expectedEntry = NAR.NarDirectory [("link", NAR.NarSymlink "bin/tool")]+            eager <- NAR.serialiseFromPathWith NAR.CaseHackDisabled dir+            streamed <- NAR.withNarSource NAR.CaseHackDisabled dir drainSource+            removeDirectoryRecursive dir+            eagerOk <- assertEqual "eager target spelling" expectedEntry eager+            streamOk <- assertEqual "streamed target spelling" (NAR.serialise expectedEntry) streamed+            pure (eagerOk && streamOk),       -- The walk's boundary encoding: a Unicode disk name enters the       -- archive as its UTF-8 bytes on every platform.       test "serialiseFromPath encodes a Unicode disk name as UTF-8" $ do