hocker 1.0.5 → 1.0.6
raw patch · 17 files changed
+132/−53 lines, 17 filesdep +megaparsecdep +prettyprinterdep +word8dep −ansi-wl-pprintdep ~asyncdep ~hnixdep ~turtle
Dependencies added: megaparsec, prettyprinter, word8
Dependencies removed: ansi-wl-pprint
Dependency ranges changed: async, hnix, turtle
Files
- CHANGELOG.md +7/−0
- hocker.cabal +10/−8
- src/Data/Docker/Nix/FetchDocker.hs +35/−16
- src/Data/Docker/Nix/Lib.hs +1/−1
- src/Hocker/Lib.hs +15/−7
- src/Hocker/Types.hs +1/−1
- src/Hocker/Types/Exceptions.hs +1/−1
- src/Hocker/Types/Hash.hs +1/−1
- src/Hocker/Types/ImageName.hs +1/−1
- src/Hocker/Types/ImageTag.hs +1/−1
- src/Hocker/Types/URI.hs +1/−1
- src/Network/Wreq/Docker/Image.hs +1/−1
- src/Network/Wreq/Docker/Image/Lib.hs +1/−1
- src/Network/Wreq/Docker/Registry.hs +3/−3
- src/Network/Wreq/ErrorHandling.hs +1/−1
- test/Tests/Data/Docker/Nix/FetchDocker.hs +44/−3
- test/data/golden-debian_jessie.nix +8/−6
CHANGELOG.md view
@@ -1,5 +1,12 @@ # Changelog +## 1.0.6+### Changed+- Support and require hnix-0.7.0 or higher.+- Support GHC 8.10.1.+- Use nixpkgs 20.03 in Nix builds.+- Discard support for Nix versions < 1.12.+ ## 1.0.5 ### Fixed - Add the golden test data to the source distribution by using `data-files`
hocker.cabal view
@@ -1,5 +1,5 @@ name: hocker-version: 1.0.5+version: 1.0.6 synopsis: Interact with the docker registry and generate nix build instructions homepage: https://github.com/awakesecurity/hocker#readme Bug-Reports: https://github.com/awakesecurity/hocker/issues@@ -68,8 +68,7 @@ base >= 4.9 && < 5, aeson >= 1.0.0.0, aeson-pretty >= 0.8,- ansi-wl-pprint >= 0.6.7.3,- async >= 2.0.0.0 && < 2.2,+ async >= 2.0.0.0 && < 2.3, bytestring >= 0.10, concurrentoutput >= 0.2, containers >= 0.5,@@ -80,12 +79,13 @@ exceptions >= 0.8, filepath >= 1.4, foldl >= 1.0,- hnix >= 0.3.4,+ hnix >= 0.7.0, http-client >= 0.4, http-types >= 0.9.1, lens >= 4.0, lens-aeson >= 1.0, lifted-base >= 0.2.3.8,+ megaparsec >= 7.0.0, memory >= 0.11, mtl >= 2.2, neat-interpolation >= 0.3.2,@@ -93,6 +93,7 @@ network-uri >= 2.6, optparse-applicative >= 0.13, optparse-generic >= 1.2.0,+ prettyprinter >= 1.1.1, pooled-io >= 0.0.2, pureMD5 >= 2.1, scientific >= 0.3,@@ -101,7 +102,7 @@ text >= 1.2, time >= 1.4, transformers >= 0.4,- turtle >= 1.3.0 && < 1.5,+ turtle >= 1.3.0 && < 1.6, unordered-containers >= 0.2, uri-bytestring >= 0.2, vector >= 0.11,@@ -201,7 +202,7 @@ bytestring >= 0.10, data-fix >= 0.0.3, filepath >= 1.4,- hnix >= 0.3.4,+ hnix >= 0.5.2, hocker, lens >= 4.0, mtl >= 2.2,@@ -225,7 +226,6 @@ build-depends: base >= 4.9 && < 5, aeson >= 0.9.0.1,- ansi-wl-pprint >= 0.6.7.3, bytestring >= 0.10, containers >= 0.5, cryptonite >= 0.13,@@ -233,13 +233,15 @@ mtl >= 2.2, network >= 2.6, network-uri >= 2.6,+ prettyprinter >= 1.1.1, tasty >= 0.11, tasty-golden >= 2.3, tasty-hunit >= 0.9, tasty-quickcheck >= 0.8, tasty-smallcheck >= 0.8, text >= 1.2,- unordered-containers >= 0.2+ unordered-containers >= 0.2,+ word8 >= 0.1.0 ghc-options: -threaded -rtsopts -with-rtsopts=-N
src/Data/Docker/Nix/FetchDocker.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}@@ -23,12 +24,13 @@ import Data.Coerce import Data.Fix import Data.Maybe-import Data.Monoid+import Data.Semigroup ((<>)) import Data.Text (Text) import qualified Data.Text as Text import Data.Text.Encoding (decodeUtf8') import Data.Text.Encoding.Error-import Nix.Expr+import Nix.Expr hiding (inherit)+import qualified Nix.Expr (inherit) import URI.ByteString import Data.Docker.Image.Types@@ -38,7 +40,21 @@ import Hocker.Types import Hocker.Types.Exceptions import Hocker.Types.ImageTag+import Text.Megaparsec.Pos (Pos, mkPos) +-- | @hnix-0.5.0:inherit@ requires a source location as its final argument.+inheritAdapter :: FilePath -> Pos -> Pos -> [NKeyName e] -> Binding e+inheritAdapter sourceName sourceLine sourceColumn ks = Nix.Expr.inherit ks+#if MIN_VERSION_hnix(0,5,0)+ SourcePos{..}+#endif++-- | @hnix-0.5.0@ omits mkApp.+#if MIN_VERSION_hnix(0,5,0)+mkApp :: NExpr -> NExpr -> NExpr+mkApp e = Fix . NBinary NApp e+#endif+ {- Example output of the pretty-printed, generated Nix expression AST. { fetchdocker, fetchDockerConfig, fetchDockerLayer }: fetchdocker rec {@@ -99,8 +115,6 @@ pluckedConfigDigest = Hocker.Lib.stripHashId $ manifestJSON ^. key "config" . key "digest" . _String pluckedLayerDigests = Hocker.Lib.stripHashId <$> pluckLayersFrom manifestJSON -- {-| Generate a top-level Nix Expression AST from a 'HockerImageMeta' record, a config digest, and a list of layer digests. @@ -134,19 +148,24 @@ , StaticKey "imageName" ] let genLayerId i = mkSym . Text.pack $ "layer" <> show i- let fetchconfig = mkFetchDockerConfig (inherit $ ((StaticKey "tag"):commonInherits)) configDigest+ let fetchconfig = mkFetchDockerConfig (inheritAdapter ("generated for " ++ show imageName) (mkPos 1) (mkPos 1) $ ((StaticKey "tag"):commonInherits)) configDigest fetchlayers = mkLets- (mkFetchDockerLayers (inherit commonInherits) layerDigests)+ (mkFetchDockerLayers (inheritAdapter "common inherits" (mkPos 1) (mkPos 1) commonInherits) layerDigests) (mkList $ fmap genLayerId [0..(Prelude.length layerDigests)-1]) fetchDockerExpr <- mkFetchDocker dim fetchconfig fetchlayers pure (mkFunction (mkParamset- [ ("fetchdocker", Nothing)- , ("fetchDockerConfig", Nothing)+ [ ("fetchDockerConfig", Nothing) , ("fetchDockerLayer", Nothing)- ]) fetchDockerExpr)+ , ("fetchdocker", Nothing)+ ] -- List keys in sorted order so that we do not care+ -- whether hnix sorts keys or preserves this order.+#if MIN_VERSION_hnix(0,5,0)+ False -- not variadic+#endif+ ) fetchDockerExpr) -- | Generate a @fetchdocker { ... }@ function call and argument -- attribute set. Please see 'generateFetchDockerExpr' documentation@@ -155,7 +174,8 @@ mkFetchDocker HockerImageMeta{..} fetchconfig fetchlayers = do registry <- Bifunctor.first mkHockerException serializedRegistry pure- (mkApp (mkSym constFetchdocker)+ (mkSym constFetchdocker+ @@ (recAttrsE [ ("name", mkStr $ fromMaybe imageName altImageName) , ("registry", mkStr registry)@@ -172,7 +192,6 @@ mkHockerException err = HockerException (show err) Nothing Nothing - -- | Generate a @fetchDockerConfig { ... }@ function call and -- argument attrset. --@@ -181,8 +200,8 @@ -- the output expression. mkFetchDockerConfig :: Binding NExpr -> Base32Digest -> NExpr mkFetchDockerConfig inherits (Base32Digest digest) =- mkApp (mkSym constFetchDockerConfig)- (Fix $ NSet [ inherits, "sha256" $= (mkStr digest) ])+ mkSym constFetchDockerConfig @@+ (Fix $ NSet NNonRecursive [ inherits, "sha256" $= (mkStr digest) ]) -- | Generate a list of Nix expression ASTs representing -- @fetchDockerLayer { ... }@ function calls.@@ -208,9 +227,9 @@ where mkLayerId i = Text.pack $ "layer" <> show i mkFetchLayer (i, ((Base16Digest d16), (Base32Digest d32))) =- (mkLayerId i) $= mkApp (mkSym constFetchDockerLayer)- (Fix $ NSet+ (mkLayerId i) $= (mkSym constFetchDockerLayer @@+ (Fix $ NSet NNonRecursive [ inherits , "layerDigest" $= (mkStr d16) -- Required in order to perform a registry request , "sha256" $= (mkStr d32) -- Required by Nix for fixed output derivations- ])+ ]))
src/Data/Docker/Nix/Lib.hs view
@@ -15,7 +15,7 @@ module Data.Docker.Nix.Lib where -import Control.Foldl as Foldl+import qualified Control.Foldl as Foldl import Turtle import Control.Monad.Except as Except import qualified Data.Text as Text
src/Hocker/Lib.hs view
@@ -28,9 +28,13 @@ import qualified Data.ByteString.Char8 as C8 import Data.ByteString.Lazy.Char8 as C8L import Data.Coerce-import Data.Monoid+import Data.Semigroup ((<>)) import Data.Text (Text) import qualified Data.Text as Text+import Data.Text.Prettyprint.Doc (LayoutOptions(..),+ PageWidth(..), SimpleDocStream)+import qualified Data.Text.Prettyprint.Doc+import qualified Data.Text.Prettyprint.Doc.Render.Text import Data.Text.Encoding (encodeUtf8) import qualified Network.Wreq as Wreq import Nix.Expr (NExpr)@@ -39,9 +43,7 @@ import System.Environment (getProgName) import System.Exit as Exit import System.FilePath.Posix as File-import Text.PrettyPrint.ANSI.Leijen as Text.PrettyPrint (SimpleDoc,- displayS,- renderPretty)+import qualified System.IO import URI.ByteString import Data.Docker.Image.Types@@ -169,13 +171,19 @@ splitRepository (ImageName (Text.pack -> n)) = over _2 Text.tail $ Text.break (=='/') n -- | Given a nix expression AST, produce a pretty printer document.-renderNixExpr :: NExpr -> Text.PrettyPrint.SimpleDoc-renderNixExpr = renderPretty 0.4 120 . prettyNix+renderNixExpr :: NExpr -> SimpleDocStream ann+renderNixExpr =+ Data.Text.Prettyprint.Doc.layoutSmart layoutOptions . prettyNix+ where+ layoutOptions = LayoutOptions { layoutPageWidth = AvailablePerLine 120 0.4 } -- | Print a nix expression AST using the 'renderNixExpr' pretty -- printing renderer. pprintNixExpr :: NExpr -> IO ()-pprintNixExpr expr = Prelude.putStrLn (displayS (renderNixExpr expr) "")+pprintNixExpr expr =+ Data.Text.Prettyprint.Doc.Render.Text.renderIO System.IO.stdout stream+ where+ stream = renderNixExpr expr -- | Given an executable's name, try to find it in the PATH. findExec :: (MonadIO m, Except.MonadError HockerException m)
src/Hocker/Types.hs view
@@ -31,7 +31,7 @@ import qualified Crypto.Hash as Hash import qualified Data.ByteString.Lazy import Data.Char (toUpper)-import Data.Monoid+import Data.Semigroup ((<>)) import Data.Text (Text) import qualified Data.Text as Text import qualified Network.Wreq as Wreq
src/Hocker/Types/Exceptions.hs view
@@ -19,7 +19,7 @@ import Control.DeepSeq import Control.Exception-import Data.Monoid+import Data.Semigroup ((<>)) import GHC.Generics data HockerException = HockerException
src/Hocker/Types/Hash.hs view
@@ -17,7 +17,7 @@ import qualified Data.ByteArray as BA import qualified Data.ByteArray.Encoding as BA import qualified Data.ByteString.Char8 as C8-import Data.Monoid+import Data.Semigroup ((<>)) import qualified Data.Text import qualified Options.Applicative as Options import Options.Generic
src/Hocker/Types/ImageName.hs view
@@ -15,7 +15,7 @@ module Hocker.Types.ImageName where import Control.DeepSeq-import Data.Monoid+import Data.Semigroup ((<>)) import qualified Options.Applicative as Options import Options.Generic
src/Hocker/Types/ImageTag.hs view
@@ -15,7 +15,7 @@ module Hocker.Types.ImageTag where import Control.DeepSeq-import Data.Monoid+import Data.Semigroup ((<>)) import qualified Options.Applicative as Options import Options.Generic
src/Hocker/Types/URI.hs view
@@ -16,7 +16,7 @@ import Control.Lens import qualified Data.ByteString.Char8 as C8-import Data.Monoid+import Data.Semigroup ((<>)) import qualified Data.Text as Text import qualified Options.Applicative as Options import Options.Applicative.Builder
src/Network/Wreq/Docker/Image.hs view
@@ -25,7 +25,7 @@ import Data.Coerce import Data.Either import Data.HashSet as Set-import Data.Monoid+import Data.Semigroup ((<>)) import Data.Text (Text) import qualified Data.Text as Text import Data.Text.Encoding (decodeUtf8')
src/Network/Wreq/Docker/Image/Lib.hs view
@@ -24,7 +24,7 @@ import qualified Data.ByteString.Lazy.Char8 as C8L import Data.Coerce import qualified Data.HashMap.Strict as HashMap-import Data.Monoid+import Data.Semigroup ((<>)) import qualified Data.Text as Text import qualified Network.Wreq as Wreq import qualified System.Directory as Directory
src/Network/Wreq/Docker/Registry.hs view
@@ -27,7 +27,6 @@ import Control.Lens import qualified Control.Monad.Except as Except import Control.Monad.Reader-import Data.Monoid import qualified Crypto.Hash as Hash import Data.Aeson.Lens import Data.ByteString.Lazy.Char8 as C8L@@ -35,6 +34,7 @@ import Data.Text.Encoding (decodeUtf8, encodeUtf8) import URI.ByteString import NeatInterpolation+import Data.Semigroup ((<>)) import qualified Data.Text as Text import qualified Network.Wreq as Wreq import System.Directory@@ -64,7 +64,7 @@ -- -- If 'Credentials' is either 'BearerToken' or 'Basic' then produce a -- 'Wreq.Auth' value for that type of credential.--- +-- -- If @Nothing@ is provided _and_ the provided 'RegistryURI' matches -- the default registry, make a request to -- @https://auth.docker.io/token@ for a temporary pull-only bearer@@ -131,7 +131,7 @@ mkURL (ImageName n) r = C8.unpack (serializeURIRef' $ Hocker.Lib.joinURIPath [n, "blobs", digest] r) -- | Retrieve a compressed layer blob by its hash digest.--- +-- -- TODO: take advantage of registry's support for the Range header so -- we can stream downloads. fetchLayer :: Layer -> Hocker RspBS
src/Network/Wreq/ErrorHandling.hs view
@@ -21,7 +21,7 @@ import Control.Lens import Control.Monad.Except import Data.ByteString.Char8 as C8-import Data.Monoid+import Data.Semigroup ((<>)) import Network.HTTP.Client import Network.HTTP.Types.Status
test/Tests/Data/Docker/Nix/FetchDocker.hs view
@@ -15,15 +15,19 @@ import Control.Exception as CE import Control.Monad.Except as Except+import Data.ByteString as BS import Data.ByteString.Lazy.Char8 as C8L import Data.Either (either) import qualified Data.Text as Text+import qualified Data.Text.Prettyprint.Doc.Render.String+import Data.Word8 as W8 import Network.URI import Test.Tasty import Test.Tasty.Golden+import Test.Tasty.Golden.Advanced (goldenTest) import Test.Tasty.HUnit-import Text.PrettyPrint.ANSI.Leijen as Text.PrettyPrint (displayS)+import Text.Printf (printf) import Data.Docker.Image.Types import Data.Docker.Nix.FetchDocker as Nix.FetchDocker@@ -33,8 +37,43 @@ import Hocker.Types import Hocker.Types.ImageTag +-- | Compare a given string against the golden file contents,+-- ignoring differences in contiguous nonempty spans of whitespace,+-- and the presence or absence of whitespace before or after a comma.+goldenVsStringCanonicalize+ :: TestName -- ^ test name+ -> FilePath -- ^ path to golden file+ -> IO C8L.ByteString -- ^ action that returns string to compare+ -> TestTree -- ^ the test verifies that the returned string equals the+ -- golden file contents when ignoring differences in whitespace+goldenVsStringCanonicalize name ref act =+ goldenTest+ name+ (BS.readFile ref)+ (C8L.toStrict <$> act)+ cmp+ upd+ where+ cmp x y = cmpCanonicalize msg x y+ where+ msg = printf "Test output was different from '%s'. It was: %s" ref (show y)+ upd = BS.writeFile ref++cmpCanonicalize ::+ String -> BS.ByteString -> BS.ByteString -> IO (Maybe String)+cmpCanonicalize e x y =+ return $ if canonicalize x == canonicalize y then Nothing else Just e+ where+ canonicalize = BS.pack . BS.foldr op []+ op x acc+ | W8.isSpace x, y : _ <- acc, y == W8._space = acc+ | W8.isSpace x, y : _ <- acc, y == W8._comma = acc+ | W8.isSpace x = W8._space : acc+ | x == W8._comma, y : ys <- acc, y == W8._space = W8._comma : ys+ | otherwise = x : acc+ tests = testGroup "FetchDocker Nix Generation Tests"- [ goldenVsString+ [ goldenVsStringCanonicalize "Golden vs. Generated `fetchDocker' Nix Expression" "test/data/golden-debian_jessie.nix" generateFetchDockerNix@@ -66,7 +105,9 @@ , altImageName = Nothing } + let display = Data.Text.Prettyprint.Doc.Render.String.renderString+ either (Hocker.Lib.die . Text.pack . show)- (return . C8L.pack . (flip displayS "") . Hocker.Lib.renderNixExpr)+ (return . C8L.pack . display . Hocker.Lib.renderNixExpr) nixExpression
test/data/golden-debian_jessie.nix view
@@ -1,5 +1,7 @@-{ fetchDockerConfig, fetchDockerLayer, fetchdocker }:-fetchdocker rec {+{ fetchDockerConfig+ , fetchDockerLayer+ , fetchdocker }:+ fetchdocker rec { name = "debian"; registry = "https://registry-1.docker.io/v2/"; repository = "library";@@ -8,12 +10,12 @@ imageConfig = fetchDockerConfig { inherit tag registry repository imageName; sha256 = "1rwinmvfc8jxn54y7qnj82acrc97y7xcnn22zaz67y76n4wbwjh5";- };+ }; imageLayers = let layer0 = fetchDockerLayer { inherit registry repository imageName; layerDigest = "cd0a524342efac6edff500c17e625735bbe479c926439b263bbe3c8518a0849c"; sha256 = "1744l0c8ag5y7ck9nhr6r5wy9frmaxi7xh80ypgnxb7g891m42nd";- };- in [ layer0 ];- }+ };+ in [ layer0 ];+ }