summaryrefslogtreecommitdiff
path: root/src/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Main.hs')
-rw-r--r--src/Main.hs130
1 files changed, 104 insertions, 26 deletions
diff --git a/src/Main.hs b/src/Main.hs
index 971bffe..9e9214f 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -6,45 +6,75 @@ import Control.Monad.Reader
import Data.ByteString.Lazy qualified as BL
import Data.List
+import Data.List.NonEmpty qualified as NE
import Data.Proxy
import Data.Text qualified as T
import System.Console.GetOpt
+import System.Directory
import System.Environment
import System.Exit
+import System.FilePath
import System.IO
import Command
+import Command.Checkout
+import Command.JobId
import Command.Run
import Config
+import Repo
+import Terminal
import Version
data CmdlineOptions = CmdlineOptions
{ optShowHelp :: Bool
, optShowVersion :: Bool
+ , optCommon :: CommonOptions
+ , optStorage :: Maybe FilePath
}
defaultCmdlineOptions :: CmdlineOptions
defaultCmdlineOptions = CmdlineOptions
{ optShowHelp = False
, optShowVersion = False
+ , optCommon = defaultCommonOptions
+ , optStorage = Nothing
}
-options :: [OptDescr (CmdlineOptions -> CmdlineOptions)]
+options :: [ OptDescr (CmdlineOptions -> Except String CmdlineOptions) ]
options =
- [ Option ['h'] ["help"]
- (NoArg $ \opts -> opts { optShowHelp = True })
+ [ Option [ 'h' ] [ "help" ]
+ (NoArg $ \opts -> return opts { optShowHelp = True })
"show this help and exit"
- , Option ['V'] ["version"]
- (NoArg $ \opts -> opts { optShowVersion = True })
+ , Option [ 'V' ] [ "version" ]
+ (NoArg $ \opts -> return opts { optShowVersion = True })
"show version and exit"
+ , Option [ 'j' ] [ "jobs" ]
+ (ReqArg (\num opts -> return opts { optCommon = (optCommon opts) { optJobs = read num }}) "<num>")
+ ("number of jobs to run simultaneously (default " <> show (optJobs defaultCommonOptions) <> ")")
+ , Option [] [ "repo" ]
+ (ReqArg (\value opts ->
+ case span (/= ':') value of
+ ( repo, ':' : path ) -> return opts
+ { optCommon = (optCommon opts)
+ { optRepo = DeclaredRepo (RepoName $ T.pack repo) path : optRepo (optCommon opts)
+ }
+ }
+ _ -> throwError $ "--repo: invalid value `" <> value <> "'"
+ ) "<repo>:<path>")
+ ("override or declare repo path")
+ , Option [] [ "storage" ]
+ (ReqArg (\value opts -> return opts { optStorage = Just value }) "<path>")
+ "set storage path"
]
data SomeCommandType = forall c. Command c => SC (Proxy c)
-commands :: [ SomeCommandType ]
+commands :: NE.NonEmpty SomeCommandType
commands =
- [ SC $ Proxy @RunCommand
+ ( SC $ Proxy @RunCommand) NE.:|
+ [ SC $ Proxy @CheckoutCommand
+ , SC $ Proxy @JobIdCommand
]
lookupCommand :: String -> Maybe SomeCommandType
@@ -55,25 +85,40 @@ lookupCommand name = find p commands
main :: IO ()
main = do
args <- getArgs
- (opts, cmdargs) <- case getOpt RequireOrder options args of
- (o, cmdargs, []) -> return (foldl (flip id) defaultCmdlineOptions o, cmdargs)
+ let ( mbConfigPath, args' ) = case args of
+ (path : rest)
+ | any isPathSeparator path -> ( Just path, rest )
+ _ -> ( Nothing, args )
+
+ (opts, cmdargs) <- case getOpt RequireOrder options args' of
+ (os, cmdargs, []) -> do
+ let merge :: ([String], CmdlineOptions) -> (CmdlineOptions -> Except String CmdlineOptions) -> ([String], CmdlineOptions)
+ merge ( errs, o ) f = case runExcept $ f o of
+ Left err -> ( err : errs, o )
+ Right o' -> ( errs, o' )
+
+ case foldl merge ( [], defaultCmdlineOptions ) os of
+ ( [], opts ) -> return ( opts , cmdargs )
+ ( errs, _ ) -> do
+ hPutStrLn stderr $ unlines (reverse errs) <> "Try `minici --help' for more information."
+ exitFailure
(_, _, errs) -> do
hPutStrLn stderr $ concat errs <> "Try `minici --help' for more information."
exitFailure
when (optShowHelp opts) $ do
- let header = "Usage: minici [<option>...] <command> [<args>]\n\nCommon options are:"
+ let header = "Usage: minici [<job-file>] [<option>...] <command> [<args>]\n\nCommon options are:"
commandDesc (SC proxy) = " " <> padCommand (commandName proxy) <> commandDescription proxy
padTo n str = str <> replicate (n - length str) ' '
padCommand = padTo (maxCommandNameLength + 3)
commandNameLength (SC proxy) = length $ commandName proxy
- maxCommandNameLength = maximum $ map commandNameLength commands
+ maxCommandNameLength = maximum $ fmap commandNameLength commands
putStr $ usageInfo header options <> unlines (
[ ""
, "Available commands:"
- ] ++ map commandDesc commands
+ ] ++ map commandDesc (NE.toList commands)
)
exitSuccess
@@ -81,8 +126,17 @@ main = do
putStrLn versionLine
exitSuccess
- (ncmd, cargs) <- case cmdargs of
- [] -> return (head commands, [])
+ ( configPath, cmdargs' ) <- case ( mbConfigPath, cmdargs ) of
+ ( Just path, _ )
+ -> return ( Just path, cmdargs )
+ ( _, path : rest )
+ | any isPathSeparator path
+ -> return ( Just path, rest )
+ _ -> ( , cmdargs ) <$> findConfig
+
+ ( ncmd, cargs ) <- case cmdargs' of
+ [] -> return ( NE.head commands, [] )
+
(cname : cargs)
| Just nc <- lookupCommand cname -> return (nc, cargs)
| otherwise -> do
@@ -92,7 +146,7 @@ main = do
]
exitFailure
- runSomeCommand ncmd cargs
+ runSomeCommand configPath opts ncmd cargs
data FullCommandOptions c = FullCommandOptions
{ fcoSpecific :: CommandOptions c
@@ -114,8 +168,10 @@ fullCommandOptions proxy =
"show this help and exit"
]
-runSomeCommand :: SomeCommandType -> [ String ] -> IO ()
-runSomeCommand (SC tproxy) args = do
+runSomeCommand :: Maybe FilePath -> CmdlineOptions -> SomeCommandType -> [ String ] -> IO ()
+runSomeCommand ciConfigPath gopts (SC tproxy) args = do
+ let ciOptions = optCommon gopts
+ ciStorageDir = optStorage gopts
let exitWithErrors errs = do
hPutStrLn stderr $ concat errs <> "Try `minici " <> commandName tproxy <> " --help' for more information."
exitFailure
@@ -132,12 +188,34 @@ runSomeCommand (SC tproxy) args = do
putStr $ usageInfo (T.unpack $ commandUsage tproxy) (fullCommandOptions tproxy)
exitSuccess
- Just configPath <- findConfig
- BL.readFile configPath >>= return . parseConfig >>= \case
- Left err -> do
- putStr err
- exitFailure
- Right config -> do
- let cmd = commandInit tproxy (fcoSpecific opts) cmdargs
- let CommandExec exec = commandExec cmd
- flip runReaderT config exec
+ ciConfig <- case ciConfigPath of
+ Just path -> parseConfig <$> BL.readFile path
+ Nothing -> return $ Left "no job file found"
+
+ let cmd = commandInit tproxy (fcoSpecific opts) cmdargs
+ let CommandExec exec = commandExec cmd
+
+ ciContainingRepo <- maybe (return Nothing) (openRepo . takeDirectory) ciConfigPath
+
+ let openDeclaredRepo dir decl = do
+ let path = dir </> repoPath decl
+ openRepo path >>= \case
+ Just repo -> return ( repoName decl, repo )
+ Nothing -> do
+ absPath <- makeAbsolute path
+ hPutStrLn stderr $ "Failed to open repo `" <> showRepoName (repoName decl) <> "' at " <> repoPath decl <> " (" <> absPath <> ")"
+ exitFailure
+
+ cmdlineRepos <- forM (optRepo ciOptions) (openDeclaredRepo "")
+ configRepos <- case ( ciConfigPath, ciConfig ) of
+ ( Just path, Right config ) ->
+ forM (configRepos config) $ \decl -> do
+ case lookup (repoName decl) cmdlineRepos of
+ Just repo -> return ( repoName decl, repo )
+ Nothing -> openDeclaredRepo (takeDirectory path) decl
+ _ -> return []
+
+ let ciOtherRepos = configRepos ++ cmdlineRepos
+
+ ciTerminalOutput <- initTerminalOutput
+ flip runReaderT CommandInput {..} exec