PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/aura/exec/Flags.hs

http://github.com/fosskers/aura
Haskell | 547 lines | 467 code | 65 blank | 15 comment | 7 complexity | 2866f616fe0022ec8ec7ac74cad29a55 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-4.0
  1. module Flags
  2. ( Program(..), opts
  3. , PacmanOp( Sync ), SyncOp( SyncUpgrade ), SyncSwitch(..), MiscOp
  4. , AuraOp(..), AurSwitch(..), _AurSync, _AurIgnore, _AurIgnoreGroup
  5. , AurOp(..), BackupOp(..), CacheOp(..), LogOp(..), OrphanOp(..)
  6. ) where
  7. import Aura.Cache (defaultPackageCache)
  8. import Aura.Pacman (defaultLogFile, pacmanConfFile)
  9. import Aura.Settings
  10. import Aura.Types
  11. import Lens.Micro (Traversal')
  12. import Options.Applicative
  13. import RIO hiding (exp, log)
  14. import RIO.FilePath
  15. import RIO.List.Partial (foldr1)
  16. import qualified RIO.NonEmpty as NEL
  17. import qualified RIO.NonEmpty.Partial as NELP
  18. import qualified RIO.Set as S
  19. import qualified RIO.Text as T
  20. ---
  21. -- | A description of a run of Aura to attempt.
  22. data Program = Program {
  23. _operation :: Either (PacmanOp, Set MiscOp) AuraOp
  24. -- ^ Whether Aura handles everything, or the ops and input are just passed down to Pacman.
  25. , _commons :: CommonConfig
  26. -- ^ Settings common to both Aura and Pacman.
  27. , _buildConf :: BuildConfig
  28. -- ^ Settings specific to building packages.
  29. , _language :: Maybe Language
  30. -- ^ The human language of text output.
  31. , _logLevel :: LogLevel
  32. -- ^ The default RIO logging level.
  33. } deriving (Show)
  34. -- | Inherited operations that are fed down to Pacman.
  35. data PacmanOp = Database (Either DatabaseOp (NonEmpty PkgName))
  36. | Files (Set FilesOp)
  37. | Query (Either QueryOp (Set QueryFilter, Set PkgName))
  38. | Remove (Set RemoveOp) (NonEmpty PkgName)
  39. | Sync (Either (NonEmpty SyncOp) (Set PkgName)) (Set SyncSwitch)
  40. | TestDeps (NonEmpty Text)
  41. | Upgrade (Set UpgradeSwitch) (NonEmpty PkgName)
  42. deriving (Show)
  43. instance Flagable PacmanOp where
  44. asFlag (Database (Left o)) = "-D" : asFlag o
  45. asFlag (Database (Right fs)) = "-D" : asFlag fs
  46. asFlag (Files os) = "-F" : asFlag os
  47. asFlag (Query (Left o)) = "-Q" : asFlag o
  48. asFlag (Query (Right (fs, ps))) = "-Q" : asFlag ps ++ asFlag fs
  49. asFlag (Remove os ps) = "-R" : asFlag os ++ asFlag ps
  50. asFlag (Sync (Left o) ss) = "-S" : asFlag ss ++ asFlag o
  51. asFlag (Sync (Right ps) ss) = "-S" : asFlag ss ++ asFlag ps
  52. asFlag (TestDeps ps) = "-T" : asFlag ps
  53. asFlag (Upgrade s ps) = "-U" : asFlag s ++ asFlag ps
  54. data DatabaseOp = DBCheck
  55. | DBAsDeps (NonEmpty Text)
  56. | DBAsExplicit (NonEmpty Text)
  57. deriving (Show)
  58. instance Flagable DatabaseOp where
  59. asFlag DBCheck = ["--check"]
  60. asFlag (DBAsDeps ps) = "--asdeps" : asFlag ps
  61. asFlag (DBAsExplicit ps) = "--asexplicit" : asFlag ps
  62. data FilesOp = FilesList (NonEmpty Text)
  63. | FilesOwns Text
  64. | FilesSearch Text
  65. | FilesRegex
  66. | FilesRefresh
  67. | FilesMachineReadable
  68. deriving (Eq, Ord, Show)
  69. instance Flagable FilesOp where
  70. asFlag (FilesList fs) = "--list" : asFlag fs
  71. asFlag (FilesOwns f) = ["--owns", f]
  72. asFlag (FilesSearch f) = ["--search", f]
  73. asFlag FilesRegex = ["--regex"]
  74. asFlag FilesRefresh = ["--refresh"]
  75. asFlag FilesMachineReadable = ["--machinereadable"]
  76. data QueryOp = QueryChangelog (NonEmpty Text)
  77. | QueryGroups (NonEmpty Text)
  78. | QueryInfo (NonEmpty Text)
  79. | QueryCheck (NonEmpty Text)
  80. | QueryList (NonEmpty Text)
  81. | QueryOwns (NonEmpty Text)
  82. | QueryFile (NonEmpty Text)
  83. | QuerySearch Text
  84. deriving (Show)
  85. instance Flagable QueryOp where
  86. asFlag (QueryChangelog ps) = "--changelog" : asFlag ps
  87. asFlag (QueryGroups ps) = "--groups" : asFlag ps
  88. asFlag (QueryInfo ps) = "--info" : asFlag ps
  89. asFlag (QueryCheck ps) = "--check" : asFlag ps
  90. asFlag (QueryList ps) = "--list" : asFlag ps
  91. asFlag (QueryOwns ps) = "--owns" : asFlag ps
  92. asFlag (QueryFile ps) = "--file" : asFlag ps
  93. asFlag (QuerySearch t) = ["--search", t]
  94. data QueryFilter = QueryDeps
  95. | QueryExplicit
  96. | QueryForeign
  97. | QueryNative
  98. | QueryUnrequired
  99. | QueryUpgrades
  100. deriving (Eq, Ord, Show)
  101. instance Flagable QueryFilter where
  102. asFlag QueryDeps = ["--deps"]
  103. asFlag QueryExplicit = ["--explicit"]
  104. asFlag QueryForeign = ["--foreign"]
  105. asFlag QueryNative = ["--native"]
  106. asFlag QueryUnrequired = ["--unrequired"]
  107. asFlag QueryUpgrades = ["--upgrades"]
  108. data RemoveOp = RemoveCascade
  109. | RemoveNoSave
  110. | RemoveRecursive
  111. | RemoveUnneeded
  112. deriving (Eq, Ord, Show)
  113. instance Flagable RemoveOp where
  114. asFlag RemoveCascade = ["--cascade"]
  115. asFlag RemoveNoSave = ["--nosave"]
  116. asFlag RemoveRecursive = ["--recursive"]
  117. asFlag RemoveUnneeded = ["--unneeded"]
  118. data SyncOp = SyncClean
  119. | SyncGroups (NonEmpty Text)
  120. | SyncInfo (NonEmpty Text)
  121. | SyncList Text
  122. | SyncSearch Text
  123. | SyncUpgrade (Set Text)
  124. | SyncDownload (NonEmpty Text)
  125. deriving (Eq, Ord, Show)
  126. instance Flagable SyncOp where
  127. asFlag SyncClean = ["--clean"]
  128. asFlag (SyncGroups gs) = "--groups" : asFlag gs
  129. asFlag (SyncInfo ps) = "--info" : asFlag ps
  130. asFlag (SyncList r) = ["--list", r]
  131. asFlag (SyncSearch s) = ["--search", s]
  132. asFlag (SyncUpgrade ps) = "--sysupgrade" : asFlag ps
  133. asFlag (SyncDownload ps) = "--downloadonly" : asFlag ps
  134. data SyncSwitch = SyncRefresh
  135. | SyncIgnore (Set PkgName)
  136. | SyncIgnoreGroup (Set PkgGroup)
  137. | SyncOverwrite Text
  138. deriving (Eq, Ord, Show)
  139. instance Flagable SyncSwitch where
  140. asFlag SyncRefresh = ["--refresh"]
  141. asFlag (SyncIgnore ps) = ["--ignore", T.intercalate "," $ asFlag ps ]
  142. asFlag (SyncIgnoreGroup gs) = ["--ignoregroup" , T.intercalate "," $ asFlag gs ]
  143. asFlag (SyncOverwrite glob) = "--overwrite" : asFlag glob
  144. data UpgradeSwitch = UpgradeAsDeps
  145. | UpgradeAsExplicit
  146. | UpgradeIgnore (Set PkgName)
  147. | UpgradeIgnoreGroup (Set PkgGroup)
  148. | UpgradeOverwrite Text
  149. deriving (Eq, Ord, Show)
  150. instance Flagable UpgradeSwitch where
  151. asFlag UpgradeAsDeps = ["--asdeps"]
  152. asFlag UpgradeAsExplicit = ["--asexplicit"]
  153. asFlag (UpgradeIgnore ps) = ["--ignore", T.intercalate "," $ asFlag ps ]
  154. asFlag (UpgradeIgnoreGroup gs) = ["--ignoregroup", T.intercalate "," $ asFlag gs ]
  155. asFlag (UpgradeOverwrite glob) = "--overwrite" : asFlag glob
  156. -- | Flags common to several Pacman operations.
  157. data MiscOp = MiscArch FilePath
  158. | MiscAssumeInstalled Text
  159. | MiscColor Text
  160. | MiscConfirm
  161. | MiscDBOnly
  162. | MiscDBPath FilePath
  163. | MiscGpgDir FilePath
  164. | MiscHookDir FilePath
  165. | MiscNoDeps
  166. | MiscNoProgress
  167. | MiscNoScriptlet
  168. | MiscPrint
  169. | MiscPrintFormat Text
  170. | MiscRoot FilePath
  171. | MiscVerbose
  172. deriving (Eq, Ord, Show)
  173. instance Flagable MiscOp where
  174. asFlag (MiscArch p) = ["--arch", T.pack p]
  175. asFlag (MiscAssumeInstalled p) = ["--assume-installed", p]
  176. asFlag (MiscColor c) = ["--color", c]
  177. asFlag (MiscDBPath p) = ["--dbpath", T.pack p]
  178. asFlag (MiscGpgDir p) = ["--gpgdir", T.pack p]
  179. asFlag (MiscHookDir p) = ["--hookdir", T.pack p]
  180. asFlag (MiscPrintFormat s) = ["--print-format", s]
  181. asFlag (MiscRoot p) = ["--root", T.pack p]
  182. asFlag MiscConfirm = ["--confirm"]
  183. asFlag MiscDBOnly = ["--dbonly"]
  184. asFlag MiscNoDeps = ["--nodeps"]
  185. asFlag MiscNoProgress = ["--noprogressbar"]
  186. asFlag MiscNoScriptlet = ["--noscriptlet"]
  187. asFlag MiscPrint = ["--print"]
  188. asFlag MiscVerbose = ["--verbose"]
  189. -- | Operations unique to Aura.
  190. data AuraOp = AurSync (Either AurOp (NonEmpty PkgName)) (Set AurSwitch)
  191. | Backup (Maybe BackupOp)
  192. | Cache (Either CacheOp (NonEmpty PkgName))
  193. | Log (Maybe LogOp)
  194. | Orphans (Maybe OrphanOp)
  195. | Version
  196. | Languages
  197. | ViewConf
  198. deriving (Show)
  199. _AurSync :: Traversal' AuraOp (Set AurSwitch)
  200. _AurSync f (AurSync o s) = AurSync o <$> f s
  201. _AurSync _ x = pure x
  202. data AurOp = AurDeps (NonEmpty PkgName)
  203. | AurInfo (NonEmpty PkgName)
  204. | AurPkgbuild (NonEmpty PkgName)
  205. | AurSearch Text
  206. | AurUpgrade (Set PkgName)
  207. | AurJson (NonEmpty PkgName)
  208. | AurTarball (NonEmpty PkgName)
  209. deriving (Show)
  210. data AurSwitch = AurIgnore (Set PkgName)
  211. | AurIgnoreGroup (Set PkgGroup)
  212. | AurRepoSync
  213. deriving (Eq, Ord, Show)
  214. _AurIgnore :: Traversal' AurSwitch (Set PkgName)
  215. _AurIgnore f (AurIgnore s) = AurIgnore <$> f s
  216. _AurIgnore _ x = pure x
  217. _AurIgnoreGroup :: Traversal' AurSwitch (Set PkgGroup)
  218. _AurIgnoreGroup f (AurIgnoreGroup s) = AurIgnoreGroup <$> f s
  219. _AurIgnoreGroup _ x = pure x
  220. data BackupOp = BackupClean Word | BackupRestore | BackupList deriving (Show)
  221. data CacheOp = CacheBackup FilePath | CacheClean Word | CacheCleanNotSaved | CacheSearch Text deriving (Show)
  222. data LogOp = LogInfo (NonEmpty PkgName) | LogSearch Text deriving (Show)
  223. data OrphanOp = OrphanAbandon | OrphanAdopt (NonEmpty PkgName) deriving (Show)
  224. opts :: ParserInfo Program
  225. opts = info (program <**> helper)
  226. (fullDesc <> header "Aura - Package manager for Arch Linux and the AUR.")
  227. program :: Parser Program
  228. program = Program
  229. <$> (fmap Right aurOps <|> (curry Left <$> pacOps <*> misc))
  230. <*> commonConfig
  231. <*> buildConfig
  232. <*> optional language
  233. <*> logLevel
  234. where
  235. aurOps = aursync <|> backups <|> cache <|> log <|> orphans <|> version' <|> languages <|> viewconf
  236. pacOps = database <|> files <|> queries <|> remove <|> sync <|> testdeps <|> upgrades
  237. aursync :: Parser AuraOp
  238. aursync = bigA *>
  239. (AurSync
  240. <$> (fmap (Right . NEL.map (PkgName . T.toLower)) someArgs <|> fmap Left mods)
  241. <*> (S.fromList <$> many switches)
  242. )
  243. where bigA = flag' () (long "aursync" <> short 'A' <> help "Install packages from the AUR.")
  244. mods = ds <|> ainfo <|> pkgb <|> search <|> upgrade <|> aur <|> tarball
  245. ds = AurDeps <$> (flag' () (long "deps" <> short 'd' <> hidden <> help "View dependencies of an AUR package.") *> somePkgs')
  246. ainfo = AurInfo <$> (flag' () (long "info" <> short 'i' <> hidden <> help "View AUR package information.") *> somePkgs')
  247. pkgb = AurPkgbuild <$> (flag' () (long "pkgbuild" <> short 'p' <> hidden <> help "View an AUR package's PKGBUILD file.") *> somePkgs')
  248. search = AurSearch <$> strOption (long "search" <> short 's' <> metavar "STRING" <> hidden <> help "Search the AUR via a search string.")
  249. upgrade = AurUpgrade <$> (flag' () (long "sysupgrade" <> short 'u' <> hidden <> help "Upgrade all installed AUR packages.") *> fmap (S.map PkgName) manyArgs')
  250. aur = AurJson <$> (flag' () (long "json" <> hidden <> help "Retrieve package JSON straight from the AUR.") *> somePkgs')
  251. tarball = AurTarball <$> (flag' () (long "downloadonly" <> short 'w' <> hidden <> help "Download a package tarball.") *> somePkgs')
  252. switches = ign <|> igg <|> y
  253. ign = AurIgnore . S.fromList . map PkgName . T.split (== ',')
  254. <$> strOption (long "ignore" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore given packages.")
  255. igg = AurIgnoreGroup . S.fromList . map PkgGroup . T.split (== ',')
  256. <$> strOption (long "ignoregroup" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore packages from the given groups.")
  257. y = flag' AurRepoSync (short 'y' <> hidden <> help "Do an -Sy before continuing.")
  258. backups :: Parser AuraOp
  259. backups = bigB *> (Backup <$> optional mods)
  260. where bigB = flag' () (long "save" <> short 'B' <> help "Save a package state.")
  261. mods = clean <|> restore <|> lst
  262. clean = BackupClean <$> option auto (long "clean" <> short 'c' <> metavar "N" <> hidden <> help "Keep the most recent N states, delete the rest.")
  263. restore = flag' BackupRestore (long "restore" <> short 'r' <> hidden <> help "Restore a previous package state.")
  264. lst = flag' BackupList (long "list" <> short 'l' <> hidden <> help "Show all saved package state filenames.")
  265. cache :: Parser AuraOp
  266. cache = bigC *> (Cache <$> (fmap Left mods <|> fmap Right somePkgs))
  267. where bigC = flag' () (long "downgrade" <> short 'C' <> help "Interact with the package cache.")
  268. mods = backup <|> clean <|> clean' <|> search
  269. backup = CacheBackup <$> option (eitherReader absFilePath) (long "backup" <> short 'b' <> metavar "PATH" <> help "Backup the package cache to a given directory." <> hidden)
  270. clean = CacheClean <$> option auto (long "clean" <> short 'c' <> metavar "N" <> help "Save the most recent N versions of a package in the cache, deleting the rest." <> hidden)
  271. clean' = flag' CacheCleanNotSaved (long "notsaved" <> help "Clean out any cached package files which doesn't appear in any saved state." <> hidden)
  272. search = CacheSearch <$> strOption (long "search" <> short 's' <> metavar "STRING" <> help "Search the package cache via a search string." <> hidden)
  273. log :: Parser AuraOp
  274. log = bigL *> (Log <$> optional mods)
  275. where bigL = flag' () (long "viewlog" <> short 'L' <> help "View the Pacman log.")
  276. mods = inf <|> sch
  277. inf = LogInfo <$> (flag' () (long "info" <> short 'i' <> help "Display the installation history for given packages." <> hidden) *> somePkgs')
  278. sch = LogSearch <$> strOption (long "search" <> short 's' <> metavar "STRING" <> help "Search the Pacman log via a search string." <> hidden)
  279. orphans :: Parser AuraOp
  280. orphans = bigO *> (Orphans <$> optional mods)
  281. where bigO = flag' () (long "orphans" <> short 'O' <> help "Display all orphan packages.")
  282. mods = abandon <|> adopt
  283. abandon = flag' OrphanAbandon (long "abandon" <> short 'j' <> hidden <> help "Uninstall all orphan packages.")
  284. adopt = OrphanAdopt <$> (flag' () (long "adopt" <> hidden <> help "Mark some packages' install reason as 'Explicit'.") *> somePkgs')
  285. version' :: Parser AuraOp
  286. version' = flag' Version (long "version" <> short 'V' <> help "Display Aura's version.")
  287. languages :: Parser AuraOp
  288. languages = flag' Languages (long "languages" <> help "Show all human languages available for output.")
  289. viewconf :: Parser AuraOp
  290. viewconf = flag' ViewConf (long "viewconf" <> help "View the Pacman config file.")
  291. buildConfig :: Parser BuildConfig
  292. buildConfig = BuildConfig <$> makepkg <*> bp <*> optional bu <*> trunc <*> buildSwitches
  293. where makepkg = S.fromList <$> many (ia <|> as <|> si)
  294. ia = flag' IgnoreArch (long "ignorearch" <> hidden <> help "Exposed makepkg flag.")
  295. as = flag' AllSource (long "allsource" <> hidden <> help "Exposed makepkg flag.")
  296. si = flag' SkipInteg (long "skipinteg" <> hidden <> help "Skip all makepkg integrity checks.")
  297. bp = option (eitherReader absFilePath) (long "build" <> metavar "PATH" <> hidden <> help "Directory in which to build packages.")
  298. <|> pure defaultBuildDir
  299. bu = User <$> strOption (long "builduser" <> metavar "USER" <> hidden <> help "User account to build as.")
  300. trunc = fmap Head (option auto (long "head" <> metavar "N" <> hidden <> help "Only show top N search results."))
  301. <|> fmap Tail (option auto (long "tail" <> metavar "N" <> hidden <> help "Only show last N search results."))
  302. <|> pure None
  303. buildSwitches :: Parser (Set BuildSwitch)
  304. buildSwitches = S.fromList <$> many (lv <|> dmd <|> dsm <|> dpb <|> rbd <|> he <|> ucp <|> dr <|> sa <|> fo <|> npc <|> asd)
  305. where dmd = flag' DeleteMakeDeps (long "delmakedeps" <> short 'a' <> hidden <> help "Uninstall makedeps after building.")
  306. dsm = flag' DontSuppressMakepkg (long "unsuppress" <> short 'x' <> hidden <> help "Unsuppress makepkg output.")
  307. dpb = flag' DiffPkgbuilds (long "diff" <> short 'k' <> hidden <> help "Show PKGBUILD diffs.")
  308. rbd = flag' RebuildDevel (long "devel" <> hidden <> help "Rebuild all git/hg/svn/darcs-based packages.")
  309. he = flag' HotEdit (long "hotedit" <> hidden <> help "Edit a PKGBUILD before building.")
  310. ucp = flag' UseCustomizepkg (long "custom" <> hidden <> help "Run customizepkg before building.")
  311. dr = flag' DryRun (long "dryrun" <> hidden <> help "Run dependency checks and PKGBUILD diffs, but don't build.")
  312. sa = flag' SortAlphabetically (long "abc" <> hidden <> help "Sort search results alphabetically.")
  313. lv = flag' LowVerbosity (long "quiet" <> short 'q' <> hidden <> help "Display less information.")
  314. fo = flag' ForceBuilding (long "force" <> hidden <> help "Always (re)build specified packages.")
  315. npc = flag' NoPkgbuildCheck (long "noanalysis" <> hidden <> help "Do not analyse PKGBUILDs for security flaws.")
  316. asd = flag' AsDeps (long "asdeps" <> hidden <> help "All installed packages will be marked as dependencies.")
  317. commonConfig :: Parser CommonConfig
  318. commonConfig = CommonConfig <$> cap <*> cop <*> lfp <*> commonSwitches
  319. where cap = fmap Right
  320. (option (eitherReader absFilePath) (long "cachedir" <> hidden <> help "Use an alternate package cache location."))
  321. <|> pure (Left defaultPackageCache)
  322. cop = fmap Right
  323. (option (eitherReader absFilePath) (long "config" <> hidden <> help "Use an alternate Pacman config file."))
  324. <|> pure (Left pacmanConfFile)
  325. lfp = fmap Right
  326. (option (eitherReader absFilePath) (long "logfile" <> hidden <> help "Use an alternate Pacman log."))
  327. <|> pure (Left defaultLogFile)
  328. commonSwitches :: Parser (Set CommonSwitch)
  329. commonSwitches = S.fromList <$> many (nc <|> no <|> dbg <|> clr <|> ovr)
  330. where nc = flag' NoConfirm (long "noconfirm" <> hidden <> help "Never ask for Aura or Pacman confirmation.")
  331. no = flag' NeededOnly (long "needed" <> hidden <> help "Don't rebuild/reinstall up-to-date packages.")
  332. dbg = flag' Debug (long "debug" <> hidden <> help "Print useful debugging info.")
  333. ovr = Overwrite <$> strOption (long "overwrite" <> hidden <> help "Bypas file conflict checks." <> metavar "GLOB")
  334. clr = Colour . f <$> strOption (long "color" <> metavar "WHEN" <> hidden <> help "Colourize the output.")
  335. f :: String -> ColourMode
  336. f "never" = Never
  337. f "always" = Always
  338. f _ = Auto
  339. database :: Parser PacmanOp
  340. database = bigD *> (Database <$> (fmap Right somePkgs <|> fmap Left mods))
  341. where bigD = flag' () (long "database" <> short 'D' <> help "Interact with the package database.")
  342. mods = check <|> asdeps <|> asexp
  343. check = flag' DBCheck (long "check" <> short 'k' <> hidden <> help "Test local database validity.")
  344. asdeps = DBAsDeps <$> (flag' () (long "asdeps" <> hidden <> help "Mark packages as being dependencies.") *> someArgs')
  345. asexp = DBAsExplicit <$> (flag' () (long "asexplicit" <> hidden <> help "Mark packages as being explicitely installed.") *> someArgs')
  346. files :: Parser PacmanOp
  347. files = bigF *> (Files <$> fmap S.fromList (many mods))
  348. where bigF = flag' () (long "files" <> short 'F' <> help "Interact with the file database.")
  349. mods = lst <|> own <|> sch <|> rgx <|> rfr <|> mch
  350. lst = FilesList <$> (flag' () (long "list" <> short 'l' <> hidden <> help "List the files owned by given packages.") *> someArgs')
  351. own = FilesOwns <$> strOption (long "owns" <> short 'o' <> metavar "FILE" <> hidden <> help "Query the package that owns FILE.")
  352. sch = FilesSearch <$> strOption (long "search" <> short 's' <> metavar "FILE" <> hidden <> help "Find package files that match the given FILEname.")
  353. rgx = flag' FilesRegex (long "regex" <> short 'x' <> hidden <> help "Interpret the input of -Fs as a regex.")
  354. rfr = flag' FilesRefresh (long "refresh" <> short 'y' <> hidden <> help "Download fresh package databases.")
  355. mch = flag' FilesMachineReadable (long "machinereadable" <> hidden <> help "Produce machine-readable output.")
  356. queries :: Parser PacmanOp
  357. queries = bigQ *> (Query <$> (fmap Right query <|> fmap Left mods))
  358. where bigQ = flag' () (long "query" <> short 'Q' <> help "Interact with the local package database.")
  359. query = curry (second (S.map PkgName)) <$> queryFilters <*> manyArgs
  360. mods = chl <|> gps <|> inf <|> lst <|> own <|> fls <|> sch <|> chk
  361. chl = QueryChangelog <$> (flag' () (long "changelog" <> short 'c' <> hidden <> help "View a package's changelog.") *> someArgs')
  362. gps = QueryGroups <$> (flag' () (long "groups" <> short 'g' <> hidden <> help "View all members of a package group.") *> someArgs')
  363. inf = QueryInfo <$> (flag' () (long "info" <> short 'i' <> hidden <> help "View package information.") *> someArgs')
  364. lst = QueryList <$> (flag' () (long "list" <> short 'l' <> hidden <> help "List files owned by a package.") *> someArgs')
  365. chk = QueryCheck <$> (flag' () (long "check" <> short 'k' <> hidden <> help "Check that package files exist.") *> someArgs')
  366. own = QueryOwns <$> (flag' () (long "owns" <> short 'o' <> hidden <> help "Find the package some file belongs to.") *> someArgs')
  367. fls = QueryFile <$> (flag' () (long "file" <> short 'p' <> hidden <> help "Query a package file.") *> someArgs')
  368. sch = QuerySearch <$> strOption (long "search" <> short 's' <> metavar "REGEX" <> hidden <> help "Search the local database.")
  369. queryFilters :: Parser (Set QueryFilter)
  370. queryFilters = S.fromList <$> many (dps <|> exp <|> frg <|> ntv <|> urq <|> upg)
  371. where dps = flag' QueryDeps (long "deps" <> short 'd' <> hidden <> help "[filter] Only list packages installed as deps.")
  372. exp = flag' QueryExplicit (long "explicit" <> short 'e' <> hidden <> help "[filter] Only list explicitly installed packages.")
  373. frg = flag' QueryForeign (long "foreign" <> short 'm' <> hidden <> help "[filter] Only list AUR packages.")
  374. ntv = flag' QueryNative (long "native" <> short 'n' <> hidden <> help "[filter] Only list official packages.")
  375. urq = flag' QueryUnrequired (long "unrequired" <> short 't' <> hidden <> help "[filter] Only list packages not required as a dependency to any other.")
  376. upg = flag' QueryUpgrades (long "upgrades" <> short 'u' <> hidden <> help "[filter] Only list outdated packages.")
  377. remove :: Parser PacmanOp
  378. remove = bigR *> (Remove <$> mods <*> somePkgs)
  379. where bigR = flag' () (long "remove" <> short 'R' <> help "Uninstall packages.")
  380. mods = S.fromList <$> many (cascade <|> nosave <|> recurse <|> unneeded)
  381. cascade = flag' RemoveCascade (long "cascade" <> short 'c' <> hidden <> help "Remove packages and all others that depend on them.")
  382. nosave = flag' RemoveNoSave (long "nosave" <> short 'n' <> hidden <> help "Remove configuration files as well.")
  383. recurse = flag' RemoveRecursive (long "recursive" <> short 's' <> hidden <> help "Remove unneeded dependencies.")
  384. unneeded = flag' RemoveUnneeded (long "unneeded" <> short 'u' <> hidden <> help "Remove unneeded packages.")
  385. sync :: Parser PacmanOp
  386. sync = bigS *> (Sync <$> (fmap (Right . S.map PkgName) manyArgs <|> fmap Left mods) <*> (S.fromList <$> many (ref <|> ign <|> igg)))
  387. where bigS = flag' () (long "sync" <> short 'S' <> help "Install official packages.")
  388. ref = flag' SyncRefresh (long "refresh" <> short 'y' <> hidden <> help "Update the package database.")
  389. mods = NELP.fromList <$> some (cln <|> gps <|> inf <|> lst <|> sch <|> upg <|> dnl)
  390. cln = flag' SyncClean (long "clean" <> short 'c' <> hidden <> help "Remove old packages from the cache.")
  391. gps = SyncGroups <$> (flag' () (long "groups" <> short 'g' <> hidden <> help "View members of a package group.") *> someArgs')
  392. inf = SyncInfo <$> (flag' () (long "info" <> short 'i' <> hidden <> help "View package information.") *> someArgs')
  393. lst = SyncList <$> strOption (long "list" <> short 'l' <> metavar "REPO" <> hidden <> help "List the packages in a REPO.")
  394. sch = SyncSearch <$> strOption (long "search" <> short 's' <> metavar "REGEX" <> hidden <> help "Search the official package repos.")
  395. upg = SyncUpgrade <$> (flag' () (long "sysupgrade" <> short 'u' <> hidden <> help "Upgrade installed packages.") *> manyArgs')
  396. dnl = SyncDownload <$> (flag' () (long "downloadonly" <> short 'w' <> hidden <> help "Download package tarballs.") *> someArgs')
  397. ign = SyncIgnore . S.fromList . map PkgName . T.split (== ',') <$>
  398. strOption (long "ignore" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore given packages.")
  399. igg = SyncIgnoreGroup . S.fromList . map PkgGroup . T.split (== ',') <$>
  400. strOption (long "ignoregroup" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore packages from the given groups.")
  401. misc :: Parser (Set MiscOp)
  402. misc = S.fromList <$> many (ar <|> dbp <|> roo <|> ver <|> gpg <|> hd <|> con <|> dbo <|> nop <|> nos <|> pf <|> nod <|> prt <|> asi)
  403. where ar = MiscArch
  404. <$> option (eitherReader absFilePath) (long "arch" <> metavar "ARCH" <> hidden <> help "Use an alternate architecture.")
  405. dbp = MiscDBPath
  406. <$> option (eitherReader absFilePath) (long "dbpath" <> short 'b' <> metavar "PATH" <> hidden <> help "Use an alternate database location.")
  407. roo = MiscRoot
  408. <$> option (eitherReader absFilePath) (long "root" <> short 'r' <> metavar "PATH" <> hidden <> help "Use an alternate installation root.")
  409. ver = flag' MiscVerbose (long "verbose" <> short 'v' <> hidden <> help "Be more verbose.")
  410. gpg = MiscGpgDir
  411. <$> option (eitherReader absFilePath) (long "gpgdir" <> metavar "PATH" <> hidden <> help "Use an alternate GnuGPG directory.")
  412. hd = MiscHookDir
  413. <$> option (eitherReader absFilePath) (long "hookdir" <> metavar "PATH" <> hidden <> help "Use an alternate hook directory.")
  414. con = flag' MiscConfirm (long "confirm" <> hidden <> help "Always ask for confirmation.")
  415. dbo = flag' MiscDBOnly (long "dbonly" <> hidden <> help "Only modify database entries, not package files.")
  416. nop = flag' MiscNoProgress (long "noprogressbar" <> hidden <> help "Don't show a progress bar when downloading.")
  417. nos = flag' MiscNoScriptlet (long "noscriptlet" <> hidden <> help "Don't run available install scriptlets.")
  418. pf = MiscPrintFormat <$> strOption (long "print-format" <> metavar "STRING" <> hidden <> help "Specify how targets should be printed.")
  419. nod = flag' MiscNoDeps (long "nodeps" <> short 'd' <> hidden <> help "Skip dependency version checks.")
  420. prt = flag' MiscPrint (long "print" <> short 'p' <> hidden <> help "Print the targets instead of performing the operation.")
  421. asi = MiscAssumeInstalled <$> strOption (long "assume-installed" <> metavar "<package=version>" <> hidden <> help "Add a virtual package to satisfy dependencies.")
  422. testdeps :: Parser PacmanOp
  423. testdeps = bigT *> (TestDeps <$> someArgs)
  424. where bigT = flag' () (long "deptest" <> short 'T' <> help "Test dependencies - useful for scripts.")
  425. upgrades :: Parser PacmanOp
  426. upgrades = bigU *> (Upgrade <$> (S.fromList <$> many mods) <*> somePkgs)
  427. where bigU = flag' () (long "upgrade" <> short 'U' <> help "Install given package files.")
  428. mods = asd <|> ase <|> ign <|> igg
  429. asd = flag' UpgradeAsDeps (long "asdeps" <> hidden)
  430. ase = flag' UpgradeAsExplicit (long "asexplicit" <> hidden)
  431. ign = UpgradeIgnore . S.fromList . map PkgName . T.split (== ',') <$>
  432. strOption (long "ignore" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore given packages.")
  433. igg = UpgradeIgnoreGroup . S.fromList . map PkgGroup . T.split (== ',') <$>
  434. strOption (long "ignoregroup" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore packages from the given groups.")
  435. somePkgs :: Parser (NonEmpty PkgName)
  436. somePkgs = NELP.fromList . map PkgName <$> some (argument str (metavar "PACKAGES"))
  437. -- | Same as `someArgs`, but the help message "brief display" won't show PACKAGES.
  438. somePkgs' :: Parser (NonEmpty PkgName)
  439. somePkgs' = NELP.fromList . map PkgName <$> some (argument str (metavar "PACKAGES" <> hidden))
  440. -- | One or more arguments.
  441. someArgs :: Parser (NonEmpty Text)
  442. someArgs = NEL.nub . NELP.fromList <$> some (argument str (metavar "PACKAGES"))
  443. -- | Same as `someArgs`, but the help message "brief display" won't show PACKAGES.
  444. someArgs' :: Parser (NonEmpty Text)
  445. someArgs' = NEL.nub . NELP.fromList <$> some (argument str (metavar "PACKAGES" <> hidden))
  446. -- | Zero or more arguments.
  447. manyArgs :: Parser (Set Text)
  448. manyArgs = S.fromList <$> many (argument str (metavar "PACKAGES"))
  449. -- | Zero or more arguments.
  450. manyArgs' :: Parser (Set Text)
  451. manyArgs' = S.fromList <$> many (argument str (metavar "PACKAGES" <> hidden))
  452. language :: Parser Language
  453. language = foldr1 (<|>) $ map (\(f, v) -> flag' v (long f <> hidden)) langs
  454. where langs = [ ( "japanese", Japanese ), ( "日本語", Japanese )
  455. , ( "polish", Polish ), ( "polski", Polish )
  456. , ( "croatian", Croatian ), ( "hrvatski", Croatian )
  457. , ( "swedish", Swedish ), ( "svenska", Swedish )
  458. , ( "german", German ), ( "deutsch", German )
  459. , ( "spanish", Spanish ), ( "español", Spanish )
  460. , ( "portuguese", Portuguese ), ( "português", Portuguese )
  461. , ( "french", French), ( "français", French )
  462. , ( "russian", Russian ), ( "русский", Russian )
  463. , ( "italian", Italian ), ( "italiano", Italian )
  464. , ( "serbian", Serbian ), ( "српски", Serbian )
  465. , ( "norwegian", Norwegian ), ( "norsk", Norwegian )
  466. , ( "indonesian", Indonesia )
  467. , ( "chinese", Chinese ), ( "中文", Chinese )
  468. , ( "esperanto", Esperanto )
  469. , ( "dutch", Dutch ), ( "nederlands", Dutch ) ]
  470. logLevel :: Parser LogLevel
  471. logLevel = option (eitherReader l)
  472. (long "log-level" <> metavar "debug|info|warn|error" <> value LevelInfo
  473. <> help "The minimum level of log messages to display (default: info)")
  474. where
  475. l :: String -> Either String LogLevel
  476. l "debug" = Right LevelDebug
  477. l "info" = Right LevelInfo
  478. l "warn" = Right LevelWarn
  479. l "error" = Right LevelError
  480. l _ = Left "Must be one of debug|info|warn|error"
  481. absFilePath :: String -> Either String FilePath
  482. absFilePath fp = bool (Left $ "Not absolute: " <> fp) (Right fp) $ isAbsolute fp