packages feed

nova-cache 0.2.1.0 → 0.2.2.0

raw patch · 5 files changed

+117/−36 lines, 5 files

Files

CHANGELOG.md view
@@ -1,5 +1,14 @@ # Changelog +## 0.2.2.0 — 2026-02-23++- Gate `NovaCache.Compression` and `lzma` dependency behind a `compression`+  cabal flag (default on, backwards compatible)+- Consumers that only need hashing/NAR/narinfo can build with `-compression`+  to avoid the system `liblzma` C dependency+- Compression tests moved to separate test suite (`nova-cache-compression-test`)+- No changes to any library source modules+ ## 0.2.1.0 — 2026-02-22  - Server: `validateNarInfo` wired into PUT handler — rejects malformed uploads
README.md view
@@ -25,7 +25,7 @@ - **NAR** — Binary serialization and deserialization of the Nix ARchive format using `Builder` monoid composition - **NarInfo** — Parse and render the key-value narinfo text format - **Signing** — Ed25519 fingerprint signing and verification for binary cache trust-- **Compression** — xz compress/decompress for NAR transport+- **Compression** — xz compress/decompress for NAR transport (behind `compression` cabal flag, default on) - **Store** — Filesystem storage backend for narinfo and NAR files - **Validate** — Pure protocol validation: field semantics, content hashes, Ed25519 signatures — all errors collected, not short-circuited - **Server** — Optional WAI/Warp HTTP server implementing the cache protocol (behind `server` cabal flag)@@ -279,13 +279,13 @@   └──────────────────────────────────────────┘               IO Boundary (thin)-  ┌──────────────────────────────────────────┐-  │  Compression    Store    Server (flag)   │-  └──────────────────────────────────────────┘+  ┌──────────────────────────────────────────────────────┐+  │  Compression (flag)    Store    Server (flag)       │+  └──────────────────────────────────────────────────────┘ ``` -- **9 modules**, 7 pure + 2 at the IO boundary-- **74 tests**, hand-rolled harness, no framework dependencies+- **9 modules**, 7 pure + 2 at the IO boundary (Compression optional via flag)+- **54 core tests + 3 compression tests**, hand-rolled harness, no framework dependencies - **Zero partial functions** — total by construction - **Strict by default** — bang patterns on all data fields @@ -400,11 +400,18 @@ ## Build & Test  ```bash-cabal build                              # Build library-cabal test                               # Run all tests (74 tests, 9 groups)+cabal build                              # Build library (compression on by default)+cabal build -f-compression               # Build without lzma C dependency+cabal test                               # Run all tests cabal build --ghc-options="-Werror"      # Warnings as errors cabal build --flag server                # Build with WAI server cabal haddock                            # Generate docs+```++Consumers that only need hashing, NAR, or narinfo can disable the `compression` flag to avoid the system `liblzma` dependency:++```cabal+constraints: nova-cache -compression ```  ---
nova-cache.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               nova-cache-version:            0.2.1.0+version:            0.2.2.0 synopsis:           Pure Nix binary cache protocol library description:   A focused, minimal, pure-first library implementing the full Nix binary@@ -27,10 +27,14 @@   default:     False   manual:      True +flag compression+  description: Enable LZMA/XZ compression (requires system liblzma)+  default:     True+  manual:      True+ library   exposed-modules:     NovaCache.Base32-    NovaCache.Compression     NovaCache.Hash     NovaCache.NAR     NovaCache.NarInfo@@ -39,6 +43,10 @@     NovaCache.StorePath     NovaCache.Validate +  if flag(compression)+    exposed-modules: NovaCache.Compression+    build-depends:   lzma >= 0.0.1 && < 0.1+   build-depends:       base                >= 4.16 && < 5     , base64-bytestring   >= 1.2 && < 1.3@@ -47,7 +55,6 @@     , crypton             >= 1.0 && < 2     , directory           >= 1.3 && < 1.4     , filepath            >= 1.4 && < 1.6-    , lzma                >= 0.0.1 && < 0.1     , memory              >= 0.18 && < 1     , text                >= 2.0 && < 2.2     , unix                >= 2.7 && < 2.9@@ -102,6 +109,23 @@     , nova-cache     , memory              >= 0.18 && < 1     , text                >= 2.0 && < 2.2++test-suite nova-cache-compression-test+  if !flag(compression)+    buildable: False++  type:             exitcode-stdio-1.0+  main-is:          CompressionTest.hs+  hs-source-dirs:   test+  default-language: Haskell2010+  default-extensions:+    OverloadedStrings+  ghc-options:      -Wall -Wcompat++  build-depends:+      base                >= 4.16 && < 5+    , bytestring          >= 0.11 && < 0.13+    , nova-cache  source-repository head   type:     git
+ test/CompressionTest.hs view
@@ -0,0 +1,66 @@+module Main (main) where++import qualified Data.ByteString as BS+import qualified NovaCache.Compression as Compression+import System.Exit (exitFailure, exitSuccess)+import System.IO (hFlush, stdout)++-- | Run a named test, short-circuit on first failure.+test :: String -> IO Bool -> IO Bool+test name action = do+  putStr ("  " ++ name ++ "... ")+  hFlush stdout+  result <- action+  if result+    then do+      putStrLn "OK"+      pure True+    else do+      putStrLn "FAILED"+      pure False++-- | Assert equality.+assertEqual :: (Eq a, Show a) => String -> a -> a -> IO Bool+assertEqual label expected actual+  | expected == actual = pure True+  | otherwise = do+      putStrLn ""+      putStrLn ("    " ++ label)+      putStrLn ("    expected: " ++ show expected)+      putStrLn ("    actual:   " ++ show actual)+      pure False++-- | Assert a Bool is True.+assertTrue :: String -> Bool -> IO Bool+assertTrue _ True = pure True+assertTrue label False = do+  putStrLn ""+  putStrLn ("    " ++ label ++ ": expected True")+  pure False++main :: IO ()+main = do+  putStrLn "nova-cache compression tests"+  putStrLn "=============================="+  putStrLn ""+  putStrLn "Compression:"+  ok1 <-+    test "compress/decompress roundtrip" $+      let input = BS.pack [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]+          compressed = Compression.compressXz input+          decompressed = Compression.decompressXz compressed+       in assertEqual "roundtrip" input decompressed+  ok2 <-+    test "compress/decompress roundtrip (empty)" $+      let compressed = Compression.compressXz BS.empty+          decompressed = Compression.decompressXz compressed+       in assertEqual "roundtrip empty" BS.empty decompressed+  ok3 <-+    test "compressed is smaller for repetitive data" $+      let input = BS.replicate 10000 0x42+          compressed = Compression.compressXz input+       in assertTrue "smaller" (BS.length compressed < BS.length input)+  putStrLn ""+  if ok1 && ok2 && ok3+    then putStrLn "All compression tests passed." >> exitSuccess+    else putStrLn "Some compression tests failed." >> exitFailure
test/Main.hs view
@@ -9,7 +9,6 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified NovaCache.Base32 as Base32-import qualified NovaCache.Compression as Compression import qualified NovaCache.Hash as Hash import qualified NovaCache.NAR as NAR import qualified NovaCache.NarInfo as NarInfo@@ -122,7 +121,6 @@       testNAR,       testNarInfo,       testSigning,-      testCompression,       testFileStore,       testValidate     ]@@ -490,29 +488,6 @@       NarInfo.niSigs = [],       NarInfo.niCA = Nothing     }---- ------------------------------------------------------------------------------ Compression tests--- -----------------------------------------------------------------------------testCompression :: IO Bool-testCompression =-  runGroup-    "Compression"-    [ test "compress/decompress roundtrip" $-        let input = BS.pack [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]-            compressed = Compression.compressXz input-            decompressed = Compression.decompressXz compressed-         in assertEqual "roundtrip" input decompressed,-      test "compress/decompress roundtrip (empty)" $-        let compressed = Compression.compressXz BS.empty-            decompressed = Compression.decompressXz compressed-         in assertEqual "roundtrip empty" BS.empty decompressed,-      test "compressed is smaller for repetitive data" $-        let input = BS.replicate 10000 0x42-            compressed = Compression.compressXz input-         in assertTrue "smaller" (BS.length compressed < BS.length input)-    ]  -- --------------------------------------------------------------------------- -- FileStore tests