CurryInfo: cpm-3.3.0 / CPM.Options

classes:

              
documentation:
--------------------------------------------------------------------------------
--- This module defines the options of CPM and operations to process them.
--------------------------------------------------------------------------------
name:
CPM.Options
operations:
>.> addOpts applyEither applyParse checkOpts checkoutOpts cleanOpts configOpts defaultOptions depsOpts diffOpts docOpts execOpts infoOpts installOpts linkOpts listOpts newOpts optionParser readLogLevel readRcOption readVersion' searchOpts testOpts uninstallOpts updateOpts upgradeOpts uploadOpts
sourcecode:
module CPM.Options
 where

import Prelude hiding   ( (<|>) )
import Data.Char        ( toLower )
import Data.List        ( splitOn )

import Language.Curry.Resources ( curryPackagesDocURL )
import OptParse

import CPM.Helpers      ( stripEnclosing )
import CPM.Package      ( Version, readVersion )
import CPM.ErrorLogger

------------------------------------------------------------------------------

--- The global options of CPM.
data Options = Options
  { optLogLevel    :: LogLevel
  , optDefConfig   :: [(String,String)]
  , optShowVersion :: Bool
  , optWithTime    :: Bool
  , optCommand     :: Command }

--- The default options: no command, no timing, info log level
defaultOptions :: Options
defaultOptions = Options Info [] False False NoCommand

--- The CPM commands with their options.
data Command
  = NoCommand
  | Help
  | ConfigCmd  ConfigOptions
  | Deps       DepsOptions
  | Check      CheckOptions
  | Checkout   CheckoutOptions
  | Install    InstallOptions
  | Uninstall  UninstallOptions
  | PkgInfo    InfoOptions
  | Compiler   ExecOptions
  | Update     UpdateOptions
  | List       ListOptions
  | Search     SearchOptions
  | Upgrade    UpgradeOptions
  | Link       LinkOptions
  | Add        AddOptions
  | Exec       ExecOptions
  | Doc        DocOptions
  | Test       TestOptions
  | Diff       DiffOptions
  | Init
  | New        NewOptions
  | Clean      CleanOptions
  | Upload     UploadOptions

data ConfigOptions = ConfigOptions
  { configAll :: Bool  -- show also installed packages?
  }

data DepsOptions = DepsOptions
  { depsPath       :: Bool  -- show CURRYPATH only?
  , depsVSCode     :: Bool  -- set the full import path in the VS Code settings file
  , depsLangServer :: Bool  -- set the full import path into file .curry/language-server/paths.json
  , depsFull       :: Bool  -- show full tree in textual representation?
  , depsGraph      :: Bool  -- show dot graph instead of tree?
  , depsView       :: Bool  -- view dot graph with `dotviewcommand` of rc file?
  }

data CheckOptions = CheckOptions
  { chkInfo    :: Bool  -- show more information
  , chkSource  :: Bool  -- check source code with CurryCheck?
  }

data CheckoutOptions = CheckoutOptions
  { coPackage    :: String
  , coVersion    :: Maybe Version
  , coPrerelease :: Bool
  , coOutput     :: String }

data InstallOptions = InstallOptions
  { instTarget     :: Maybe String
  , instVersion    :: Maybe Version
  , instPrerelease :: Bool
  , instExecutable :: Bool
  , instExecOnly   :: Bool }

data UninstallOptions = UninstallOptions
  { uninstPackage :: Maybe String
  , uninstVersion :: Maybe Version }

data InfoOptions = InfoOptions
  { infoPackage :: Maybe String
  , infoVersion :: Maybe Version
  , infoAll     :: Bool
  , infoPlain   :: Bool  -- plain output, no bold/color
  }

data ListOptions = ListOptions
  { listVers   :: Bool   -- list all versions of each package
  , listSystem :: Bool   -- list package compatible with current Curry system
  , listCSV    :: Bool   -- list in CSV format
  , listCat    :: Bool   -- list all categories
  }

data SearchOptions = SearchOptions
  { searchQuery  :: String -- the term to search for
  , searchModule :: Bool   -- search for some module?
  , searchExec   :: Bool   -- search for some executable?
  }

data UpgradeOptions = UpgradeOptions
  { upgrTarget :: Maybe String }

data LinkOptions = LinkOptions
  { lnkSource :: String }

data AddOptions = AddOptions
  { addPackage    :: Bool
  , addDependency :: Bool
  , addSource     :: String
  , forceAdd      :: Bool
  }

data NewOptions = NewOptions
  { projectName :: String }

data CleanOptions = CleanOptions
  { cleanDeps   :: Bool }

data UpdateOptions = UpdateOptions
  { indexURLs     :: [String]   -- the URLs of additional index repositories
  , cleanCache    :: Bool       -- clean also repository cache?
  , downloadIndex :: Bool       -- download the index repository?
  , useRepoCache  :: Bool       -- use repository cache to create repository DB?
  , writeCSV      :: Bool       -- write also a CSV file of the repository DB?
  }

data UploadOptions = UploadOptions
  { setTag        :: Bool   -- set the tag in the current repository?
  , forceUpdate   :: Bool   -- force update if package with same version exists
  , uploadPublish :: Bool   -- publish (if allowed) the uploaded package?
  , uploadLogin   :: String -- Masala login name of the uploader
  , uploadPasswd  :: String -- Masala password of the uploader
  }

data ExecOptions = ExecOptions
  { exeCommand :: String   -- the command to be executed
  }

data DocOptions = DocOptions
  { docDir        :: Maybe String    -- documentation directory
  , docModules    :: Maybe [String]  -- modules to be documented
  , docReadme     :: Bool            -- generate README as HTML
  , docPrograms   :: Bool            -- generate documentation for programs
  , docManual     :: Bool            -- generate manual (if specified)
  , docGenImports :: Bool            -- generate documentation for imported pkgs
                                     -- (otherwise, use their standard docs)
  , docPackageURL :: String          -- the URL prefix where all repository
                                     -- packages are documented
}

data TestOptions = TestOptions
  { testModules   :: Maybe [String]  -- modules to be tested
  , testCompile   :: Bool            -- only compile modules?
  , testSafe      :: Bool            -- safe test? (no scripts, no I/O props)
  , testFile      :: String          -- file to write test statistics as CSV
  , testCheckOpts :: [String]        -- additional options passed to CurryCheck
  }

data DiffOptions = DiffOptions
  { diffVersion   :: Maybe Version   -- version to be compared
  , diffModules   :: Maybe [String]  -- modules to be compared
  , diffAPI       :: Bool            -- check API equivalence
  , diffBehavior  :: Bool            -- test behavior equivalence
  , diffGroundEqu :: Bool            -- test ground equivalence only
  , diffUseAna    :: Bool            -- use termination analysis for safe tests
  }

configOpts :: Options -> ConfigOptions
configOpts s = case optCommand s of
  ConfigCmd opts -> opts
  _              -> ConfigOptions False

depsOpts :: Options -> DepsOptions
depsOpts s = case optCommand s of
  Deps opts -> opts
  _         -> DepsOptions False False False False False False

checkOpts :: Options -> CheckOptions
checkOpts s = case optCommand s of
  Check opts -> opts
  _          -> CheckOptions False True

checkoutOpts :: Options -> CheckoutOptions
checkoutOpts s = case optCommand s of
  Checkout opts -> opts
  _             -> CheckoutOptions "" Nothing False ""

installOpts :: Options -> InstallOptions
installOpts s = case optCommand s of
  Install opts -> opts
  _            -> InstallOptions Nothing Nothing False True False

uninstallOpts :: Options -> UninstallOptions
uninstallOpts s = case optCommand s of
  Uninstall opts -> opts
  _              -> UninstallOptions Nothing Nothing

infoOpts :: Options -> InfoOptions
infoOpts s = case optCommand s of
  PkgInfo opts -> opts
  _            -> InfoOptions Nothing Nothing False False

listOpts :: Options -> ListOptions
listOpts s = case optCommand s of
  List opts -> opts
  _         -> ListOptions False False False False

searchOpts :: Options -> SearchOptions
searchOpts s = case optCommand s of
  Search opts -> opts
  _           -> SearchOptions "" False False

upgradeOpts :: Options -> UpgradeOptions
upgradeOpts s = case optCommand s of
  Upgrade opts -> opts
  _            -> UpgradeOptions Nothing

linkOpts :: Options -> LinkOptions
linkOpts s = case optCommand s of
  Link opts -> opts
  _         -> LinkOptions ""

addOpts :: Options -> AddOptions
addOpts s = case optCommand s of
  Add opts -> opts
  _        -> AddOptions False False "" False

newOpts :: Options -> NewOptions
newOpts s = case optCommand s of
  New opts -> opts
  _        -> NewOptions ""

cleanOpts :: Options -> CleanOptions
cleanOpts s = case optCommand s of
  Clean opts -> opts
  _          -> CleanOptions False

updateOpts :: Options -> UpdateOptions
updateOpts s = case optCommand s of
  Update opts -> opts
  _           -> UpdateOptions [] True True True False

uploadOpts :: Options -> UploadOptions
uploadOpts s = case optCommand s of
  Upload opts -> opts
  _           -> UploadOptions False False True "" ""

execOpts :: Options -> ExecOptions
execOpts s = case optCommand s of
  Exec opts -> opts
  _         -> ExecOptions ""

docOpts :: Options -> DocOptions
docOpts s = case optCommand s of
  Doc opts -> opts
  _        -> DocOptions Nothing Nothing True True True False
                         curryPackagesDocURL

testOpts :: Options -> TestOptions
testOpts s = case optCommand s of
  Test opts -> opts
  _         -> TestOptions Nothing False False "" []

diffOpts :: Options -> DiffOptions
diffOpts s = case optCommand s of
  Diff opts -> opts
  _         -> DiffOptions Nothing Nothing True True False True

readLogLevel :: String -> Either String LogLevel
readLogLevel s = case map toLower s of
  "debug" -> Right Debug
  "info"  -> Right Info
  "quiet" -> Right Quiet
  _       -> Left $ "Illegal verbosity value: " ++ s

readRcOption :: String -> Either String (String,String)
readRcOption s =
  let (option,value) = break (=='=') s
  in if null value then Left $ "Error in option definition: '=' missing"
                   else Right $ (option, stripEnclosing '"' '"' (tail value))

readVersion' :: String -> Either String Version
readVersion' s = case readVersion s of
  Nothing -> Left $ "'" ++ s ++ "' is not a valid version"
  Just  v -> Right v

applyEither :: [Options -> Either String Options] -> Options
            -> Either String Options
applyEither [] z = Right z
applyEither (f:fs) z = case f z of
  Left err -> Left err
  Right z' -> applyEither fs z'

applyParse :: [Options -> Either String Options] -> Either String Options
applyParse fs = applyEither fs defaultOptions

(>.>) :: Either String a -> (a -> b) -> Either String b
a >.> f = case a of
  Left err -> Left err
  Right  v -> Right $ f v

optionParser :: [String] -> ParseSpec (Options -> Either String Options)
optionParser allargs = optParser
  (   flag (\a -> Right $ a { optShowVersion = True })
        (  long "version"
        <> short "V"
        <> help "Show version and quit" )
  <.> option (\s a -> readLogLevel s >.> \ll -> a { optLogLevel = ll })
       (  long "verbosity"
       <> short "v"
       <> metavar "LEVEL"
       <> help "Log level for the application. Valid values: info|debug|quiet" )
  <.> option (\s a -> readRcOption s >.> \kv ->
                      a { optDefConfig = optDefConfig a ++ [kv] })
        (  long "define"
        <> short "d"
        <> metavar "DEFINITION"
        <> help "Overwrite definition of cpmrc file with 'option=value'." )
  <.> flag (\a -> Right $ a { optWithTime = True })
        (  long "time"
        <> short "t"
        <> help "Show elapsed time with every log output" )
  <.> commands (metavar "COMMAND")
        (   command "add"
              (help "Add a package (as dependency or to the local repository)")
              Right
              addArgs
        <|> command "check" (help "Check a package")
                    (\a -> Right $ a { optCommand = Check (checkOpts a) })
                    checkArgs
        <|> command "checkout" (help "Checkout a package") Right
                    (checkoutArgs Checkout)
        <|> command "clean" (help "Clean the current package")
                    (\a -> Right $ a { optCommand = Clean (cleanOpts a)})
                    cleanArgs
        <|>  command "config"
                    (help "Show current configuration of CPM")
                    (\a -> Right $ a { optCommand = ConfigCmd (configOpts a) })
                    configArgs
        <|> command "curry"
           (help "Load package spec and start Curry with correct dependencies.")
                 (\a -> Right $ a { optCommand = Compiler (execOpts a) })
                 curryArgs
        <|> command "deps" (help "Calculate and show dependencies")
                           (\a -> Right $ a { optCommand = Deps (depsOpts a) })
                           depsArgs
        <|> command "diff"
                    (help "Diff the current package against another version")
                    (\a -> Right $ a { optCommand = Diff (diffOpts a) })
                    diffArgs
        <|> command "doc"
           (help "Generation documentation for current package (with CurryDoc)")
                    (\a -> Right $ a { optCommand = Doc (docOpts a) })
                    docArgs
        <|> command "exec"
                    (help "Execute a command with the CURRYPATH set")
                    (\a -> Right $ a { optCommand = Exec (execOpts a) })
                    execArgs
        <|> command "help" (help "Show list of all commands and quit")
                           (\a -> Right $ a { optCommand = Help }) []
        <|> command "info" (help "Print package information")
                    (\a -> Right $ a { optCommand = PkgInfo (infoOpts a) })
                    infoArgs
        <|> command "init"
                    (help "Initialize the current directory as a package")
                    (\a -> Right $ a { optCommand = Init }) []
        <|> command "install" (help "Install a package with its dependencies.")
                     (\a -> Right $ a { optCommand = Install (installOpts a) })
                     installArgs
        <|> command "link" (help "Link a package to the local cache") Right
                    linkArgs
        <|> command "list" (help "List all packages of the repository")
                    (\a -> Right $ a { optCommand = List (listOpts a) })
                    listArgs
        <|> command "new" (help "Create a new package") Right newArgs
        <|> command "search" (help "Search the package repository") Right
                    searchArgs
        <|> command "test" (help "Test the current package (with CurryCheck)")
                    (\a -> Right $ a { optCommand = Test (testOpts a) })
                    testArgs
        <|> command "uninstall" (help "Uninstall a package")
                 (\a -> Right $ a { optCommand = Uninstall (uninstallOpts a) })
                 uninstallArgs
        <|> command "upgrade" (help "Upgrade one or more packages")
                    (\a -> Right $ a { optCommand = Upgrade (upgradeOpts a) })
                    upgradeArgs
        <|> command "update"
                    (help "Update the package index")
                    (\a -> Right $ a { optCommand = Update (updateOpts a) })
                    updateArgs
        <|> command "upload"
                    (help "Upload current package to Masala/CPM package server")
                    (\a -> Right $ a { optCommand = Upload (uploadOpts a) })
                    uploadArgs
        ) )
 where
  cleanArgs =
    flag (\a -> Right $ a { optCommand = Clean (cleanOpts a)
                                               { cleanDeps = True } })
         (  short "d"
         <> long "dependencies"
         <> help "Remove also dependencies in current package"
         <> optional )

  configArgs =
    flag (\a -> Right $ a { optCommand = ConfigCmd (configOpts a)
                                                   { configAll = True } })
         (  short "a"
         <> long "all"
         <> help "Show also names of installed packages"
         <> optional )

  depsArgs =
        flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsPath = True } })
             (  short "p"
             <> long "path"
             <> help "Show value of CURRYPATH only"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsVSCode = True } })
             (  short "c"
             <> long "code"
             <> help "Set full path in file '.vscode/settings.json'"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsLangServer = True } })
             (  short "l"
             <> long "language-server"
             <> help "Write full path into file '.curry/language-server/paths.json'"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsFull = True } })
             (  short "f"
             <> long "full"
             <> help "Show full dependency tree (with repeated packages)"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsGraph = True } })
             (  short "g"
             <> long "graph"
             <> help "Show dependencies as dot graph (in Graphviz format)"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Deps (depsOpts a)
                                                  { depsView = True } })
             (  short "v"
             <> long "viewgraph"
             <> help "View dependency graph (with 'dotviewcommand')"
             <> optional )

  checkArgs =
        flag (\a -> Right $ a { optCommand = Check (checkOpts a)
                                                   { chkInfo = True } })
             (  short "i"
             <> long "info"
             <> help "Show more information about the package"
             <> optional )
    <.> flag (\a -> Right $ a { optCommand = Check (checkOpts a)
                                                   { chkSource = False } })
             (  short "n"
             <> long "nosource"
             <> help "Do not check modules sources"
             <> optional )

  checkoutArgs cmd =
        arg (\s a -> Right $ a { optCommand = cmd (checkoutOpts a)
                                                  { coPackage = s } })
          (  metavar "PACKAGE"
          <> help "The package name" )
    <.> arg (\s a -> readVersion' s >.> \v ->
                     a { optCommand = cmd (checkoutOpts a)
                                          { coVersion = Just v } })
          (  metavar "VERSION"
          <> help "The package version"
          <> optional)
    <.> option (\s a -> Right $ a { optCommand =
                                     cmd (checkoutOpts a) { coOutput = s } })
          (  long "output"
          <> short "o"
          <> help "The directory to store the package (default: PACKAGE)"
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = cmd (checkoutOpts a)
                                                 { coPrerelease = True } })
          (  short "p"
          <> long "pre"
          <> help "Try pre-release versions when searching for newest version.")

  installArgs =
        arg (\s a -> Right $ a { optCommand = Install (installOpts a)
                                                      { instTarget = Just s } })
          (  metavar "TARGET"
          <> help "A package name or the path to a file"
          <> optional)
    <.> arg (\s a -> readVersion' s >.> \v ->
             a { optCommand = Install (installOpts a) { instVersion = Just v } })
          (  metavar "VERSION"
          <> help "The package version"
          <> optional)
    <.> flag (\a -> Right $ a { optCommand = Install (installOpts a)
                                               { instPrerelease = True } })
          (  short "p"
          <> long "pre"
          <> help "Try pre-release versions when searching for newest version.")
    <.> flag (\a -> Right $ a { optCommand = Install (installOpts a)
                                               { instExecutable = False } })
          (  short "n"
          <> long "noexec"
          <> help "Do not install executable.")
    <.> flag (\a -> Right $ a { optCommand = Install (installOpts a)
                                               { instExecOnly = True } })
          (  short "x"
          <> long "exec"
          <> help "Install executable only (do not re-install dependencies).")

  uninstallArgs =
        arg (\s a -> Right $ a { optCommand =
             Uninstall (uninstallOpts a) { uninstPackage = Just s } })
          (  metavar "PACKAGE"
          <> help "The package to be uninstalled"
          <> optional)
    <.> arg (\s a -> readVersion' s >.> \v ->
                     a { optCommand = Uninstall (uninstallOpts a)
                                                { uninstVersion = Just v } })
          (  metavar "VERSION"
          <> help "The version to be uninstalled"
          <> optional)

  newArgs =
   arg (\s a -> Right $ a { optCommand = New (newOpts a)
                                             { projectName = s } })
       (  metavar "PROJECT"
       <> help "The name of the new project" )

  curryArgs =
    rest (\_ a -> Right $ a { optCommand = Compiler (execOpts a)
                                            { exeCommand = unwords remargs } })
         (  metavar "ARGS"
         <> help "The options to pass to the compiler"
         <> optional )
    where
     remargs = tail (snd (break (=="curry") allargs))

  updateArgs =
    option (\s a -> let opts = updateOpts a
                    in Right $ a { optCommand = Update opts
                                     { indexURLs = s : indexURLs opts } })
         (  short "u"
         <> long "url"
         <> metavar "URL"
         <> help "URL of the central package index" )
    <.> flag (\a -> Right $ a { optCommand = Update (updateOpts a)
                                               { cleanCache = False } })
             (  short "c"
             <> long "clean"
             <> help "Do not clean global package cache" )
    <.> flag (\a -> Right $ a { optCommand = Update (updateOpts a)
                                               { downloadIndex = False } })
             (  short "d"
             <> long "download"
             <> help "Do not download the global repository index" )
    <.> flag (\a -> Right $ a { optCommand = Update (updateOpts a)
                                               { useRepoCache = False } })
             (  short "n"
             <> long "nocache"
             <> help "Do not download global repository cache files" )
    <.> flag (\a -> Right $ a { optCommand = Update (updateOpts a)
                                               { writeCSV = True } })
             (  short "w"
             <> long "writecsv"
             <> help "Write also a CSV file of the cache database" )

  uploadArgs =
       flag (\a -> Right $ a { optCommand =
                                 Upload (uploadOpts a) { setTag = True } })
            (  short "t"
            <> long "tag"
            <> help "Tag the git repository with current version" )
   <.> flag (\a -> Right $ a { optCommand =
                                 Upload (uploadOpts a) { forceUpdate = True } })
            (  short "f"
            <> long "force"
            <> help "Force, i.e., overwrite existing package version" )
   <.> flag (\a -> Right $ a { optCommand =
                                 Upload (uploadOpts a) { uploadPublish = False } })
            (  short "n"
            <> long "nopublish"
            <> help "Do not publish the uploaded package version" )
   <.> option (\s a -> Right $ a { optCommand =
                                    Upload (uploadOpts a) { uploadLogin = s } })
              (  long "login"
              <> short "l"
              <> help "The login name to Masala"
              <> optional )
   <.> option (\s a -> Right $ a { optCommand =
                                    Upload (uploadOpts a) { uploadPasswd = s } })
              (  long "password"
              <> short "p"
              <> help "The password for the Masala login"
              <> optional )

  execArgs =
    rest (\_ a -> Right $ a { optCommand = Exec (execOpts a)
                                            { exeCommand = unwords remargs } })
         (  metavar "CMD"
         <> help "The command to be executed."
         <> optional )
    where
     remargs = tail (snd (break (=="exec") allargs))

  infoArgs =
        arg (\s a -> Right $ a { optCommand = PkgInfo (infoOpts a)
                                                { infoPackage = Just s } })
          (  metavar "PACKAGE"
          <> help ("The package name. If no name is specified, CPM tries " ++
                   "to read a package specification in the current directory.")
          <> optional)
    <.> arg (\s a -> readVersion' s >.> \v -> a
                                 { optCommand = PkgInfo (infoOpts a)
                                                  { infoVersion = Just v } })
          (  metavar "VERSION"
          <> help ("The package version. If no version is specified, " ++
                   "CPM uses the latest version of the specified package.")
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = PkgInfo (infoOpts a)
                                               { infoAll = True } })
          (  short "a"
          <> long "all"
          <> help "Show all infos" )
    <.> flag (\a -> Right $ a { optCommand = PkgInfo (infoOpts a)
                                               { infoPlain = True } })
          (  short "p"
          <> long "plain"
          <> help "Plain output (no control characters for bold or colors)"
          <> optional )

  docArgs =
    option (\s a -> Right $ a { optCommand =
                                  Doc (docOpts a) { docDir = Just s } })
          (  long "docdir"
          <> short "d"
          <> help "The documentation directory (default: 'cdoc')"
          <> optional )
    <.>
    option (\s a -> Right $ a { optCommand = Doc (docOpts a)
                                      { docModules = Just $ splitOn "," s } })
          (  long "modules"
          <> short "m"
          <> help ("The modules to be documented, " ++
                   "separate multiple modules by comma")
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = Doc (docOpts a)
                                  { docManual = False, docPrograms = False } })
          (  short "r"
          <> long "readme"
          <> help "Generate only README as HTML"
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = Doc (docOpts a)
                                  { docManual = False, docReadme = False } })
          (  short "p"
          <> long "programs"
          <> help "Generate only program documentation (with CurryDoc)"
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = Doc (docOpts a)
                                  { docPrograms = False, docReadme = False } })
          (  short "t"
          <> long "text"
          <> help "Generate only manual (according to package specification)"
          <> optional )
    <.> flag (\a -> Right $ a { optCommand = Doc (docOpts a)
                                               { docGenImports = True } })
          (  short "f"
          <> long "full"
          <> help "Generate full program documentation (i.e., also imported packages)"
          <> optional )
    <.> option (\s a -> Right $ a { optCommand =
                                      Doc (docOpts a) { docPackageURL = s } })
          (  long "url"
          <> short "u"
          <> help ("The URL prefix where all repository packages are " ++
                   "documented. Default: " ++ curryPackagesDocURL)
          <> optional )

  testArgs =
    option (\s a -> Right $ a { optCommand = Test (testOpts a)
                                      { testModules = Just $ splitOn "," s } })
          (  long "modules"
          <> short "m"
          <> help "The modules to be tested, separate multiple modules by comma"
          <> optional )
    <.>
    flag (\a -> Right $ a { optCommand =
                              Test (testOpts a) { testCompile = True } })
         (  short "c"
         <> long "compile"
         <> help "Only compile modules (no tests with CurryCheck)"
         <> optional )
    <.>
    flag (\a -> Right $ a { optCommand =
                              Test (testOpts a) { testSafe = True } })
         (  short "s"
         <> long "safe"
         <> help "Safe test mode (no script tests, no I/O tests)"
         <> optional )
    <.>
    option (\s a -> Right $ a { optCommand =
                                  Test (testOpts a) { testFile = s } })
          (  long "file"
          <> short "f"
          <> help "File to store test statistics in CSV format"
          <> optional )
    <.>
    option (\s a -> Right $ a { optCommand =
                                  Test (testOpts a) { testCheckOpts =
                                            s : testCheckOpts (testOpts a) } })
          (  long "option"
          <> short "o"
          <> help "Option passed to CurryCheck (without prefix '--'!)"
          <> optional )

  diffArgs =
       arg (\s a -> readVersion' s >.> \v ->
                 a { optCommand = Diff (diffOpts a) { diffVersion = Just v } })
           (  metavar "VERSION"
           <> help ("The other package version. If no version is specified, " ++
                    "CPM diffs against the latest repository version.")
           <> optional )
   <.> option (\s a -> Right $ a { optCommand = Diff (diffOpts a)
                                     { diffModules = Just $ splitOn "," s } })
         (  long "modules"
         <> short "m"
         <> help "The modules to compare, separate multiple modules by comma"
         <> optional )
   <.> flag (\a -> Right $ a { optCommand = Diff (diffOpts a)
                          { diffAPI = True, diffBehavior = False } })
         (  long "api-only"
         <> short "a"
         <> help "Diff only the API")
   <.> flag (\a -> Right $ a { optCommand = Diff (diffOpts a)
                          { diffAPI = False, diffBehavior = True } })
         (  long "behavior-only"
         <> short "b"
         <> help "Diff only the behavior")
   <.> flag (\a -> Right $ a { optCommand = Diff (diffOpts a)
                                                   { diffGroundEqu = True } })
         (  long "ground"
         <> short "g"
         <> help "Check ground equivalence only when comparing behavior")
   <.> flag (\a -> Right $ a { optCommand = Diff (diffOpts a)
                                                   { diffUseAna = False } })
         (  long "unsafe"
         <> short "u"
         <> help
         "Do not use automatic termination analysis for safe behavior checking")

  listArgs =
        flag (\a -> Right $ a { optCommand =
                                  List (listOpts a) { listVers = True } })
          (  short "v"
          <> long "versions"
          <> help "List all versions" )
    <.> flag (\a -> Right $ a { optCommand =
                                  List (listOpts a) { listSystem = True } })
          (  short "s"
          <> long "system"
          <> help "List packages compatible with current compiler" )
    <.> flag (\a -> Right $ a { optCommand =
                                  List (listOpts a) { listCSV = True } })
          (  short "t"
          <> long "csv"
          <> help "Show in CSV table format" )
    <.> flag (\a -> Right $ a { optCommand =
                                  List (listOpts a) { listCat = True } })
          (  short "c"
          <> long "category"
          <> help "Show all categories" )

  searchArgs =
        flag (\a -> Right $ a { optCommand = Search (searchOpts a)
                                               { searchModule = True } })
             (  short "m"
             <> long "module"
             <> help "Search for an exported module" )
    <.> flag (\a -> Right $ a { optCommand = Search (searchOpts a)
                                               { searchExec = True } })
             (  short "x"
             <> long "exec"
             <> help "Search for the name of an executable" )
    <.> arg (\s a -> Right $ a { optCommand = Search (searchOpts a)
                                                { searchQuery = s } })
            (  metavar "QUERY"
            <> help "The search term" )

  upgradeArgs =
    arg (\s a -> Right $ a { optCommand = Upgrade (upgradeOpts a)
                                            { upgrTarget = Just s } })
        (  metavar "PACKAGE"
        <> help "The package to upgrade"
        <> optional )

  linkArgs =
    arg (\s a -> Right $ a { optCommand = Link (linkOpts a) { lnkSource = s } })
        (  metavar "SOURCE"
        <> help "The directory to link" )

  addArgs =
       flag (\a -> Right $ a { optCommand =
                                 Add (addOpts a) { addPackage = True } })
            (  short "p"
            <> long "package"
            <> help "Add a local package to the local repository" )
   <.> flag (\a -> Right $ a { optCommand =
                                 Add (addOpts a) { addDependency = True } })
            (  short "d"
            <> long "dependency"
            <> help "Add only dependency to the current package" )
   <.> flag (\a -> Right $ a { optCommand =
                                 Add (addOpts a) { forceAdd = True } })
            (  short "f"
            <> long "force"
            <> help "Force, i.e., overwrite existing package" )
   <.> arg (\s a -> Right $ a { optCommand =
                                  Add (addOpts a) { addSource = s } })
         (  metavar "PACKAGE"
         <> help "The package name (or directory for option '-p') to be added" )

------------------------------------------------------------------------------
types:
AddOptions CheckOptions CheckoutOptions CleanOptions Command ConfigOptions DepsOptions DiffOptions DocOptions ExecOptions InfoOptions InstallOptions LinkOptions ListOptions NewOptions Options SearchOptions TestOptions UninstallOptions UpdateOptions UpgradeOptions UploadOptions
unsafe:
safe