hnix-store-json 0.1.0.0 → 0.2.0.0
raw patch · 48 files changed
+1445/−187 lines, 48 filesdep +bytestringdep +cryptondep +dependent-sumdep −data-default-classdep −deriving-aesonPVP ok
version bump matches the API change (PVP)
Dependencies added: bytestring, crypton, dependent-sum, monoidal-containers, some, these, time, unordered-containers, vector
Dependencies removed: data-default-class, deriving-aeson
API changes (from Hackage documentation)
- System.Nix.JSON: data LowerLeading
- System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON (System.Nix.Realisation.DerivationOutput System.Nix.OutputName.OutputName)
- System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSONKey (System.Nix.Realisation.DerivationOutput System.Nix.OutputName.OutputName)
- System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON (System.Nix.Realisation.DerivationOutput System.Nix.OutputName.OutputName)
- System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSONKey (System.Nix.Realisation.DerivationOutput System.Nix.OutputName.OutputName)
- System.Nix.JSON: instance Deriving.Aeson.StringModifier System.Nix.JSON.LowerLeading
+ System.Nix.JSON: HashJSON :: DSum HashAlgo Digest -> HashJSON
+ System.Nix.JSON: [unHashJSON] :: HashJSON -> DSum HashAlgo Digest
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON (System.Nix.StorePath.Metadata.Metadata System.Nix.StorePath.StorePath)
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Build.BuildFailureStatus
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Build.BuildResult
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Build.BuildSuccessStatus
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.ContentAddress.ContentAddress
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.ChildNode
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.ContentAddressedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.Derivation
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.DerivedPathMap
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.FixedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Derivation.InputAddressedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.DerivedPath.DerivedPath
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.DerivedPath.OutputsSpec
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.DerivedPath.SingleDerivedPath
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.JSON.HashJSON
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.OutputName.OutputName
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Realisation.BuildTraceKey
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSON System.Nix.Signature.NamedSignature
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSONKey System.Nix.OutputName.OutputName
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSONKey System.Nix.StorePath.StorePath
+ System.Nix.JSON: instance Data.Aeson.Types.FromJSON.FromJSONKey System.Nix.StorePath.StorePathName
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON (System.Nix.StorePath.Metadata.Metadata System.Nix.StorePath.StorePath)
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Build.BuildFailureStatus
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Build.BuildResult
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Build.BuildSuccessStatus
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.ContentAddress.ContentAddress
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.ChildNode
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.ContentAddressedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.Derivation
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.DerivedPathMap
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.FixedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Derivation.InputAddressedDerivationOutput
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.DerivedPath.DerivedPath
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.DerivedPath.OutputsSpec
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.DerivedPath.SingleDerivedPath
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.JSON.HashJSON
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.OutputName.OutputName
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Realisation.BuildTraceKey
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSON System.Nix.Signature.NamedSignature
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSONKey System.Nix.OutputName.OutputName
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSONKey System.Nix.StorePath.StorePath
+ System.Nix.JSON: instance Data.Aeson.Types.ToJSON.ToJSONKey System.Nix.StorePath.StorePathName
+ System.Nix.JSON: instance GHC.Classes.Eq System.Nix.JSON.HashJSON
+ System.Nix.JSON: instance GHC.Show.Show System.Nix.JSON.HashJSON
+ System.Nix.JSON: newtype HashJSON
Files
- CHANGELOG.md +25/−0
- hnix-store-json.cabal +67/−3
- src/System/Nix/JSON.hs +463/−103
- tests/BuildResultSpec.hs +43/−0
- tests/ContentAddressSpec.hs +24/−0
- tests/DerivationSpec.hs +151/−0
- tests/DerivedPathSpec.hs +55/−0
- tests/HashSpec.hs +26/−0
- tests/JSONSpec.hs +23/−81
- tests/OutputsSpecSpec.hs +36/−0
- tests/PathInfoSpec.hs +95/−0
- tests/RealisationSpec.hs +79/−0
- tests/SingleDerivedPathSpec.hs +39/−0
- tests/StorePathSpec.hs +19/−0
- tests/UpstreamData.hs +16/−0
- upstream-libstore-data/build-result/not-deterministic.json +9/−0
- upstream-libstore-data/build-result/output-rejected.json +9/−0
- upstream-libstore-data/build-result/success.json +19/−0
- upstream-libstore-data/content-address/nar.json +4/−0
- upstream-libstore-data/content-address/text.json +4/−0
- upstream-libstore-data/derivation/dyn-dep-derivation.json +41/−0
- upstream-libstore-data/derivation/output-caFixedFlat.json +4/−0
- upstream-libstore-data/derivation/output-caFixedNAR.json +4/−0
- upstream-libstore-data/derivation/output-caFixedText.json +4/−0
- upstream-libstore-data/derivation/output-caFloating.json +4/−0
- upstream-libstore-data/derivation/output-inputAddressed.json +3/−0
- upstream-libstore-data/derivation/simple-derivation.json +28/−0
- upstream-libstore-data/derived-path/multi_built_built.json +10/−0
- upstream-libstore-data/derived-path/multi_built_built_wildcard.json +9/−0
- upstream-libstore-data/derived-path/multi_opaque.json +1/−0
- upstream-libstore-data/derived-path/mutli_built.json +7/−0
- upstream-libstore-data/derived-path/single_built.json +4/−0
- upstream-libstore-data/derived-path/single_built_built.json +7/−0
- upstream-libstore-data/derived-path/single_opaque.json +1/−0
- upstream-libstore-data/outputs-spec/all.json +3/−0
- upstream-libstore-data/outputs-spec/name.json +3/−0
- upstream-libstore-data/outputs-spec/names.json +4/−0
- upstream-libstore-data/path-info/json-3/empty_impure.json +12/−0
- upstream-libstore-data/path-info/json-3/empty_pure.json +8/−0
- upstream-libstore-data/path-info/json-3/impure.json +27/−0
- upstream-libstore-data/path-info/json-3/pure.json +14/−0
- upstream-libstore-data/realisation/simple.json +10/−0
- upstream-libstore-data/realisation/unkeyed-simple.json +4/−0
- upstream-libstore-data/realisation/unkeyed-with-signature.json +9/−0
- upstream-libstore-data/realisation/with-signature.json +15/−0
- upstream-libstore-data/store-path/simple.json +1/−0
- upstream-libutil-data/hash/sha256.json +1/−0
- upstream-libutil-data/hash/sha512.json +1/−0
CHANGELOG.md view
@@ -1,3 +1,28 @@+# [0.2.0.0](https://github.com/haskell-nix/hnix-store/compare/json-0.1.0.0...json-0.2.0.0) 2026-10-21++The test suite is now much more comprenesive, uses test data from upstream Nix to make sure the JSON formats match.++* JSON instance for `StorePath` now doesn't include the store dir, matching upstream.+ (This keeps it canonical.)++* Removed `deriving-aeson` and `constraints-extras` dependencies; all JSON instances are now hand-written.++* New JSON instances for:+ * `Hash`+ * `ContentAddress`+ * `OutputsSpec`+ * `SingleDerivedPath`+ * `DerivedPath`+ * `Derivation`+ * `Signature`+ * `NamedSignature`+ * `BuildTraceKey`+ * `Realisation`+ * `RealisationWithId`+ * `BuildSuccessStatus`, `BuildFailureStatus`+ * `BuildResult`+ * `Metadata StorePath` (path-info version 3 format)+ # 0.1.0.0 2024-07-31 * Initial release
hnix-store-json.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: hnix-store-json-version: 0.1.0.0+version: 0.2.0.0 synopsis: JSON serialization for core types description: Aeson instances for core types, required for remote store protocol@@ -16,6 +16,40 @@ CHANGELOG.md extra-source-files: README.md+data-files:+ upstream-libstore-data/content-address/nar.json+ upstream-libstore-data/content-address/text.json+ upstream-libstore-data/derived-path/multi_built_built.json+ upstream-libstore-data/derived-path/multi_built_built_wildcard.json+ upstream-libstore-data/derived-path/multi_opaque.json+ upstream-libstore-data/derived-path/mutli_built.json+ upstream-libstore-data/derived-path/single_built_built.json+ upstream-libstore-data/derived-path/single_built.json+ upstream-libstore-data/derived-path/single_opaque.json+ upstream-libstore-data/derivation/dyn-dep-derivation.json+ upstream-libstore-data/derivation/output-caFixedFlat.json+ upstream-libstore-data/derivation/output-caFixedNAR.json+ upstream-libstore-data/derivation/output-caFixedText.json+ upstream-libstore-data/derivation/output-caFloating.json+ upstream-libstore-data/derivation/output-inputAddressed.json+ upstream-libstore-data/derivation/simple-derivation.json+ upstream-libstore-data/outputs-spec/all.json+ upstream-libstore-data/outputs-spec/name.json+ upstream-libstore-data/outputs-spec/names.json+ upstream-libstore-data/realisation/simple.json+ upstream-libstore-data/realisation/unkeyed-simple.json+ upstream-libstore-data/realisation/unkeyed-with-signature.json+ upstream-libstore-data/realisation/with-signature.json+ upstream-libstore-data/build-result/not-deterministic.json+ upstream-libstore-data/build-result/output-rejected.json+ upstream-libstore-data/build-result/success.json+ upstream-libstore-data/store-path/simple.json+ upstream-libstore-data/path-info/json-3/empty_impure.json+ upstream-libstore-data/path-info/json-3/empty_pure.json+ upstream-libstore-data/path-info/json-3/impure.json+ upstream-libstore-data/path-info/json-3/pure.json+ upstream-libutil-data/hash/sha256.json+ upstream-libutil-data/hash/sha512.json common commons ghc-options: -Wall@@ -25,6 +59,7 @@ , DeriveGeneric , DerivingVia , FlexibleInstances+ , ImportQualifiedPost , LambdaCase , RecordWildCards , StandaloneDeriving@@ -38,10 +73,16 @@ build-depends: base >=4.12 && <5 , hnix-store-core >= 0.8+ , aeson >= 2.0 && < 3.0 , attoparsec- , deriving-aeson >= 0.2+ , containers+ , crypton+ , dependent-sum+ , monoidal-containers , text+ , these+ , time hs-source-dirs: src test-suite json@@ -49,7 +90,21 @@ type: exitcode-stdio-1.0 main-is: Spec.hs other-modules:+ BuildResultSpec+ ContentAddressSpec+ DerivationSpec+ DerivedPathSpec+ HashSpec JSONSpec+ OutputsSpecSpec+ PathInfoSpec+ RealisationSpec+ SingleDerivedPathSpec+ StorePathSpec+ UpstreamData+ Paths_hnix_store_json+ autogen-modules:+ Paths_hnix_store_json hs-source-dirs: tests build-tool-depends:@@ -59,7 +114,16 @@ , hnix-store-core , hnix-store-json , hnix-store-tests+ , aeson+ , bytestring , containers- , data-default-class+ , crypton+ , dependent-sum , hspec+ , monoidal-containers+ , some+ , these+ , time+ , unordered-containers+ , vector
src/System/Nix/JSON.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MonoLocalBinds #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-| Description : JSON serialization@@ -7,28 +9,45 @@ providing (From|To)JSON for Realisation type which is required for `-remote`. -}-module System.Nix.JSON where+module System.Nix.JSON+ ( HashJSON(..)+ ) where +import Control.Applicative ((<|>))+import Crypto.Hash (Digest) import Data.Aeson-import Deriving.Aeson-import System.Nix.Base (BaseEncoding(NixBase32))-import System.Nix.OutputName (OutputName)-import System.Nix.Realisation (DerivationOutput, Realisation, RealisationWithId(..))-import System.Nix.Signature (Signature)-import System.Nix.StorePath (StoreDir(..), StorePath, StorePathName, StorePathHashPart)--import qualified Data.Aeson.KeyMap-import qualified Data.Aeson.Types-import qualified Data.Attoparsec.Text-import qualified Data.Char-import qualified Data.Text-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Builder-import qualified System.Nix.Base-import qualified System.Nix.OutputName-import qualified System.Nix.Realisation-import qualified System.Nix.Signature-import qualified System.Nix.StorePath+import Data.Aeson.Key qualified+import Data.Aeson.KeyMap qualified+import Data.Aeson.Types (Parser)+import Data.Aeson.Types qualified+import Data.Attoparsec.Text qualified+import Data.Dependent.Sum+import Data.Foldable (toList)+import Data.Map.Monoidal qualified+import Data.Map.Strict qualified+import Data.Maybe (fromMaybe, maybeToList)+import Data.Set qualified+import Data.Some+import Data.Text (Text)+import Data.Text qualified+import Data.These+import Data.These.Combinators+import Data.Time (diffUTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import System.Nix.Base qualified+import System.Nix.Build (BuildResult(..), BuildSuccess(..), BuildFailure(..), BuildSuccessStatus(..), BuildFailureStatus(..))+import System.Nix.ContentAddress+import System.Nix.Derivation+import System.Nix.DerivedPath (DerivedPath(..), OutputsSpec(..), SingleDerivedPath(..))+import System.Nix.Hash+import System.Nix.OutputName (OutputName, mkOutputName)+import System.Nix.OutputName qualified+import System.Nix.Realisation (BuildTraceKey(..), Realisation(..), RealisationWithId(..))+import System.Nix.Signature (Signature, NamedSignature(..))+import System.Nix.Signature qualified+import System.Nix.StorePath (StorePath, StorePathName, StorePathHashPart, mkStorePathName, unStorePathName, parseBasePathFromText)+import System.Nix.StorePath qualified+import System.Nix.StorePath.Metadata (Metadata(..), StorePathTrust(..)) instance ToJSON StorePathName where toJSON = toJSON . System.Nix.StorePath.unStorePathName@@ -54,18 +73,8 @@ ) instance ToJSON StorePath where- toJSON =- toJSON- -- TODO: hacky, we need to stop requiring StoreDir for- -- StorePath rendering and have a distinct- -- types for rooted|unrooted paths- . Data.Text.drop 1- . System.Nix.StorePath.storePathToText (StoreDir mempty)-- toEncoding =- toEncoding- . Data.Text.drop 1- . System.Nix.StorePath.storePathToText (StoreDir mempty)+ toJSON = toJSON . System.Nix.StorePath.storePathBaseToText+ toEncoding = toEncoding . System.Nix.StorePath.storePathBaseToText instance FromJSON StorePath where parseJSON =@@ -73,53 +82,174 @@ ( either (fail . show) pure- . System.Nix.StorePath.parsePathFromText (StoreDir mempty)- . Data.Text.cons '/'+ . parseBasePathFromText ) -instance ToJSON (DerivationOutput OutputName) where- toJSON =- toJSON- . Data.Text.Lazy.toStrict- . Data.Text.Lazy.Builder.toLazyText- . System.Nix.Realisation.derivationOutputBuilder- System.Nix.OutputName.unOutputName+instance ToJSONKey StorePath where+ toJSONKey = Data.Aeson.Types.toJSONKeyText System.Nix.StorePath.storePathBaseToText - toEncoding =- toEncoding- . Data.Text.Lazy.toStrict- . Data.Text.Lazy.Builder.toLazyText- . System.Nix.Realisation.derivationOutputBuilder- System.Nix.OutputName.unOutputName+instance FromJSONKey StorePath where+ fromJSONKey = FromJSONKeyTextParser $+ either (fail . show) pure . parseBasePathFromText -instance ToJSONKey (DerivationOutput OutputName) where- toJSONKey =- Data.Aeson.Types.toJSONKeyText- $ Data.Text.Lazy.toStrict- . Data.Text.Lazy.Builder.toLazyText- . System.Nix.Realisation.derivationOutputBuilder- System.Nix.OutputName.unOutputName+deriving newtype instance FromJSON DerivedPathMap+deriving newtype instance ToJSON DerivedPathMap -instance FromJSON (DerivationOutput OutputName) where- parseJSON =- withText "DerivationOutput OutputName"- ( either- (fail . show)- pure- . System.Nix.Realisation.derivationOutputParser- System.Nix.OutputName.mkOutputName- )+instance FromJSON ChildNode where+ parseJSON = withObject "ChildNode" $ \obj -> do+ outputs <- obj .: "outputs"+ dynamicOutputs <- obj .: "dynamicOutputs"+ ChildNode <$> case (Data.Set.null outputs, Data.Map.Monoidal.null dynamicOutputs) of+ (False, True) -> pure $ This outputs+ (True, False) -> pure $ That dynamicOutputs+ (False, False) -> pure $ These outputs dynamicOutputs+ (True, True) -> fail "outputs and dynamic outputs cannot both be empty" -instance FromJSONKey (DerivationOutput OutputName) where- fromJSONKey =- FromJSONKeyTextParser- ( either- (fail . show)- pure- . System.Nix.Realisation.derivationOutputParser- System.Nix.OutputName.mkOutputName- )+instance ToJSON ChildNode where+ toJSON (ChildNode cn) = object+ [ "outputs" .= fromMaybe Data.Set.empty (justHere cn)+ , "dynamicOutputs" .= fromMaybe Data.Map.Monoidal.empty (justThere cn)+ ] +-- | Input-addressed derivation output JSON instance+instance FromJSON InputAddressedDerivationOutput where+ parseJSON = withObject "InputAddressedDerivationOutput" $ \obj ->+ InputAddressedDerivationOutput <$> obj .: "path"++instance ToJSON InputAddressedDerivationOutput where+ toJSON (InputAddressedDerivationOutput path) =+ object ["path" .= path]++-- | Fixed derivation output JSON instance+instance FromJSON FixedDerivationOutput where+ parseJSON = withObject "FixedDerivationOutput" $ \obj -> do+ method <- obj .: "method" >>= either fail pure . textToMethod+ HashJSON hash <- obj .: "hash"+ pure $ FixedDerivationOutput method hash++instance ToJSON FixedDerivationOutput where+ toJSON (FixedDerivationOutput method hash) =+ object+ [ "method" .= methodToText method+ , "hash" .= HashJSON hash+ ]++-- | Content-addressed derivation output JSON instance+instance FromJSON ContentAddressedDerivationOutput where+ parseJSON = withObject "ContentAddressedDerivationOutput" $ \obj -> do+ method <- obj .: "method" >>= either fail pure . textToMethod+ hashAlgo <- obj .: "hashAlgo" >>= either fail pure . textToAlgo+ pure $ ContentAddressedDerivationOutput method hashAlgo++instance ToJSON ContentAddressedDerivationOutput where+ toJSON (ContentAddressedDerivationOutput method (Some hashAlgo)) =+ object+ [ "method" .= methodToText method+ , "hashAlgo" .= algoToText hashAlgo+ ]++-- Helper to parse DerivationOutputs from JSON+parseDerivationOutputs :: Object -> Parser DerivationOutputs+parseDerivationOutputs obj = do+ let outputPairs = Data.Aeson.KeyMap.toList obj+ case outputPairs of+ [] -> pure $ DerivationType_InputAddressing :=> mempty+ (_, firstVal) : _ -> do+ -- Parse the first output to determine the derivation type+ withObject "first output" (\first -> do+ -- Determine type by checking which fields are present+ let hasPath = Data.Aeson.KeyMap.member "path" first+ hasMethod = Data.Aeson.KeyMap.member "method" first+ hasHash = Data.Aeson.KeyMap.member "hash" first+ hasHashAlgo = Data.Aeson.KeyMap.member "hashAlgo" first++ case (hasPath, hasMethod, hasHash, hasHashAlgo) of+ (True, False, False, False) -> do+ -- Input-addressed+ outputs <- Data.Map.Strict.fromList <$> mapM (\(k, v) -> do+ outputName <- either (fail . show) pure $ mkOutputName $ Data.Aeson.Key.toText k+ output <- parseJSON v+ pure (outputName, output)) outputPairs+ pure $ DerivationType_InputAddressing :=> outputs+ (False, True, True, False) -> do+ -- Fixed+ outputs <- Data.Map.Strict.fromList <$> mapM (\(k, v) -> do+ outputName <- either (fail . show) pure $ mkOutputName $ Data.Aeson.Key.toText k+ output <- parseJSON v+ pure (outputName, output)) outputPairs+ pure $ DerivationType_Fixed :=> outputs+ (False, True, False, True) -> do+ -- Content-addressed+ outputs <- Data.Map.Strict.fromList <$> mapM (\(k, v) -> do+ outputName <- either (fail . show) pure $ mkOutputName $ Data.Aeson.Key.toText k+ output <- parseJSON v+ pure (outputName, output)) outputPairs+ pure $ DerivationType_ContentAddressing :=> outputs+ _ -> fail $ "Invalid output format: " <> show (hasPath, hasMethod, hasHash, hasHashAlgo)+ ) firstVal++-- Helper to serialize DerivationOutputs to JSON+derivationOutputsToJSON :: DerivationOutputs -> Value+derivationOutputsToJSON (ty :=> outputs) = case ty of+ DerivationType_InputAddressing -> toJSON outputs+ DerivationType_Fixed -> toJSON outputs+ DerivationType_ContentAddressing -> toJSON outputs++instance FromJSONKey StorePathName where+ fromJSONKey = FromJSONKeyTextParser $ either (fail . show) pure . mkStorePathName++instance ToJSONKey StorePathName where+ toJSONKey = Data.Aeson.Types.toJSONKeyText unStorePathName++deriving newtype instance FromJSON OutputName+deriving newtype instance ToJSON OutputName+deriving newtype instance FromJSONKey OutputName+deriving newtype instance ToJSONKey OutputName++-- | TODO: hacky, we need to stop assuming StoreDir for+-- StorePath to and from JSON+instance FromJSON Derivation where+ parseJSON = withObject "Derivation" $ \v -> do+ name <- v .: "name"+ inputs <- v .: "inputs" >>= \inputsObj -> DerivationInputs+ <$> inputsObj .: "srcs"+ <*> inputsObj .: "drvs"+ outputs <- v .: "outputs" >>= parseDerivationOutputs+ Derivation name outputs+ <$> pure inputs+ <*> v .: "system"+ <*> v .: "builder"+ <*> v .: "args"+ <*> v .: "env"++instance ToJSON Derivation where+ toJSON (Derivation name outputs (DerivationInputs inputSrcs inputDrvs) system builder args env) =+ object [ "version" .= (4 :: Int)+ , "name" .= name+ , "outputs" .= derivationOutputsToJSON outputs+ , "inputs" .= object+ [ "srcs" .= inputSrcs+ , "drvs" .= inputDrvs+ ]+ , "system" .= system+ , "builder" .= builder+ , "args" .= args+ , "env" .= env+ ]++instance ToJSON BuildTraceKey where+ toJSON btk =+ object+ [ "drvPath" .= buildTraceKeyDrvPath btk+ , "outputName" .= buildTraceKeyOutput btk+ ]++instance FromJSON BuildTraceKey where+ parseJSON = withObject "BuildTraceKey" $ \o ->+ BuildTraceKey+ <$> o .: "drvPath"+ <*> o .: "outputName"+ instance ToJSON Signature where toJSON = toJSON . System.Nix.Signature.signatureToText toEncoding = toEncoding . System.Nix.Signature.signatureToText@@ -134,43 +264,273 @@ System.Nix.Signature.signatureParser ) -data LowerLeading-instance StringModifier LowerLeading where- getStringModifier "" = ""- getStringModifier (c:xs) = Data.Char.toLower c : xs+instance ToJSON NamedSignature where+ toJSON ns =+ object+ [ "keyName" .= publicKey ns+ , "sig" .= sig ns+ ] -deriving- via CustomJSON- '[FieldLabelModifier- '[ StripPrefix "realisation"- , LowerLeading- , Rename "dependencies" "dependentRealisations"- ]- ] Realisation- instance ToJSON Realisation-deriving- via CustomJSON- '[FieldLabelModifier- '[ StripPrefix "realisation"- , LowerLeading- , Rename "dependencies" "dependentRealisations"- ]- ] Realisation- instance FromJSON Realisation+instance FromJSON NamedSignature where+ parseJSON = withObject "NamedSignature" $ \o -> do+ keyName <- o .: "keyName"+ sigVal <- o .: "sig"+ pure $ NamedSignature { publicKey = keyName, sig = sigVal } +-- | Needed to avoid overlapping instances+newtype HashJSON = HashJSON { unHashJSON :: DSum HashAlgo Digest }+ deriving (Eq, Show)++instance ToJSON HashJSON where+ toJSON (HashJSON (algo :=> digest)) =+ -- SRI format: "algo-base64hash"+ toJSON $ algoToText algo <> "-" <> encodeDigestWith Base64 digest++instance FromJSON HashJSON where+ parseJSON = withText "HashJSON" $ \t -> do+ -- SRI format: "algo-base64hash"+ let (algoText, rest) = Data.Text.breakOn "-" t+ case Data.Text.uncons rest of+ Nothing -> fail "HashJSON: missing '-' separator"+ Just ('-', _hashText) ->+ either fail (pure . HashJSON) $ mkNamedDigest algoText t+ _ -> fail "HashJSON: missing '-' separator"++instance ToJSON ContentAddress where+ toJSON (ContentAddress method digest) =+ object+ [ "hash" .= HashJSON digest+ , "method" .= methodToText method+ ]++instance FromJSON ContentAddress where+ parseJSON = withObject "ContentAddress" $ \obj -> do+ HashJSON digest <- obj .: "hash"+ methodText <- obj .: "method"+ method <- either fail pure $ textToMethod methodText+ pure $ ContentAddress method digest++-- | OutputsSpec encodes as an array. The wildcard "*" is a singleton+-- array ["*"] to match upstream Nix JSON format.+instance ToJSON OutputsSpec where+ toJSON OutputsSpec_All = toJSON ["*" :: Text]+ toJSON (OutputsSpec_Names names) = toJSON $ Data.Set.toList names++instance FromJSON OutputsSpec where+ parseJSON = withArray "OutputsSpec" $ \arr -> do+ outputs <- mapM parseJSON (toList arr)+ if outputs == ["*" :: Text]+ then pure OutputsSpec_All+ else do+ names <- mapM (either (fail . show) pure . System.Nix.OutputName.mkOutputName) outputs+ pure $ OutputsSpec_Names (Data.Set.fromList names)++instance ToJSON SingleDerivedPath where+ toJSON (SingleDerivedPath_Opaque path) = toJSON path+ toJSON (SingleDerivedPath_Built drvPath output) =+ object+ [ "drvPath" .= toJSON drvPath+ , "output" .= output+ ]++instance FromJSON SingleDerivedPath where+ parseJSON v = parseOpaque v <|> parseBuilt v+ where+ parseOpaque = fmap SingleDerivedPath_Opaque . parseJSON+ parseBuilt = withObject "SingleDerivedPath_Built" $ \obj ->+ SingleDerivedPath_Built+ <$> obj .: "drvPath"+ <*> obj .: "output"++instance ToJSON DerivedPath where+ toJSON (DerivedPath_Opaque path) = toJSON path+ toJSON (DerivedPath_Built drvPath outputs) =+ object+ [ "drvPath" .= toJSON drvPath+ , "outputs" .= outputs+ ]++instance FromJSON DerivedPath where+ parseJSON v = parseOpaque v <|> parseBuilt v+ where+ parseOpaque = fmap DerivedPath_Opaque . parseJSON+ parseBuilt = withObject "DerivedPath_Built" $ \obj ->+ DerivedPath_Built+ <$> obj .: "drvPath"+ <*> obj .: "outputs"++instance ToJSON Realisation where+ toJSON r =+ object+ [ "outPath" .= realisationOutPath r+ , "signatures" .= realisationSignatures r+ ]++instance FromJSON Realisation where+ parseJSON = withObject "Realisation" $ \o ->+ Realisation+ <$> o .: "outPath"+ <*> o .:? "signatures" .!= mempty+ -- For a keyed version of Realisation--- we use RealisationWithId (DerivationOutput OutputName, Realisation)--- instead of Realisation.id :: (DerivationOutput OutputName)+-- we use RealisationWithId (BuildTraceKey, Realisation)+-- instead of Realisation.id :: BuildTraceKey -- field. instance ToJSON RealisationWithId where toJSON (RealisationWithId (drvOut, r)) =- case toJSON r of- Object o -> Object $ Data.Aeson.KeyMap.insert "id" (toJSON drvOut) o- _ -> error "absurd"+ object+ [ "key" .= drvOut+ , "value" .= r+ ] instance FromJSON RealisationWithId where- parseJSON v@(Object o) = do- r <- parseJSON @Realisation v- drvOut <- o .: "id"+ parseJSON = withObject "RealisationWithId" $ \o -> do+ drvOut <- o .: "key"+ r <- o .: "value" pure (RealisationWithId (drvOut, r))- parseJSON x = fail $ "Expected Object but got " ++ show x++-- BuildSuccessStatus enum to/from JSON as strings+instance ToJSON BuildSuccessStatus where+ toJSON BuildSuccessStatus_Built = String "Built"+ toJSON BuildSuccessStatus_Substituted = String "Substituted"+ toJSON BuildSuccessStatus_AlreadyValid = String "AlreadyValid"+ toJSON BuildSuccessStatus_ResolvesToAlreadyValid = String "ResolvesToAlreadyValid"++instance FromJSON BuildSuccessStatus where+ parseJSON = withText "BuildSuccessStatus" $ \case+ "Built" -> pure BuildSuccessStatus_Built+ "Substituted" -> pure BuildSuccessStatus_Substituted+ "AlreadyValid" -> pure BuildSuccessStatus_AlreadyValid+ "ResolvesToAlreadyValid" -> pure BuildSuccessStatus_ResolvesToAlreadyValid+ other -> fail $ "Unknown BuildSuccessStatus: " ++ Data.Text.unpack other++-- BuildFailureStatus enum to/from JSON as strings+instance ToJSON BuildFailureStatus where+ toJSON BuildFailureStatus_PermanentFailure = String "PermanentFailure"+ toJSON BuildFailureStatus_InputRejected = String "InputRejected"+ toJSON BuildFailureStatus_OutputRejected = String "OutputRejected"+ toJSON BuildFailureStatus_TransientFailure = String "TransientFailure"+ toJSON BuildFailureStatus_CachedFailure = String "CachedFailure"+ toJSON BuildFailureStatus_TimedOut = String "TimedOut"+ toJSON BuildFailureStatus_MiscFailure = String "MiscFailure"+ toJSON BuildFailureStatus_DependencyFailed = String "DependencyFailed"+ toJSON BuildFailureStatus_LogLimitExceeded = String "LogLimitExceeded"+ toJSON BuildFailureStatus_NotDeterministic = String "NotDeterministic"+ toJSON BuildFailureStatus_NoSubstituters = String "NoSubstituters"+ toJSON BuildFailureStatus_HashMismatch = String "HashMismatch"++instance FromJSON BuildFailureStatus where+ parseJSON = withText "BuildFailureStatus" $ \case+ "PermanentFailure" -> pure BuildFailureStatus_PermanentFailure+ "InputRejected" -> pure BuildFailureStatus_InputRejected+ "OutputRejected" -> pure BuildFailureStatus_OutputRejected+ "TransientFailure" -> pure BuildFailureStatus_TransientFailure+ "CachedFailure" -> pure BuildFailureStatus_CachedFailure+ "TimedOut" -> pure BuildFailureStatus_TimedOut+ "MiscFailure" -> pure BuildFailureStatus_MiscFailure+ "DependencyFailed" -> pure BuildFailureStatus_DependencyFailed+ "LogLimitExceeded" -> pure BuildFailureStatus_LogLimitExceeded+ "NotDeterministic" -> pure BuildFailureStatus_NotDeterministic+ "NoSubstituters" -> pure BuildFailureStatus_NoSubstituters+ "HashMismatch" -> pure BuildFailureStatus_HashMismatch+ other -> fail $ "Unknown BuildFailureStatus: " ++ Data.Text.unpack other++-- BuildResult JSON instances+instance ToJSON BuildResult where+ toJSON (BuildResult status timesBuilt startTime stopTime cpuUser cpuSystem) =+ case status of+ Right (BuildSuccess successStatus builtOutputs) ->+ object $ concat+ [ [ "success" .= True+ , "status" .= successStatus+ , "builtOutputs" .= builtOutputs+ , "timesBuilt" .= timesBuilt+ , "startTime" .= (floor (realToFrac (diffUTCTime startTime (posixSecondsToUTCTime 0)) :: Double) :: Integer)+ , "stopTime" .= (floor (realToFrac (diffUTCTime stopTime (posixSecondsToUTCTime 0)) :: Double) :: Integer)+ ]+ , maybeToList $ ("cpuUser" .=) <$> cpuUser+ , maybeToList $ ("cpuSystem" .=) <$> cpuSystem+ ]+ Left (BuildFailure failureStatus errorMsg isNonDeterministic) ->+ object+ [ "success" .= False+ , "status" .= failureStatus+ , "errorMsg" .= errorMsg+ , "isNonDeterministic" .= isNonDeterministic+ , "timesBuilt" .= timesBuilt+ , "startTime" .= (floor (realToFrac (diffUTCTime startTime (posixSecondsToUTCTime 0)) :: Double) :: Integer)+ , "stopTime" .= (floor (realToFrac (diffUTCTime stopTime (posixSecondsToUTCTime 0)) :: Double) :: Integer)+ ]++instance FromJSON BuildResult where+ parseJSON = withObject "BuildResult" $ \obj -> do+ success <- obj .: "success"+ timesBuilt <- obj .: "timesBuilt"+ startTimeSeconds <- obj .: "startTime"+ stopTimeSeconds <- obj .: "stopTime"+ let startTime = posixSecondsToUTCTime (fromInteger startTimeSeconds)+ stopTime = posixSecondsToUTCTime (fromInteger stopTimeSeconds)++ buildResultStatus <- if success+ then do+ successStatus <- obj .: "status"+ builtOutputs <- obj .:? "builtOutputs" .!= mempty+ pure $ Right (BuildSuccess successStatus builtOutputs)+ else do+ failureStatus <- obj .: "status"+ errorMsg <- obj .: "errorMsg"+ isNonDeterministic <- obj .: "isNonDeterministic"+ pure $ Left (BuildFailure failureStatus errorMsg isNonDeterministic)++ buildResultCpuUser <- obj .:? "cpuUser"+ buildResultCpuSystem <- obj .:? "cpuSystem"++ pure BuildResult+ { buildResultStatus = buildResultStatus+ , buildResultTimesBuilt = timesBuilt+ , buildResultStartTime = startTime+ , buildResultStopTime = stopTime+ , buildResultCpuUser = buildResultCpuUser+ , buildResultCpuSystem = buildResultCpuSystem+ }++-- | Metadata (path-info) JSON, version 3 format+instance ToJSON (Metadata StorePath) where+ toJSON m = object+ [ "version" .= (3 :: Int)+ , "storeDir" .= ("/nix/store" :: Text)+ , "narHash" .= HashJSON (metadataNarHash m)+ , "narSize" .= fromMaybe 0 (metadataNarBytes m)+ , "references" .= metadataReferences m+ , "ca" .= metadataContentAddress m+ , "deriver" .= metadataDeriverPath m+ , "registrationTime" .=+ let t = metadataRegistrationTime m+ in if t == posixSecondsToUTCTime 0+ then Nothing @Integer+ else Just (floor (realToFrac (diffUTCTime t (posixSecondsToUTCTime 0)) :: Double) :: Integer)+ , "signatures" .= metadataSigs m+ , "ultimate" .= (metadataTrust m == BuiltLocally)+ ]++instance FromJSON (Metadata StorePath) where+ parseJSON = withObject "Metadata" $ \o -> do+ HashJSON narHash <- o .: "narHash"+ narSize <- o .: "narSize"+ references <- o .:? "references" .!= mempty+ ca <- o .:? "ca"+ deriver <- o .:? "deriver"+ regTime <- o .:? "registrationTime"+ sigs <- o .:? "signatures" .!= mempty+ ultimate <- o .:? "ultimate" .!= False+ pure Metadata+ { metadataDeriverPath = deriver+ , metadataNarHash = narHash+ , metadataReferences = references+ , metadataRegistrationTime =+ maybe (posixSecondsToUTCTime 0) (posixSecondsToUTCTime . fromInteger) regTime+ , metadataNarBytes = if narSize == (0 :: Int) then Nothing else Just (fromIntegral narSize)+ , metadataTrust = if ultimate then BuiltLocally else BuiltElsewhere+ , metadataSigs = sigs+ , metadataContentAddress = ca+ }
+ tests/BuildResultSpec.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module BuildResultSpec where++import Data.Aeson (eitherDecode)+import Data.ByteString.Lazy qualified as BSL+import Paths_hnix_store_json (getDataFileName)+import Test.Hspec (Spec, describe, it, shouldSatisfy)++import System.Nix.Build (BuildResult(..), BuildFailure(..), BuildFailureStatus(..))+import System.Nix.JSON ()++-- For success.json, we'll just check that it parses successfully+-- The exact BuildTraceKey values are derived from the hash in the JSON++-- We just check that the failures parse correctly since they don't have complex nested structures++spec :: Spec+spec = do+ describe "upstream Nix test data" $ do+ it "parses success.json" $ do+ path <- getDataFileName "upstream-libstore-data/build-result/success.json"+ json <- BSL.readFile path+ let result = eitherDecode json :: Either String BuildResult+ result `shouldSatisfy` \case+ Right (BuildResult (Right _) 3 _ _ (Just 500000000) (Just 604000000)) -> True+ _ -> False++ it "parses not-deterministic.json" $ do+ path <- getDataFileName "upstream-libstore-data/build-result/not-deterministic.json"+ json <- BSL.readFile path+ let result = eitherDecode json :: Either String BuildResult+ result `shouldSatisfy` \case+ Right (BuildResult (Left (BuildFailure BuildFailureStatus_NotDeterministic "no idea why" False)) 1 _ _ Nothing Nothing) -> True+ _ -> False++ it "parses output-rejected.json" $ do+ path <- getDataFileName "upstream-libstore-data/build-result/output-rejected.json"+ json <- BSL.readFile path+ let result = eitherDecode json :: Either String BuildResult+ result `shouldSatisfy` \case+ Right (BuildResult (Left (BuildFailure BuildFailureStatus_OutputRejected "no idea why" False)) 3 _ _ Nothing Nothing) -> True+ _ -> False
+ tests/ContentAddressSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module ContentAddressSpec where++import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.ContentAddress (ContentAddress(..), ContentAddressMethod(..))+import System.Nix.Hash (mkNamedDigest)+import System.Nix.JSON ()++spec :: Spec+spec = do+ describe "upstream Nix test data" $ do+ parsesUpstream "upstream-libstore-data/content-address" "nar.json" $+ ContentAddress+ ContentAddressMethod_NixArchive+ (forceRight $ mkNamedDigest "sha256" "9vLqj0XYoFfJVmoz+ZR02i5camYE1zYSFlDicwxvsKM=")++ parsesUpstream "upstream-libstore-data/content-address" "text.json" $+ ContentAddress+ ContentAddressMethod_Text+ (forceRight $ mkNamedDigest "sha256" "8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts=")
+ tests/DerivationSpec.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+module DerivationSpec where++import Crypto.Hash (SHA256)+import Data.Aeson (eitherDecode)+import Data.ByteString.Lazy qualified as BSL+import Data.Dependent.Sum (DSum(..))+import Data.Map.Monoidal qualified as MonoidalMap+import Data.Map.Strict qualified as Map+import Data.Set qualified as Set+import Data.Some (Some(..))+import Data.These (These(..))+import Data.Vector qualified as Vector+import Paths_hnix_store_json (getDataFileName)+import Test.Hspec (Spec, describe, it, shouldBe)+import Test.Hspec.Nix (forceRight)++import System.Nix.Base (BaseEncoding(..))+import System.Nix.ContentAddress (ContentAddressMethod(..))+import System.Nix.Derivation+ ( ChildNode(..)+ , Derivation+ , Derivation'(..)+ , DerivationInputs(..)+ , DerivedPathMap(..)+ , DerivationType(..)+ , InputAddressedDerivationOutput(..)+ , FixedDerivationOutput(..)+ , ContentAddressedDerivationOutput(..)+ )+import System.Nix.Hash (HashAlgo(..), decodeDigestWith)+import System.Nix.JSON ()+import System.Nix.OutputName qualified+import System.Nix.StorePath (mkStorePathName, parseBasePathFromText)++simpleDerivation :: Derivation+simpleDerivation = Derivation+ { name = forceRight $ mkStorePathName "simple-derivation"+ , outputs = DerivationType_InputAddressing :=> mempty+ , inputs = DerivationInputs+ { srcs = Set.singleton $ forceRight $ parseBasePathFromText "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"+ , drvs = DerivedPathMap $ MonoidalMap.singleton+ (forceRight $ parseBasePathFromText "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv")+ (ChildNode $ This $ Set.fromList+ [ forceRight $ System.Nix.OutputName.mkOutputName "cat"+ , forceRight $ System.Nix.OutputName.mkOutputName "dog"+ ])+ }+ , platform = "wasm-sel4"+ , builder = "foo"+ , args = Vector.fromList ["bar", "baz"]+ , env = Map.fromList [("BIG_BAD", "WOLF")]+ }++dynDepDerivation :: Derivation+dynDepDerivation = Derivation+ { name = forceRight $ mkStorePathName "dyn-dep-derivation"+ , outputs = DerivationType_InputAddressing :=> mempty+ , inputs = DerivationInputs+ { srcs = Set.singleton $ forceRight $ parseBasePathFromText "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"+ , drvs = DerivedPathMap $ MonoidalMap.singleton+ (forceRight $ parseBasePathFromText "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv")+ (ChildNode $ These+ (Set.fromList+ [ forceRight $ System.Nix.OutputName.mkOutputName "cat"+ , forceRight $ System.Nix.OutputName.mkOutputName "dog"+ ])+ (MonoidalMap.fromList+ [ ( forceRight $ System.Nix.OutputName.mkOutputName "cat"+ , ChildNode $ This $ Set.singleton $ forceRight $ System.Nix.OutputName.mkOutputName "kitten"+ )+ , ( forceRight $ System.Nix.OutputName.mkOutputName "goose"+ , ChildNode $ This $ Set.singleton $ forceRight $ System.Nix.OutputName.mkOutputName "gosling"+ )+ ])+ )+ }+ , platform = "wasm-sel4"+ , builder = "foo"+ , args = Vector.fromList ["bar", "baz"]+ , env = Map.fromList [("BIG_BAD", "WOLF")]+ }++spec :: Spec+spec = do+ describe "upstream Nix test data" $ do+ describe "full derivations" $ do+ it "parses simple-derivation.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/simple-derivation.json"+ json <- BSL.readFile path+ eitherDecode json `shouldBe` Right simpleDerivation++ it "parses dyn-dep-derivation.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/dyn-dep-derivation.json"+ json <- BSL.readFile path+ eitherDecode json `shouldBe` Right dynDepDerivation++ describe "output types" $ do+ it "parses output-inputAddressed.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/output-inputAddressed.json"+ json <- BSL.readFile path+ output <- case eitherDecode json of+ Right output -> pure output+ Left err -> fail err++ let expectedPath = forceRight $ parseBasePathFromText "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"++ output `shouldBe` InputAddressedDerivationOutput expectedPath++ it "parses output-caFixedFlat.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/output-caFixedFlat.json"+ json <- BSL.readFile path+ output <- case eitherDecode json of+ Right output -> pure output+ Left err -> fail err++ let expectedHash = either error id $ decodeDigestWith @SHA256 Base64 "iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="++ output `shouldBe` FixedDerivationOutput ContentAddressMethod_Flat (HashAlgo_SHA256 :=> expectedHash)++ it "parses output-caFixedNAR.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/output-caFixedNAR.json"+ json <- BSL.readFile path+ output <- case eitherDecode json of+ Right output -> pure output+ Left err -> fail err++ let expectedHash = either error id $ decodeDigestWith @SHA256 Base64 "iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="++ output `shouldBe` FixedDerivationOutput ContentAddressMethod_NixArchive (HashAlgo_SHA256 :=> expectedHash)++ it "parses output-caFixedText.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/output-caFixedText.json"+ json <- BSL.readFile path+ output <- case eitherDecode json of+ Right output -> pure output+ Left err -> fail err++ let expectedHash = either error id $ decodeDigestWith @SHA256 Base64 "iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="++ output `shouldBe` FixedDerivationOutput ContentAddressMethod_Text (HashAlgo_SHA256 :=> expectedHash)++ it "parses output-caFloating.json" $ do+ path <- getDataFileName "upstream-libstore-data/derivation/output-caFloating.json"+ json <- BSL.readFile path+ output <- case eitherDecode json of+ Right output -> pure output+ Left err -> fail err++ output `shouldBe` ContentAddressedDerivationOutput ContentAddressMethod_NixArchive (Some HashAlgo_SHA256)
+ tests/DerivedPathSpec.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module DerivedPathSpec where++import Data.Set qualified+import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.DerivedPath (DerivedPath(..), OutputsSpec(..), SingleDerivedPath(..))+import System.Nix.JSON ()+import System.Nix.OutputName qualified+import System.Nix.StorePath (parseBasePathFromText)++-- upstream-nix/src/libstore-tests/data/derived-path/multi_opaque.json+upstreamMultiOpaque :: DerivedPath+upstreamMultiOpaque = DerivedPath_Opaque $+ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"++-- upstream-nix/src/libstore-tests/data/derived-path/mutli_built.json+upstreamMultiBuilt :: DerivedPath+upstreamMultiBuilt = DerivedPath_Built+ (SingleDerivedPath_Opaque $ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv")+ (OutputsSpec_Names $ Data.Set.fromList+ [ forceRight $ System.Nix.OutputName.mkOutputName "bar"+ , forceRight $ System.Nix.OutputName.mkOutputName "baz"+ ])++-- upstream-nix/src/libstore-tests/data/derived-path/multi_built_built.json+upstreamMultiBuiltBuilt :: DerivedPath+upstreamMultiBuiltBuilt = DerivedPath_Built+ (SingleDerivedPath_Built+ (SingleDerivedPath_Opaque $ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv")+ (forceRight $ System.Nix.OutputName.mkOutputName "bar"))+ (OutputsSpec_Names $ Data.Set.fromList+ [ forceRight $ System.Nix.OutputName.mkOutputName "baz"+ , forceRight $ System.Nix.OutputName.mkOutputName "quux"+ ])++-- upstream-nix/src/libstore-tests/data/derived-path/multi_built_built_wildcard.json+upstreamMultiBuiltBuiltWildcard :: DerivedPath+upstreamMultiBuiltBuiltWildcard = DerivedPath_Built+ (SingleDerivedPath_Built+ (SingleDerivedPath_Opaque $ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv")+ (forceRight $ System.Nix.OutputName.mkOutputName "bar"))+ OutputsSpec_All++spec :: Spec+spec = do+ let dir = "upstream-libstore-data/derived-path"+ describe "upstream Nix test data" $ do+ parsesUpstream dir "multi_opaque.json" upstreamMultiOpaque+ parsesUpstream dir "mutli_built.json" upstreamMultiBuilt+ parsesUpstream dir "multi_built_built.json" upstreamMultiBuiltBuilt+ parsesUpstream dir "multi_built_built_wildcard.json" upstreamMultiBuiltBuiltWildcard
+ tests/HashSpec.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module HashSpec where++import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.Hash (mkNamedDigest)+import System.Nix.JSON (HashJSON(..))++-- upstream-nix/src/libutil-tests/data/hash/sha256.json+upstreamSHA256 :: HashJSON+upstreamSHA256 = HashJSON $ forceRight $ mkNamedDigest "sha256" "8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="++-- upstream-nix/src/libutil-tests/data/hash/sha512.json+-- Note: sha512.json also contains a sha256 SRI hash (same test value as sha256.json)+upstreamSHA512 :: HashJSON+upstreamSHA512 = HashJSON $ forceRight $ mkNamedDigest "sha256" "8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="++spec :: Spec+spec = do+ let dir = "upstream-libutil-data/hash"+ describe "upstream Nix test data" $ do+ parsesUpstream dir "sha256.json" upstreamSHA256+ parsesUpstream dir "sha512.json" upstreamSHA512
tests/JSONSpec.hs view
@@ -1,26 +1,21 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} module JSONSpec where -import Data.Aeson (ToJSON, FromJSON, decode, encode)-import Data.Default.Class (Default(def))-import Test.Hspec (Expectation, Spec, describe, it, shouldBe)+import Data.Aeson (ToJSON, FromJSON, eitherDecode, encode)+import Test.Hspec (Expectation, Spec, describe)+import Test.Hspec.Nix (roundtrips) import Test.Hspec.QuickCheck (prop)-import Test.Hspec.Nix (forceRight, roundtrips) import System.Nix.Arbitrary ()+import System.Nix.ContentAddress (ContentAddress)+import System.Nix.Derivation (Derivation)+import System.Nix.DerivedPath (DerivedPath, OutputsSpec, SingleDerivedPath) import System.Nix.JSON ()-import System.Nix.OutputName (OutputName)-import System.Nix.Realisation (DerivationOutput(..), Realisation(..))-import System.Nix.Signature (Signature)+import System.Nix.Realisation (BuildTraceKey, Realisation)+import System.Nix.Signature (Signature, NamedSignature) import System.Nix.StorePath (StorePath, StorePathName, StorePathHashPart) -import qualified Data.Map-import qualified Data.Set-import qualified System.Nix.Hash-import qualified System.Nix.OutputName-import qualified System.Nix.Signature-import qualified System.Nix.StorePath- roundtripsJSON :: ( Eq a , Show a@@ -29,73 +24,20 @@ ) => a -> Expectation-roundtripsJSON = roundtrips encode decode--sampleDerivationOutput :: DerivationOutput OutputName-sampleDerivationOutput = DerivationOutput- { derivationOutputHash =- forceRight- $ System.Nix.Hash.mkNamedDigest- "sha256"- "1b4sb93wp679q4zx9k1ignby1yna3z7c4c2ri3wphylbc2dwsys0"- , derivationOutputOutput =- forceRight- $ System.Nix.OutputName.mkOutputName "foo"- }--sampleRealisation0 :: Realisation-sampleRealisation0 = Realisation- { realisationOutPath =- forceRight- $ System.Nix.StorePath.parsePath- def- "/nix/store/cdips4lakfk1qbf1x68fq18wnn3r5r14-builder.sh"- , realisationSignatures = mempty- , realisationDependencies = mempty- }--sampleRealisation1 :: Realisation-sampleRealisation1 = Realisation- { realisationOutPath =- forceRight- $ System.Nix.StorePath.parsePath- def- "/nix/store/5rwxzi7pal3qhpsyfc16gzkh939q1np6-curl-7.82.0.drv"- , realisationSignatures =- Data.Set.fromList- $ forceRight- . System.Nix.Signature.parseSignature- <$> [ "fW3iEMfyx6IZzGNswD54BjclfkXiYzh0xRXddrXfJ1rp1l8p1xTi9/0g2EibbwLFb6p83cwIJv5KtTGksC54CQ=="- , "SMjnB3mPgXYjXacU+xN24BdzXlAgGAuFnYwPddU3bhjfHBeQus/OimdIPMgR/JMKFPHXORrk7pbjv68vecTEBA=="- ]- , realisationDependencies =- Data.Map.fromList- [ ( sampleDerivationOutput- , forceRight- $ System.Nix.StorePath.parsePathFromText- def- "/nix/store/9472ijanf79nlkb5n1yh57s7867p1930-testFixed"- )- ]- }+roundtripsJSON = roundtrips encode eitherDecode spec :: Spec spec = do- describe "JSON" $ do- describe "roundtrips" $ do- prop "StorePathName" $ roundtripsJSON @StorePathName- prop "StorePathHashPart" $ roundtripsJSON @StorePathHashPart- prop "StorePath" $ roundtripsJSON @StorePath- prop "DerivationOutput OutputName" $ roundtripsJSON @(DerivationOutput OutputName)- prop "Signature" $ roundtripsJSON @Signature- prop "Realisation" $ roundtripsJSON @Realisation-- describe "ground truth" $ do- it "sampleDerivationOutput matches preimage" $- encode sampleDerivationOutput `shouldBe` "\"sha256:1b4sb93wp679q4zx9k1ignby1yna3z7c4c2ri3wphylbc2dwsys0!foo\""-- it "sampleRealisation0 matches preimage" $- encode sampleRealisation0 `shouldBe` "{\"outPath\":\"cdips4lakfk1qbf1x68fq18wnn3r5r14-builder.sh\",\"signatures\":[],\"dependentRealisations\":{}}"-- it "sampleRealisation1 matches preimage" $- encode sampleRealisation1 `shouldBe` "{\"outPath\":\"5rwxzi7pal3qhpsyfc16gzkh939q1np6-curl-7.82.0.drv\",\"signatures\":[\"SMjnB3mPgXYjXacU+xN24BdzXlAgGAuFnYwPddU3bhjfHBeQus/OimdIPMgR/JMKFPHXORrk7pbjv68vecTEBA==\",\"fW3iEMfyx6IZzGNswD54BjclfkXiYzh0xRXddrXfJ1rp1l8p1xTi9/0g2EibbwLFb6p83cwIJv5KtTGksC54CQ==\"],\"dependentRealisations\":{\"sha256:1b4sb93wp679q4zx9k1ignby1yna3z7c4c2ri3wphylbc2dwsys0!foo\":\"9472ijanf79nlkb5n1yh57s7867p1930-testFixed\"}}"+ describe "roundtrips" $ do+ prop "StorePathName" $ roundtripsJSON @StorePathName+ prop "StorePathHashPart" $ roundtripsJSON @StorePathHashPart+ prop "StorePath" $ roundtripsJSON @StorePath+ prop "ContentAddress" $ roundtripsJSON @ContentAddress+ prop "OutputsSpec" $ roundtripsJSON @OutputsSpec+ prop "SingleDerivedPath" $ roundtripsJSON @SingleDerivedPath+ prop "DerivedPath" $ roundtripsJSON @DerivedPath+ prop "Derivation" $ roundtripsJSON @Derivation+ prop "BuildTraceKey" $ roundtripsJSON @BuildTraceKey+ prop "Signature" $ roundtripsJSON @Signature+ prop "NamedSignature" $ roundtripsJSON @NamedSignature+ prop "Realisation" $ roundtripsJSON @Realisation
+ tests/OutputsSpecSpec.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module OutputsSpecSpec where++import Data.Set qualified+import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.DerivedPath (OutputsSpec(..))+import System.Nix.JSON ()+import System.Nix.OutputName qualified++-- upstream-nix/src/libstore-tests/data/outputs-spec/all.json+upstreamAll :: OutputsSpec+upstreamAll = OutputsSpec_All++-- upstream-nix/src/libstore-tests/data/outputs-spec/name.json+upstreamName :: OutputsSpec+upstreamName = OutputsSpec_Names $+ Data.Set.singleton $ forceRight $ System.Nix.OutputName.mkOutputName "a"++-- upstream-nix/src/libstore-tests/data/outputs-spec/names.json+upstreamNames :: OutputsSpec+upstreamNames = OutputsSpec_Names $ Data.Set.fromList+ [ forceRight $ System.Nix.OutputName.mkOutputName "a"+ , forceRight $ System.Nix.OutputName.mkOutputName "b"+ ]++spec :: Spec+spec = do+ let dir = "upstream-libstore-data/outputs-spec"+ describe "upstream Nix test data" $ do+ parsesUpstream dir "all.json" upstreamAll+ parsesUpstream dir "name.json" upstreamName+ parsesUpstream dir "names.json" upstreamNames
+ tests/PathInfoSpec.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module PathInfoSpec where++import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import Data.HashSet qualified+import Data.Set qualified+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)++import Crypto.Hash (Digest)+import Data.Dependent.Sum (DSum)++import System.Nix.ContentAddress (ContentAddress(..), ContentAddressMethod(..))+import System.Nix.Hash (HashAlgo, mkNamedDigest)+import System.Nix.JSON ()+import System.Nix.Signature (NamedSignature(..))+import System.Nix.Signature qualified+import System.Nix.StorePath (StorePath)+import System.Nix.StorePath qualified+import System.Nix.StorePath.Metadata (Metadata(..), StorePathTrust(..))++barPath :: StorePath+barPath = forceRight $ System.Nix.StorePath.parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"++barDrvPath :: StorePath+barDrvPath = forceRight $ System.Nix.StorePath.parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv"++fooPath :: StorePath+fooPath = forceRight $ System.Nix.StorePath.parseBasePathFromText "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"++sig1 :: NamedSignature+sig1 = NamedSignature+ { publicKey = "asdf"+ , sig = forceRight $ System.Nix.Signature.parseSignature "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ }++sig2 :: NamedSignature+sig2 = NamedSignature+ { publicKey = "qwer"+ , sig = forceRight $ System.Nix.Signature.parseSignature "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ }++theNarHash :: DSum HashAlgo Digest+theNarHash = forceRight $ mkNamedDigest "sha256" "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="++theCa :: ContentAddress+theCa = ContentAddress+ ContentAddressMethod_NixArchive+ (forceRight $ mkNamedDigest "sha256" "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=")++spec :: Spec+spec = do+ let dir = "upstream-libstore-data/path-info/json-3"++ describe "upstream Nix test data (path-info json-3)" $ do+ parsesUpstream dir "pure.json" Metadata+ { metadataDeriverPath = Nothing+ , metadataNarHash = theNarHash+ , metadataReferences = Data.HashSet.fromList [barPath, fooPath]+ , metadataRegistrationTime = posixSecondsToUTCTime 0+ , metadataNarBytes = Just 34878+ , metadataTrust = BuiltElsewhere+ , metadataSigs = mempty+ , metadataContentAddress = Just theCa+ }++ parsesUpstream dir "impure.json" Metadata+ { metadataDeriverPath = Just barDrvPath+ , metadataNarHash = theNarHash+ , metadataReferences = Data.HashSet.fromList [barPath, fooPath]+ , metadataRegistrationTime = posixSecondsToUTCTime 23423+ , metadataNarBytes = Just 34878+ , metadataTrust = BuiltLocally+ , metadataSigs = Data.Set.fromList [sig1, sig2]+ , metadataContentAddress = Just theCa+ }++ parsesUpstream dir "empty_pure.json" emptyMetadata++ parsesUpstream dir "empty_impure.json" emptyMetadata++emptyMetadata :: Metadata StorePath+emptyMetadata = Metadata+ { metadataDeriverPath = Nothing+ , metadataNarHash = theNarHash+ , metadataReferences = mempty+ , metadataRegistrationTime = posixSecondsToUTCTime 0+ , metadataNarBytes = Nothing+ , metadataTrust = BuiltElsewhere+ , metadataSigs = mempty+ , metadataContentAddress = Nothing+ }
+ tests/RealisationSpec.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module RealisationSpec where++import Data.Aeson (eitherDecode, encode)+import Data.ByteString.Lazy qualified as BSL+import Paths_hnix_store_json (getDataFileName)+import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.JSON ()+import System.Nix.OutputName qualified+import System.Nix.Realisation (BuildTraceKey(..), Realisation(..), RealisationWithId(..))+import System.Nix.StorePath qualified++sampleRealisation0 :: Realisation+sampleRealisation0 = Realisation+ { realisationOutPath =+ forceRight+ $ System.Nix.StorePath.parseBasePath+ "cdips4lakfk1qbf1x68fq18wnn3r5r14-builder.sh"+ , realisationSignatures = mempty+ }++-- upstream-nix/src/libstore-tests/data/realisation/simple.json+upstreamSimpleRealisation :: RealisationWithId+upstreamSimpleRealisation = RealisationWithId+ ( BuildTraceKey+ { buildTraceKeyDrvPath =+ forceRight+ $ System.Nix.StorePath.parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv"+ , buildTraceKeyOutput =+ forceRight+ $ System.Nix.OutputName.mkOutputName "foo"+ }+ , Realisation+ { realisationOutPath =+ forceRight+ $ System.Nix.StorePath.parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"+ , realisationSignatures = mempty+ }+ )++-- upstream-nix/src/libstore-tests/data/realisation/unkeyed-simple.json+upstreamUnkeyedSimple :: Realisation+upstreamUnkeyedSimple = Realisation+ { realisationOutPath =+ forceRight+ $ System.Nix.StorePath.parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"+ , realisationSignatures = mempty+ }++spec :: Spec+spec = do+ describe "ground truth" $ do+ it "sampleRealisation0 matches preimage (relative paths)" $+ encode sampleRealisation0 `shouldBe` "{\"outPath\":\"cdips4lakfk1qbf1x68fq18wnn3r5r14-builder.sh\",\"signatures\":[]}"++ let dir = "upstream-libstore-data/realisation"+ describe "upstream Nix test data" $ do+ parsesUpstream dir "simple.json" upstreamSimpleRealisation+ parsesUpstream dir "unkeyed-simple.json" upstreamUnkeyedSimple++ it "parses with-signature.json" $ do+ path <- getDataFileName "upstream-libstore-data/realisation/with-signature.json"+ json <- BSL.readFile path+ let result = eitherDecode json :: Either String RealisationWithId+ result `shouldSatisfy` \case+ Right _ -> True+ Left _ -> False++ it "parses unkeyed-with-signature.json" $ do+ path <- getDataFileName "upstream-libstore-data/realisation/unkeyed-with-signature.json"+ json <- BSL.readFile path+ let result = eitherDecode json :: Either String Realisation+ result `shouldSatisfy` \case+ Right _ -> True+ Left _ -> False
+ tests/SingleDerivedPathSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module SingleDerivedPathSpec where++import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.DerivedPath (SingleDerivedPath(..))+import System.Nix.JSON ()+import System.Nix.OutputName qualified+import System.Nix.StorePath (parseBasePathFromText)++-- upstream-nix/src/libstore-tests/data/derived-path/single_opaque.json+upstreamSingleOpaque :: SingleDerivedPath+upstreamSingleOpaque = SingleDerivedPath_Opaque $+ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"++-- upstream-nix/src/libstore-tests/data/derived-path/single_built.json+upstreamSingleBuilt :: SingleDerivedPath+upstreamSingleBuilt = SingleDerivedPath_Built+ (SingleDerivedPath_Opaque $ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv")+ (forceRight $ System.Nix.OutputName.mkOutputName "bar")++-- upstream-nix/src/libstore-tests/data/derived-path/single_built_built.json+upstreamSingleBuiltBuilt :: SingleDerivedPath+upstreamSingleBuiltBuilt = SingleDerivedPath_Built+ (SingleDerivedPath_Built+ (SingleDerivedPath_Opaque $ forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv")+ (forceRight $ System.Nix.OutputName.mkOutputName "bar"))+ (forceRight $ System.Nix.OutputName.mkOutputName "baz")++spec :: Spec+spec = do+ let dir = "upstream-libstore-data/derived-path"+ describe "upstream Nix test data" $ do+ parsesUpstream dir "single_opaque.json" upstreamSingleOpaque+ parsesUpstream dir "single_built.json" upstreamSingleBuilt+ parsesUpstream dir "single_built_built.json" upstreamSingleBuiltBuilt
+ tests/StorePathSpec.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module StorePathSpec where++import Test.Hspec (Spec, describe)+import Test.Hspec.Nix (forceRight)+import UpstreamData (parsesUpstream)++import System.Nix.JSON ()+import System.Nix.StorePath (StorePath, parseBasePathFromText)++-- upstream-nix/src/libstore-tests/data/store-path/simple.json+upstreamSimple :: StorePath+upstreamSimple = forceRight $ parseBasePathFromText "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"++spec :: Spec+spec = do+ describe "upstream Nix test data" $ do+ parsesUpstream "upstream-libstore-data/store-path" "simple.json" upstreamSimple
+ tests/UpstreamData.hs view
@@ -0,0 +1,16 @@+module UpstreamData+ ( parsesUpstream+ ) where++import Data.Aeson (FromJSON, eitherDecode)+import Data.ByteString.Lazy qualified as BSL+import Paths_hnix_store_json (getDataFileName)+import Test.Hspec (Spec, it, shouldBe)++-- | Helper to test parsing upstream Nix test data files.+parsesUpstream :: (Eq a, Show a, FromJSON a) => FilePath -> FilePath -> a -> Spec+parsesUpstream dir filename expected =+ it ("parses " <> filename) $ do+ path <- getDataFileName (dir ++ "/" ++ filename)+ json <- BSL.readFile path+ eitherDecode json `shouldBe` Right expected
+ upstream-libstore-data/build-result/not-deterministic.json view
@@ -0,0 +1,9 @@+{+ "errorMsg": "no idea why",+ "isNonDeterministic": false,+ "startTime": 0,+ "status": "NotDeterministic",+ "stopTime": 0,+ "success": false,+ "timesBuilt": 1+}
+ upstream-libstore-data/build-result/output-rejected.json view
@@ -0,0 +1,9 @@+{+ "errorMsg": "no idea why",+ "isNonDeterministic": false,+ "startTime": 30,+ "status": "OutputRejected",+ "stopTime": 50,+ "success": false,+ "timesBuilt": 3+}
+ upstream-libstore-data/build-result/success.json view
@@ -0,0 +1,19 @@+{+ "builtOutputs": {+ "bar": {+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",+ "signatures": []+ },+ "foo": {+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",+ "signatures": []+ }+ },+ "cpuSystem": 604000000,+ "cpuUser": 500000000,+ "startTime": 30,+ "status": "Built",+ "stopTime": 50,+ "success": true,+ "timesBuilt": 3+}
+ upstream-libstore-data/content-address/nar.json view
@@ -0,0 +1,4 @@+{+ "hash": "sha256-9vLqj0XYoFfJVmoz+ZR02i5camYE1zYSFlDicwxvsKM=",+ "method": "nar"+}
+ upstream-libstore-data/content-address/text.json view
@@ -0,0 +1,4 @@+{+ "hash": "sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts=",+ "method": "text"+}
+ upstream-libstore-data/derivation/dyn-dep-derivation.json view
@@ -0,0 +1,41 @@+{+ "args": [+ "bar",+ "baz"+ ],+ "builder": "foo",+ "env": {+ "BIG_BAD": "WOLF"+ },+ "inputs": {+ "drvs": {+ "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {+ "dynamicOutputs": {+ "cat": {+ "dynamicOutputs": {},+ "outputs": [+ "kitten"+ ]+ },+ "goose": {+ "dynamicOutputs": {},+ "outputs": [+ "gosling"+ ]+ }+ },+ "outputs": [+ "cat",+ "dog"+ ]+ }+ },+ "srcs": [+ "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"+ ]+ },+ "name": "dyn-dep-derivation",+ "outputs": {},+ "system": "wasm-sel4",+ "version": 4+}
+ upstream-libstore-data/derivation/output-caFixedFlat.json view
@@ -0,0 +1,4 @@+{+ "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",+ "method": "flat"+}
+ upstream-libstore-data/derivation/output-caFixedNAR.json view
@@ -0,0 +1,4 @@+{+ "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",+ "method": "nar"+}
+ upstream-libstore-data/derivation/output-caFixedText.json view
@@ -0,0 +1,4 @@+{+ "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",+ "method": "text"+}
+ upstream-libstore-data/derivation/output-caFloating.json view
@@ -0,0 +1,4 @@+{+ "hashAlgo": "sha256",+ "method": "nar"+}
+ upstream-libstore-data/derivation/output-inputAddressed.json view
@@ -0,0 +1,3 @@+{+ "path": "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"+}
+ upstream-libstore-data/derivation/simple-derivation.json view
@@ -0,0 +1,28 @@+{+ "args": [+ "bar",+ "baz"+ ],+ "builder": "foo",+ "env": {+ "BIG_BAD": "WOLF"+ },+ "inputs": {+ "drvs": {+ "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {+ "dynamicOutputs": {},+ "outputs": [+ "cat",+ "dog"+ ]+ }+ },+ "srcs": [+ "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"+ ]+ },+ "name": "simple-derivation",+ "outputs": {},+ "system": "wasm-sel4",+ "version": 4+}
+ upstream-libstore-data/derived-path/multi_built_built.json view
@@ -0,0 +1,10 @@+{+ "drvPath": {+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "output": "bar"+ },+ "outputs": [+ "baz",+ "quux"+ ]+}
+ upstream-libstore-data/derived-path/multi_built_built_wildcard.json view
@@ -0,0 +1,9 @@+{+ "drvPath": {+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "output": "bar"+ },+ "outputs": [+ "*"+ ]+}
+ upstream-libstore-data/derived-path/multi_opaque.json view
@@ -0,0 +1,1 @@+"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
+ upstream-libstore-data/derived-path/mutli_built.json view
@@ -0,0 +1,7 @@+{+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "outputs": [+ "bar",+ "baz"+ ]+}
+ upstream-libstore-data/derived-path/single_built.json view
@@ -0,0 +1,4 @@+{+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "output": "bar"+}
+ upstream-libstore-data/derived-path/single_built_built.json view
@@ -0,0 +1,7 @@+{+ "drvPath": {+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "output": "bar"+ },+ "output": "baz"+}
+ upstream-libstore-data/derived-path/single_opaque.json view
@@ -0,0 +1,1 @@+"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
+ upstream-libstore-data/outputs-spec/all.json view
@@ -0,0 +1,3 @@+[+ "*"+]
+ upstream-libstore-data/outputs-spec/name.json view
@@ -0,0 +1,3 @@+[+ "a"+]
+ upstream-libstore-data/outputs-spec/names.json view
@@ -0,0 +1,4 @@+[+ "a",+ "b"+]
+ upstream-libstore-data/path-info/json-3/empty_impure.json view
@@ -0,0 +1,12 @@+{+ "ca": null,+ "deriver": null,+ "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",+ "narSize": 0,+ "references": [],+ "registrationTime": null,+ "signatures": [],+ "storeDir": "/nix/store",+ "ultimate": false,+ "version": 3+}
+ upstream-libstore-data/path-info/json-3/empty_pure.json view
@@ -0,0 +1,8 @@+{+ "ca": null,+ "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",+ "narSize": 0,+ "references": [],+ "storeDir": "/nix/store",+ "version": 3+}
+ upstream-libstore-data/path-info/json-3/impure.json view
@@ -0,0 +1,27 @@+{+ "ca": {+ "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",+ "method": "nar"+ },+ "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",+ "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",+ "narSize": 34878,+ "references": [+ "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",+ "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"+ ],+ "registrationTime": 23423,+ "signatures": [+ {+ "keyName": "asdf",+ "sig": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ },+ {+ "keyName": "qwer",+ "sig": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ }+ ],+ "storeDir": "/nix/store",+ "ultimate": true,+ "version": 3+}
+ upstream-libstore-data/path-info/json-3/pure.json view
@@ -0,0 +1,14 @@+{+ "ca": {+ "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",+ "method": "nar"+ },+ "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",+ "narSize": 34878,+ "references": [+ "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",+ "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"+ ],+ "storeDir": "/nix/store",+ "version": 3+}
+ upstream-libstore-data/realisation/simple.json view
@@ -0,0 +1,10 @@+{+ "key": {+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",+ "outputName": "foo"+ },+ "value": {+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",+ "signatures": []+ }+}
+ upstream-libstore-data/realisation/unkeyed-simple.json view
@@ -0,0 +1,4 @@+{+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",+ "signatures": []+}
+ upstream-libstore-data/realisation/unkeyed-with-signature.json view
@@ -0,0 +1,9 @@+{+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "signatures": [+ {+ "keyName": "asdf",+ "sig": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ }+ ]+}
+ upstream-libstore-data/realisation/with-signature.json view
@@ -0,0 +1,15 @@+{+ "key": {+ "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",+ "outputName": "foo"+ },+ "value": {+ "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",+ "signatures": [+ {+ "keyName": "asdf",+ "sig": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="+ }+ ]+ }+}
+ upstream-libstore-data/store-path/simple.json view
@@ -0,0 +1,1 @@+"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
+ upstream-libutil-data/hash/sha256.json view
@@ -0,0 +1,1 @@+"sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="
+ upstream-libutil-data/hash/sha512.json view
@@ -0,0 +1,1 @@+"sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="