diff options
Diffstat (limited to 'src/Eval.hs')
| -rw-r--r-- | src/Eval.hs | 57 | 
1 files changed, 57 insertions, 0 deletions
| diff --git a/src/Eval.hs b/src/Eval.hs index a071770..1828468 100644 --- a/src/Eval.hs +++ b/src/Eval.hs @@ -1,18 +1,23 @@  module Eval (      EvalInput(..),      EvalError(..), textEvalError, +    Eval, runEval,      evalJob,      evalJobSet, +    evalJobReference,  ) where  import Control.Monad  import Control.Monad.Except +import Control.Monad.Reader  import Data.Bifunctor +import Data.List  import Data.Text (Text)  import Data.Text qualified as T +import Config  import Job.Types  import Repo @@ -27,6 +32,13 @@ data EvalError  textEvalError :: EvalError -> Text  textEvalError (OtherEvalError text) = text + +type Eval a = ReaderT EvalInput (ExceptT EvalError IO) a + +runEval :: Eval a -> EvalInput -> IO (Either EvalError a) +runEval action einput = runExceptT $ flip runReaderT einput action + +  evalJob :: EvalInput -> DeclaredJob -> Except EvalError Job  evalJob EvalInput {..} decl = do      otherCheckout <- forM (jobOtherCheckout decl) $ \( DeclaredJobRepo name, revision, checkout ) -> do @@ -52,3 +64,48 @@ evalJobSet ei decl = do          }    where      runExceptStr = first (T.unpack . textEvalError) . runExcept + + +canonicalJobName :: [ Text ] -> Config -> Eval [ JobIdPart ] +canonicalJobName (r : rs) config = do +    einput <- ask +    let name = JobName r +    case find ((name ==) . jobName) (configJobs config) of +        Just djob -> do +            job <- either throwError return $ runExcept $ evalJob einput djob +            let repos = nub $ map (\( EvaluatedJobRepo repo, _, _ ) -> repo) $ jobOtherCheckout job +            (JobIdName name :) <$> canonicalOtherCheckouts rs repos +        Nothing -> throwError $ OtherEvalError $ "job ‘" <> r <> "’ not found" +canonicalJobName [] _ = throwError $ OtherEvalError "expected job name" + +canonicalOtherCheckouts :: [ Text ] -> [ Repo ] -> Eval [ JobIdPart ] +canonicalOtherCheckouts (r : rs) (repo : repos) = do +    tree <- tryReadCommit repo r >>= \case +        Just commit -> getCommitTree commit +        Nothing -> tryReadTree repo r >>= \case +            Just tree -> return tree +            Nothing -> throwError $ OtherEvalError $ "failed to resolve ‘" <> r <> "’ to a commit or tree in " <> T.pack (show repo) +    (JobIdTree (treeId tree) :) <$> canonicalOtherCheckouts rs repos +canonicalOtherCheckouts []       []       = return [] +canonicalOtherCheckouts []       (_ : _ ) = throwError $ OtherEvalError $ "expected commit or tree reference" +canonicalOtherCheckouts (r : _)  []       = throwError $ OtherEvalError $ "unexpected job ref part ‘" <> r <> "’" + +canonicalCommitConfig :: [ Text ] -> Repo -> Eval [ JobIdPart ] +canonicalCommitConfig (r : rs) repo = do +    tree <- tryReadCommit repo r >>= \case +        Just commit -> getCommitTree commit +        Nothing -> tryReadTree repo r >>= \case +            Just tree -> return tree +            Nothing -> throwError $ OtherEvalError $ "failed to resolve ‘" <> r <> "’ to a commit or tree in " <> T.pack (show repo) +    config <- either fail return =<< loadConfigForCommit tree +    (JobIdTree (treeId tree) :) <$> canonicalJobName rs config +canonicalCommitConfig [] _ = throwError $ OtherEvalError "expected commit or tree reference" + +evalJobReference :: Config -> JobRef -> Eval JobId +evalJobReference config (JobRef rs) = +    fmap JobId $ do +        asks eiContainingRepo >>= \case +            Just defRepo -> do +                canonicalCommitConfig rs defRepo +            Nothing -> do +                canonicalJobName rs config |