packages feed

language-docker 2.0.1 → 3.0.0

raw patch · 12 files changed

+289/−62 lines, 12 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Language.Docker: type Arguments = [String]
- Language.Docker: type Image = String
- Language.Docker.Syntax: type Arguments = [String]
- Language.Docker.Syntax: type Image = String
+ Language.Docker: Image :: Maybe Registry -> String -> Image
+ Language.Docker: Registry :: String -> Registry
+ Language.Docker: [$sel:imageName:Image] :: Image -> String
+ Language.Docker: [$sel:registryName:Image] :: Image -> Maybe Registry
+ Language.Docker: copyFromStage :: MonadFree EInstruction m => CopySource -> NonEmpty SourcePath -> TargetPath -> m ()
+ Language.Docker: data Arguments
+ Language.Docker: data Image
+ Language.Docker: fromStage :: CopyArgs -> CopySource -> CopyArgs
+ Language.Docker: newtype Registry
+ Language.Docker: ownedBy :: CopyArgs -> Chown -> CopyArgs
+ Language.Docker: to :: NonEmpty SourcePath -> TargetPath -> CopyArgs
+ Language.Docker: toSources :: NonEmpty String -> NonEmpty SourcePath
+ Language.Docker: toTarget :: String -> TargetPath
+ Language.Docker.EDSL: copyFromStage :: MonadFree EInstruction m => CopySource -> NonEmpty SourcePath -> TargetPath -> m ()
+ Language.Docker.EDSL: fromStage :: CopyArgs -> CopySource -> CopyArgs
+ Language.Docker.EDSL: ownedBy :: CopyArgs -> Chown -> CopyArgs
+ Language.Docker.EDSL: to :: NonEmpty SourcePath -> TargetPath -> CopyArgs
+ Language.Docker.EDSL: toSources :: NonEmpty String -> NonEmpty SourcePath
+ Language.Docker.EDSL: toTarget :: String -> TargetPath
+ Language.Docker.Parser: registry :: Parser Registry
+ Language.Docker.PrettyPrint: prettyPrintImage :: Image -> Doc
+ Language.Docker.Syntax: Arguments :: [String] -> Arguments
+ Language.Docker.Syntax: Image :: Maybe Registry -> String -> Image
+ Language.Docker.Syntax: Registry :: String -> Registry
+ Language.Docker.Syntax: [$sel:imageName:Image] :: Image -> String
+ Language.Docker.Syntax: [$sel:registryName:Image] :: Image -> Maybe Registry
+ Language.Docker.Syntax: data Image
+ Language.Docker.Syntax: instance Data.String.IsString Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax: instance Data.String.IsString Language.Docker.Syntax.Chown
+ Language.Docker.Syntax: instance Data.String.IsString Language.Docker.Syntax.CopySource
+ Language.Docker.Syntax: instance Data.String.IsString Language.Docker.Syntax.Image
+ Language.Docker.Syntax: instance Data.String.IsString Language.Docker.Syntax.Registry
+ Language.Docker.Syntax: instance GHC.Classes.Eq Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax: instance GHC.Classes.Eq Language.Docker.Syntax.Image
+ Language.Docker.Syntax: instance GHC.Classes.Eq Language.Docker.Syntax.Registry
+ Language.Docker.Syntax: instance GHC.Classes.Ord Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax: instance GHC.Classes.Ord Language.Docker.Syntax.Image
+ Language.Docker.Syntax: instance GHC.Classes.Ord Language.Docker.Syntax.Registry
+ Language.Docker.Syntax: instance GHC.Exts.IsList Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax: instance GHC.Show.Show Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax: instance GHC.Show.Show Language.Docker.Syntax.Image
+ Language.Docker.Syntax: instance GHC.Show.Show Language.Docker.Syntax.Registry
+ Language.Docker.Syntax: newtype Arguments
+ Language.Docker.Syntax: newtype Registry
+ Language.Docker.Syntax.Lift: instance Language.Haskell.TH.Syntax.Lift Language.Docker.Syntax.Arguments
+ Language.Docker.Syntax.Lift: instance Language.Haskell.TH.Syntax.Lift Language.Docker.Syntax.Image
+ Language.Docker.Syntax.Lift: instance Language.Haskell.TH.Syntax.Lift Language.Docker.Syntax.Registry
- Language.Docker: EDigestedImage :: String -> ByteString -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker: EDigestedImage :: Image -> ByteString -> (Maybe ImageAlias) -> EBaseImage
- Language.Docker: ETaggedImage :: String -> String -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker: ETaggedImage :: Image -> String -> (Maybe ImageAlias) -> EBaseImage
- Language.Docker: EUntaggedImage :: String -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker: EUntaggedImage :: Image -> (Maybe ImageAlias) -> EBaseImage
- Language.Docker: arg :: forall m_aCPK. MonadFree EInstruction m_aCPK => String -> Maybe String -> m_aCPK ()
+ Language.Docker: arg :: forall m_aERC. MonadFree EInstruction m_aERC => String -> Maybe String -> m_aERC ()
- Language.Docker: check :: String -> Check
+ Language.Docker: check :: Arguments -> Check
- Language.Docker: cmd :: MonadFree EInstruction m => String -> m ()
+ Language.Docker: cmd :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker: cmdArgs :: forall m_aCPm. MonadFree EInstruction m_aCPm => Arguments -> m_aCPm ()
+ Language.Docker: cmdArgs :: forall m_aERe. MonadFree EInstruction m_aERe => Arguments -> m_aERe ()
- Language.Docker: comment :: forall m_aCPO. MonadFree EInstruction m_aCPO => String -> m_aCPO ()
+ Language.Docker: comment :: forall m_aERG. MonadFree EInstruction m_aERG => String -> m_aERG ()
- Language.Docker: copy :: MonadFree EInstruction m => NonEmpty SourcePath -> TargetPath -> m ()
+ Language.Docker: copy :: MonadFree EInstruction m => CopyArgs -> m ()
- Language.Docker: digested :: String -> ByteString -> EBaseImage
+ Language.Docker: digested :: Image -> ByteString -> EBaseImage
- Language.Docker: embed :: forall m_aCPX. MonadFree EInstruction m_aCPX => [InstructionPos] -> m_aCPX ()
+ Language.Docker: embed :: forall m_aERP. MonadFree EInstruction m_aERP => [InstructionPos] -> m_aERP ()
- Language.Docker: entrypoint :: MonadFree EInstruction m => String -> m ()
+ Language.Docker: entrypoint :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker: entrypointArgs :: forall m_aCPB. MonadFree EInstruction m_aCPB => Arguments -> m_aCPB ()
+ Language.Docker: entrypointArgs :: forall m_aERt. MonadFree EInstruction m_aERt => Arguments -> m_aERt ()
- Language.Docker: env :: forall m_aCPH. MonadFree EInstruction m_aCPH => Pairs -> m_aCPH ()
+ Language.Docker: env :: forall m_aERz. MonadFree EInstruction m_aERz => Pairs -> m_aERz ()
- Language.Docker: expose :: forall m_aCPv. MonadFree EInstruction m_aCPv => Ports -> m_aCPv ()
+ Language.Docker: expose :: forall m_aERn. MonadFree EInstruction m_aERn => Ports -> m_aERn ()
- Language.Docker: from :: forall m_aCOk. MonadFree EInstruction m_aCOk => EBaseImage -> m_aCOk ()
+ Language.Docker: from :: forall m_aEQc. MonadFree EInstruction m_aEQc => EBaseImage -> m_aEQc ()
- Language.Docker: healthcheck :: forall m_aCPR. MonadFree EInstruction m_aCPR => Check -> m_aCPR ()
+ Language.Docker: healthcheck :: forall m_aERJ. MonadFree EInstruction m_aERJ => Check -> m_aERJ ()
- Language.Docker: label :: forall m_aCP7. MonadFree EInstruction m_aCP7 => Pairs -> m_aCP7 ()
+ Language.Docker: label :: forall m_aEQZ. MonadFree EInstruction m_aEQZ => Pairs -> m_aEQZ ()
- Language.Docker: maintainer :: forall m_aCPE. MonadFree EInstruction m_aCPE => String -> m_aCPE ()
+ Language.Docker: maintainer :: forall m_aERw. MonadFree EInstruction m_aERw => String -> m_aERw ()
- Language.Docker: onBuildRaw :: forall m_aCPU. MonadFree EInstruction m_aCPU => Instruction -> m_aCPU ()
+ Language.Docker: onBuildRaw :: forall m_aERM. MonadFree EInstruction m_aERM => Instruction -> m_aERM ()
- Language.Docker: run :: MonadFree EInstruction m => String -> m ()
+ Language.Docker: run :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker: runArgs :: forall m_aCPj. MonadFree EInstruction m_aCPj => Arguments -> m_aCPj ()
+ Language.Docker: runArgs :: forall m_aERb. MonadFree EInstruction m_aERb => Arguments -> m_aERb ()
- Language.Docker: stopSignal :: forall m_aCPa. MonadFree EInstruction m_aCPa => String -> m_aCPa ()
+ Language.Docker: stopSignal :: forall m_aER2. MonadFree EInstruction m_aER2 => String -> m_aER2 ()
- Language.Docker: tagged :: String -> String -> EBaseImage
+ Language.Docker: tagged :: Image -> String -> EBaseImage
- Language.Docker: user :: forall m_aCP4. MonadFree EInstruction m_aCP4 => String -> m_aCP4 ()
+ Language.Docker: user :: forall m_aEQW. MonadFree EInstruction m_aEQW => String -> m_aEQW ()
- Language.Docker: volume :: forall m_aCPy. MonadFree EInstruction m_aCPy => String -> m_aCPy ()
+ Language.Docker: volume :: forall m_aERq. MonadFree EInstruction m_aERq => String -> m_aERq ()
- Language.Docker: workdir :: forall m_aCPs. MonadFree EInstruction m_aCPs => Directory -> m_aCPs ()
+ Language.Docker: workdir :: forall m_aERk. MonadFree EInstruction m_aERk => Directory -> m_aERk ()
- Language.Docker.EDSL: addArgs :: forall m_aCOZ. MonadFree EInstruction m_aCOZ => NonEmpty SourcePath -> TargetPath -> Chown -> m_aCOZ ()
+ Language.Docker.EDSL: addArgs :: forall m_aEQR. MonadFree EInstruction m_aEQR => NonEmpty SourcePath -> TargetPath -> Chown -> m_aEQR ()
- Language.Docker.EDSL: arg :: forall m_aCPK. MonadFree EInstruction m_aCPK => String -> Maybe String -> m_aCPK ()
+ Language.Docker.EDSL: arg :: forall m_aERC. MonadFree EInstruction m_aERC => String -> Maybe String -> m_aERC ()
- Language.Docker.EDSL: check :: String -> Check
+ Language.Docker.EDSL: check :: Arguments -> Check
- Language.Docker.EDSL: cmd :: MonadFree EInstruction m => String -> m ()
+ Language.Docker.EDSL: cmd :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker.EDSL: cmdArgs :: forall m_aCPm. MonadFree EInstruction m_aCPm => Arguments -> m_aCPm ()
+ Language.Docker.EDSL: cmdArgs :: forall m_aERe. MonadFree EInstruction m_aERe => Arguments -> m_aERe ()
- Language.Docker.EDSL: comment :: forall m_aCPO. MonadFree EInstruction m_aCPO => String -> m_aCPO ()
+ Language.Docker.EDSL: comment :: forall m_aERG. MonadFree EInstruction m_aERG => String -> m_aERG ()
- Language.Docker.EDSL: copy :: MonadFree EInstruction m => NonEmpty SourcePath -> TargetPath -> m ()
+ Language.Docker.EDSL: copy :: MonadFree EInstruction m => CopyArgs -> m ()
- Language.Docker.EDSL: copyArgs :: forall m_aCPd. MonadFree EInstruction m_aCPd => NonEmpty SourcePath -> TargetPath -> Chown -> CopySource -> m_aCPd ()
+ Language.Docker.EDSL: copyArgs :: forall m_aER5. MonadFree EInstruction m_aER5 => NonEmpty SourcePath -> TargetPath -> Chown -> CopySource -> m_aER5 ()
- Language.Docker.EDSL: digested :: String -> ByteString -> EBaseImage
+ Language.Docker.EDSL: digested :: Image -> ByteString -> EBaseImage
- Language.Docker.EDSL: embed :: forall m_aCPX. MonadFree EInstruction m_aCPX => [InstructionPos] -> m_aCPX ()
+ Language.Docker.EDSL: embed :: forall m_aERP. MonadFree EInstruction m_aERP => [InstructionPos] -> m_aERP ()
- Language.Docker.EDSL: entrypoint :: MonadFree EInstruction m => String -> m ()
+ Language.Docker.EDSL: entrypoint :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker.EDSL: entrypointArgs :: forall m_aCPB. MonadFree EInstruction m_aCPB => Arguments -> m_aCPB ()
+ Language.Docker.EDSL: entrypointArgs :: forall m_aERt. MonadFree EInstruction m_aERt => Arguments -> m_aERt ()
- Language.Docker.EDSL: env :: forall m_aCPH. MonadFree EInstruction m_aCPH => Pairs -> m_aCPH ()
+ Language.Docker.EDSL: env :: forall m_aERz. MonadFree EInstruction m_aERz => Pairs -> m_aERz ()
- Language.Docker.EDSL: expose :: forall m_aCPv. MonadFree EInstruction m_aCPv => Ports -> m_aCPv ()
+ Language.Docker.EDSL: expose :: forall m_aERn. MonadFree EInstruction m_aERn => Ports -> m_aERn ()
- Language.Docker.EDSL: from :: forall m_aCOk. MonadFree EInstruction m_aCOk => EBaseImage -> m_aCOk ()
+ Language.Docker.EDSL: from :: forall m_aEQc. MonadFree EInstruction m_aEQc => EBaseImage -> m_aEQc ()
- Language.Docker.EDSL: healthcheck :: forall m_aCPR. MonadFree EInstruction m_aCPR => Check -> m_aCPR ()
+ Language.Docker.EDSL: healthcheck :: forall m_aERJ. MonadFree EInstruction m_aERJ => Check -> m_aERJ ()
- Language.Docker.EDSL: label :: forall m_aCP7. MonadFree EInstruction m_aCP7 => Pairs -> m_aCP7 ()
+ Language.Docker.EDSL: label :: forall m_aEQZ. MonadFree EInstruction m_aEQZ => Pairs -> m_aEQZ ()
- Language.Docker.EDSL: maintainer :: forall m_aCPE. MonadFree EInstruction m_aCPE => String -> m_aCPE ()
+ Language.Docker.EDSL: maintainer :: forall m_aERw. MonadFree EInstruction m_aERw => String -> m_aERw ()
- Language.Docker.EDSL: onBuildRaw :: forall m_aCPU. MonadFree EInstruction m_aCPU => Instruction -> m_aCPU ()
+ Language.Docker.EDSL: onBuildRaw :: forall m_aERM. MonadFree EInstruction m_aERM => Instruction -> m_aERM ()
- Language.Docker.EDSL: run :: MonadFree EInstruction m => String -> m ()
+ Language.Docker.EDSL: run :: MonadFree EInstruction m => Arguments -> m ()
- Language.Docker.EDSL: runArgs :: forall m_aCPj. MonadFree EInstruction m_aCPj => Arguments -> m_aCPj ()
+ Language.Docker.EDSL: runArgs :: forall m_aERb. MonadFree EInstruction m_aERb => Arguments -> m_aERb ()
- Language.Docker.EDSL: shell :: forall m_aCPp. MonadFree EInstruction m_aCPp => Arguments -> m_aCPp ()
+ Language.Docker.EDSL: shell :: forall m_aERh. MonadFree EInstruction m_aERh => Arguments -> m_aERh ()
- Language.Docker.EDSL: stopSignal :: forall m_aCPa. MonadFree EInstruction m_aCPa => String -> m_aCPa ()
+ Language.Docker.EDSL: stopSignal :: forall m_aER2. MonadFree EInstruction m_aER2 => String -> m_aER2 ()
- Language.Docker.EDSL: tagged :: String -> String -> EBaseImage
+ Language.Docker.EDSL: tagged :: Image -> String -> EBaseImage
- Language.Docker.EDSL: user :: forall m_aCP4. MonadFree EInstruction m_aCP4 => String -> m_aCP4 ()
+ Language.Docker.EDSL: user :: forall m_aEQW. MonadFree EInstruction m_aEQW => String -> m_aEQW ()
- Language.Docker.EDSL: volume :: forall m_aCPy. MonadFree EInstruction m_aCPy => String -> m_aCPy ()
+ Language.Docker.EDSL: volume :: forall m_aERq. MonadFree EInstruction m_aERq => String -> m_aERq ()
- Language.Docker.EDSL: workdir :: forall m_aCPs. MonadFree EInstruction m_aCPs => Directory -> m_aCPs ()
+ Language.Docker.EDSL: workdir :: forall m_aERk. MonadFree EInstruction m_aERk => Directory -> m_aERk ()
- Language.Docker.EDSL.Types: EDigestedImage :: String -> ByteString -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker.EDSL.Types: EDigestedImage :: Image -> ByteString -> (Maybe ImageAlias) -> EBaseImage
- Language.Docker.EDSL.Types: ETaggedImage :: String -> String -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker.EDSL.Types: ETaggedImage :: Image -> String -> (Maybe ImageAlias) -> EBaseImage
- Language.Docker.EDSL.Types: EUntaggedImage :: String -> (Maybe ImageAlias) -> EBaseImage
+ Language.Docker.EDSL.Types: EUntaggedImage :: Image -> (Maybe ImageAlias) -> EBaseImage

Files

README.md view
@@ -110,15 +110,17 @@ import qualified System.Directory     as Directory import qualified System.FilePath      as FilePath import qualified System.FilePath.Glob as Glob-import Data.String (fromString)+import Data.List.NonEmpty (fromList)+ main = do     str <- toDockerfileStrIO $ do         fs <- liftIO $ do             cwd <- Directory.getCurrentDirectory             fs <- Glob.glob "./test/*.hs"-            return (map (FilePath.makeRelative cwd) fs)+	    let relativeFiles = map (FilePath.makeRelative cwd) fs+            return (fromList relativeFiles)         from "ubuntu"-	mapM_ (\f -> add [fromString f] (fromString $ "/app/" ++ takeFileName f)) fs+	copy $ (toSources fs) `to` "/app/"     putStr str ``` 
language-docker.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: fb162f741f166683adaef8b45dca1eb857c508babbbb8de4977c9634b0e85e8f+-- hash: e8cfea2aac29c979db723d52ddb6f2d6db1d5fdb3166ddc8f77daeab9c1142e0  name:           language-docker-version:        2.0.1+version:        3.0.0 synopsis:       Dockerfile parser, pretty-printer and embedded DSL description:    All functions for parsing, printing and writting Dockerfiles are exported through @Language.Docker@. For more fine-grained operations look for specific modules that implement a certain functionality.                 See the <https://github.com/hadolint/language-docker GitHub project> for the source-code and examples.
src/Language/Docker.hs view
@@ -25,6 +25,12 @@     , Language.Docker.EDSL.label     , Language.Docker.EDSL.stopSignal     , Language.Docker.EDSL.copy+    , Language.Docker.EDSL.copyFromStage+    , Language.Docker.EDSL.to+    , Language.Docker.EDSL.fromStage+    , Language.Docker.EDSL.ownedBy+    , Language.Docker.EDSL.toSources+    , Language.Docker.EDSL.toTarget     , Language.Docker.EDSL.run     , Language.Docker.EDSL.runArgs     , Language.Docker.EDSL.cmd@@ -70,7 +76,8 @@     , Language.Docker.Syntax.AddArgs(..)     , Language.Docker.Syntax.Check(..)     , Language.Docker.Syntax.CheckArgs(..)-    , Language.Docker.Syntax.Image+    , Language.Docker.Syntax.Image(..)+    , Language.Docker.Syntax.Registry(..)     , Language.Docker.Syntax.ImageAlias(..)     , Language.Docker.Syntax.Tag     , Language.Docker.Syntax.Ports
src/Language/Docker/EDSL.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE TemplateHaskell #-}  module Language.Docker.EDSL where@@ -10,6 +13,7 @@ import Control.Monad.Writer import Data.ByteString (ByteString) import Data.List.NonEmpty (NonEmpty)+import Data.String (fromString)  import qualified Language.Docker.PrettyPrint as PrettyPrint import qualified Language.Docker.Syntax as Syntax@@ -85,28 +89,53 @@ -- 'Language.Docker.PrettyPrint' -- -- @--- import           Language.Docker+-- import Language.Docker -- -- main :: IO () -- main = writeFile "something.dockerfile" $ toDockerfileStr $ do --     from (tagged "fpco/stack-build" "lts-6.9") --     add ["."] "/app/language-docker" --     workdir "/app/language-docker"---     run (words "stack build --test --only-dependencies")---     cmd (words "stack test")+--     run "stack build --test --only-dependencies"+--     cmd "stack test" -- @ toDockerfileStr :: EDockerfileM a -> String toDockerfileStr = PrettyPrint.prettyPrint . toDockerfile +-- | Use a docker image in a FROM instruction without a tag+--+-- The following two examples are equivalent+--+-- @+-- from $ untagged "fpco/stack-build"+-- @+--+-- Is equivalent to, when having OverloadedStrings:+--+-- @+-- from "fpco/stack-build"+-- @ untagged :: String -> EBaseImage-untagged = flip EUntaggedImage Nothing+untagged = flip EUntaggedImage Nothing . fromString -tagged :: String -> String -> EBaseImage+-- | Use a specific tag for a docker image. This function is meant+-- to be used as an infix operator.+--+-- @+-- from $ "fpco/stack-build" `tagged` "lts-10.3"+-- @+tagged :: Syntax.Image -> String -> EBaseImage tagged imageName tag = ETaggedImage imageName tag Nothing -digested :: String -> ByteString -> EBaseImage+digested :: Syntax.Image -> ByteString -> EBaseImage digested imageName hash = EDigestedImage imageName hash Nothing +-- | Alias a FROM instruction to be used as a build stage.+-- This function is meant to be used as an infix operator.+--+-- @+-- from $ "fpco/stack-build" `aliased` "builder"+-- @ aliased :: EBaseImage -> String -> EBaseImage aliased image alias =     case image of@@ -114,6 +143,118 @@         ETaggedImage n t _ -> ETaggedImage n t (Just $ Syntax.ImageAlias alias)         EDigestedImage n h _ -> EDigestedImage n h (Just $ Syntax.ImageAlias alias) +-- | Create a RUN instruction with the given arguments.+--+-- @+-- run "apt-get install wget"+-- @+run :: MonadFree EInstruction m => Syntax.Arguments -> m ()+run = runArgs++-- | Create an ENTRYPOINT instruction with the given arguments.+--+-- @+-- entrypoint "/usr/local/bin/program --some-flag"+-- @+entrypoint :: MonadFree EInstruction m => Syntax.Arguments -> m ()+entrypoint = entrypointArgs++-- | Create a CMD instruction with the given arguments.+--+-- @+-- cmd "my-program --some-flag"+-- @+cmd :: MonadFree EInstruction m => Syntax.Arguments -> m ()+cmd = cmdArgs++-- | Create a COPY instruction. This function is meant to be+-- used with the compinators 'to', 'fromStage' and 'ownedBy'+--+-- @+-- copy $ ["foo.js", "bar.js"] `to` "."+-- copy $ ["some_file"] `to` "/some/path" `fromStage` "builder"+-- @+copy :: MonadFree EInstruction m => Syntax.CopyArgs -> m ()+copy (Syntax.CopyArgs sources dest ch src) = copyArgs sources dest ch src++-- | Create a COPY instruction from a given build stage.+-- This is a shorthand version of using 'copy' with combinators.+--+-- @+-- copyFromStage "builder" ["foo.js", "bar.js"] "."+-- @+copyFromStage ::+       MonadFree EInstruction m+    => Syntax.CopySource+    -> NonEmpty Syntax.SourcePath+    -> Syntax.TargetPath+    -> m ()+copyFromStage stage source dest = copy $ Syntax.CopyArgs source dest Syntax.NoChown stage++-- | Create an ADD instruction. This is often used as a shorthand version+-- of copy when no extra options are needed. Currently there is no way to+-- pass extra options to ADD, so you are encouraged to use 'copy' instead.+--+-- @+-- add ["foo.js", "bar.js"] "."+-- @+add :: MonadFree EInstruction m => NonEmpty Syntax.SourcePath -> Syntax.TargetPath -> m ()+add sources dest = addArgs sources dest Syntax.NoChown++-- | Converts a NonEmpty list of strings to a NonEmpty list of 'Syntax.SourcePath'+--+-- This is a convenience function when you need to pass a non-static list of+-- strings that you build somewhere as an argument for 'copy' or 'add'+--+-- @+-- someFiles <- glob "*.js"+-- copy $ (toSources someFiles) `to` "."+-- @+toSources :: NonEmpty String -> NonEmpty Syntax.SourcePath+toSources = fmap Syntax.SourcePath++-- | Converts a String into a 'Syntax.TargetPath'+--+-- This is a convenience function when you need to pass a string variable+-- as an argument for 'copy' or 'add'+--+-- @+-- let destination = buildSomePath pwd+-- add ["foo.js"] (toTarget destination)+-- @+toTarget :: String -> Syntax.TargetPath+toTarget = Syntax.TargetPath++-- | Adds the --from= option to a COPY instruction.+--+-- This function is meant to be used as an infix operator:+--+-- @+-- copy $ ["foo.js"] `to` "." `fromStage` "builder"+-- @+fromStage :: Syntax.CopyArgs -> Syntax.CopySource -> Syntax.CopyArgs+fromStage args src = args {Syntax.sourceFlag = src}++-- | Adds the --chown= option to a COPY instruction.+--+-- This function is meant to be used as an infix operator:+--+-- @+-- copy $ ["foo.js"] `to` "." `ownedBy` "www-data:www-data"+-- @+ownedBy :: Syntax.CopyArgs -> Syntax.Chown -> Syntax.CopyArgs+ownedBy args owner = args {Syntax.chownFlag = owner}++-- | Usedto join source paths with atarget path as an arguments for 'copy'+--+-- This function is meant to be used as an infix operator:+--+-- @+-- copy $ ["foo.js"] `to` "." `ownedBy`+-- @+to :: NonEmpty Syntax.SourcePath -> Syntax.TargetPath -> Syntax.CopyArgs+to sources dest = Syntax.CopyArgs sources dest Syntax.NoChown Syntax.NoSource+ ports :: [Syntax.Port] -> Syntax.Ports ports = Syntax.Ports @@ -129,26 +270,11 @@ portRange :: Integer -> Integer -> Syntax.Port portRange = Syntax.PortRange -run :: MonadFree EInstruction m => String -> m ()-run = runArgs . words--entrypoint :: MonadFree EInstruction m => String -> m ()-entrypoint = entrypointArgs . words--cmd :: MonadFree EInstruction m => String -> m ()-cmd = cmdArgs . words--copy :: MonadFree EInstruction m => NonEmpty Syntax.SourcePath -> Syntax.TargetPath -> m ()-copy sources dest = copyArgs sources dest Syntax.NoChown Syntax.NoSource--add :: MonadFree EInstruction m => NonEmpty Syntax.SourcePath -> Syntax.TargetPath -> m ()-add sources dest = addArgs sources dest Syntax.NoChown--check :: String -> Syntax.Check+check :: Syntax.Arguments -> Syntax.Check check command =     Syntax.Check         Syntax.CheckArgs-        { Syntax.checkCommand = words command+        { Syntax.checkCommand = command         , Syntax.interval = Nothing         , Syntax.timeout = Nothing         , Syntax.startPeriod = Nothing
src/Language/Docker/EDSL/Types.hs view
@@ -8,18 +8,18 @@ import qualified Language.Docker.Syntax as Syntax  data EBaseImage-    = EUntaggedImage String+    = EUntaggedImage Syntax.Image                      (Maybe Syntax.ImageAlias)-    | ETaggedImage String+    | ETaggedImage Syntax.Image                    String                    (Maybe Syntax.ImageAlias)-    | EDigestedImage String+    | EDigestedImage Syntax.Image                      ByteString                      (Maybe Syntax.ImageAlias)     deriving (Show, Eq, Ord)  instance IsString EBaseImage where-    fromString = flip EUntaggedImage Nothing+    fromString = flip EUntaggedImage Nothing . fromString  data EInstruction next     = From EBaseImage@@ -57,7 +57,8 @@                  next     | Env Syntax.Pairs           next-    | Arg String (Maybe String)+    | Arg String+          (Maybe String)           next     | Comment String               next
src/Language/Docker/Parser.hs view
@@ -32,13 +32,20 @@     text <- many (noneOf "\n")     return $ Comment text +registry :: Parser Registry+registry = do+    name <- many1 (noneOf "\t\n /")+    void $ char '/'+    return $ Registry name+ taggedImage :: Parser BaseImage taggedImage = do+    registryName <- (Just <$> try registry) <|> return Nothing     name <- many (noneOf "\t\n: ")     void $ char ':'     tag <- many1 (noneOf "\t\n: ")     maybeAlias <- maybeImageAlias-    return $ TaggedImage name tag maybeAlias+    return $ TaggedImage (Image registryName name) tag maybeAlias  digestedImage :: Parser BaseImage digestedImage = do@@ -46,15 +53,16 @@     void $ char '@'     digest <- many1 (noneOf "\t\n@ ")     maybeAlias <- maybeImageAlias-    return $ DigestedImage name (pack digest) maybeAlias+    return $ DigestedImage (Image Nothing name) (pack digest) maybeAlias  untaggedImage :: Parser BaseImage untaggedImage = do+    registryName <- (Just <$> try registry) <|> return Nothing     name <- many (noneOf "\n\t:@ ")     notInvalidTag name     notInvalidDigest name     maybeAlias <- maybeImageAlias-    return $ UntaggedImage name maybeAlias+    return $ UntaggedImage (Image registryName name) maybeAlias   where     notInvalidTag :: String -> Parser ()     notInvalidTag name =@@ -327,13 +335,15 @@  -- Parse arguments of a command in the exec form argumentsExec :: Parser Arguments-argumentsExec = brackets $ commaSep stringLiteral+argumentsExec = do+  args <- brackets $ commaSep stringLiteral+  return $ Arguments args  -- Parse arguments of a command in the shell form argumentsShell :: Parser Arguments argumentsShell = do     args <- untilEol-    return $ words args+    return $ Arguments (words args)  arguments :: Parser Arguments arguments = try argumentsExec <|> try argumentsShell
src/Language/Docker/PrettyPrint.hs view
@@ -8,7 +8,7 @@  import qualified Data.ByteString.Char8 as ByteString (unpack) import Data.List (foldl', intersperse)-import Data.List.NonEmpty (NonEmpty, toList)+import Data.List.NonEmpty as NonEmpty (NonEmpty(..), toList) import Data.String import Language.Docker.Syntax import Prelude hiding ((>>), (>>=), return)@@ -29,19 +29,23 @@ prettyPrintInstructionPos :: InstructionPos -> String prettyPrintInstructionPos (InstructionPos i _ _) = render (prettyPrintInstruction i) +prettyPrintImage :: Image -> Doc+prettyPrintImage (Image Nothing name) = text name+prettyPrintImage (Image (Just (Registry reg)) name) = text reg <> char '/' <> text name+ prettyPrintBaseImage :: BaseImage -> Doc prettyPrintBaseImage b =     case b of-        DigestedImage name digest alias -> do-            text name+        DigestedImage img digest alias -> do+            prettyPrintImage img             char '@'             text (ByteString.unpack digest)             prettyAlias alias-        UntaggedImage name alias -> do+        UntaggedImage (Image _ name) alias -> do             text name             prettyAlias alias-        TaggedImage name tag alias -> do-            text name+        TaggedImage img tag alias -> do+            prettyPrintImage img             char ':'             text tag             prettyAlias alias@@ -60,13 +64,13 @@ prettyPrintPair (k, v) = text k <> char '=' <> text (show v)  prettyPrintArguments :: Arguments -> Doc-prettyPrintArguments as = text (unwords (map helper as))+prettyPrintArguments (Arguments as) = text (unwords (map helper as))   where     helper "&&" = "\\\n &&"     helper a = a  prettyPrintJSON :: Arguments -> Doc-prettyPrintJSON as = brackets $ hsep $ intersperse comma $ map (doubleQuotes . text) as+prettyPrintJSON (Arguments as) = brackets $ hsep $ intersperse comma $ map (doubleQuotes . text) as  prettyPrintPort :: Port -> Doc prettyPrintPort (PortStr str) = text str@@ -76,7 +80,12 @@  prettyPrintFileList :: NonEmpty SourcePath -> TargetPath -> Doc prettyPrintFileList sources (TargetPath dest) =-    hsep $ [text s | SourcePath s <- toList sources] ++ [text dest]+    let ending =+            case (reverse dest, sources) of+                ('/':_, _) -> "" -- If the target ends with / then no extra ending is needed+                (_, _fst :| _snd:_) -> "/" -- More than one source means that the target should end in /+                _ -> ""+    in hsep $ [text s | SourcePath s <- toList sources] ++ [text dest <> text ending]  prettyPrintChown :: Chown -> Doc prettyPrintChown chown =
src/Language/Docker/Syntax.hs view
@@ -4,13 +4,31 @@ module Language.Docker.Syntax where  import Data.ByteString.Char8 (ByteString)+import Data.List (intercalate, isInfixOf) import Data.List.NonEmpty (NonEmpty)-import Data.String (IsString)+import Data.List.Split (endBy)+import Data.String (IsString(..)) import Data.Time.Clock (DiffTime) import GHC.Exts (IsList(..)) -type Image = String+data Image = Image+    { registryName :: Maybe Registry+    , imageName :: String+    } deriving (Show, Eq, Ord) +instance IsString Image where+    fromString img =+        if "/" `isInfixOf` img+            then let parts = endBy "/" img+                 in case parts of+                        registry:rest -> Image (Just (Registry registry)) (intercalate "/" rest)+                        _ -> Image Nothing img+            else Image Nothing img++newtype Registry =+    Registry String+    deriving (Show, Eq, Ord, IsString)+ type Tag = String  data Protocol@@ -68,11 +86,23 @@     | NoChown     deriving (Show, Eq, Ord) +instance IsString Chown where+    fromString ch =+        case ch of+            "" -> NoChown+            _ -> Chown ch+ data CopySource     = CopySource String     | NoSource     deriving (Show, Eq, Ord) +instance IsString CopySource where+    fromString src =+        case src of+            "" -> NoSource+            _ -> CopySource src+ newtype Duration = Duration     { durationTime :: DiffTime     } deriving (Show, Eq, Ord, Num)@@ -99,6 +129,18 @@     | NoCheck     deriving (Show, Eq, Ord) +newtype Arguments =+    Arguments [String]+    deriving (Show, Eq, Ord)++instance IsString Arguments where+  fromString = Arguments . words++instance IsList Arguments where+    type Item Arguments = String+    fromList = Arguments+    toList (Arguments ps) = ps+ data CheckArgs = CheckArgs     { checkCommand :: Arguments     , interval :: Maybe Duration@@ -107,7 +149,6 @@     , retries :: Maybe Retries     } deriving (Show, Eq, Ord) -type Arguments = [String]  type Pairs = [(String, String)] 
src/Language/Docker/Syntax/Lift.hs view
@@ -23,9 +23,15 @@  deriveLift ''Ports +deriveLift ''Registry++deriveLift ''Image+ deriveLift ''ImageAlias  deriveLift ''BaseImage++deriveLift ''Arguments  deriveLift ''Instruction 
test/Language/Docker/EDSL/QuasiSpec.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE QuasiQuotes #-} module Language.Docker.EDSL.QuasiSpec   where 
test/Language/Docker/EDSLSpec.hs view
@@ -60,10 +60,26 @@          it "parses and prints from aliases correctly" $ do             let r = prettyPrint $ toDockerfile $ do-                        from ("node" `tagged` "10.1" `aliased` "node-build")+                        from $ "node" `tagged` "10.1" `aliased` "node-build"                         run "echo foo"             r `shouldBe` unlines [ "FROM node:10.1 AS node-build"                                  , "RUN echo foo"+                                 ]++        it "parses and prints copy instructions" $ do+            let r = prettyPrint $ toDockerfile $ do+                        from "scratch"+                        copy $ ["foo.js"] `to` "bar.js"+                        copy $ ["foo.js", "bar.js"] `to` "."+                        copy $ ["foo.js", "bar.js"] `to` "baz/"+                        copy $ ["something"] `to` "crazy" `fromStage` "builder"+                        copy $ ["this"] `to` "that" `fromStage` "builder" `ownedBy` "www-data"+            r `shouldBe` unlines [ "FROM scratch"+                                 , "COPY foo.js bar.js"+                                 , "COPY foo.js bar.js ./"+                                 , "COPY foo.js bar.js baz/"+                                 , "COPY --from=builder something crazy"+                                 , "COPY --chown=www-data --from=builder this that"                                  ]      describe "toDockerfileStrIO" $
test/Language/Docker/ParserSpec.hs view
@@ -39,6 +39,14 @@             it "parse diggested image" $                 assertAst "FROM ubuntu@sha256:0ef2e08ed3fab AS foo" [From (DigestedImage "ubuntu" "sha256:0ef2e08ed3fab" (Just $ ImageAlias "foo"))] +        describe "parse FROM with registry" $ do+            it "registry without port" $+                assertAst "FROM foo.com/node" [From (UntaggedImage (Image (Just "foo.com") "node") Nothing)]+            it "parse with port and tag" $+                assertAst+                "FROM myregistry.com:5000/imagename:5.12-dev"+                [From (TaggedImage (Image (Just "myregistry.com:5000") "imagename") "5.12-dev" Nothing)]+         describe "parse LABEL" $ do             it "parse label" $ assertAst "LABEL foo=bar" [Label[("foo", "bar")]]             it "parse space separated label" $ assertAst "LABEL foo bar baz" [Label[("foo", "bar baz")]]@@ -137,7 +145,7 @@                 "HEALTHCHECK --interval=5m \\\nCMD curl -f http://localhost/"                 [Healthcheck $                     Check $-                      CheckArgs (words "curl -f http://localhost/") (Just $ fromInteger 300) Nothing Nothing Nothing+                      CheckArgs "curl -f http://localhost/" (Just 300) Nothing Nothing Nothing                 ]              it "parse healthcheck with retries" $@@ -145,7 +153,7 @@                 "HEALTHCHECK --retries=10 CMD curl -f http://localhost/"                 [Healthcheck $                     Check $-                      CheckArgs (words "curl -f http://localhost/") Nothing Nothing Nothing (Just $ Retries 10)+                      CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing (Just $ Retries 10)                 ]              it "parse healthcheck with timeout" $@@ -153,7 +161,7 @@                 "HEALTHCHECK --timeout=10s CMD curl -f http://localhost/"                 [Healthcheck $                     Check $-                      CheckArgs (words "curl -f http://localhost/") Nothing (Just $ fromInteger 10) Nothing Nothing+                      CheckArgs "curl -f http://localhost/" Nothing (Just 10) Nothing Nothing                 ]              it "parse healthcheck with start-period" $@@ -161,7 +169,7 @@                 "HEALTHCHECK --start-period=2m CMD curl -f http://localhost/"                 [Healthcheck $                     Check $-                      CheckArgs (words "curl -f http://localhost/") Nothing Nothing (Just $ fromInteger 120) Nothing+                      CheckArgs "curl -f http://localhost/" Nothing Nothing (Just 120) Nothing                 ]              it "parse healthcheck with all flags" $@@ -170,10 +178,10 @@                 [Healthcheck $                     Check $                       CheckArgs-                        (words "curl -f http://localhost/")-                        (Just $ fromInteger 5)-                        (Just $ fromInteger 60)-                        (Just $ fromInteger 2)+                        "curl -f http://localhost/"+                        (Just 5)+                        (Just 60)+                        (Just 2)                         (Just $ Retries 3)                 ] @@ -182,7 +190,7 @@                 "HEALTHCHECK CMD curl -f http://localhost/"                 [Healthcheck $                     Check $-                      CheckArgs (words "curl -f http://localhost/") Nothing Nothing Nothing Nothing+                      CheckArgs "curl -f http://localhost/" Nothing Nothing Nothing Nothing                 ]          describe "parse MAINTAINER" $ do