packages feed

b9 0.5.43 → 0.5.44

raw patch · 12 files changed

+406/−425 lines, 12 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- B9.Builder: buildArtifacts :: ArtifactGenerator -> B9Invokation String ()
- B9.Content.YamlObject: instance Data.Binary.Class.Binary Data.Aeson.Types.Internal.Value
- B9.Invokation: data B9Invokation res a
- B9.Invokation: doAfterConfiguration :: (Maybe a -> ReaderT B9Config IO a) -> B9Invokation a ()
- B9.Invokation: ignoreActionResults :: B9Invokation a () -> B9Invokation () ()
- B9.Invokation: instance Control.Monad.IO.Class.MonadIO (B9.Invokation.B9Invokation res)
- B9.Invokation: instance Control.Monad.State.Class.MonadState (B9.Invokation.InternalState res) (B9.Invokation.B9Invokation res)
- B9.Invokation: instance GHC.Base.Applicative (B9.Invokation.B9Invokation res)
- B9.Invokation: instance GHC.Base.Functor (B9.Invokation.B9Invokation res)
- B9.Invokation: instance GHC.Base.Monad (B9.Invokation.B9Invokation res)
- B9.Invokation: invokeB9 :: B9Invokation res () -> IO (Maybe res)
- B9.Invokation: mergeAfterConfigurationActionResults :: (Maybe a -> Maybe b -> ReaderT B9Config IO b) -> B9Invokation a () -> B9Invokation b ()
- B9.Invokation: modifyInvokationConfig :: (B9Config -> B9Config) -> B9Invokation a ()
- B9.Invokation: modifyPermanentConfig :: (B9Config -> B9Config) -> B9Invokation a ()
- B9.Invokation: overrideB9ConfigPath :: SystemPath -> B9Invokation a ()
- B9.Invokation: overrideWorkingDirectory :: FilePath -> B9Invokation a ()
+ B9.ArtifactGeneratorImpl: buildArtifacts :: ArtifactGenerator -> B9 String
+ B9.B9Config: askRuntimeConfig :: Monad m => B9ConfigAction m B9Config
+ B9.B9Config: data B9ConfigAction m a
+ B9.B9Config: execB9ConfigAction :: MonadIO m => B9ConfigAction m a -> B9ConfigOverride -> m a
+ B9.B9Config: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (B9.B9Config.B9ConfigAction m)
+ B9.B9Config: instance GHC.Base.Applicative m => GHC.Base.Applicative (B9.B9Config.B9ConfigAction m)
+ B9.B9Config: instance GHC.Base.Functor m => GHC.Base.Functor (B9.B9Config.B9ConfigAction m)
+ B9.B9Config: instance GHC.Base.Monad m => GHC.Base.Monad (B9.B9Config.B9ConfigAction m)
+ B9.B9Config: instance GHC.Show.Show B9.B9Config.B9ConfigOverride
+ B9.B9Config: invokeB9 :: MonadIO m => B9ConfigAction m a -> m a
+ B9.B9Config: localRuntimeConfig :: Monad m => (B9Config -> B9Config) -> B9ConfigAction m a -> B9ConfigAction m a
+ B9.B9Config: modifyPermanentConfig :: Monad m => Endo B9Config -> B9ConfigAction m ()
+ B9.B9Config: noB9ConfigOverride :: B9ConfigOverride
+ B9.B9Config: overrideB9Config :: (B9Config -> B9Config) -> B9ConfigOverride -> B9ConfigOverride
+ B9.B9Config: overrideB9ConfigPath :: SystemPath -> B9ConfigOverride -> B9ConfigOverride
+ B9.B9Config: overrideKeepBuildDirs :: Bool -> B9ConfigOverride -> B9ConfigOverride
+ B9.B9Config: overrideVerbosity :: LogLevel -> B9ConfigOverride -> B9ConfigOverride
+ B9.B9Config: overrideWorkingDirectory :: FilePath -> B9ConfigOverride -> B9ConfigOverride
+ B9.B9Monad: errorExitL :: String -> B9 ()
+ B9.Content.YamlObject: [_fromYamlObject] :: YamlObject -> Value
- B9: runAddRepo :: RemoteRepo -> B9Invokation Bool ()
+ B9: runAddRepo :: MonadIO m => RemoteRepo -> B9ConfigAction m ()
- B9: runBuildArtifacts :: [FilePath] -> B9Invokation String ()
+ B9: runBuildArtifacts :: MonadIO m => [FilePath] -> B9ConfigAction m String
- B9: runFormatBuildFiles :: [FilePath] -> B9Invokation Bool ()
+ B9: runFormatBuildFiles :: MonadIO m => [FilePath] -> m ()
- B9: runGcLocalRepoCache :: B9Invokation Bool ()
+ B9: runGcLocalRepoCache :: MonadIO m => B9ConfigAction m ()
- B9: runGcRemoteRepoCache :: B9Invokation Bool ()
+ B9: runGcRemoteRepoCache :: MonadIO m => B9ConfigAction m ()
- B9: runListSharedImages :: B9Invokation [SharedImage] ()
+ B9: runListSharedImages :: MonadIO m => B9ConfigAction m [SharedImage]
- B9: runLookupLocalSharedImage :: SharedImageName -> B9Invokation (Maybe SharedImageBuildId) ()
+ B9: runLookupLocalSharedImage :: MonadIO m => SharedImageName -> B9ConfigAction m (Maybe SharedImageBuildId)
- B9: runPull :: Maybe SharedImageName -> B9Invokation Bool ()
+ B9: runPull :: MonadIO m => Maybe SharedImageName -> B9ConfigAction m ()
- B9: runPush :: SharedImageName -> B9Invokation Bool ()
+ B9: runPush :: MonadIO m => SharedImageName -> B9ConfigAction m ()
- B9: runRun :: SharedImageName -> [String] -> B9Invokation String ()
+ B9: runRun :: MonadIO m => SharedImageName -> [String] -> B9ConfigAction m String
- B9: runShowVersion :: B9Invokation Bool ()
+ B9: runShowVersion :: MonadIO m => m ()
- B9.B9Config: b9ConfigToConfigParser :: B9Config -> ConfigParser -> Either CPError ConfigParser
+ B9.B9Config: b9ConfigToConfigParser :: B9Config -> Either CPError ConfigParser
- B9.B9Config: modifyConfigParser :: (B9Config -> B9Config) -> ConfigParser -> Either CPError ConfigParser
+ B9.B9Config: modifyConfigParser :: ConfigParser -> Endo B9Config -> Either CPError ConfigParser
- B9.B9Monad: run :: (Maybe a -> B9 a) -> B9Invokation a ()
+ B9.B9Monad: run :: MonadIO m => B9 a -> B9ConfigAction m a
- B9.Shake.Actions: b9InvokationAction :: B9Invokation a () -> Action a
+ B9.Shake.Actions: b9InvokationAction :: B9ConfigAction Action a -> B9ConfigOverride -> Action a
- B9.Shake.SharedImageRules: enableSharedImageRules :: Rules ()
+ B9.Shake.SharedImageRules: enableSharedImageRules :: B9ConfigOverride -> Rules ()

Files

b9.cabal view
@@ -1,5 +1,5 @@ name:                b9-version:             0.5.43+version:             0.5.44  synopsis:            A tool and library for building virtual machine images. @@ -75,7 +75,6 @@                    , B9.B9Config.LibVirtLXC                    , B9.B9Config.Repository                    , B9.B9Monad-                   , B9.Builder                    , B9.Content.AST                    , B9.Content.ErlangPropList                    , B9.Content.ErlTerms@@ -86,7 +85,6 @@                    , B9.DiskImages                    , B9.DSL                    , B9.ExecEnv-                   , B9.Invokation                    , B9.LibVirtLXC                    , B9.MBR                    , B9.PartitionTable
src/cli/Main.hs view
@@ -7,27 +7,34 @@  main :: IO () main = do-    b9Opts <- parseCommandLine-    result <- invokeB9 (applyB9RunParameters b9Opts)-    exit (maybe False (const True) result)-    where exit success = when (not success) (exitWith (ExitFailure 128))+    b9Opts  <- parseCommandLine+    applyB9RunParameters b9Opts + -- | A data structure that contains the `B9Invokation` -- as well as build parameters.-data B9RunParameters a =+data B9RunParameters =   B9RunParameters             B9ConfigOverride-            (B9Invokation a ())+            Cmd             BuildVariables -applyB9RunParameters :: B9RunParameters a -> B9Invokation a ()-applyB9RunParameters (B9RunParameters overrides action vars) = do-    modifyInvokationConfig-      (over envVars (++ vars) . const (overrides ^. customB9Config))-    mapM_ overrideB9ConfigPath (overrides ^. customB9ConfigPath)-    action+type Cmd = B9ConfigAction IO () -parseCommandLine :: IO (B9RunParameters ())+applyB9RunParameters :: B9RunParameters -> IO ()+applyB9RunParameters (B9RunParameters overrides act vars) =+    let cfg =+            noB9ConfigOverride+                &  customB9Config+                %~ ( over envVars (++ vars)+                   . const (overrides ^. customB9Config)+                   )+                &  maybe id+                         overrideB9ConfigPath+                         (overrides ^. customB9ConfigPath)+    in  execB9ConfigAction act cfg++parseCommandLine :: IO B9RunParameters parseCommandLine = execParser     ( info         (helper <*> (B9RunParameters <$> globals <*> cmds <*> buildVars))@@ -38,8 +45,8 @@         )     )   where-    b9HelpHeader =-        linebreak <> text ("B9 - a benign VM-Image build tool v. " ++ b9VersionString)+    b9HelpHeader = linebreak+        <> text ("B9 - a benign VM-Image build tool v. " ++ b9VersionString)   globals :: Parser B9ConfigOverride@@ -125,37 +132,50 @@         = let minLogLevel = if verbose                   then Just LogTrace                   else if quiet then Just LogError else Nothing-              b9cfg  = mempty & verbosity       .~ minLogLevel-                              & logFile         .~ logF-                              & profileFile     .~ profF-                              & buildDirRoot    .~ buildRoot-                              & keepTempDirs    .~ keep-                              & uniqueBuildDirs .~ not notUnique-                              & repository      .~ repo-                              & repositoryCache .~ (Path <$> mRepoCache)-+              b9cfg =+                  mempty+                      &  verbosity+                      .~ minLogLevel+                      &  logFile+                      .~ logF+                      &  profileFile+                      .~ profF+                      &  buildDirRoot+                      .~ buildRoot+                      &  keepTempDirs+                      .~ keep+                      &  uniqueBuildDirs+                      .~ not notUnique+                      &  repository+                      .~ repo+                      &  repositoryCache+                      .~ (Path <$> mRepoCache)           in  B9ConfigOverride                   { _customB9ConfigPath = Path <$> cfg-                  , _customB9Config = b9cfg+                  , _customB9Config     = b9cfg                   } -cmds :: Parser (B9Invokation () ())+cmds :: Parser Cmd cmds = subparser     (  command           "version"-          ( info (pure (ignoreActionResults runShowVersion))+          ( info (pure runShowVersion)                  (progDesc "Show program version and exit.")           )     <> command            "build"            ( info-               (ignoreActionResults . runBuildArtifacts <$> buildFileParser)+               (void . runBuildArtifacts <$> buildFileParser)+                (progDesc "Merge all build file and generate all artifacts.")            )     <> command            "run"            ( info-               (ignoreActionResults <$> (runRun <$> sharedImageNameParser <*> many (strArgument idm)))+               (   (\x y -> void (runRun x y))+               <$> sharedImageNameParser+               <*> many (strArgument idm)+               )                ( progDesc                    "Run a command on the lastest version of the specified shared image. All modifications are lost on exit."                )@@ -163,7 +183,7 @@     <> command            "push"            ( info-               (ignoreActionResults . runPush <$> sharedImageNameParser)+               (runPush <$> sharedImageNameParser)                ( progDesc                    "Push the lastest shared image from cache to the selected  remote repository."                )@@ -171,7 +191,7 @@     <> command            "pull"            ( info-               (ignoreActionResults . runPull <$> optional sharedImageNameParser)+               (runPull <$> optional sharedImageNameParser)                ( progDesc                    "Either pull shared image meta data from all repositories, or only from just a selected one. If additionally the name of a shared images was specified, pull the newest version from either the selected repo, or from the repo with the most recent version."                )@@ -179,7 +199,7 @@     <> command            "clean-local"            ( info-               (pure (ignoreActionResults runGcLocalRepoCache))+               (pure runGcLocalRepoCache)                ( progDesc                    "Remove old versions of shared images from the local cache."                )@@ -187,23 +207,24 @@     <> command            "clean-remote"            ( info-               (pure (ignoreActionResults runGcRemoteRepoCache))+               (pure runGcRemoteRepoCache)                ( progDesc                    "Remove cached meta-data of a remote repository. If no '-r' is given, clean the meta data of ALL remote repositories."                )            )     <> command            "list"-           (info (pure (ignoreActionResults runListSharedImages)) (progDesc "List shared images."))+           (info (pure (void runListSharedImages)) (progDesc "List shared images."))     <> command            "add-repo"-           ( info (ignoreActionResults . runAddRepo <$> remoteRepoParser)+           ( info (runAddRepo <$> remoteRepoParser)                   (progDesc "Add a remote repo.")            )     <> command            "reformat"-           ( info (ignoreActionResults . runFormatBuildFiles <$> buildFileParser)-                  (progDesc "Re-Format all build files.")+           ( info+               ( runFormatBuildFiles    <$> buildFileParser              )+               (progDesc "Re-Format all build files.")            )     ) @@ -267,4 +288,3 @@         <*> (   SharedImageName             <$> strArgument (help "Shared image name" <> metavar "NAME")             )-
src/lib/B9.hs view
@@ -25,25 +25,44 @@           , runLookupLocalSharedImage           , module X) where import Control.Applicative as X+import Control.Exception(throwIO, catch) import Control.Monad as X import Control.Monad.IO.Class as X-import Control.Exception(throwIO, catch)+import Control.Monad.Reader as X (ReaderT, local, ask)+import Control.Lens as X (Lens, (^.), (.~), (%~), (&)) import System.IO.Error (isDoesNotExistError) import System.Directory (removeFile)-import Data.Monoid as X+import Data.Function (on) import Data.List as X import Data.Maybe as X+import Data.Monoid as X import Text.Show.Pretty as X (ppShow) import System.Exit as X (exitWith, ExitCode(..)) import System.FilePath as X         (takeDirectory, takeFileName, replaceExtension, (</>), (<.>)) import Text.Printf as X (printf) import Data.Version as X-import B9.Builder as X-import B9.Invokation as X+import B9.B9Monad as X+import Data.ConfigFile.B9Extras as X+import B9.B9Config as X+import B9.ExecEnv as X+import B9.DiskImages as X+import B9.DiskImageBuilder as X+import B9.ShellScript as X+import B9.Repository as X+import B9.RepositoryIO as X+import B9.ArtifactGenerator as X+import B9.ArtifactGeneratorImpl as X+import B9.Vm as X+import B9.VmBuilder as X+import B9.QCUtil as X+import B9.Content.AST as X+import B9.Content.StringTemplate as X+import B9.Content.ErlTerms as X+import B9.Content.ErlangPropList as X+import B9.Content.YamlObject as X+import B9.Content.Generator as X import Paths_b9 (version)-import Data.Function (on)-import Control.Lens as Lens ((^.), over, (.~), (%~), set)  -- | Return the cabal package version of the B9 library. b9Version :: Version@@ -54,50 +73,61 @@ b9VersionString :: String b9VersionString = showVersion version -runShowVersion :: B9Invokation Bool ()-runShowVersion = doAfterConfiguration $ const $ do-  liftIO $ putStrLn b9VersionString-  return True+-- | Just print the 'b9VersionString'+runShowVersion :: MonadIO m => m ()+runShowVersion = liftIO $ putStrLn b9VersionString -runBuildArtifacts :: [FilePath] -> B9Invokation String ()+-- | Execute the artifact generators defined in a list of text files.+-- Read the text files in the list and parse them as 'ArtifactGenerator's+-- then 'mappend' them and apply 'buildArtifacts' to them.+runBuildArtifacts :: MonadIO m => [FilePath] -> B9ConfigAction m String runBuildArtifacts buildFiles = do   generators <- mapM consult buildFiles-  buildArtifacts (mconcat generators)+  run (buildArtifacts (mconcat generators)) -runFormatBuildFiles :: [FilePath] -> B9Invokation Bool ()-runFormatBuildFiles buildFiles = doAfterConfiguration $ const $ liftIO $ do+-- | Read all text files and parse them as 'ArtifactGenerator's.+-- Then overwrite the files with their contents but _pretty printed_+-- (i.e. formatted).+runFormatBuildFiles :: MonadIO m => [FilePath] -> m ()+runFormatBuildFiles buildFiles = liftIO $ do   generators <- mapM consult buildFiles   let generatorsFormatted = map ppShow (generators :: [ArtifactGenerator])-  putStrLn `mapM` (generatorsFormatted)-  (uncurry writeFile) `mapM` (buildFiles `zip` generatorsFormatted)-  return True--runPush :: SharedImageName -> B9Invokation Bool ()-runPush name = do-  modifyInvokationConfig (keepTempDirs .~ False)-  run $ const $ do-    conf <- getConfig-    if not (isJust (conf ^. repository))-      then do-        errorL-          "No repository specified! Use '-r' to specify a repo BEFORE 'push'."-        return False-      else do-        pushSharedImageLatestVersion name-        return True+  putStrLn `mapM` generatorsFormatted+  zipWithM_ writeFile buildFiles generatorsFormatted +-- | Upload a 'SharedImageName' to the default remote repository.+-- Note: The remote repository is specified in the 'B9Config'.+runPush :: MonadIO m => SharedImageName -> B9ConfigAction m ()+runPush name = localRuntimeConfig (keepTempDirs .~ False) $ run $ do+  conf <- getConfig+  if isNothing (conf ^. repository)+    then+      errorExitL+        "No repository specified! Use '-r' to specify a repo BEFORE 'push'."+    else+      pushSharedImageLatestVersion name -runPull :: Maybe SharedImageName -> B9Invokation Bool ()-runPull mName = do-  modifyInvokationConfig (keepTempDirs .~ False)-  run (const (pullRemoteRepos >> maybePullImage))-  where maybePullImage = maybe (return True) pullLatestImage mName+-- | Either pull a list of available 'SharedImageName's from the remote+-- repository if 'Nothing' is passed as parameter, or pull the latest version+-- of the image from the remote repository. Note: The remote repository is+-- specified in the 'B9Config'.+runPull :: MonadIO m => Maybe SharedImageName -> B9ConfigAction m ()+runPull mName =+  localRuntimeConfig (keepTempDirs .~ False)+                     (run (pullRemoteRepos >> maybePullImage))+  where maybePullImage =+          mapM_ (\name -> pullLatestImage name >>= failIfFalse name) mName+        failIfFalse _name True =+          return ()+        failIfFalse name False =+          errorExitL (printf "failed to pull: %s" (show name)) -runRun :: SharedImageName -> [String] -> B9Invokation String ()-runRun (SharedImageName name) cmdAndArgs = do-  modifyInvokationConfig-    (Lens.set keepTempDirs False . Lens.set interactive True)-  buildArtifacts runCmdAndArgs+-- | Execute an interactive root shell in a running container from a+-- 'SharedImageName'.+runRun :: MonadIO m => SharedImageName -> [String] -> B9ConfigAction m String+runRun (SharedImageName name) cmdAndArgs = localRuntimeConfig+  ((keepTempDirs .~ False) . (interactive .~ True))+  (run (buildArtifacts runCmdAndArgs))  where   runCmdAndArgs = Artifact     (IID ("run-" ++ name))@@ -111,28 +141,24 @@    where     cmdAndArgs' = if null cmdAndArgs then ["/usr/bin/zsh"] else cmdAndArgs --runGcLocalRepoCache :: B9Invokation Bool ()-runGcLocalRepoCache = do-  modifyInvokationConfig (keepTempDirs .~ False)-  impl+-- | Delete all obsolete versions of all 'SharedImageName's.+runGcLocalRepoCache :: MonadIO m => B9ConfigAction m ()+runGcLocalRepoCache = localRuntimeConfig (keepTempDirs .~ False) (run impl)  where-  impl = run $ const $ do-    toDelete <- (obsoleteSharedmages . map snd)-      <$> lookupSharedImages (== Cache) (const True)+  impl = do+    toDelete <- obsoleteSharedmages . map snd <$> lookupSharedImages+      (== Cache)+      (const True)     imgDir <- getSharedImagesCacheDir     let filesToDelete = (imgDir </>) <$> (infoFiles ++ imgFiles)         infoFiles     = sharedImageFileName <$> toDelete-        imgFiles      = (imageFileName . sharedImageImage) <$> toDelete+        imgFiles      = imageFileName . sharedImageImage <$> toDelete     if null filesToDelete-      then liftIO $ do-        putStrLn "\n\nNO IMAGES TO DELETE\n"-        return True+      then liftIO $ putStrLn "\n\nNO IMAGES TO DELETE\n"       else liftIO $ do         putStrLn "DELETING FILES:"         putStrLn (unlines filesToDelete)         mapM_ removeIfExists filesToDelete-        return True   obsoleteSharedmages :: [SharedImage] -> [SharedImage]   obsoleteSharedmages =     concatMap (tail . reverse) . filter ((> 1) . length) . groupBy@@ -143,56 +169,72 @@     handleExists e | isDoesNotExistError e = return ()                    | otherwise             = throwIO e -runGcRemoteRepoCache :: B9Invokation Bool ()-runGcRemoteRepoCache = do-  modifyInvokationConfig (keepTempDirs .~ False)-  run $ const $ do-    repos <- getSelectedRepos-    cache <- getRepoCache-    mapM_ (cleanRemoteRepo cache) repos-    return True+-- | Clear the shared image cache for a remote. Note: The remote repository is+-- specified in the 'B9Config'.+runGcRemoteRepoCache :: MonadIO m => B9ConfigAction m ()+runGcRemoteRepoCache = localRuntimeConfig+  (keepTempDirs .~ False)+  ( run+    ( do+      repos <- getSelectedRepos+      cache <- getRepoCache+      mapM_ (cleanRemoteRepo cache) repos+    )+  ) -runListSharedImages :: B9Invokation [SharedImage] ()-runListSharedImages = do-  modifyInvokationConfig (keepTempDirs .~ False)-  run $ const $ do-    remoteRepo <- getSelectedRemoteRepo-    let repoPred = maybe (== Cache) ((==) . toRemoteRepository) remoteRepo-    allRepos <- getRemoteRepos-    if isNothing remoteRepo-      then liftIO $ do-        putStrLn "Showing local shared images only."-        putStrLn-          $ "\nTo view the contents of a remote repo add \n\+-- | Print a list of shared images cached locally or remotely, if a remote+-- repository was selected. Note: The remote repository is+-- specified in the 'B9Config'.+runListSharedImages :: MonadIO m => B9ConfigAction m [SharedImage]+runListSharedImages = localRuntimeConfig+  (keepTempDirs .~ False)+  ( run+    ( do+      remoteRepo <- getSelectedRemoteRepo+      let repoPred = maybe (== Cache) ((==) . toRemoteRepository) remoteRepo+      allRepos <- getRemoteRepos+      if isNothing remoteRepo+        then liftIO $ do+          putStrLn "Showing local shared images only."+          putStrLn+            "\nTo view the contents of a remote repo add \n\                         \the '-r' switch with one of the remote \n\                         \repository ids."-      else liftIO $ putStrLn-        ("Showing shared images on: " ++ remoteRepoRepoId (fromJust remoteRepo))-    when (not (null allRepos)) $ liftIO $ do-      putStrLn "\nAvailable remote repositories:"-      mapM_ (putStrLn . (" * " ++) . remoteRepoRepoId) allRepos-    imgs <- lookupSharedImages repoPred (const True)-    if null imgs-      then liftIO $ putStrLn "\n\nNO SHARED IMAGES\n"-      else liftIO $ do-        putStrLn ""-        putStrLn $ prettyPrintSharedImages $ map snd imgs-    return $ map snd imgs-+        else liftIO $ putStrLn+          (  "Showing shared images on: "+          ++ remoteRepoRepoId (fromJust remoteRepo)+          )+      unless (null allRepos) $ liftIO $ do+        putStrLn "\nAvailable remote repositories:"+        mapM_ (putStrLn . (" * " ++) . remoteRepoRepoId) allRepos+      imgs <- lookupSharedImages repoPred (const True)+      if null imgs+        then liftIO $ putStrLn "\n\nNO SHARED IMAGES\n"+        else liftIO $ do+          putStrLn ""+          putStrLn $ prettyPrintSharedImages $ map snd imgs+      return (map snd imgs)+    )+  ) -runAddRepo :: RemoteRepo -> B9Invokation Bool ()+-- | Check the SSH settings for a remote repository and add it to the user wide+-- B9 configuration file.+runAddRepo :: MonadIO m => RemoteRepo -> B9ConfigAction m () runAddRepo repo = do   repo' <- remoteRepoCheckSshPrivKey repo   modifyPermanentConfig-    (  remoteRepos-    %~ ( mappend [repo']-       . filter ((== remoteRepoRepoId repo') . remoteRepoRepoId)-       )+    ( Endo+      (  remoteRepos+      %~ ( mappend [repo']+         . filter ((== remoteRepoRepoId repo') . remoteRepoRepoId)+         )+      )     ) +-- | Find the most recent version of a 'SharedImageName' in the local image cache. runLookupLocalSharedImage-  :: SharedImageName -> B9Invokation (Maybe SharedImageBuildId) ()-runLookupLocalSharedImage n = run $ const $ do+  :: MonadIO m => SharedImageName -> B9ConfigAction m (Maybe SharedImageBuildId)+runLookupLocalSharedImage n = run $ do   traceL (printf "Searching for cached image: %s" (show n))   imgs <- lookupSharedImages isAvailableOnLocalHost hasTheDesiredName   traceL "Candidate images: "
src/lib/B9/ArtifactGeneratorImpl.hs view
@@ -13,7 +13,6 @@ import B9.Content.StringTemplate import B9.Content.Generator import B9.Content.AST- import qualified Data.ByteString as B import qualified Data.Text as T import qualified Data.Text.Encoding as E@@ -32,6 +31,16 @@ import System.Directory import Text.Printf import Text.Show.Pretty (ppShow)++-- | Execute an 'ArtifactGenerator' and return a 'B9Invokation' that returns+-- the build id obtained by 'getBuildId'.+buildArtifacts :: ArtifactGenerator -> B9 String+buildArtifacts artifactGenerator = do+  traceL . ("CWD: " ++) =<< liftIO getCurrentDirectory+  infoL "BUILDING ARTIFACTS"+  getConfig >>= traceL . printf "USING BUILD CONFIGURATION: %v" . ppShow+  assemble artifactGenerator+  getBuildId  -- | Return a list of relative paths for the /local/ files to be generated -- by the ArtifactGenerator. This excludes 'Shared' and Transient image targets.
src/lib/B9/B9Config.hs view
@@ -17,8 +17,20 @@                    , libVirtLXCConfigs                    , remoteRepos                    , B9ConfigOverride(..)+                   , noB9ConfigOverride+                   , B9ConfigAction()+                   , execB9ConfigAction+                   , invokeB9+                   , askRuntimeConfig+                   , localRuntimeConfig+                   , modifyPermanentConfig                    , customB9Config                    , customB9ConfigPath+                   , overrideB9ConfigPath+                   , overrideB9Config+                   , overrideWorkingDirectory+                   , overrideVerbosity+                   , overrideKeepBuildDirs                    , defaultB9ConfigFile                    , defaultRepositoryCache                    , defaultB9Config@@ -38,16 +50,22 @@ import Data.Maybe (fromMaybe) import Control.Exception import Data.Function (on)+import Control.Lens as Lens (makeLenses, (^.), (.~), over, set)+import Control.Monad ((>=>)) import Control.Monad.IO.Class+import Control.Monad.Reader+import Control.Monad.Writer import System.Directory import qualified Data.Semigroup as Sem-import Data.Monoid import Data.List (partition, sortBy) import Data.ConfigFile.B9Extras+          ( SystemPath(..), ConfigParser, CPError, Get_C+          , OptionSpec, resolve, ensureDir, readIniFile+          , IniFileException(..), merge, to_string+          , add_section, emptyCP, setshow, get) import B9.B9Config.LibVirtLXC as X import B9.B9Config.Repository as X-import Control.Lens.TH-import Control.Monad ((>=>))+import Text.Printf (printf)  type BuildVariables = [(String,String)] @@ -98,11 +116,116 @@ data B9ConfigOverride = B9ConfigOverride   { _customB9ConfigPath :: Maybe SystemPath   , _customB9Config     :: B9Config-  }+  } deriving Show +-- | An empty default 'B9ConfigOverride' value, that will neither apply any+-- additional 'B9Config' nor change the path of the configuration file.+noB9ConfigOverride :: B9ConfigOverride+noB9ConfigOverride = B9ConfigOverride Nothing mempty+ makeLenses ''B9Config makeLenses ''B9ConfigOverride +-- | Convenience utility to override the B9 configuration file path.+overrideB9ConfigPath :: SystemPath -> B9ConfigOverride -> B9ConfigOverride+overrideB9ConfigPath p = customB9ConfigPath .~ Just p++-- | Modify the runtime configuration.+overrideB9Config+  :: (B9Config -> B9Config) -> B9ConfigOverride -> B9ConfigOverride+overrideB9Config = over customB9Config++-- | Define the current working directory to be used when building.+overrideWorkingDirectory :: FilePath -> B9ConfigOverride -> B9ConfigOverride+overrideWorkingDirectory p = customB9Config . buildDirRoot .~ Just p+++-- | Overwrite the 'verbosity' settings in the configuration with those given.+overrideVerbosity :: LogLevel -> B9ConfigOverride -> B9ConfigOverride+overrideVerbosity = overrideB9Config . Lens.set verbosity . Just++-- | Overwrite the 'keepTempDirs' flag in the configuration with those given.+overrideKeepBuildDirs :: Bool -> B9ConfigOverride -> B9ConfigOverride+overrideKeepBuildDirs = overrideB9Config . Lens.set keepTempDirs++-- | A monad that gives access to the (transient) 'B9Config' to be used to+-- _runtime_ with 'askRuntimeConfig' or 'localRuntimeConfig', and that allows+-- to write permanent 'B9Config' changes back to the configuration file using+-- 'modifyPermanentConfig'. Execute a 'B9ConfigAction' by invoking+-- either 'invokeB9' (which is simple) or 'execB9ConfigAction'.+newtype B9ConfigAction m a = B9ConfigAction+  { runB9ConfigAction :: ReaderT B9Config (WriterT [Endo B9Config] m) a}+  deriving ( Functor, Applicative, Monad, MonadIO )++-- | Return the runtime configuration, that should be the configuration merged+-- from all configuration sources. This is the configuration to be used during+-- a VM image build.+askRuntimeConfig :: Monad m => B9ConfigAction m B9Config+askRuntimeConfig = B9ConfigAction ask++-- | Run an action with an updated runtime configuration.+localRuntimeConfig+  :: Monad m+  => (B9Config -> B9Config)+  -> B9ConfigAction m a+  -> B9ConfigAction m a+localRuntimeConfig f = B9ConfigAction . local f . runB9ConfigAction++-- | Add a modification to the permanent configuration file.+modifyPermanentConfig :: Monad m => Endo B9Config -> B9ConfigAction m ()+modifyPermanentConfig f = B9ConfigAction (tell [f])++-- | Execute a 'B9ConfigAction'.+-- It will take a 'B9ConfigOverride' as input. The 'B9Config' in that value is+-- treated as the _runtime_ configuration, and the '_customConfigPath' is used+-- as the alternative location of the configuration file.+-- The configuration file is read from either the path in '_customB9ConfigPath'+-- or from 'defaultB9ConfigFile'.+-- Every modification done via 'modifyPermanentConfig' is applied to+-- the **contents** of the configuration file+-- and written back to that file, note that these changes are ONLY reflected+-- in the configuration file and **not** in the _runtime configuration_.+--+-- See also 'invokeB9', which does not need the 'B9ConfigOverride' parameter.+execB9ConfigAction :: MonadIO m => B9ConfigAction m a -> B9ConfigOverride -> m a+execB9ConfigAction act cfg = do+  let cfgPath = cfg ^. customB9ConfigPath+  cp <- openOrCreateB9Config cfgPath++  case parseB9Config cp of+    Left e -> do+      fail+        ( printf "Internal configuration load error, please report this: %s\n"+                 (show e)+        )++    Right permanentConfig -> do+      let runtimeCfg = permanentConfig Sem.<> (cfg ^. customB9Config)+      (res, permanentB9ConfigUpdates) <- runWriterT+        (runReaderT (runB9ConfigAction act) runtimeCfg)++      let cpExtErr = modifyConfigParser cp <$> permanentB9ConfigUpdate+          permanentB9ConfigUpdate = if null permanentB9ConfigUpdates+            then Nothing+            else Just (mconcat permanentB9ConfigUpdates)+      cpExt <- maybe+        (return Nothing)+        ( either+          ( fail+          . printf+              "Internal configuration update error! Please report this: %s\n"+          . show+          )+          (return . Just)+        )+        cpExtErr+      mapM_ (writeB9ConfigParser (cfg ^. customB9ConfigPath)) cpExt+      return res+-- | Run a 'B9ConfigAction' using 'noB9ConfigOverride'.+-- See 'execB9ConfigAction' for more details.+invokeB9 :: MonadIO m => B9ConfigAction m a -> m a+invokeB9 = flip execB9ConfigAction noB9ConfigOverride+ -- | Open the configuration file that contains the 'B9Config'. -- If the configuration does not exist, write a default configuration file, -- and create a all missing directories.@@ -115,7 +238,7 @@     if exists       then readIniFile (Path cfgFile)       else-        let res = b9ConfigToConfigParser defaultB9Config emptyCP+        let res = b9ConfigToConfigParser defaultB9Config         in  case res of               Left  e  -> throwIO (IniFileException cfgFile e)               Right cp -> writeFile cfgFile (to_string cp) >> return cp@@ -176,17 +299,16 @@  -- | Parse a 'B9Config', modify it, and merge it back to the given 'ConfigParser'. modifyConfigParser-  :: (B9Config -> B9Config) -> ConfigParser -> Either CPError ConfigParser-modifyConfigParser f cp = do+  :: ConfigParser -> Endo B9Config -> Either CPError ConfigParser+modifyConfigParser cp f = do   cfg <- parseB9Config cp-  cp2 <- b9ConfigToConfigParser (f cfg) emptyCP+  cp2 <- b9ConfigToConfigParser (appEndo f cfg)   return (merge cp cp2) --- | Append a config file section for the 'B9Config' to a 'ConfigParser'.-b9ConfigToConfigParser-  :: B9Config -> ConfigParser -> Either CPError ConfigParser-b9ConfigToConfigParser c cp = do-  cp1 <- add_section cp cfgFileSection+-- | Append a config file section for the 'B9Config' to an empty 'ConfigParser'.+b9ConfigToConfigParser :: B9Config -> Either CPError ConfigParser+b9ConfigToConfigParser c = do+  cp1 <- add_section emptyCP cfgFileSection   cp2 <- setshow cp1 cfgFileSection verbosityK (_verbosity c)   cp3 <- setshow cp2 cfgFileSection logFileK (_logFile c)   cp4 <- setshow cp3 cfgFileSection buildDirRootK (_buildDirRoot c)
src/lib/B9/B9Monad.hs view
@@ -7,20 +7,18 @@ This module is used by the _effectful_ functions in this library. -} module B9.B9Monad-       (B9, run, traceL, dbgL, infoL, errorL, getConfig,+       (B9, run, traceL, dbgL, infoL, errorL, errorExitL, getConfig,         getBuildId, getBuildDate, getBuildDir, getExecEnvType,         getSelectedRemoteRepo, getRemoteRepos, getRepoCache, cmd)        where  import B9.B9Config-import B9.Invokation import B9.Repository import Control.Applicative import Control.Exception (bracket) import Control.Monad import Control.Monad.IO.Class import Control.Monad.State-import Control.Monad.Reader(ask) import Control.Lens((&), (.~)) import qualified Data.ByteString.Char8 as B import Data.Functor ()@@ -57,14 +55,14 @@              String   deriving (Eq,Show) -run :: (Maybe a -> B9 a) -> B9Invokation a ()-run actionFunction = doAfterConfiguration $ \previousResult -> do-  cfg <- ask++run :: MonadIO m => B9 a -> B9ConfigAction m a+run action = do+  cfg <- askRuntimeConfig   liftIO $ do     buildId <- generateBuildId     now     <- getCurrentTime-    let action = actionFunction previousResult-    withBuildDir cfg buildId (withLogFile cfg . runImpl action cfg buildId now)+    withBuildDir cfg buildId (withLogFile cfg . runImpl cfg buildId now)  where   withLogFile cfg f = maybe     (f Nothing)@@ -72,38 +70,39 @@     (_logFile cfg)   withBuildDir cfg buildId =     bracket (createBuildDir cfg buildId) (removeBuildDir cfg)-  runImpl action cfg buildId now buildDir logFileHandle = do-    maybe (return ()) setCurrentDirectory (_buildDirRoot cfg)-    -- Check repositories-    repoCache <- initRepoCache-      (fromMaybe defaultRepositoryCache (_repositoryCache cfg))-    let buildDate = formatTime undefined "%F-%T" now-    remoteRepos' <- mapM (initRemoteRepo repoCache) (_remoteRepos cfg)-    let-      ctx = BuildState buildId-                       buildDate-                       (cfg & remoteRepos .~ remoteRepos')-                       buildDir-                       logFileHandle-                       selectedRemoteRepo-                       repoCache-                       []-                       now-                       (_interactive cfg)-      selectedRemoteRepo = do-        sel <- _repository cfg-        lookupRemoteRepo remoteRepos' sel <|> error-          ( printf-            "selected remote repo '%s' not configured, valid remote repos are: '%s'"-            sel-            (show remoteRepos')-          )-    (r, ctxOut) <- runStateT (runB9 (wrappedAction action)) ctx-    -- Write a profiling report-    when (isJust (_profileFile cfg)) $ writeFile-      (fromJust (_profileFile cfg))-      (unlines $ show <$> reverse (bsProf ctxOut))-    return r+  runImpl cfg buildId now buildDir logFileHandle =+    bracket getCurrentDirectory setCurrentDirectory $ \_ -> do+      traverse setCurrentDirectory (_buildDirRoot cfg)+      -- Check repositories+      repoCache <- initRepoCache+        (fromMaybe defaultRepositoryCache (_repositoryCache cfg))+      let buildDate = formatTime undefined "%F-%T" now+      remoteRepos' <- mapM (initRemoteRepo repoCache) (_remoteRepos cfg)+      let+        ctx = BuildState buildId+                         buildDate+                         (cfg & remoteRepos .~ remoteRepos')+                         buildDir+                         logFileHandle+                         selectedRemoteRepo+                         repoCache+                         []+                         now+                         (_interactive cfg)+        selectedRemoteRepo = do+          sel <- _repository cfg+          lookupRemoteRepo remoteRepos' sel <|> error+            ( printf+              "selected remote repo '%s' not configured, valid remote repos are: '%s'"+              sel+              (show remoteRepos')+            )+      (r, ctxOut) <- runStateT (runB9 wrappedAction) ctx+      -- Write a profiling report+      when (isJust (_profileFile cfg)) $ writeFile+        (fromJust (_profileFile cfg))+        (unlines $ show <$> reverse (bsProf ctxOut))+      return r   createBuildDir cfg buildId = if _uniqueBuildDirs cfg     then do       let subDir = "BUILD-" ++ buildId@@ -127,7 +126,7 @@       $ removeDirectoryRecursive buildDir   generateBuildId = printf "%08X" <$> (randomIO :: IO Word32)   -- Run the action build action-  wrappedAction action = do+  wrappedAction = do     startTime <- gets bsStartTime     r         <- action     now       <- liftIO getCurrentTime@@ -226,6 +225,9 @@ errorL :: String -> B9 () errorL = b9Log LogError +errorExitL :: String -> B9 ()+errorExitL e = b9Log LogError e >> fail e+ b9Log :: LogLevel -> String -> B9 () b9Log level msg = do   lv  <- gets $ _verbosity . bsCfg@@ -267,13 +269,3 @@        let durMS = IoActionDuration (stop `diffUTCTime` start)        modify $ \ctx -> ctx {bsProf = durMS : bsProf ctx}        return res----------
− src/lib/B9/Builder.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE GADTs #-}-{-|-Highest-level build functions and and B9-re-exports.--}-module B9.Builder (buildArtifacts, module X) where-import B9.B9Monad as X-import Data.ConfigFile.B9Extras as X-import B9.B9Config as X-import B9.ExecEnv as X-import B9.DiskImages as X-import B9.DiskImageBuilder as X-import B9.Invokation as X-import B9.ShellScript as X-import B9.Repository as X-import B9.RepositoryIO as X-import B9.ArtifactGenerator as X-import B9.ArtifactGeneratorImpl as X-import B9.Vm as X-import B9.VmBuilder as X-import B9.QCUtil as X-import B9.Content.AST as X-import B9.Content.StringTemplate as X-import B9.Content.ErlTerms as X-import B9.Content.ErlangPropList as X-import B9.Content.YamlObject as X-import B9.Content.Generator as X--import Text.Printf ( printf )-import Text.Show.Pretty (ppShow)-import Control.Monad.IO.Class-import System.Directory---- | Execute an 'ArtifactGenerator' and return a 'B9Invokation' that returns--- the build id obtained by 'getBuildId'.-buildArtifacts :: ArtifactGenerator -> B9Invokation String ()-buildArtifacts artifactGenerator = run $ const $ do-  traceL . ("CWD: " ++) =<< liftIO getCurrentDirectory-  infoL "BUILDING ARTIFACTS"-  getConfig >>= traceL . printf "USING BUILD CONFIGURATION: %v" . ppShow-  assemble artifactGenerator-  getBuildId
src/lib/B9/Content/YamlObject.hs view
@@ -28,18 +28,17 @@ -- | A wrapper type around yaml values with a Semigroup instance useful for -- combining yaml documents describing system configuration like e.g. user-data. data YamlObject =-    YamlObject Data.Yaml.Value+    YamlObject {_fromYamlObject :: Data.Yaml.Value}     deriving (Eq,Data,Typeable,Generic)  instance Hashable YamlObject-instance Binary YamlObject instance NFData YamlObject -instance Binary Data.Yaml.Value where-  put = put . encode+instance Binary YamlObject where+  put = put . encode . _fromYamlObject   get = do     v <- get-    return $ fromJust $ decode v+    return $ YamlObject $ fromJust $ decode v  instance Read YamlObject where   readsPrec _ = readsYamlObject
− src/lib/B9/Invokation.hs
@@ -1,161 +0,0 @@-module B9.Invokation ( B9Invokation()-                     , invokeB9-                     , overrideWorkingDirectory-                     , mergeAfterConfigurationActionResults-                     , ignoreActionResults-                     , doAfterConfiguration-                     , overrideB9ConfigPath-                     , modifyInvokationConfig-                     , modifyPermanentConfig) where--import B9.B9Config-import Data.ConfigFile.B9Extras-import Control.Monad.IO.Class-import Control.Monad.State-import Control.Monad.Reader-import Control.Lens-import Control.Exception (bracket)-import System.Directory (getCurrentDirectory, setCurrentDirectory)-import Data.Semigroup as Sem-import Data.Maybe (fromMaybe)-import Text.Printf ( printf )---- | A monad encapsulating all configuration adaptions happening before any actual--- build actions are performed. Use 'invokeB9' to execute these things.--- Inside the 'B9Invokation' monad you can influence and inspect the b9--- configuration, the permanent, as well as the transient.-newtype B9Invokation res a = B9Inv {runB9Invokation :: StateT (InternalState res) IO a}-  deriving (MonadState (InternalState res), Monad, Applicative, Functor, MonadIO)---- | Internal state of the 'B9Invokation'-data InternalState a = IS { _initialConfigOverride   :: B9ConfigOverride-                          , _permanentB9ConfigUpdate :: Maybe (ConfigParser -> Either CPError ConfigParser)-                          , _changeWorkingDirectory  :: Maybe FilePath-                          , _buildAction             :: Maybe (ReaderT B9Config IO a)-                          }--makeLenses ''InternalState--initialState :: InternalState a-initialState = IS (B9ConfigOverride Nothing mempty) Nothing Nothing Nothing---- | Run a 'B9Invokation'.--- If the user has no B9 config file yet, a default config file will be created.-invokeB9 :: B9Invokation res () -> IO (Maybe res)-invokeB9 act = do-    st <- execStateT (runB9Invokation act) initialState-    let cfgPath = st ^. initialConfigOverride . customB9ConfigPath-    cp0 <- openOrCreateB9Config cfgPath-    let cpExtErr = fmap ($ cp0) (st ^. permanentB9ConfigUpdate)-    cpExt <- maybe-        (return Nothing)-        ( either-            ( fail-            . printf "Internal configuration error! Please report this: %s\n"-            . show-            )-            (return . Just)-        )-        cpExtErr-    let cp = fromMaybe cp0 cpExt-    mapM_ (writeB9ConfigParser cfgPath) cpExt-    case parseB9Config cp of-        Left e -> fail (printf "Configuration error: %s\n" (show e))-        Right permanentConfig -> do-            let-                runtimeCfg =-                    permanentConfig-                        Sem.<> st-                        ^.     initialConfigOverride-                        .      customB9Config-                completeBuildAction = bracket-                    getCurrentDirectory-                    setCurrentDirectory-                    ( const-                        ( do-                            mapM_ setCurrentDirectory-                                  (st ^. changeWorkingDirectory)-                            runReaderT (sequence (st ^. buildAction)) runtimeCfg-                        )-                    )-            completeBuildAction---- | Add an action to be executed once the configuration has been done.--- The action will be called with the result of the previous action defined by--- this function. In case this is the first action added 'Nothing' is passed.-doAfterConfiguration :: (Maybe a -> ReaderT B9Config IO a) -> B9Invokation a ()-doAfterConfiguration action = buildAction %= appendOrSet-  where-    appendOrSet Nothing  = Just (action Nothing)-    appendOrSet (Just x) = Just (x >>= action . Just)---- | Combine the result of a given 'B9Invokation' and the results of the action--- defined by 'doAfterConfiguration' in the current state.-mergeAfterConfigurationActionResults-    :: (Maybe a -> Maybe b -> ReaderT B9Config IO b)-    -> B9Invokation a ()-    -> B9Invokation b ()-mergeAfterConfigurationActionResults f ba = do-    st <- liftIO $ execStateT (runB9Invokation ba) initialState-    let fb mbAction = Just $ do-            ma <- sequence (st ^. buildAction)-            mb <- sequence mbAction-            f ma mb-    buildAction %= fb---- | Ignore the results of the actions defined by 'doAfterConfiguration'.--- All actions will be executed, but the result will be replaced with '()'.-ignoreActionResults :: B9Invokation a () -> B9Invokation () ()-ignoreActionResults =-    mergeAfterConfigurationActionResults (const (const (return ())))---- | Override the B9 configuration path-overrideB9ConfigPath :: SystemPath -> B9Invokation a ()-overrideB9ConfigPath p = initialConfigOverride . customB9ConfigPath .= Just p---- | Override the current working directory during execution of the actions--- added with 'doAfterConfiguration'.-overrideWorkingDirectory :: FilePath -> B9Invokation a ()-overrideWorkingDirectory p = changeWorkingDirectory .= Just p---- | Modify the current 'B9Config'. The modifications are not reflected in the--- config file or the 'ConfigParser' returned by 'askInvokationConfigParser'.-modifyInvokationConfig :: (B9Config -> B9Config) -> B9Invokation a ()-modifyInvokationConfig f = initialConfigOverride . customB9Config %= f---- | Modify the current 'B9Config'. The modifications are not reflected in the--- config file or the 'ConfigParser' returned by 'askInvokationConfigParser'.-modifyPermanentConfig :: (B9Config -> B9Config) -> B9Invokation a ()-modifyPermanentConfig g = permanentB9ConfigUpdate %= go-  where-    go Nothing  = go (Just return)-    go (Just f) = Just (\cp -> f cp >>= modifyConfigParser g)-----------------------------
src/lib/B9/Shake/Actions.hs view
@@ -5,11 +5,11 @@ import Development.Shake.FilePath import B9 --- | Convert a 'B9Invokation' action into a Shake 'Action'.-b9InvokationAction :: B9Invokation a () -> Action a-b9InvokationAction invokationAction = do-    mres <- liftIO (invokeB9 invokationAction)-    maybe (fail "ERROR: Internal error while invoking a b9 action!") return mres+-- | Convert a 'B9Invokation' action into a Shake 'Action'. This is just+-- an alias for 'execB9ConfigAction' since 'Action' is an instance of 'MonadIO'+-- and 'execB9ConfigAction' work on any .+b9InvokationAction :: B9ConfigAction Action a -> B9ConfigOverride -> Action a+b9InvokationAction = execB9ConfigAction  -- | An action that does the equivalent of -- @b9c build -f <b9file> -- (args !! 0) (args !! 1) ... (args !! (length args - 1))@@@ -19,7 +19,8 @@ buildB9File b9Root b9File args = do     let f = b9Root </> b9File     need [f]-    b9InvokationAction $ do-        modifyInvokationConfig (appendPositionalArguments args)-        overrideWorkingDirectory b9Root-        runBuildArtifacts [f]+    invokeB9+        ( localRuntimeConfig+            (appendPositionalArguments args . (buildDirRoot .~ Just b9Root))+            (runBuildArtifacts [f])+        )
src/lib/B9/Shake/SharedImageRules.hs view
@@ -11,12 +11,11 @@ import qualified Data.ByteString.Lazy as LazyByteString import qualified Data.Binary as Binary import B9-import B9.Shake.Actions (b9InvokationAction)  -- | In order to use 'needSharedImage' and 'customSharedImageAction' you need to -- call this action before using any of the afore mentioned.-enableSharedImageRules :: Rules ()-enableSharedImageRules = addBuiltinRule noLint go+enableSharedImageRules :: B9ConfigOverride -> Rules ()+enableSharedImageRules b9inv = addBuiltinRule noLint go  where   go :: SharedImageName      -> Maybe ByteString.ByteString@@ -49,7 +48,7 @@               result = RunResult change newBuildIdBin newBuildId           return result     where-      getImgBuildId = b9InvokationAction (runLookupLocalSharedImage nameQ)+      getImgBuildId = execB9ConfigAction (runLookupLocalSharedImage nameQ) b9inv        decodeBuildId :: ByteString.ByteString -> SharedImageBuildId       decodeBuildId = Binary.decode . LazyByteString.fromStrict@@ -62,7 +61,7 @@         rules <- getUserRules         case userRuleMatch rules imgMatch of           [] -> fail $ "No rules to build B9 shared image " ++ show nameQ ++ " found"-          [act] -> act+          [act] -> act b9inv           _rs  -> fail $ "Multiple rules for the B9 shared image " ++ show nameQ ++ " found"         where           imgMatch (SharedImageCustomActionRule name mkImage) =@@ -81,9 +80,9 @@ customSharedImageAction b9img customAction =   addUserRule (SharedImageCustomActionRule b9img customAction')   where-    customAction' = do+    customAction' b9inv = do       customAction-      mCurrentBuildId <- b9InvokationAction (runLookupLocalSharedImage b9img)+      mCurrentBuildId <- execB9ConfigAction (runLookupLocalSharedImage b9img) b9inv       putLoud (printf "Finished custom action, for %s, build-id is: %s"                       (show b9img) (show mCurrentBuildId))       maybe (errorSharedImageNotFound b9img) return mCurrentBuildId@@ -92,7 +91,7 @@ type instance RuleResult SharedImageName = SharedImageBuildId  data SharedImageCustomActionRule =-  SharedImageCustomActionRule SharedImageName (Action SharedImageBuildId)+  SharedImageCustomActionRule SharedImageName (B9ConfigOverride -> Action SharedImageBuildId)   deriving Typeable  errorSharedImageNotFound :: Monad m => SharedImageName -> m a
stack.yaml view
@@ -2,6 +2,7 @@ packages: - '.' extra-deps: []-resolver: lts-11.0+resolver: lts-11.3 allow-newer: true # pvp-bounds: lower+require-stack-version: ">=1.6.5"