nix-narinfo (empty) → 0.1.0.0
raw patch · 13 files changed
+405/−0 lines, 13 filesdep +QuickCheckdep +attoparsecdep +basesetup-changed
Dependencies added: QuickCheck, attoparsec, base, containers, filepath, hspec, nix-narinfo, text
Files
- LICENSE +30/−0
- README.md +7/−0
- Setup.hs +2/−0
- app/Main.hs +15/−0
- nix-narinfo.cabal +68/−0
- src/Nix/NarInfo.hs +10/−0
- src/Nix/NarInfo/Builder.hs +58/−0
- src/Nix/NarInfo/Parser.hs +63/−0
- src/Nix/NarInfo/Types.hs +63/−0
- test/ParseSpec.hs +28/−0
- test/Property.hs +53/−0
- test/Spec.hs +1/−0
- test/SpecHelper.hs +7/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Richard Marko (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,7 @@+nix-narinfo+===========++Parse and build `.narinfo` files.++Loosely based on [cachix-api](https://github.com/cachix/cachix/tree/master/cachix-api) `NarInfo` type.+Inspired by [nix-derivation](https://github.com/Gabriel439/Haskell-Nix-Derivation-Library/) library.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,15 @@+module Main where++import Nix.NarInfo++import Data.Attoparsec.Text+import Data.Text.IO+import Data.Text.Lazy.Builder+import Data.Text.Lazy.IO++main = do+ txt <- Data.Text.IO.readFile "./test/samples/0"+ case Data.Attoparsec.Text.parseOnly parseNarInfo txt of+ Left e -> error e+ Right ni -> Data.Text.Lazy.IO.putStr $+ Data.Text.Lazy.Builder.toLazyText $ buildNarInfo ni
+ nix-narinfo.cabal view
@@ -0,0 +1,68 @@+name: nix-narinfo+version: 0.1.0.0+synopsis: Parse and render .narinfo files+description: Support for parsing and rendering Nix .narinfo files+homepage: https://github.com/sorki/nix-narinfo+license: BSD3+license-file: LICENSE+author: Richard Marko+maintainer: srk@48.io+copyright: 2020 Richard Marko+category: Nix+build-type: Simple+cabal-version: >=1.10++extra-source-files:+ README.md++library+ hs-source-dirs: src+ exposed-modules: Nix.NarInfo+ other-modules: Nix.NarInfo.Builder+ , Nix.NarInfo.Parser+ , Nix.NarInfo.Types+ build-depends: base >= 4.7 && < 5+ , containers+ , text+ , attoparsec+ default-language: Haskell2010++executable pretty-narinfo+ hs-source-dirs: app+ main-is: Main.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends: base+ , attoparsec+ , text+ , nix-narinfo+ default-language: Haskell2010+++test-suite nix-narinfo-samples+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ other-modules: ParseSpec+ SpecHelper+ build-depends: base >= 4.7 && < 5+ , attoparsec+ , text+ , nix-narinfo+ , hspec+ default-language: Haskell2010++test-suite nix-narinfo-property+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Property.hs+ build-depends: base >= 4.7 && < 5+ , attoparsec+ , filepath+ , text+ , nix-narinfo+ , QuickCheck+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/sorki/nix-narinfo
+ src/Nix/NarInfo.hs view
@@ -0,0 +1,10 @@+module Nix.NarInfo (+ module Nix.NarInfo.Builder+ , module Nix.NarInfo.Parser+ , module Nix.NarInfo.Types+ ) where++import Nix.NarInfo.Builder+import Nix.NarInfo.Parser+import Nix.NarInfo.Types+
+ src/Nix/NarInfo/Builder.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Nix.NarInfo.Builder+ ( -- * Builder+ buildNarInfo+ , buildNarInfoWith+ ) where++import Data.Set (Set)+import Data.Text (Text)+import Data.Text.Lazy.Builder (Builder)+import Nix.NarInfo.Types++import qualified Control.Applicative+import qualified Data.Char+import qualified Data.Set+import qualified Data.List+import qualified Data.Text+import qualified Data.Text.Lazy.Builder++buildNarInfo :: (NarInfo FilePath Text Text) -> Builder+buildNarInfo = buildNarInfoWith+ (\_needPrefix fp -> Data.Text.Lazy.Builder.fromString fp)+ Data.Text.Lazy.Builder.fromText+ Data.Text.Lazy.Builder.fromText++buildNarInfoWith :: (Ord fp)+ => (Bool -> fp -> Builder)+ -> (txt -> Builder)+ -> (hash -> Builder)+ -> NarInfo fp txt hash+ -> Builder+buildNarInfoWith filepath string hash (NarInfo{..}) =+ keyPath "StorePath" storePath+ <> key "URL" url+ <> key "Compression" compression+ <> keyHash "FileHash" fileHash+ <> keyNum "FileSize" fileSize+ <> keyHash "NarHash" narHash+ <> keyNum "NarSize" narSize++ <> key' "References" (mconcat+ $ Data.List.intersperse " "+ $ map (filepath False)+ $ Data.List.sort $ Data.Set.toList references)++ <> optKey "Deriver" deriver+ <> optKey "System" system+ <> optKey "Sig" sig+ <> optKey "Ca" ca+ where+ key' k v = k <> ": " <> v <> "\n"+ key k v = key' k (string v)+ keyNum k v = key' k (Data.Text.Lazy.Builder.fromString . show $ v)+ keyPath k v = key' k (filepath True v)+ keyHash k v = key' k (hash v)+ optKey k = maybe mempty (key k)
+ src/Nix/NarInfo/Parser.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Nix.NarInfo.Parser+ ( -- * Parser+ parseNarInfo+ , parseNarInfoWith+ ) where++import Data.Set (Set)+import Data.Text (Text)+import Data.Attoparsec.Text (Parser)+import Nix.NarInfo.Types++import qualified Control.Applicative+import qualified Data.Char+import qualified Data.Set+import qualified Data.Text+import qualified Data.Attoparsec.Text++parseNarInfo :: Parser (NarInfo FilePath Text Text)+parseNarInfo = parseNarInfoWith pathParse textParse hashParse+ where+ textParse = Data.Attoparsec.Text.takeWhile (not . Data.Char.isSpace)+ pathParse _hasPrefix = Data.Text.unpack <$> textParse+ hashParse = textParse++parseNarInfoWith :: (Ord fp)+ => (Bool -> Parser fp) -- True when path prefix is present+ -> Parser txt+ -> Parser hash+ -> Parser (NarInfo fp txt hash)+parseNarInfoWith pathParser textParser hashParser = do+ storePath <- keyPath "StorePath"+ url <- key "URL"+ compression <- key "Compression"+ fileHash <- keyHash "FileHash"+ fileSize <- keyNum "FileSize"+ narHash <- keyHash "NarHash"+ narSize <- keyNum "NarSize"++ references <- Data.Set.fromList <$> (parseKey "References" $+ (pathParser False) `Data.Attoparsec.Text.sepBy` Data.Attoparsec.Text.char ' ')++ deriver <- optKey "Deriver"+ system <- optKey "System"+ sig <- optKey "Sig"+ ca <- optKey "Ca"++ return $ NarInfo {..}+ where+ parseKey key parser = do+ Data.Attoparsec.Text.string key+ Data.Attoparsec.Text.string ": "+ out <- parser+ Data.Attoparsec.Text.char '\n'+ return out++ key = flip parseKey textParser+ optKey = Control.Applicative.optional . key+ keyNum x = parseKey x Data.Attoparsec.Text.decimal+ keyPath x = parseKey x (pathParser True)+ keyHash x = parseKey x hashParser
+ src/Nix/NarInfo/Types.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+++module Nix.NarInfo.Types+ ( -- * Types+ NarInfo(..)+ , SimpleNarInfo+ ) where++import Data.Set (Set)+import Data.Text (Text)+import GHC.Generics++-- NarInfo URL includes storePath hash and .narinfo suffix+-- Note: storePath is with prefix but references are shortRefs (without /nix/store prefix)+--+-- Both `parseNarInfoWith` and `buildNarInfoWith` need+-- a path parser/printer which takes an argument+-- whether the path is prefixed or not.+--+data NarInfo fp txt hash = NarInfo+ { -- | Absolute path of the derivation in nix store.+ storePath :: fp+ , -- | Relative url (to current domain) to download nar file.+ url :: txt+ , -- | Name of the compression algorithm, eg. xz.+ compression :: txt+ , -- | Hash of the compressed nar file.+ -- NOTE: to compute use "nix-hash --type sha256 --flat"+ -- (srk) this isn't fixed to sha256 but a prefix indicates the type e.g.: sha256:1a6lzf...+ -- default is sha256 thought+ fileHash :: hash+ , -- | File size of compressed nar file.+ -- NOTE: du -b+ fileSize :: Integer+ , -- | Hash of the decompressed nar file.+ -- NOTE: to compute use "nix-hash --type sha256 --flat --base32"+ -- (srk) this isn't fixed to sha256 but a prefix indicates the type e.g.: sha256:1a6lzf...+ -- default is sha256 thought+ narHash :: hash+ , -- | File size of decompressed nar file.+ -- NOTE: du -b+ narSize :: Integer+ , -- | Immediate dependencies of the storePath.+ -- NOTE: nix-store -q --references+ references :: Set fp+ , -- | Relative store path (to nix store root) of the deriver.+ -- NOTE: nix-store -q --deriver+ deriver :: Maybe txt+ , -- | System+ system :: Maybe txt+ , -- | Signature of fields: storePath, narHash, narSize, refs.+ sig :: Maybe txt+ , -- | Content-addressed+ -- Store path is computed from a cryptographic hash+ -- of the contents of the path, plus some other bits of data like+ -- the "name" part of the path.+ ca :: Maybe txt+ }+ deriving (Eq, Generic, Show)++type SimpleNarInfo = NarInfo FilePath Text Text
+ test/ParseSpec.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++module ParseSpec where++import Data.Attoparsec.Text+import Data.Text.IO+import Data.Text.Lazy+import Data.Text.Lazy.Builder+import Data.Text.Lazy.IO++import SpecHelper++roundTrip fname = do+ txt <- Data.Text.IO.readFile $ "./test/samples/" ++ fname+ case Data.Attoparsec.Text.parseOnly parseNarInfo txt of+ Left e -> error e+ Right ni -> do+ let built = Data.Text.Lazy.Builder.toLazyText $ buildNarInfo ni+ (Data.Text.Lazy.toStrict built) `shouldBe` txt++spec :: Spec+spec = do+ it "roundtrips samples" $ do+ mapM_ (roundTrip . show) [0]++main :: IO ()+main = hspec spec
+ test/Property.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Main where++import Data.Text (Text)+import System.FilePath+import Nix.NarInfo (NarInfo(..))+import Test.QuickCheck (Arbitrary(..))++import qualified Data.Attoparsec.Text.Lazy+import qualified Data.Text+import qualified Data.Text.Lazy.Builder+import qualified Nix.NarInfo+import qualified Test.QuickCheck++instance Arbitrary Text where+ arbitrary = fmap Data.Text.pack arbitrary++instance Arbitrary (NarInfo FilePath Text Text) where+ arbitrary = do+ storePath <- arbitrary+ url <- arbitrary+ compression <- arbitrary+ fileHash <- arbitrary+ fileSize <- arbitrary+ narHash <- arbitrary+ narSize <- arbitrary+ references <- arbitrary+ deriver <- arbitrary+ system <- arbitrary+ sig <- arbitrary+ ca <- arbitrary+ return (NarInfo {..})++property :: NarInfo FilePath Text Text -> Bool+property narinfo0 = eitherRes == Right narinfo0+ where+ builder = Nix.NarInfo.buildNarInfo narinfo0++ text = Data.Text.Lazy.Builder.toLazyText builder++ result =+ Data.Attoparsec.Text.Lazy.parse Nix.NarInfo.parseNarInfo text++ eitherRes =+ Data.Attoparsec.Text.Lazy.eitherResult result++main :: IO ()+main = Test.QuickCheck.quickCheck property
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/SpecHelper.hs view
@@ -0,0 +1,7 @@+module SpecHelper+ ( module Test.Hspec+ , module Nix.NarInfo+ ) where++import Test.Hspec+import Nix.NarInfo