packages feed

aura 2.0.3 → 2.0.4

raw patch · 35 files changed

+698/−776 lines, 35 filesdep +riodep −base-preludedep −directorydep −fused-effects

Dependencies added: rio

Dependencies removed: base-prelude, directory, fused-effects

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Aura Changelog +## 2.0.4 (2020-02-08)++- Removed `fused-effects` dependency in favour of `rio` to simplify code.+ ## 2.0.3  - Updated Spanish translations. Thanks to Max Ferrer!
aura.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.2 name:               aura-version:            2.0.3+version:            2.0.4 synopsis:   A secure package manager for Arch Linux and the AUR, written in Haskell. @@ -12,7 +12,7 @@   AUR package managers.  category:           System-homepage:           https://github.com/aurapm/aura+homepage:           https://github.com/fosskers/aura author:             Colin Woodbury maintainer:         colin@fosskers.ca license:            GPL-3.0-only@@ -34,22 +34,21 @@     -funclutter-valid-hole-fits    build-depends:-    , base          >=4.12 && <5-    , base-prelude  >=1.2  && <1.4-    , bytestring    ^>=0.10-    , containers    ^>=0.6-    , microlens     ^>=0.4-    , paths         ^>=0.2-    , text          ^>=1.2-    , versions      ^>=3.5+    , base        >=4.12   && <5+    , bytestring  ^>=0.10+    , containers  ^>=0.6+    , microlens   ^>=0.4+    , paths       ^>=0.2+    , rio         ^>=0.1.13+    , text        ^>=1.2+    , versions    ^>=3.5  common libexec   build-depends:     , errors                       ^>=2.3-    , fused-effects                >=0.4 && <1.1     , http-client                  >=0.5 && <0.7     , nonempty-containers          ^>=0.3-    , prettyprinter                >=1.2 && < 1.6+    , prettyprinter                >=1.2 && <1.6     , prettyprinter-ansi-terminal  ^>=1.1     , transformers                 ^>=0.5     , typed-process                ^>=0.2@@ -93,9 +92,8 @@     , algebraic-graphs  >=0.1  && <0.5     , aur               ^>=6.3     , compactable       ^>=0.1-    , directory         ^>=1.3     , filepath          ^>=1.4-    , generic-lens      >=1.1 && < 1.3+    , generic-lens      >=1.1  && <1.3     , http-types        >=0.9  && <0.13     , language-bash     ^>=0.8     , megaparsec        ^>=7@@ -106,7 +104,7 @@     , semigroupoids     >=5.2  && <5.4     , stm               ^>=2.5     , these             ^>=1.0-    , time              >=1.8 && < 1.10+    , time              >=1.8  && <1.10     , unliftio          ^>=0.2  executable aura@@ -121,7 +119,7 @@   build-depends:     , aura     , http-client-tls       ^>=0.3-    , optparse-applicative  >=0.14 && < 0.16+    , optparse-applicative  >=0.14 && <0.16     , pretty-simple         >=2.1  && <3.3  test-suite aura-test
doc/aura.8 view
@@ -1,7 +1,7 @@ .\" Man page for `aura` .\" Written by Colin Woodbury <colin@fosskers.ca> -.TH aura 8 "June 2018" "Aura" "Aura Manual"+.TH aura 8 "January 2020" "Aura" "Aura Manual"  .\" Disable hyphenation. .nh
exec/Flags.hs view
@@ -11,14 +11,15 @@ import           Aura.Pacman (defaultLogFile, pacmanConfFile) import           Aura.Settings import           Aura.Types-import           BasePrelude hiding (Version, exp, log, option) import qualified Data.List.NonEmpty as NEL-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Lens.Micro import           Options.Applicative+import           RIO hiding (exp, log)+import           RIO.List.Partial (foldr1)+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path (Absolute, Path, fromAbsoluteFilePath, toFilePath)  ---@@ -26,7 +27,7 @@ -- | A description of a run of Aura to attempt. data Program = Program {   -- ^ Whether Aura handles everything, or the ops and input are just passed down to Pacman.-  _operation   :: Either (PacmanOp, S.Set MiscOp) AuraOp+  _operation   :: Either (PacmanOp, Set MiscOp) AuraOp   -- ^ Settings common to both Aura and Pacman.   , _commons   :: CommonConfig   -- ^ Settings specific to building packages.@@ -36,12 +37,12 @@  -- | Inherited operations that are fed down to Pacman. data PacmanOp = Database (Either DatabaseOp (NESet PkgName))-              | Files    (S.Set FilesOp)-              | Query    (Either QueryOp (S.Set QueryFilter, S.Set PkgName))-              | Remove   (S.Set RemoveOp) (NESet PkgName)-              | Sync     (Either SyncOp (S.Set PkgName)) (S.Set SyncSwitch)-              | TestDeps (NESet T.Text)-              | Upgrade  (S.Set UpgradeSwitch) (NESet PkgName)+              | Files    (Set FilesOp)+              | Query    (Either QueryOp (Set QueryFilter, Set PkgName))+              | Remove   (Set RemoveOp) (NESet PkgName)+              | Sync     (Either SyncOp (Set PkgName)) (Set SyncSwitch)+              | TestDeps (NESet Text)+              | Upgrade  (Set UpgradeSwitch) (NESet PkgName)               deriving (Show)  instance Flagable PacmanOp where@@ -57,8 +58,8 @@   asFlag (Upgrade s ps)           = "-U" : asFlag s ++ asFlag ps  data DatabaseOp = DBCheck-                | DBAsDeps     (NESet T.Text)-                | DBAsExplicit (NESet T.Text)+                | DBAsDeps     (NESet Text)+                | DBAsExplicit (NESet Text)                 deriving (Show)  instance Flagable DatabaseOp where@@ -66,9 +67,9 @@   asFlag (DBAsDeps ps)     = "--asdeps" : asFlag ps   asFlag (DBAsExplicit ps) = "--asexplicit" : asFlag ps -data FilesOp = FilesList  (NESet T.Text)-             | FilesOwns   T.Text-             | FilesSearch T.Text+data FilesOp = FilesList  (NESet Text)+             | FilesOwns   Text+             | FilesSearch Text              | FilesRegex              | FilesRefresh              | FilesMachineReadable@@ -82,14 +83,14 @@   asFlag FilesRefresh         = ["--refresh"]   asFlag FilesMachineReadable = ["--machinereadable"] -data QueryOp = QueryChangelog (NESet T.Text)-             | QueryGroups    (NESet T.Text)-             | QueryInfo      (NESet T.Text)-             | QueryCheck     (NESet T.Text)-             | QueryList      (NESet T.Text)-             | QueryOwns      (NESet T.Text)-             | QueryFile      (NESet T.Text)-             | QuerySearch     T.Text+data QueryOp = QueryChangelog (NESet Text)+             | QueryGroups    (NESet Text)+             | QueryInfo      (NESet Text)+             | QueryCheck     (NESet Text)+             | QueryList      (NESet Text)+             | QueryOwns      (NESet Text)+             | QueryFile      (NESet Text)+             | QuerySearch     Text              deriving (Show)  instance Flagable QueryOp where@@ -131,12 +132,12 @@   asFlag RemoveUnneeded  = ["--unneeded"]  data SyncOp = SyncClean-            | SyncGroups   (NESet T.Text)-            | SyncInfo     (NESet T.Text)-            | SyncList      T.Text-            | SyncSearch    T.Text-            | SyncUpgrade  (S.Set T.Text)-            | SyncDownload (NESet T.Text)+            | SyncGroups   (NESet Text)+            | SyncInfo     (NESet Text)+            | SyncList      Text+            | SyncSearch    Text+            | SyncUpgrade  (Set Text)+            | SyncDownload (NESet Text)             deriving (Show)  instance Flagable SyncOp where@@ -149,8 +150,8 @@   asFlag (SyncDownload ps) = "--downloadonly" : asFlag ps  data SyncSwitch = SyncRefresh-                | SyncIgnore      (S.Set PkgName)-                | SyncIgnoreGroup (S.Set PkgGroup)+                | SyncIgnore      (Set PkgName)+                | SyncIgnoreGroup (Set PkgGroup)                 deriving (Eq, Ord, Show)  instance Flagable SyncSwitch where@@ -160,8 +161,8 @@  data UpgradeSwitch = UpgradeAsDeps                    | UpgradeAsExplicit-                   | UpgradeIgnore      (S.Set PkgName)-                   | UpgradeIgnoreGroup (S.Set PkgGroup)+                   | UpgradeIgnore      (Set PkgName)+                   | UpgradeIgnoreGroup (Set PkgGroup)                    deriving (Eq, Ord, Show)  instance Flagable UpgradeSwitch where@@ -172,8 +173,8 @@  -- | Flags common to several Pacman operations. data MiscOp = MiscArch    (Path Absolute)-            | MiscAssumeInstalled T.Text-            | MiscColor   T.Text+            | MiscAssumeInstalled Text+            | MiscColor   Text             | MiscConfirm             | MiscDBOnly             | MiscDBPath  (Path Absolute)@@ -183,7 +184,7 @@             | MiscNoProgress             | MiscNoScriptlet             | MiscPrint-            | MiscPrintFormat T.Text+            | MiscPrintFormat Text             | MiscRoot    (Path Absolute)             | MiscVerbose             deriving (Eq, Ord, Show)@@ -206,7 +207,7 @@   asFlag MiscVerbose             = ["--verbose"]  -- | Operations unique to Aura.-data AuraOp = AurSync (Either AurOp (NESet PkgName)) (S.Set AurSwitch)+data AuraOp = AurSync (Either AurOp (NESet PkgName)) (Set AurSwitch)             | Backup  (Maybe  BackupOp)             | Cache   (Either CacheOp (NESet PkgName))             | Log     (Maybe  LogOp)@@ -216,35 +217,35 @@             | ViewConf             deriving (Show) -_AurSync :: Traversal' AuraOp (S.Set AurSwitch)+_AurSync :: Traversal' AuraOp (Set AurSwitch) _AurSync f (AurSync o s) = AurSync o <$> f s _AurSync _ x             = pure x  data AurOp = AurDeps     (NESet PkgName)            | AurInfo     (NESet PkgName)            | AurPkgbuild (NESet PkgName)-           | AurSearch    T.Text-           | AurUpgrade  (S.Set PkgName)+           | AurSearch    Text+           | AurUpgrade  (Set PkgName)            | AurJson     (NESet PkgName)            deriving (Show) -data AurSwitch = AurIgnore      (S.Set PkgName)-               | AurIgnoreGroup (S.Set PkgGroup)+data AurSwitch = AurIgnore      (Set PkgName)+               | AurIgnoreGroup (Set PkgGroup)                deriving (Eq, Ord, Show) -_AurIgnore :: Traversal' AurSwitch (S.Set PkgName)+_AurIgnore :: Traversal' AurSwitch (Set PkgName) _AurIgnore f (AurIgnore s) = AurIgnore <$> f s _AurIgnore _ x             = pure x -_AurIgnoreGroup :: Traversal' AurSwitch (S.Set PkgGroup)+_AurIgnoreGroup :: Traversal' AurSwitch (Set PkgGroup) _AurIgnoreGroup f (AurIgnoreGroup s) = AurIgnoreGroup <$> f s _AurIgnoreGroup _ x                  = pure x  data BackupOp = BackupClean Word | BackupRestore | BackupList deriving (Show) -data CacheOp = CacheBackup (Path Absolute) | CacheClean Word | CacheCleanNotSaved | CacheSearch T.Text deriving (Show)+data CacheOp = CacheBackup (Path Absolute) | CacheClean Word | CacheCleanNotSaved | CacheSearch Text deriving (Show) -data LogOp = LogInfo (NESet PkgName) | LogSearch T.Text deriving (Show)+data LogOp = LogInfo (NESet PkgName) | LogSearch Text deriving (Show)  data OrphanOp = OrphanAbandon | OrphanAdopt (NESet PkgName) deriving (Show) @@ -333,7 +334,7 @@           <|> fmap Tail (option auto (long "tail" <> metavar "N" <> hidden <> help "Only show last N search results."))           <|> pure None -buildSwitches :: Parser (S.Set BuildSwitch)+buildSwitches :: Parser (Set BuildSwitch) buildSwitches = S.fromList <$> many (lv <|> dmd <|> dsm <|> dpb <|> rbd <|> he <|> ucp <|> dr <|> sa <|> fo <|> npc)   where dmd = flag' DeleteMakeDeps (long "delmakedeps" <> short 'a' <> hidden <> help "Uninstall makedeps after building.")         dsm = flag' DontSuppressMakepkg (long "unsuppress" <> short 'x' <> hidden <> help "Unsuppress makepkg output.")@@ -359,7 +360,7 @@                    (strOption (long "logfile"  <> hidden <> help "Use an alternate Pacman log."))               <|> pure (Left defaultLogFile) -commonSwitches :: Parser (S.Set CommonSwitch)+commonSwitches :: Parser (Set CommonSwitch) commonSwitches = S.fromList <$> many (nc <|> no <|> dbg <|> clr)   where nc  = flag' NoConfirm  (long "noconfirm" <> hidden <> help "Never ask for Aura or Pacman confirmation.")         no  = flag' NeededOnly (long "needed"    <> hidden <> help "Don't rebuild/reinstall up-to-date packages.")@@ -403,7 +404,7 @@         fls   = QueryFile <$> (flag' () (long "file" <> short 'p' <> hidden <> help "Query a package file.") *> someArgs')         sch   = QuerySearch <$> strOption (long "search" <> short 's' <> metavar "REGEX" <> hidden <> help "Search the local database.") -queryFilters :: Parser (S.Set QueryFilter)+queryFilters :: Parser (Set QueryFilter) queryFilters = S.fromList <$> many (dps <|> exp <|> frg <|> ntv <|> urq <|> upg)   where dps = flag' QueryDeps (long "deps" <> short 'd' <> hidden <> help "[filter] Only list packages installed as deps.")         exp = flag' QueryExplicit (long "explicit" <> short 'e' <> hidden <> help "[filter] Only list explicitly installed packages.")@@ -438,7 +439,7 @@         igg  = SyncIgnoreGroup . S.fromList . map PkgGroup . T.split (== ',') <$>           strOption (long "ignoregroup" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore packages from the given groups.") -misc :: Parser (S.Set MiscOp)+misc :: Parser (Set MiscOp) misc = S.fromList <$> many (ar <|> dbp <|> roo <|> ver <|> gpg <|> hd <|> con <|> dbo <|> nop <|> nos <|> pf <|> nod <|> prt <|> asi)   where ar  = MiscArch . fromAbsoluteFilePath               <$> strOption (long "arch" <> metavar "ARCH" <> hidden <> help "Use an alternate architecture.")@@ -476,26 +477,26 @@           strOption (long "ignoregroup" <> metavar "PKG(,PKG,...)" <> hidden <> help "Ignore packages from the given groups.")  somePkgs :: Parser (NESet PkgName)-somePkgs = NES.fromList . fromJust . NEL.nonEmpty . map PkgName <$> some (argument str (metavar "PACKAGES"))+somePkgs = NES.fromList . NEL.fromList . map PkgName <$> some (argument str (metavar "PACKAGES"))  -- | Same as `someArgs`, but the help message "brief display" won't show PACKAGES. somePkgs' :: Parser (NESet PkgName)-somePkgs' = NES.fromList . fromJust . NEL.nonEmpty . map PkgName <$> some (argument str (metavar "PACKAGES" <> hidden))+somePkgs' = NES.fromList . NEL.fromList . map PkgName <$> some (argument str (metavar "PACKAGES" <> hidden))  -- | One or more arguments.-someArgs :: Parser (NESet T.Text)-someArgs = NES.fromList . fromJust . NEL.nonEmpty <$> some (argument str (metavar "PACKAGES"))+someArgs :: Parser (NESet Text)+someArgs = NES.fromList . NEL.fromList <$> some (argument str (metavar "PACKAGES"))  -- | Same as `someArgs`, but the help message "brief display" won't show PACKAGES.-someArgs' :: Parser (NESet T.Text)-someArgs' = NES.fromList . fromJust . NEL.nonEmpty <$> some (argument str (metavar "PACKAGES" <> hidden))+someArgs' :: Parser (NESet Text)+someArgs' = NES.fromList . NEL.fromList <$> some (argument str (metavar "PACKAGES" <> hidden))  -- | Zero or more arguments.-manyArgs :: Parser (S.Set T.Text)+manyArgs :: Parser (Set Text) manyArgs = S.fromList <$> many (argument str (metavar "PACKAGES"))  -- | Zero or more arguments.-manyArgs' :: Parser (S.Set T.Text)+manyArgs' :: Parser (Set Text) manyArgs' = S.fromList <$> many (argument str (metavar "PACKAGES" <> hidden))  language :: Parser Language
exec/Settings.hs view
@@ -26,20 +26,20 @@ import           Aura.Settings import           Aura.Types import           Aura.Utils-import           BasePrelude hiding (FilePath) import           Control.Error.Util (failWith) import           Control.Monad.Trans.Class (lift) import           Control.Monad.Trans.Except-import qualified Data.Map.Strict as M-import qualified Data.Set as S+import           Data.Bifunctor (Bifunctor(..)) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Flags-import           Lens.Micro+import           Lens.Micro (folded, (^..), _Right) import           Network.HTTP.Client (newManager) import           Network.HTTP.Client.TLS (tlsManagerSettings)+import           RIO hiding (FilePath, first)+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Environment (getEnvironment)-import           System.IO (hIsTerminalDevice, stdout)  --- 
exec/aura.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP               #-} {-# LANGUAGE DataKinds         #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE MonoLocalBinds    #-}@@ -51,19 +52,14 @@ import           Aura.Pacman import           Aura.Settings import           Aura.Types-import           BasePrelude hiding (Version)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, runError)-import           Control.Effect.Lift (Lift, runM, sendM)-import           Control.Effect.Reader (Reader, asks, runReader)-import           Data.Set (Set)+import           Aura.Utils (putTextLn)+import           Data.Bifunctor (first) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import qualified Data.Text.IO as T import           Data.Text.Prettyprint.Doc import           Data.Text.Prettyprint.Doc.Render.Terminal import           Flags import           Options.Applicative (execParser)+import           RIO hiding (first) import           Settings import           System.Path (toFilePath) import           System.Process.Typed (proc, runProcess)@@ -71,40 +67,45 @@  --- -auraVersion :: T.Text-auraVersion = "2.0.3"+#ifndef CURRENT_PACKAGE_VERSION+#define CURRENT_PACKAGE_VERSION "UNKNOWN"+#endif +auraVersion :: Text+auraVersion = CURRENT_PACKAGE_VERSION+ main :: IO () main = do   options   <- execParser opts   esettings <- getSettings options   repos     <- (<>) <$> pacmanRepo <*> aurRepo   case esettings of-    Left err -> T.putStrLn . dtot . ($ English) $ failure err+    Left err -> putTextLn . dtot . ($ English) $ failure err     Right ss -> execute ss repos options >>= exit ss  execute :: Settings -> Repository -> Program -> IO (Either (Doc AnsiStyle) ())-execute ss r p = first (($ langOf ss) . failure) <$> (runM . runReader (Env r ss) . runError . executeOpts $ _operation p)+execute ss r p = first f <$> try (runRIO (Env r ss) . execOpts $ _operation p)+  where+    f (Failure fl) = fl $ langOf ss  exit :: Settings -> Either (Doc AnsiStyle) () -> IO a exit ss (Left e)  = scold ss e *> exitFailure exit _  (Right _) = exitSuccess -executeOpts :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Either (PacmanOp, Set MiscOp) AuraOp -> m ()-executeOpts ops = do+execOpts :: Either (PacmanOp, Set MiscOp) AuraOp -> RIO Env ()+execOpts ops = do   ss <- asks settings   when (shared ss Debug) $ do-    sendM @IO . pPrintNoColor $ ops-    sendM @IO . pPrintNoColor $ buildConfigOf ss-    sendM @IO . pPrintNoColor $ commonConfigOf ss-  let p (ps, ms) = liftEitherM . sendM . pacman $+    liftIO . pPrintNoColor $ ops+    liftIO . pPrintNoColor $ buildConfigOf ss+    liftIO . pPrintNoColor $ commonConfigOf ss+  let p (ps, ms) = liftIO . pacman $         asFlag ps         ++ foldMap asFlag ms         ++ asFlag (commonConfigOf ss)         ++ bool [] ["--quiet"] (switch ss LowVerbosity)   case ops of-    Left o@(Sync (Left (SyncUpgrade _)) _, _) -> sudo (sendM $ B.saveState ss) *> p o+    Left o@(Sync (Left (SyncUpgrade _)) _, _) -> sudo (liftIO $ B.saveState ss) *> p o     Left o -> p o     Right (AurSync o _) ->       case o of@@ -117,10 +118,10 @@         Left (AurJson ps)     -> A.aurJson ps     Right (Backup o) ->       case o of-        Nothing              -> sudo . sendM $ B.saveState ss-        Just (BackupClean n) -> sudo . sendM $ B.cleanStates ss n+        Nothing              -> sudo . liftIO $ B.saveState ss+        Just (BackupClean n) -> sudo . liftIO $ B.cleanStates ss n         Just BackupRestore   -> sudo B.restoreState-        Just BackupList      -> sendM B.listStates+        Just BackupList      -> liftIO B.listStates     Right (Cache o) ->       case o of         Right ps                -> sudo $ C.downgradePackages ps@@ -132,23 +133,23 @@       case o of         Nothing            -> L.viewLogFile         Just (LogInfo ps)  -> L.logInfoOnPkg ps-        Just (LogSearch s) -> asks settings >>= sendM . flip L.searchLogFile s+        Just (LogSearch s) -> asks settings >>= liftIO . flip L.searchLogFile s     Right (Orphans o) ->       case o of-        Nothing               -> sendM O.displayOrphans-        Just OrphanAbandon    -> sudo $ sendM orphans >>= traverse_ removePkgs . NES.nonEmptySet+        Nothing               -> liftIO O.displayOrphans+        Just OrphanAbandon    -> sudo $ liftIO orphans >>= traverse_ removePkgs . NES.nonEmptySet         Just (OrphanAdopt ps) -> O.adoptPkg ps-    Right Version   -> sendM $ versionInfo >>= animateVersionMsg ss auraVersion+    Right Version   -> liftIO $ versionInfo >>= animateVersionMsg ss auraVersion     Right Languages -> displayOutputLanguages     Right ViewConf  -> viewConfFile -displayOutputLanguages :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => m ()+displayOutputLanguages :: RIO Env () displayOutputLanguages = do   ss <- asks settings-  sendM . notify ss . displayOutputLanguages_1 $ langOf ss-  sendM $ traverse_ print [English ..]+  liftIO . notify ss . displayOutputLanguages_1 $ langOf ss+  liftIO $ traverse_ (putTextLn . tshow) [English ..] -viewConfFile :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => m ()+viewConfFile :: RIO Env () viewConfFile = do   pth <- asks (either id id . configPathOf . commonConfigOf . settings)-  sendM . void . runProcess @IO $ proc "less" [toFilePath pth]+  liftIO . void . runProcess @IO $ proc "less" [toFilePath pth]
lib/Aura/Build.hs view
@@ -25,25 +25,18 @@ import           Aura.Settings import           Aura.Types import           Aura.Utils-import           BasePrelude import           Control.Compactable (traverseMaybe)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Monad.Trans.Class (lift) import           Control.Monad.Trans.Except-import qualified Data.ByteString.Lazy.Char8 as BL import           Data.Generics.Product (field) import qualified Data.List.NonEmpty as NEL import           Data.Semigroup.Foldable (fold1)-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import           Lens.Micro ((^.))-import           System.Directory (setCurrentDirectory)-import           System.IO (hFlush, stdout)+import           RIO+import           RIO.Directory (setCurrentDirectory)+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path import           System.Path.IO import           System.Process.Typed@@ -55,30 +48,27 @@ srcPkgStore = fromAbsoluteFilePath "/var/cache/aura/src"  -- | Expects files like: \/var\/cache\/pacman\/pkg\/*.pkg.tar.xz-installPkgFiles :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PackagePath -> m ()+installPkgFiles :: NESet PackagePath -> RIO Env () installPkgFiles files = do   ss <- asks settings-  sendM $ checkDBLock ss-  liftEitherM . sendM . pacman $ ["-U"] <> map (T.pack . toFilePath . path) (toList files) <> asFlag (commonConfigOf ss)+  liftIO $ checkDBLock ss+  liftIO . pacman $ ["-U"] <> map (T.pack . toFilePath . path) (toList files) <> asFlag (commonConfigOf ss)  -- | All building occurs within temp directories, -- or in a location specified by the user with flags.-buildPackages :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet Buildable -> m (NESet PackagePath)+buildPackages :: NESet Buildable -> RIO Env (NESet PackagePath) buildPackages bs = do-  g <- sendM createSystemRandom+  g <- liftIO createSystemRandom   traverseMaybe (build g) (toList bs) >>= maybe bad (pure . fold1) . NEL.nonEmpty-  where bad = throwError $ Failure buildFail_10+  where bad = throwM $ Failure buildFail_10  -- | Handles the building of Packages. Fails nicely. -- Assumed: All dependencies are already installed.-build :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  GenIO -> Buildable -> m (Maybe (NESet PackagePath))+build :: GenIO -> Buildable -> RIO Env (Maybe (NESet PackagePath)) build g p = do   ss     <- asks settings-  sendM $ notify ss (buildPackages_1 (p ^. field @"name") (langOf ss)) *> hFlush stdout-  result <- sendM $ build' ss g p+  liftIO $ notify ss (buildPackages_1 (p ^. field @"name") (langOf ss)) *> hFlush stdout+  result <- liftIO $ build' ss g p   either buildFail (pure . Just) result  -- | Should never throw an IO Exception. In theory all errors@@ -123,16 +113,16 @@ -- overwrite what's been downloaded before calling `makepkg`. overwritePkgbuild :: Settings -> Buildable -> IO () overwritePkgbuild ss p = when (switch ss HotEdit || switch ss UseCustomizepkg) $-  BL.writeFile "PKGBUILD" $ p ^. field @"pkgbuild" . field @"pkgbuild"+  writeFileBinary "PKGBUILD" $ p ^. field @"pkgbuild" . field @"pkgbuild"  -- | Inform the user that building failed. Ask them if they want to -- continue installing previous packages that built successfully.-buildFail :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => Failure -> m (Maybe a)+buildFail :: Failure -> RIO Env (Maybe a) buildFail (Failure err) = do   ss <- asks settings-  sendM . scold ss . err $ langOf ss-  response <- sendM $ optionalPrompt ss buildFail_6-  bool (throwError $ Failure buildFail_5) (pure Nothing) response+  liftIO . scold ss . err $ langOf ss+  response <- liftIO $ optionalPrompt ss buildFail_6+  bool (throwM $ Failure buildFail_5) (pure Nothing) response  -- | Moves a file to the pacman package cache and returns its location. moveToCachePath :: Settings -> Path Absolute -> IO PackagePath
lib/Aura/Cache.hs view
@@ -23,14 +23,13 @@  import           Aura.Settings import           Aura.Types-import           BasePrelude import           Data.Generics.Product (field)-import qualified Data.Map.Strict as M-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import           Lens.Micro ((^.))+import           RIO+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path     (Absolute, Path, fromAbsoluteFilePath, toFilePath, (</>)) import           System.Path.IO (getDirectoryContents)@@ -38,7 +37,7 @@ ---  -- | Every package in the current cache, paired with its original filename.-newtype Cache = Cache { _cache :: M.Map SimplePkg PackagePath }+newtype Cache = Cache { _cache :: Map SimplePkg PackagePath }  -- | The default location of the package cache: \/var\/cache\/pacman\/pkg\/ defaultPackageCache :: Path Absolute@@ -56,14 +55,14 @@ cacheContents :: Path Absolute -> IO Cache cacheContents pth = cache . map (PackagePath . (pth </>)) <$> getDirectoryContents pth --- | All packages from a given `S.Set` who have a copy in the cache.-pkgsInCache :: Settings -> NESet PkgName -> IO (S.Set PkgName)+-- | All packages from a given `Set` who have a copy in the cache.+pkgsInCache :: Settings -> NESet PkgName -> IO (Set PkgName) pkgsInCache ss ps = do   c <- cacheContents . either id id . cachePathOf $ commonConfigOf ss   pure . S.filter (`NES.member` ps) . S.map (^. field @"name") . M.keysSet $ _cache c --- | Any entries (filepaths) in the cache that match a given `T.Text`.-cacheMatches :: Settings -> T.Text -> IO [PackagePath]+-- | Any entries (filepaths) in the cache that match a given `Text`.+cacheMatches :: Settings -> Text -> IO [PackagePath] cacheMatches ss input = do   c <- cacheContents . either id id . cachePathOf $ commonConfigOf ss   pure . filter (T.isInfixOf input . T.pack . toFilePath . path) . M.elems $ _cache c
lib/Aura/Colour.hs view
@@ -13,10 +13,9 @@   , cyan, bCyan, green, yellow, red, magenta   ) where -import BasePrelude-import Data.Text (Text) import Data.Text.Prettyprint.Doc import Data.Text.Prettyprint.Doc.Render.Terminal+import RIO  --- 
lib/Aura/Commands/A.hs view
@@ -36,46 +36,44 @@ import           Aura.State (saveState) import           Aura.Types import           Aura.Utils-import           BasePrelude hiding ((<+>))-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Error.Util (hush)-import           Data.Aeson.Encode.Pretty (encodePrettyToTextBuilder)+import           Data.Aeson.Encode.Pretty (encodePretty) import           Data.Generics.Product (field) import qualified Data.List.NonEmpty as NEL-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import qualified Data.Text.IO as T-import           Data.Text.Lazy (toStrict)-import           Data.Text.Lazy.Builder (toLazyText) import           Data.Text.Prettyprint.Doc import           Data.Text.Prettyprint.Doc.Render.Terminal import           Data.Versions (Versioning, prettyV, versioning)-import           Lens.Micro (each, (^.), (^..))-import           Lens.Micro.Extras (view)+import           Lens.Micro (each, (^..)) import           Linux.Arch.Aur+import           Network.HTTP.Client (Manager)+import           RIO+import qualified RIO.ByteString as B+import qualified RIO.ByteString.Lazy as BL+import           RIO.List (intersperse)+import           RIO.List.Partial (maximum)+import qualified RIO.Set as S+import qualified RIO.Text as T+import           RIO.Text.Partial (splitOn)+import           Text.Printf (printf)  ---  -- | The result of @-Au@.-upgradeAURPkgs :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => S.Set PkgName -> m ()+upgradeAURPkgs :: Set PkgName -> RIO Env () upgradeAURPkgs pkgs = do   ss <- asks settings-  sendM . notify ss . upgradeAURPkgs_1 $ langOf ss-  sendM (foreigns ss) >>= traverse_ (upgrade pkgs) . NES.nonEmptySet+  liftIO . notify ss . upgradeAURPkgs_1 $ langOf ss+  liftIO (foreigns ss) >>= traverse_ (upgrade pkgs) . NES.nonEmptySet  -- | Foreign packages to consider for upgrading, after "ignored packages" have -- been taken into consideration.-foreigns :: Settings -> IO (S.Set SimplePkg)+foreigns :: Settings -> IO (Set SimplePkg) foreigns ss = S.filter (notIgnored . view (field @"name")) <$> foreignPackages   where notIgnored p = not . S.member p $ ignoresOf ss -upgrade :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  S.Set PkgName -> NESet SimplePkg -> m ()+upgrade :: Set PkgName -> NESet SimplePkg -> RIO Env () upgrade pkgs fs = do   ss        <- asks settings   toUpgrade <- possibleUpdates fs@@ -85,15 +83,14 @@     Just a  -> auraUpgrade a     Nothing -> do       devel <- develPkgCheck-      sendM . notify ss . upgradeAURPkgs_2 $ langOf ss-      if | null toUpgrade && null devel -> sendM . warn ss . upgradeAURPkgs_3 $ langOf ss+      liftIO . notify ss . upgradeAURPkgs_2 $ langOf ss+      if | null toUpgrade && null devel -> liftIO . warn ss . upgradeAURPkgs_3 $ langOf ss          | otherwise -> do              reportPkgsToUpgrade toUpgrade (toList devel)-             sendM . unless (switch ss DryRun) $ saveState ss+             liftIO . unless (switch ss DryRun) $ saveState ss              traverse_ I.install . NES.nonEmptySet $ S.fromList names <> pkgs <> devel -possibleUpdates :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet SimplePkg -> m [(AurInfo, Versioning)]+possibleUpdates :: NESet SimplePkg -> RIO Env [(AurInfo, Versioning)] possibleUpdates (NES.toList -> pkgs) = do   aurInfos <- aurInfo $ fmap (^. field @"name") pkgs   let !names  = map aurNameOf aurInfos@@ -101,30 +98,30 @@   pure . filter isntMostRecent . zip aurInfos $ aurPkgs ^.. each . field @"version"  -- | Is there an update for Aura that we could apply first?-auraCheck :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => [PkgName] -> m (Maybe PkgName)+auraCheck :: [PkgName] -> RIO Env (Maybe PkgName) auraCheck ps = join <$> traverse f auraPkg   where f a = do           ss <- asks settings-          bool Nothing (Just a) <$> sendM (optionalPrompt ss auraCheck_1)+          bool Nothing (Just a) <$> liftIO (optionalPrompt ss auraCheck_1)         auraPkg | "aura" `elem` ps     = Just "aura"                 | "aura-bin" `elem` ps = Just "aura-bin"                 | otherwise            = Nothing -auraUpgrade :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => PkgName -> m ()+auraUpgrade :: PkgName -> RIO Env () auraUpgrade = I.install . NES.singleton -develPkgCheck :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => m (S.Set PkgName)+develPkgCheck :: RIO Env (Set PkgName) develPkgCheck = asks settings >>= \ss ->-  if switch ss RebuildDevel then sendM develPkgs else pure S.empty+  if switch ss RebuildDevel then liftIO develPkgs else pure S.empty  -- | The result of @-Ai@.-aurPkgInfo :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => NESet PkgName -> m ()+aurPkgInfo :: NESet PkgName -> RIO Env () aurPkgInfo = aurInfo . NES.toList >=> traverse_ displayAurPkgInfo -displayAurPkgInfo :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => AurInfo -> m ()-displayAurPkgInfo ai = asks settings >>= \ss -> sendM . T.putStrLn $ renderAurPkgInfo ss ai <> "\n"+displayAurPkgInfo :: AurInfo -> RIO Env ()+displayAurPkgInfo ai = asks settings >>= \ss -> liftIO . putTextLn $ renderAurPkgInfo ss ai <> "\n" -renderAurPkgInfo :: Settings -> AurInfo -> T.Text+renderAurPkgInfo :: Settings -> AurInfo -> Text renderAurPkgInfo ss ai = dtot . colourCheck ss $ entrify ss fields entries     where fields   = infoFields . langOf $ ss           entries = [ magenta "aur"@@ -142,27 +139,26 @@                     , maybe "(null)" pretty $ aurDescriptionOf ai ]  -- | The result of @-As@.-aurPkgSearch :: (Monad m, Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  T.Text -> m ()+aurPkgSearch :: Text -> RIO Env () aurPkgSearch regex = do   ss <- asks settings-  db <- S.map (^. field @"name" . field @"name") <$> sendM foreignPackages+  db <- S.map (^. field @"name" . field @"name") <$> liftIO foreignPackages   let t = case truncationOf $ buildConfigOf ss of  -- Can't this go anywhere else?             None   -> id             Head n -> take $ fromIntegral n             Tail n -> reverse . take (fromIntegral n) . reverse   results <- fmap (\x -> (x, aurNameOf x `S.member` db)) . t             <$> aurSearch regex-  sendM $ traverse_ (T.putStrLn . renderSearch ss regex) results+  liftIO $ traverse_ (putTextLn . renderSearch ss regex) results -renderSearch :: Settings -> T.Text -> (AurInfo, Bool) -> T.Text+renderSearch :: Settings -> Text -> (AurInfo, Bool) -> Text renderSearch ss r (i, e) = searchResult     where searchResult = if switch ss LowVerbosity then sparseInfo else dtot $ colourCheck ss verboseInfo           sparseInfo   = aurNameOf i           verboseInfo  = repo <> n <+> v <+> "(" <> l <+> "|" <+> p <>                          ")" <> (if e then annotate bold " [installed]" else "") <> "\n    " <> d           repo = magenta "aur/"-          n = fold . intersperse (bCyan $ pretty r) . map (annotate bold . pretty) . T.splitOn r $ aurNameOf i+          n = fold . intersperse (bCyan $ pretty r) . map (annotate bold . pretty) . splitOn r $ aurNameOf i           d = maybe "(null)" pretty $ aurDescriptionOf i           l = yellow . pretty $ aurVotesOf i  -- `l` for likes?           p = yellow . pretty . T.pack . printf "%0.2f" $ popularityOf i@@ -171,40 +167,39 @@             Nothing -> green . pretty $ aurVersionOf i  -- | The result of @-Ap@.-displayPkgbuild :: (Monad m, Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+displayPkgbuild :: NESet PkgName -> RIO Env () displayPkgbuild ps = do   man <- asks (managerOf . settings)-  pbs <- catMaybes <$> traverse (sendM . getPkgbuild @IO man) (toList ps)-  sendM . traverse_ (T.putStrLn . strictText) $ pbs ^.. each . field @"pkgbuild"+  pbs <- catMaybes <$> traverse (liftIO . getPkgbuild man) (toList ps)+  liftIO . traverse_ (\p -> B.putStr @IO p >> B.putStr "\n") $ pbs ^.. each . field @"pkgbuild"  isntMostRecent :: (AurInfo, Versioning) -> Bool isntMostRecent (ai, v) = trueVer > Just v   where trueVer = hush . versioning $ aurVersionOf ai  -- | Similar to @-Ai@, but yields the raw data as JSON instead.-aurJson :: (Carrier sig m , Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+aurJson :: NESet PkgName -> RIO Env () aurJson ps = do   m <- asks (managerOf . settings)-  infos <- liftMaybeM (Failure connectionFailure_1) . fmap hush . sendM . info m . (^.. each . field @"name") $ toList ps-  let json = map (toStrict . toLazyText . encodePrettyToTextBuilder) infos-  sendM $ traverse_ T.putStrLn json+  infos <- liftMaybeM (Failure connectionFailure_1) . fmap hush . liftIO $ f m ps+  liftIO $ traverse_ (BL.putStrLn @IO . encodePretty) infos+  where+    f :: Manager -> NESet PkgName -> IO (Either ClientError [AurInfo])+    f m = info m . (^.. each . field @"name") . toList  ------------ -- REPORTING -------------reportPkgsToUpgrade :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  [(AurInfo, Versioning)] -> [PkgName] -> m ()+reportPkgsToUpgrade :: [(AurInfo, Versioning)] -> [PkgName] -> RIO Env () reportPkgsToUpgrade ups pns = do   ss <- asks settings-  sendM . notify ss . reportPkgsToUpgrade_1 $ langOf ss-  sendM $ putDoc (colourCheck ss . vcat $ map f ups' <> map g devels) >> T.putStrLn "\n"+  liftIO . notify ss . reportPkgsToUpgrade_1 $ langOf ss+  liftIO $ putDoc (colourCheck ss . vcat $ map f ups' <> map g devels) >> putTextLn "\n"   where devels   = pns ^.. each . field @"name"         ups'     = map (second prettyV) ups         nLen     = maximum $ map (T.length . aurNameOf . fst) ups <> map T.length devels         vLen     = maximum $ map (T.length . snd) ups'-        g = annotate (color Cyan) . pretty+        g        = annotate (color Cyan) . pretty         f (p, v) = hsep [ cyan . fill nLen . pretty $ aurNameOf p                         , "::"                         , yellow . fill vLen $ pretty v
lib/Aura/Commands/B.hs view
@@ -23,9 +23,11 @@ import           Aura.Languages import           Aura.Settings import           Aura.State-import           Aura.Utils (optionalPrompt)-import           BasePrelude-import qualified Data.Text as T+import           Aura.Utils (optionalPrompt, putTextLn)+import qualified Data.List.NonEmpty as NEL+import           RIO+import           RIO.List (partition)+import qualified RIO.Text as T import           System.Path (takeFileName, toFilePath, toUnrootedFilePath) import           System.Path.IO (removeFile) @@ -38,12 +40,16 @@   (pinned, others) <- partition p <$> traverse (\sf -> (sf,) <$> readState sf) stfs   warn ss . cleanStates_4 (length stfs) $ langOf ss   unless (null pinned) . warn ss . cleanStates_6 (length pinned) $ langOf ss-  unless (null stfs) . warn ss . cleanStates_5 (T.pack . toUnrootedFilePath . takeFileName $ head stfs) $ langOf ss+  forM_ (NEL.nonEmpty stfs) $ \stfs' -> do+    let mostRecent = T.pack . toUnrootedFilePath . takeFileName $ NEL.head stfs'+    warn ss . cleanStates_5 mostRecent $ langOf ss   okay <- optionalPrompt ss $ cleanStates_2 n   if | not okay  -> warn ss . cleanStates_3 $ langOf ss      | otherwise -> traverse_ (removeFile . fst) . drop n $ others-  where p = maybe False pinnedOf . snd+  where+    p :: (a, Maybe PkgState) -> Bool+    p = maybe False pinnedOf . snd  -- | The result of @-Bl@. listStates :: IO ()-listStates = getStateFiles >>= traverse_ (putStrLn . toFilePath)+listStates = getStateFiles >>= traverse_ (putTextLn . T.pack . toFilePath)
lib/Aura/Commands/C.hs view
@@ -31,19 +31,16 @@ import           Aura.State import           Aura.Types import           Aura.Utils-import           BasePrelude-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Data.Generics.Product (field) import           Data.List.NonEmpty (nonEmpty)-import qualified Data.Map.Strict as M-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Lens.Micro ((^?), _Just)+import           RIO+import           RIO.List (groupBy, sort, (\\))+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path import           System.Path.IO (copyFile, doesDirectoryExist, removeFile) @@ -51,113 +48,109 @@  -- | Interactive. Gives the user a choice as to exactly what versions -- they want to downgrade to.-downgradePackages :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+downgradePackages :: NESet PkgName -> RIO Env () downgradePackages pkgs = do   ss    <- asks settings   let cachePath = either id id . cachePathOf $ commonConfigOf ss-  reals <- sendM $ pkgsInCache ss pkgs+  reals <- liftIO $ pkgsInCache ss pkgs   traverse_ (report red reportBadDowngradePkgs_1) . nonEmpty . toList $ NES.toSet pkgs S.\\ reals   unless (null reals) $ do-    cache   <- sendM $ cacheContents cachePath+    cache   <- liftIO $ cacheContents cachePath     choices <- traverse (getDowngradeChoice cache) $ toList reals-    liftEitherM . sendM . pacman $ "-U" : asFlag (commonConfigOf ss) <> map (T.pack . toFilePath . path) choices+    liftIO . pacman $ "-U" : asFlag (commonConfigOf ss) <> map (T.pack . toFilePath . path) choices  -- | For a given package, get a choice from the user about which version of it to -- downgrade to.-getDowngradeChoice :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Cache -> PkgName -> m PackagePath+getDowngradeChoice :: Cache -> PkgName -> RIO Env PackagePath getDowngradeChoice cache pkg =   case nonEmpty $ getChoicesFromCache cache pkg of-    Nothing      -> throwError . Failure $ reportBadDowngradePkgs_2 pkg+    Nothing      -> throwM . Failure $ reportBadDowngradePkgs_2 pkg     Just choices -> do       ss <- asks settings-      sendM . notify ss . getDowngradeChoice_1 pkg $ langOf ss-      sendM $ getSelection (T.pack . toFilePath . path) choices+      liftIO . notify ss . getDowngradeChoice_1 pkg $ langOf ss+      liftIO $ getSelection (T.pack . toFilePath . path) choices  getChoicesFromCache :: Cache -> PkgName -> [PackagePath] getChoicesFromCache (Cache cache) p = sort . M.elems $ M.filterWithKey (\(SimplePkg pn _) _ -> p == pn) cache --- | Print all package filenames that match a given `T.Text`.-searchCache :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => T.Text -> m ()+-- | Print all package filenames that match a given `Text`.+searchCache :: Text -> RIO Env () searchCache ps = do   ss <- asks settings-  matches <- sendM $ cacheMatches ss ps-  sendM . traverse_ (putStrLn . toFilePath . path) $ sort matches+  matches <- liftIO $ cacheMatches ss ps+  liftIO . traverse_ (putTextLn . T.pack . toFilePath . path) $ sort matches  -- | The destination folder must already exist for the back-up to begin.-backupCache :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Path Absolute -> m ()+backupCache :: Path Absolute -> RIO Env () backupCache dir = do-  exists <- sendM $ doesDirectoryExist dir-  if | not exists -> throwError $ Failure backupCache_3+  exists <- liftIO $ doesDirectoryExist dir+  if | not exists -> throwM $ Failure backupCache_3      | otherwise  -> confirmBackup dir >>= backup dir -confirmBackup :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Path Absolute -> m Cache+confirmBackup :: Path Absolute -> RIO Env Cache confirmBackup dir = do   ss    <- asks settings-  cache <- sendM . cacheContents . either id id . cachePathOf $ commonConfigOf ss-  sendM . notify ss $ backupCache_4 (toFilePath dir) (langOf ss)-  sendM . notify ss $ backupCache_5 (M.size $ _cache cache) (langOf ss)-  okay  <- sendM $ optionalPrompt ss backupCache_6-  bool (throwError $ Failure backupCache_7) (pure cache) okay+  cache <- liftIO . cacheContents . either id id . cachePathOf $ commonConfigOf ss+  liftIO . notify ss $ backupCache_4 (toFilePath dir) (langOf ss)+  liftIO . notify ss $ backupCache_5 (M.size $ _cache cache) (langOf ss)+  okay  <- liftIO $ optionalPrompt ss backupCache_6+  bool (throwM $ Failure backupCache_7) (pure cache) okay -backup :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  Path Absolute -> Cache -> m ()+backup :: Path Absolute -> Cache -> RIO Env () backup dir (Cache cache) = do   ss <- asks settings-  sendM . notify ss . backupCache_8 $ langOf ss-  sendM $ putStrLn ""  -- So that the cursor can rise at first.+  liftIO . notify ss . backupCache_8 $ langOf ss+  liftIO $ putTextLn ""  -- So that the cursor can rise at first.   copyAndNotify dir (M.elems cache) 1  -- | Manages the file copying and display of the real-time progress notifier.-copyAndNotify :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  Path Absolute -> [PackagePath] -> Int -> m ()+copyAndNotify :: Path Absolute -> [PackagePath] -> Int -> RIO Env () copyAndNotify _ [] _ = pure () copyAndNotify dir (PackagePath p : ps) n = do   ss <- asks settings-  sendM $ raiseCursorBy 1-  sendM . warn ss . copyAndNotify_1 n $ langOf ss-  sendM $ copyFile p dir+  liftIO $ raiseCursorBy 1+  liftIO . warn ss . copyAndNotify_1 n $ langOf ss+  liftIO $ copyFile p dir   copyAndNotify dir ps $ n + 1  -- | Keeps a certain number of package files in the cache according to -- a number provided by the user. The rest are deleted.-cleanCache :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Word -> m ()+cleanCache :: Word -> RIO Env () cleanCache toSave-  | toSave == 0 = asks settings >>= \ss -> sendM (warn ss . cleanCache_2 $ langOf ss) >> (liftEitherM . sendM . pacman $ ["-Scc"])-  | otherwise   = do+  | toSave == 0 = do       ss <- asks settings-      sendM . warn ss . cleanCache_3 toSave $ langOf ss-      okay <- sendM $ optionalPrompt ss cleanCache_4-      bool (throwError $ Failure cleanCache_5) (clean (fromIntegral toSave)) okay+      liftIO . warn ss . cleanCache_2 $ langOf ss+      liftIO $ pacman ["-Scc"]+  | otherwise = do+      ss <- asks settings+      liftIO . warn ss . cleanCache_3 toSave $ langOf ss+      okay <- liftIO $ optionalPrompt ss cleanCache_4+      bool (throwM $ Failure cleanCache_5) (clean (fromIntegral toSave)) okay -clean :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => Int -> m ()+clean :: Int -> RIO Env () clean toSave = do   ss <- asks settings-  sendM . notify ss . cleanCache_6 $ langOf ss+  liftIO . notify ss . cleanCache_6 $ langOf ss   let cachePath = either id id . cachePathOf $ commonConfigOf ss-  (Cache cache) <- sendM $ cacheContents cachePath+  (Cache cache) <- liftIO $ cacheContents cachePath   let !files    = M.elems cache       grouped   = take toSave . reverse <$> groupByName files       toRemove  = files \\ fold grouped-  sendM $ traverse_ removeFile $ map path toRemove+  liftIO $ traverse_ (removeFile . path) toRemove  -- | Only package files with a version not in any PkgState will be -- removed.-cleanNotSaved :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => m ()+cleanNotSaved :: RIO Env () cleanNotSaved = do   ss <- asks settings-  sendM . notify ss . cleanNotSaved_1 $ langOf ss-  sfs <- sendM getStateFiles-  states <- fmap catMaybes . sendM $ traverse readState sfs+  liftIO . notify ss . cleanNotSaved_1 $ langOf ss+  sfs <- liftIO getStateFiles+  states <- fmap catMaybes . liftIO $ traverse readState sfs   let cachePath = either id id . cachePathOf $ commonConfigOf ss-  (Cache cache)  <- sendM $ cacheContents cachePath+  (Cache cache)  <- liftIO $ cacheContents cachePath   let duds = M.filterWithKey (\p _ -> any (inState p) states) cache-  prop <- sendM . optionalPrompt ss $ cleanNotSaved_2 $ M.size duds-  when prop . sendM . traverse_ removeFile . map path $ M.elems duds+  prop <- liftIO . optionalPrompt ss $ cleanNotSaved_2 $ M.size duds+  when prop . liftIO . traverse_ (removeFile . path) $ M.elems duds  -- | Typically takes the contents of the package cache as an argument. groupByName :: [PackagePath] -> [[PackagePath]]
lib/Aura/Commands/L.hs view
@@ -25,57 +25,50 @@ import           Aura.Settings import           Aura.Types (PkgName(..)) import           Aura.Utils-import           BasePrelude hiding (FilePath) import           Control.Compactable (fmapEither)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks)-import qualified Data.ByteString.Char8 as BS import           Data.Generics.Product (field) import qualified Data.List.NonEmpty as NEL import           Data.Set.NonEmpty (NESet)-import qualified Data.Text as T-import           Data.Text.Encoding as T-import           Data.Text.Encoding.Error (lenientDecode)-import qualified Data.Text.IO as T import           Data.Text.Prettyprint.Doc-import           Lens.Micro ((^.))+import           RIO hiding (FilePath)+import qualified RIO.Text as T+import qualified RIO.Text.Partial as T import           System.Path (toFilePath) import           System.Process.Typed (proc, runProcess)  ---  -- | The contents of the Pacman log file.-newtype Log = Log [T.Text]+newtype Log = Log [Text]  data LogEntry = LogEntry   { name         :: PkgName-  , firstInstall :: T.Text+  , firstInstall :: Text   , upgrades     :: Word-  , recent       :: [T.Text] }+  , recent       :: [Text] }  -- | Pipes the pacman log file through a @less@ session.-viewLogFile :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => m ()+viewLogFile :: RIO Env () viewLogFile = do   pth <- asks (toFilePath . either id id . logPathOf . commonConfigOf . settings)-  sendM . void . runProcess @IO $ proc "less" [pth]+  liftIO . void . runProcess @IO $ proc "less" [pth] --- | Print all lines in the log file which contain a given `T.Text`.-searchLogFile :: Settings -> T.Text -> IO ()+-- | Print all lines in the log file which contain a given `Text`.+searchLogFile :: Settings -> Text -> IO () searchLogFile ss input = do   let pth = toFilePath . either id id . logPathOf $ commonConfigOf ss-  logFile <- map (T.decodeUtf8With lenientDecode) . BS.lines <$> BS.readFile pth-  traverse_ T.putStrLn $ searchLines input logFile+  logFile <- T.lines . decodeUtf8Lenient <$> readFileBinary pth+  traverse_ putTextLn $ searchLines input logFile  -- | The result of @-Li@.-logInfoOnPkg :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => NESet PkgName -> m ()+logInfoOnPkg :: NESet PkgName -> RIO Env () logInfoOnPkg pkgs = do   ss <- asks settings   let pth = toFilePath . either id id . logPathOf $ commonConfigOf ss-  logFile <- Log . map (T.decodeUtf8With lenientDecode) . BS.lines <$> sendM (BS.readFile pth)+  logFile <- Log . T.lines . decodeUtf8Lenient <$> liftIO (readFileBinary @IO pth)   let (bads, goods) = fmapEither (logLookup logFile) $ toList pkgs   traverse_ (report red reportNotInLog_1) $ NEL.nonEmpty bads-  sendM . traverse_ T.putStrLn $ map (renderEntry ss) goods+  liftIO . traverse_ putTextLn $ map (renderEntry ss) goods  logLookup :: Log -> PkgName -> Either PkgName LogEntry logLookup (Log lns) p = case matches of@@ -87,7 +80,7 @@              , recent = reverse . take 5 $ reverse t }   where matches = filter (T.isInfixOf (" " <> (p ^. field @"name") <> " (")) lns -renderEntry :: Settings -> LogEntry -> T.Text+renderEntry :: Settings -> LogEntry -> Text renderEntry ss (LogEntry (PkgName pn) fi us rs) =   dtot . colourCheck ss $ entrify ss fields entries <> hardline <> recents <> hardline   where fields  = logLookUpFields $ langOf ss
lib/Aura/Commands/O.hs view
@@ -14,25 +14,20 @@  module Aura.Commands.O ( displayOrphans, adoptPkg ) where -import           Aura.Core (Env(..), liftEitherM, orphans, sudo)-import           Aura.Pacman (pacman)-import           Aura.Types-import           BasePrelude-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader)-import           Data.Generics.Product (field)-import           Data.Set.NonEmpty (NESet)-import qualified Data.Text.IO as T-import           Lens.Micro.Extras (view)+import Aura.Core (Env(..), orphans, sudo)+import Aura.Pacman (pacman)+import Aura.Types+import Aura.Utils (putTextLn)+import Data.Generics.Product (field)+import Data.Set.NonEmpty (NESet)+import RIO  ---  -- | Print the result of @pacman -Qqdt@ displayOrphans :: IO ()-displayOrphans = orphans >>= traverse_ (T.putStrLn . view (field @"name"))+displayOrphans = orphans >>= traverse_ (putTextLn . view (field @"name"))  -- | Identical to @-D --asexplicit@.-adoptPkg :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => NESet PkgName -> m ()-adoptPkg pkgs = sudo . liftEitherM . sendM . pacman $ ["-D", "--asexplicit"] <> asFlag pkgs+adoptPkg :: NESet PkgName -> RIO Env ()+adoptPkg pkgs = sudo . liftIO . pacman $ ["-D", "--asexplicit"] <> asFlag pkgs
lib/Aura/Core.hs view
@@ -18,8 +18,7 @@   ( -- * Types     Env(..)   , Repository(..)-  , liftEither, liftEitherM-  , liftMaybe, liftMaybeM+  , liftMaybeM     -- * User Privileges   , sudo, trueRoot     -- * Querying the Package Database@@ -40,29 +39,23 @@ import           Aura.Settings import           Aura.Types import           Aura.Utils-import           BasePrelude hiding ((<>)) import           Control.Compactable (fmapEither)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Monad.Trans.Maybe-import qualified Data.ByteString.Lazy.Char8 as BL+import           Data.Bifunctor (bimap) import           Data.Generics.Product (field)+import           Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NEL-import           Data.Map.Strict (Map)-import           Data.Semigroup-import           Data.Set (Set)-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import qualified Data.Text.IO as T import           Data.Text.Prettyprint.Doc import           Data.Text.Prettyprint.Doc.Render.Terminal import           Data.These (These(..)) import           Lens.Micro ((^.))-import           Lens.Micro.Extras (view)+import           RIO hiding ((<>))+import qualified RIO.ByteString as B+import           RIO.List (unzip)+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path.IO (doesFileExist)  ---@@ -114,43 +107,28 @@ ----------- -- THE WORK -------------- | Lift a common return type into the `fused-effects` world. Usually used--- after a `pacman` call.-liftEither :: (Carrier sig m, Member (Error a) sig) => Either a b -> m b-liftEither = either throwError pure---- | Like `liftEither`, but the `Either` can be embedded in something else,--- usually a `Monad`.-liftEitherM :: (Carrier sig m, Member (Error a) sig) => m (Either a b) -> m b-liftEitherM m = m >>= liftEither---- | Like `liftEither`, but for `Maybe`.-liftMaybe :: (Carrier sig m, Member (Error a) sig) => a -> Maybe b -> m b-liftMaybe a = maybe (throwError a) pure---- | Like `liftEitherM`, but for `Maybe`.-liftMaybeM :: (Carrier sig m, Member (Error a) sig) => a -> m (Maybe b) -> m b-liftMaybeM a m = m >>= liftMaybe a+liftMaybeM :: (MonadThrow m, Exception e) => e -> m (Maybe a) -> m a+liftMaybeM a m = m >>= maybe (throwM a) pure  -- | Action won't be allowed unless user is root, or using sudo.-sudo :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig) => m a -> m a-sudo action = asks (hasRootPriv . envOf . settings) >>= bool (throwError $ Failure mustBeRoot_1) action+sudo :: RIO Env a -> RIO Env a+sudo act = asks (hasRootPriv . envOf . settings) >>= bool (throwM $ Failure mustBeRoot_1) act  -- | Stop the user if they are the true root. Building as root isn't allowed -- since makepkg v4.2.-trueRoot :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig) => m a -> m a+trueRoot :: RIO Env a -> RIO Env a trueRoot action = asks settings >>= \ss ->   if not (isTrueRoot $ envOf ss) && buildUserOf (buildConfigOf ss) /= Just (User "root")-    then action else throwError $ Failure trueRoot_3+    then action else throwM $ Failure trueRoot_3  -- | A list of non-prebuilt packages installed on the system. -- `-Qm` yields a list of sorted values. foreignPackages :: IO (Set SimplePkg)-foreignPackages = S.fromList . mapMaybe (simplepkg' . strictText) . BL.lines <$> pacmanOutput ["-Qm"]+foreignPackages = S.fromList . mapMaybe simplepkg' <$> pacmanLines ["-Qm"]  -- | Packages marked as a dependency, yet are required by no other package. orphans :: IO (Set PkgName)-orphans = S.fromList . map (PkgName . strictText) . BL.lines <$> pacmanOutput ["-Qqdt"]+orphans = S.fromList . map PkgName <$> pacmanLines ["-Qqdt"]  -- | Any package whose name is suffixed by git, hg, svn, darcs, cvs, or bzr. develPkgs :: IO (Set PkgName)@@ -164,11 +142,10 @@ isInstalled pkg = bool Nothing (Just pkg) <$> pacmanSuccess ["-Qq", pkg ^. field @"name"]  -- | An @-Rsu@ call.-removePkgs :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+removePkgs :: NESet PkgName -> RIO Env () removePkgs pkgs = do   pacOpts <- asks (commonConfigOf . settings)-  liftEitherM . sendM . pacman $ ["-Rsu"] <> asFlag pkgs <> asFlag pacOpts+  liftIO . pacman $ ["-Rsu"] <> asFlag pkgs <> asFlag pacOpts  -- | Depedencies which are not installed, or otherwise provided by some -- installed package.@@ -182,16 +159,16 @@ areSatisfied :: NESet Dep -> IO (These Unsatisfied Satisfied) areSatisfied ds = do   unsats <- S.fromList . mapMaybe parseDep <$> unsat-  pure . bimap Unsatisfied Satisfied $ NES.partition (\d -> S.member d unsats) ds+  pure . bimap Unsatisfied Satisfied $ NES.partition (`S.member` unsats) ds   where-    unsat :: IO [T.Text]+    unsat :: IO [Text]     unsat = pacmanLines $ "-T" : map renderedDep (toList ds)  -- | Block further action until the database is free. checkDBLock :: Settings -> IO () checkDBLock ss = do   locked <- doesFileExist lockFile-  when locked $ (warn ss . checkDBLock_1 $ langOf ss) *> getLine *> checkDBLock ss+  when locked $ (warn ss . checkDBLock_1 $ langOf ss) *> B.getLine *> checkDBLock ss  ------- -- MISC  -- Too specific for `Utilities.hs` or `Aura.Utils`@@ -211,9 +188,8 @@  -- | Report a message with multiple associated items. Usually a list of -- naughty packages.-report :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  (Doc AnsiStyle -> Doc AnsiStyle) -> (Language -> Doc AnsiStyle) -> NonEmpty PkgName -> m ()+report :: (Doc AnsiStyle -> Doc AnsiStyle) -> (Language -> Doc AnsiStyle) -> NonEmpty PkgName -> RIO Env () report c msg pkgs = do   ss <- asks settings-  sendM . putStrLnA ss . c . msg $ langOf ss-  sendM . T.putStrLn . dtot . colourCheck ss . vsep . map (cyan . pretty . view (field @"name")) $ toList pkgs+  liftIO . putStrLnA ss . c . msg $ langOf ss+  liftIO . putTextLn . dtot . colourCheck ss . vsep . map (cyan . pretty . view (field @"name")) $ toList pkgs
lib/Aura/Dependencies.hs view
@@ -1,13 +1,14 @@-{-# LANGUAGE DataKinds        #-}-{-# LANGUAGE DeriveGeneric    #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase       #-}-{-# LANGUAGE MonoLocalBinds   #-}-{-# LANGUAGE MultiWayIf       #-}-{-# LANGUAGE PatternSynonyms  #-}-{-# LANGUAGE RankNTypes       #-}-{-# LANGUAGE TupleSections    #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE DeriveGeneric     #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE MonoLocalBinds    #-}+{-# LANGUAGE MultiWayIf        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms   #-}+{-# LANGUAGE RankNTypes        #-}+{-# LANGUAGE TupleSections     #-}+{-# LANGUAGE TypeApplications  #-}  -- | -- Module    : Aura.Dependencies@@ -27,27 +28,21 @@ import           Aura.Languages import           Aura.Settings import           Aura.Types-import           Aura.Utils (maybe')-import           BasePrelude-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks)+import           Aura.Utils (maybe', putText) import           Control.Error.Util (note) import           Data.Generics.Product (field)+import           Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NEL-import           Data.Map.Strict (Map)-import qualified Data.Map.Strict as M import           Data.Semigroup.Foldable (foldMap1)-import           Data.Set (Set)-import qualified Data.Set as S import           Data.Set.NonEmpty (pattern IsEmpty, pattern IsNonEmpty, NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Data.These (these) import           Data.Versions import           Lens.Micro-import           UnliftIO.Exception (catchAny, throwString)+import           RIO+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T  --- @@ -62,16 +57,15 @@ -- interdependent, and thus can be built and installed as a group. -- -- Deeper layers of the result list (generally) depend on the previous layers.-resolveDeps :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Repository -> NESet Package -> m (NonEmpty (NESet Package))+resolveDeps :: Repository -> NESet Package -> RIO Env (NonEmpty (NESet Package)) resolveDeps repo ps = do   ss <- asks settings-  Resolution m s <- liftMaybeM (Failure connectionFailure_1) . sendM $-    (Just <$> resolveDeps' ss repo ps) `catchAny` (const $ pure Nothing)-  unless (length ps == length m) $ sendM (putStr "\n")+  res <- liftIO $ (Just <$> resolveDeps' ss repo ps) `catchAny` const (pure Nothing)+  Resolution m s <- maybe (throwM $ Failure connectionFailure_1) pure res+  unless (length ps == length m) $ liftIO (putText "\n")   let de = conflicts ss m s-  unless (null de) . throwError . Failure $ missingPkg_2 de-  either throwError pure $ sortInstall m+  unless (null de) . throwM . Failure $ missingPkg_2 de+  either throwM pure $ sortInstall m  -- | Solve dependencies for a set of `Package`s assumed to not be -- installed/satisfied.@@ -125,7 +119,7 @@ conflicts ss m s = foldMap f m   where     pm :: Map PkgName Package-    pm = M.fromList $ foldr (\p acc -> (pprov p ^. field @"provides", p) : acc) [] m+    pm = M.fromList $ map (\p -> (pprov p ^. field @"provides", p)) $ toList m      f :: Package -> [DepError]     f (FromRepo _) = []
lib/Aura/Diff.hs view
@@ -9,7 +9,7 @@ module Aura.Diff ( diff ) where  import Aura.Settings-import BasePrelude hiding (diff)+import RIO import System.Path (Absolute, Path, toFilePath) import System.Process.Typed (proc, runProcess) 
lib/Aura/Install.hs view
@@ -35,105 +35,97 @@ import           Aura.Pkgbuild.Security import           Aura.Settings import           Aura.Types-import           Aura.Utils (optionalPrompt)-import           BasePrelude hiding (FilePath, diff)+import           Aura.Utils (optionalPrompt, putTextLn) import           Control.Compactable (fmapEither)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Scheduler (Comp(..), traverseConcurrently)-import qualified Data.ByteString.Lazy.Char8 as BL import           Data.Generics.Product (HasField'(..), field, super)+import           Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NEL-import qualified Data.Map.Strict as M import           Data.Semigroup.Foldable (fold1)-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text.IO as T import           Language.Bash.Pretty (prettyText) import           Language.Bash.Syntax (ShellCommand)-import           Lens.Micro (each, (^.), (^..))-import           Lens.Micro.Extras (view)-import           System.Directory (setCurrentDirectory)-import           System.IO (hFlush, stdout)+import           Lens.Micro (each, (^..))+import           RIO hiding (FilePath)+import           RIO.Directory (setCurrentDirectory)+import           RIO.List (partition, sort)+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path (fromAbsoluteFilePath)  ---  -- | High level 'install' command. Handles installing -- dependencies.-install :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+install :: NESet PkgName -> RIO Env () install pkgs = do   ss <- asks settings   if | not $ switch ss DeleteMakeDeps -> install' pkgs      | otherwise -> do -- `-a` was used.-         orphansBefore <- sendM orphans+         orphansBefore <- liftIO orphans          install' pkgs-         orphansAfter <- sendM orphans+         orphansAfter <- liftIO orphans          let makeDeps = NES.nonEmptySet (orphansAfter S.\\ orphansBefore)-         traverse_ (\mds -> sendM (notify ss . removeMakeDepsAfter_1 $ langOf ss) *> removePkgs mds) makeDeps+         traverse_ (\mds -> liftIO (notify ss . removeMakeDepsAfter_1 $ langOf ss) *> removePkgs mds) makeDeps -install' :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+install' :: NESet PkgName -> RIO Env () install' pkgs = do   rpstry   <- asks repository   ss       <- asks settings   unneeded <- bool               (pure S.empty)-              (S.fromList . catMaybes <$> sendM (traverseConcurrently Par' isInstalled $ toList pkgs))+              (S.fromList . catMaybes <$> liftIO (traverseConcurrently Par' isInstalled $ toList pkgs))               $ shared ss NeededOnly   let !pkgs' = NES.toSet pkgs-  if | shared ss NeededOnly && unneeded == pkgs' -> sendM . warn ss . install_2 $ langOf ss+  if | shared ss NeededOnly && unneeded == pkgs' -> liftIO . warn ss . install_2 $ langOf ss      | otherwise -> do          let (ignored, notIgnored) = S.partition (`S.member` ignoresOf ss) pkgs'          installAnyway <- confirmIgnored ignored          case NES.nonEmptySet $ (notIgnored <> installAnyway) S.\\ unneeded of-           Nothing        -> sendM . warn ss . install_2 $ langOf ss+           Nothing        -> liftIO . warn ss . install_2 $ langOf ss            Just toInstall -> do              traverse_ (report yellow reportUnneededPackages_1) . NEL.nonEmpty $ toList unneeded-             (nons, toBuild) <- liftMaybeM (Failure connectionFailure_1) . sendM $ aurLookup (managerOf ss) toInstall+             (nons, toBuild) <- liftMaybeM (Failure connectionFailure_1) . liftIO $ aurLookup (managerOf ss) toInstall              pkgbuildDiffs toBuild              traverse_ (report red reportNonPackages_1) . NEL.nonEmpty $ toList nons              case NES.nonEmptySet $ S.map (\b -> b { isExplicit = True }) toBuild of-               Nothing       -> throwError $ Failure install_2+               Nothing       -> throwM $ Failure install_2                Just toBuild' -> do-                 sendM $ notify ss (install_5 $ langOf ss) *> hFlush stdout+                 liftIO $ notify ss (install_5 $ langOf ss) *> hFlush stdout                  allPkgs <- depsToInstall rpstry toBuild'                  let (repoPkgs, buildPkgs) = second uniquePkgBase $ partitionPkgs allPkgs                  unless (switch ss NoPkgbuildCheck) $ traverse_ (traverse_ analysePkgbuild) buildPkgs                  reportPkgsToInstall repoPkgs buildPkgs                  unless (switch ss DryRun) $ do-                   continue <- sendM $ optionalPrompt ss install_3-                   if | not continue -> throwError $ Failure install_4+                   continue <- liftIO $ optionalPrompt ss install_3+                   if | not continue -> throwM $ Failure install_4                       | otherwise    -> do                           traverse_ repoInstall $ NEL.nonEmpty repoPkgs                           let !mbuildPkgs = NEL.nonEmpty buildPkgs-                          traverse_ (sendM . storePkgbuilds . fold1) mbuildPkgs+                          traverse_ (liftIO . storePkgbuilds . fold1) mbuildPkgs                           traverse_ buildAndInstall mbuildPkgs  -- | Determine if a package's PKGBUILD might contain malicious bash code.-analysePkgbuild :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Buildable -> m ()+analysePkgbuild :: Buildable -> RIO Env () analysePkgbuild b = do   ss <- asks settings   let f = do-        yes <- sendM $ optionalPrompt ss security_6-        when yes . throwError $ Failure security_7+        yes <- liftIO $ optionalPrompt ss security_6+        when yes . throwM $ Failure security_7   case parsedPB $ b ^. field @"pkgbuild" of-    Nothing -> sendM (warn ss (security_1 (b ^. field @"name") $ langOf ss)) *> f+    Nothing -> liftIO (warn ss (security_1 (b ^. field @"name") $ langOf ss)) *> f     Just l  -> case bannedTerms l of       []  -> pure ()       bts -> do-        sendM $ scold ss (security_5 (b ^. field @"name") $ langOf ss)-        sendM $ traverse_ (displayBannedTerms ss) bts+        liftIO $ scold ss (security_5 (b ^. field @"name") $ langOf ss)+        liftIO $ traverse_ (displayBannedTerms ss) bts         f  displayBannedTerms :: Settings -> (ShellCommand, BannedTerm) -> IO () displayBannedTerms ss (stmt, b) = do-  putStrLn $ "\n    " <> prettyText stmt <> "\n"+  putTextLn . T.pack $ "\n    " <> prettyText stmt <> "\n"   warn ss $ reportExploit b lang   where lang = langOf ss @@ -155,29 +147,25 @@         goods = S.fromList . (^.. each . field @"name") . M.elems . M.fromListWith f $ map (view (field @"base") &&& id) bs'         bs'   = foldMap toList bs -confirmIgnored :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  S.Set PkgName -> m (S.Set PkgName)+confirmIgnored :: Set PkgName -> RIO Env (Set PkgName) confirmIgnored (toList -> ps) = do   ss <- asks settings-  S.fromList <$> filterM (sendM . optionalPrompt ss . confirmIgnored_1) ps+  S.fromList <$> filterM (liftIO . optionalPrompt ss . confirmIgnored_1) ps -depsToInstall :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  Repository -> NESet Buildable -> m (NonEmpty (NESet Package))+depsToInstall :: Repository -> NESet Buildable -> RIO Env (NonEmpty (NESet Package)) depsToInstall repo bs = do   ss <- asks settings-  traverse (sendM . packageBuildable ss) (NES.toList bs) >>= resolveDeps repo . NES.fromList+  traverse (liftIO . packageBuildable ss) (NES.toList bs) >>= resolveDeps repo . NES.fromList -repoInstall :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NonEmpty Prebuilt -> m ()+repoInstall :: NonEmpty Prebuilt -> RIO Env () repoInstall ps = do   pacOpts <- asks (asFlag . commonConfigOf . settings)-  liftEitherM . sendM . pacman $ ["-S", "--asdeps"] <> pacOpts <> asFlag (ps ^.. each . field @"name")+  liftIO . pacman $ ["-S", "--asdeps"] <> pacOpts <> asFlag (ps ^.. each . field @"name") -buildAndInstall :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NonEmpty (NESet Buildable) -> m ()+buildAndInstall :: NonEmpty (NESet Buildable) -> RIO Env () buildAndInstall bss = do   pth   <- asks (either id id . cachePathOf . commonConfigOf . settings)-  cache <- sendM $ cacheContents pth+  cache <- liftIO $ cacheContents pth   traverse_ (f cache) bss   where f (Cache cache) bs = do           ss <- asks settings@@ -187,52 +175,54 @@                 _                                       -> Left b           built <- traverse (buildPackages . NES.fromList) $ NEL.nonEmpty ps           traverse_ installPkgFiles $ built <> (NES.fromList <$> NEL.nonEmpty cached)-          sendM $ annotateDeps bs+          liftIO $ annotateDeps bs  ------------ -- REPORTING ------------ -- | Display dependencies. The result of @-Ad@.-displayPkgDeps :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NESet PkgName -> m ()+displayPkgDeps :: NESet PkgName -> RIO Env () displayPkgDeps ps = do   rpstry <- asks repository   ss <- asks settings   let f = depsToInstall rpstry >=> reportDeps (switch ss LowVerbosity) . partitionPkgs-  (_, goods) <- liftMaybeM (Failure connectionFailure_1) . sendM $ aurLookup (managerOf ss) ps+  (_, goods) <- liftMaybeM (Failure connectionFailure_1) . liftIO $ aurLookup (managerOf ss) ps   traverse_ f $ NES.nonEmptySet goods-  where reportDeps True  = sendM . uncurry reportListOfDeps+  where reportDeps True  = liftIO . uncurry reportListOfDeps         reportDeps False = uncurry reportPkgsToInstall -reportPkgsToInstall :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) =>-  [Prebuilt] -> [NESet Buildable] -> m ()+reportPkgsToInstall :: [Prebuilt] -> [NESet Buildable] -> RIO Env () reportPkgsToInstall rps bps = do   let (explicits, ds) = partition isExplicit $ foldMap toList bps   f reportPkgsToInstall_1 rps   f reportPkgsToInstall_3 ds   f reportPkgsToInstall_2 explicits-  where f m xs = traverse_ (report green m) . NEL.nonEmpty . sort $ xs ^.. each . field @"name"+  where+    f m xs = traverse_ (report green m) . NEL.nonEmpty . sort $ xs ^.. each . field @"name"  reportListOfDeps :: [Prebuilt] -> [NESet Buildable] -> IO () reportListOfDeps rps bps = f rps *> f (foldMap toList bps)   where f :: HasField' "name" s PkgName => [s] -> IO ()-        f = traverse_ T.putStrLn . sort . (^.. each . field' @"name" . field' @"name")+        f = traverse_ putTextLn . sort . (^.. each . field' @"name" . field' @"name") -pkgbuildDiffs :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => S.Set Buildable -> m ()+pkgbuildDiffs :: Set Buildable -> RIO Env () pkgbuildDiffs ps = asks settings >>= check-    where check ss | not $ switch ss DiffPkgbuilds = pure ()-                   | otherwise = traverse_ displayDiff ps-          displayDiff :: (Carrier sig m, Member (Reader Env) sig, Member (Lift IO) sig) => Buildable -> m ()-          displayDiff p = do-            ss <- asks settings-            let pn   = p ^. field @"name"-                lang = langOf ss-            isStored <- sendM $ hasPkgbuildStored pn-            if not isStored-               then sendM . warn ss $ reportPkgbuildDiffs_1 pn lang-               else sendM $ do-                 setCurrentDirectory "/tmp"-                 let new = "/tmp/new.pb"-                 BL.writeFile new $ p ^. field @"pkgbuild" . field @"pkgbuild"-                 liftIO . warn ss $ reportPkgbuildDiffs_3 pn lang-                 diff ss (pkgbuildPath pn) $ fromAbsoluteFilePath new+  where+    check :: Settings -> RIO Env ()+    check ss | not $ switch ss DiffPkgbuilds = pure ()+             | otherwise = traverse_ displayDiff ps++    displayDiff :: Buildable -> RIO Env ()+    displayDiff p = do+      ss <- asks settings+      let pn   = p ^. field @"name"+          lang = langOf ss+      isStored <- liftIO $ hasPkgbuildStored pn+      if not isStored+        then liftIO . warn ss $ reportPkgbuildDiffs_1 pn lang+        else liftIO $ do+          setCurrentDirectory "/tmp"+          let new = "/tmp/new.pb"+          writeFileBinary @IO new $ p ^. field @"pkgbuild" . field @"pkgbuild"+          liftIO . warn ss $ reportPkgbuildDiffs_3 pn lang+          diff ss (pkgbuildPath pn) $ fromAbsoluteFilePath new
lib/Aura/Languages.hs view
@@ -38,18 +38,21 @@ import           Aura.Colour import qualified Aura.Languages.Fields as Fields import           Aura.Types-import           BasePrelude hiding ((<+>)) import           Data.Generics.Product (field)-import qualified Data.Map.Strict as Map (Map, fromList, mapWithKey, toList, (!))-import qualified Data.Text as T+import           Data.List.NonEmpty (NonEmpty)+import           Data.Ratio ((%)) import           Data.Text.Prettyprint.Doc import           Data.Text.Prettyprint.Doc.Render.Terminal-import           Lens.Micro.Extras (view)+import           RIO+import           RIO.List (intersperse)+import qualified RIO.Map as M+import qualified RIO.Map.Partial as M+import qualified RIO.Text as T  --- -translators :: Map.Map Language T.Text-translators = Map.fromList+translators :: Map Language Text+translators = M.fromList     [ (Polish,     "Chris Warrick")     , (Croatian,   "Denis Kasak / \"stranac\"")     , (Swedish,    "Fredrik Haikarainen / Daniel Beecham")@@ -68,8 +71,8 @@     ]  -- These need updating! Or removing...-languageNames :: Language -> Map.Map Language T.Text-languageNames = Map.fromList . zip [ Japanese, Polish, Croatian, Swedish, German, Spanish, Portuguese, French, Russian, Italian, Serbian, Norwegian, Indonesia, Chinese, Esperanto ] . \case+languageNames :: Language -> Map Language T.Text+languageNames = M.fromList . zip [ Japanese, Polish, Croatian, Swedish, German, Spanish, Portuguese, French, Russian, Italian, Serbian, Norwegian, Indonesia, Chinese, Esperanto ] . \case     Japanese   -> [ "日本語", "ポーランド語", "クロアチア語", "スウェーデン語", "ドイツ語", "スペイン語", "ポルトガル語", "フランス語", "ロシア語", "イタリア語", "セルビア語", "ノルウェー語", "インドネシア語", "中国語", "エスペラント" ]     Polish     -> [ "Japanese", "polski", "chorwacki", "szwedzki", "niemiecki", "hiszpański", "portugalski", "francuski", "rosyjski", "", "", "", "Indonesian", "Chinese", "Esperanto" ]     Croatian   -> [ "Japanese", "poljski", "hrvatski", "švedski", "njemački", "španjolski", "portugalski", "francuski", "ruski", "talijanski", "srpski", "norveški", "Indonesian", "Chinese", "Esperanto" ]@@ -87,7 +90,7 @@     Esperanto  -> [ "La japana", "La pola", "La kroata", "La sevda", "La germana", "La hispana", "La portugala", "La franca", "La rusa", "La itala", "La serba", "La norvega", "La indonezia", "La ĉina", "Esperanto" ]     _          -> [ "Japanese", "Polish", "Croatian", "Swedish", "German", "Spanish", "Portuguese", "French", "Russian", "Italian", "Serbian", "Norwegian", "Indonesian", "Chinese", "Esperanto" ] -translatorMsgTitle :: Language -> T.Text+translatorMsgTitle :: Language -> Text translatorMsgTitle = \case     Japanese   -> "Auraの翻訳者:"     Polish     -> "Tłumacze Aury:"@@ -106,24 +109,24 @@     Esperanto  -> "Tradukistoj de Aura:"     _          -> "Aura Translators:" -translatorMsg :: Language -> [T.Text]+translatorMsg :: Language -> [Text] translatorMsg lang = title : names   where title = translatorMsgTitle lang-        names = fmap snd . Map.toList $-            Map.mapWithKey (\l t -> formatLang (assocLang l t)) translators-        assocLang lang' translator = (translator, langNames Map.! lang')+        names = fmap snd . M.toList $+            M.mapWithKey (\l t -> formatLang (assocLang l t)) translators+        assocLang lang' translator = (translator, langNames M.! lang')         formatLang (translator, lang') = " (" <> lang' <> ") " <> translator         langNames = languageNames lang  -- Wrap a String in backticks-bt :: T.Text -> Doc AnsiStyle+bt :: Text -> Doc AnsiStyle bt cs = "`" <> pretty cs <> "`"  whitespace :: Language -> Char whitespace Japanese = ' '  -- \12288 whitespace _        = ' '   -- \32 -langFromLocale :: T.Text -> Language+langFromLocale :: Text -> Language langFromLocale = T.take 2 >>> \case     "ja" -> Japanese     "pl" -> Polish@@ -300,7 +303,7 @@ -- Aura/Dependencies functions ------------------------------ -- NEEDS UPDATE TO MATCH NEW ENGLISH-getRealPkgConflicts_1 :: PkgName -> PkgName -> T.Text -> T.Text -> Language -> Doc AnsiStyle+getRealPkgConflicts_1 :: PkgName -> PkgName -> Text -> Text -> Language -> Doc AnsiStyle getRealPkgConflicts_1 (bt . view (field @"name") -> prnt) (bt . view (field @"name") -> p) (bt -> r) (bt -> d) = \case     Japanese   -> "パッケージ" <> p <> "はバージョン" <> d <> "を要するが" <> "一番最新のバージョンは" <> r <> "。"     Polish     -> "Zależność " <> p <> " powinna być w wersji " <> d <> ", ale najnowsza wersja to " <> r <> "."@@ -610,7 +613,7 @@     _          -> p <> " has no stored PKGBUILD yet."  -- NEEDS TRANSLATION-reportPkgbuildDiffs_2 :: T.Text -> Language -> Doc AnsiStyle+reportPkgbuildDiffs_2 :: Text -> Language -> Doc AnsiStyle reportPkgbuildDiffs_2 (bt -> p) = \case     Japanese   -> p <> "のPKGBUILDは最新です。"     Polish     -> "PKGBUILD pakietu " <> p <> " jest aktualny."@@ -775,7 +778,7 @@ ---------------------------- -- NEEDS TRANSLATION cleanStates_2 :: Int -> Language -> Doc AnsiStyle-cleanStates_2 n@(bt . T.pack . show -> s) = \case+cleanStates_2 n@(bt . tshow -> s) = \case     Japanese   -> s <> "個のパッケージ状態記録だけが残される。その他削除?"     Polish     -> s <> " stan pakietów zostanie zachowany. Usunąć resztę?"     Croatian   -> s <> " stanja paketa će biti zadržano. Ukloniti ostatak?"@@ -821,13 +824,13 @@   Esperanto -> "Vi havas " <+> pretty n <+> " konservajn statojn de pakaĵoj."   _         -> "You currently have" <+> pretty n <+> "saved package states." -cleanStates_5 :: T.Text -> Language -> Doc AnsiStyle+cleanStates_5 :: Text -> Language -> Doc AnsiStyle cleanStates_5 t = \case   Japanese  -> "一番最近に保存されたのは:" <> pretty t   Spanish   -> "Guardado recientemente:" <+> pretty t   Russian   -> "Последнее сохраненное:" <+> pretty t   Esperanto -> "Lastaj konservaj:" <+> pretty t-  _         -> "Mostly recently saved:" <+> pretty t+  _         -> "Most recently saved:" <+> pretty t  cleanStates_6 :: Int -> Language -> Doc AnsiStyle cleanStates_6 n = \case@@ -903,7 +906,7 @@     _          -> "Backing up cache to " <> dir  backupCache_5 :: Int -> Language -> Doc AnsiStyle-backupCache_5 (bt . T.pack . show -> n) = \case+backupCache_5 (bt . tshow -> n) = \case     Japanese   -> "パッケージのファイル数:" <> n     Polish     -> "Pliki będące częścią\xa0kopii zapasowej: " <> n     Croatian   -> "Datoteke koje su dio sigurnosne kopije: " <> n@@ -1017,7 +1020,7 @@     _          -> "This will delete the ENTIRE package cache."  cleanCache_3 :: Word -> Language -> Doc AnsiStyle-cleanCache_3 n@(bt . T.pack . show -> s) = \case+cleanCache_3 n@(bt . tshow -> s) = \case     Japanese   -> "パッケージ・ファイルは" <> s <> "個保存されます。"     Polish     -> s <> " wersji każdego pakietu zostanie zachowane."     Croatian   -> s <> " zadnjih verzija svakog paketa će biti zadržano."@@ -1133,7 +1136,7 @@ ---------------------------- -- Aura/Commands/L functions -----------------------------logLookUpFields :: Language -> [T.Text]+logLookUpFields :: Language -> [Text] logLookUpFields = sequence [ Fields.package                            , Fields.firstInstall                            , Fields.upgrades@@ -1168,7 +1171,7 @@   Spanish   -> "No se pudo contactar con el AUR. ¿Tienes conexión a internet?"   _ -> "Failed to contact the AUR. Do you have an internet connection?" -infoFields :: Language -> [T.Text]+infoFields :: Language -> [Text] infoFields = sequence [ Fields.repository                       , Fields.name                       , Fields.version@@ -1221,7 +1224,7 @@     _          -> "Up to Date"  -- NEEDS TRANSLATION-orphanedMsg :: Maybe T.Text -> Language -> Doc AnsiStyle+orphanedMsg :: Maybe Text -> Language -> Doc AnsiStyle orphanedMsg (Just m) = const (pretty m) orphanedMsg Nothing = red . \case     Japanese   -> "孤児です!"@@ -1408,17 +1411,17 @@   Spanish   -> "El PKGBUILD de" <+> bt p <+> "era demasiado complejo de analizar - puede estar ofuscando código malicioso."   _ -> "The PKGBUILD of" <+> bt p <+> "was too complex to parse - it may be obfuscating malicious code." -security_2 :: T.Text -> Language -> Doc AnsiStyle+security_2 :: Text -> Language -> Doc AnsiStyle security_2 (bt -> t) = \case   Spanish   -> t <+> "se puede usar para descargar scripts arbitrarios que este PKGBUILD no rastrea."   _ -> t <+> "can be used to download arbitrary scripts that aren't tracked by this PKGBUILD." -security_3 :: T.Text -> Language -> Doc AnsiStyle+security_3 :: Text -> Language -> Doc AnsiStyle security_3 (bt -> t) = \case   Spanish   -> t <+> "se puede usar para ejecutar código arbitrario que este PKGBUILD no rastrea."   _ -> t <+> "can be used to execute arbitrary code not tracked by this PKGBUILD." -security_4 :: T.Text -> Language -> Doc AnsiStyle+security_4 :: Text -> Language -> Doc AnsiStyle security_4 (bt -> t) = \case   Spanish   -> t <+> "indica que alguien puede estar intentando obtener acceso de root a su máquina."   _ -> t <+> "indicates that someone may be trying to gain root access to your machine."@@ -1438,17 +1441,17 @@   Spanish   -> "Se canceló el procesamiento posterior para evitar el código bash potencialmente malicioso."   _ -> "Cancelled further processing to avoid potentially malicious bash code." -security_8 :: T.Text -> Language -> Doc AnsiStyle+security_8 :: Text -> Language -> Doc AnsiStyle security_8 (bt -> t) = \case   Spanish   -> t <+> "es un comando bash integrado en los campos de la matriz del PKGBUILD."   _ -> t <+> "is a bash command inlined in your PKGBUILD array fields." -security_9 :: T.Text -> Language -> Doc AnsiStyle+security_9 :: Text -> Language -> Doc AnsiStyle security_9 (bt -> t) = \case   Spanish   -> t <+> "es algo extraño para tener en sus campos de matriz. ¿Es seguro?"   _ -> t <+> "is a strange thing to have in your array fields. Is it safe?" -security_10 :: T.Text -> Language -> Doc AnsiStyle+security_10 :: Text -> Language -> Doc AnsiStyle security_10 (bt -> t) = \case   Spanish   -> t <+> "implica que alguien estaba tratando de ser astuto con las variables para ocultar comandos maliciosos."   _ -> t <+> "implies that someone was trying to be clever with variables to hide malicious commands."
lib/Aura/Languages/Fields.hs view
@@ -13,12 +13,12 @@  module Aura.Languages.Fields where -import           Aura.Types (Language(..))-import qualified Data.Text as T+import Aura.Types (Language(..))+import RIO (Text)  --- -package :: Language -> T.Text+package :: Language -> Text package = \case     Japanese   -> "パッケージ"     Polish     -> "Pakiet"@@ -36,7 +36,7 @@     Esperanto  -> "Pakaĵo"     _          -> "Package" -firstInstall :: Language -> T.Text+firstInstall :: Language -> Text firstInstall = \case     Japanese   -> "初インストール"     Polish     -> "Pierwsza instalacja"@@ -54,7 +54,7 @@     Esperanto  -> "Unua Instalo"     _          -> "First Install" -upgrades :: Language -> T.Text+upgrades :: Language -> Text upgrades = \case     Japanese   -> "アップグレード回数"     Polish     -> "Aktualizacje"@@ -72,7 +72,7 @@     Esperanto  -> "Noveldonoj"     _          -> "Upgrades" -recentActions :: Language -> T.Text+recentActions :: Language -> Text recentActions = \case     Japanese   -> "近況"     Polish     -> "Ostatnie akcje"@@ -90,7 +90,7 @@     Esperanto  -> "Ĵusaj Agoj"     _          -> "Recent Actions" -repository :: Language -> T.Text+repository :: Language -> Text repository = \case     Japanese   -> "リポジトリ"     Polish     -> "Repozytorium"@@ -108,7 +108,7 @@     Esperanto  -> "Deponejo"     _          -> "Repository" -name :: Language -> T.Text+name :: Language -> Text name = \case     Japanese   -> "名前"     Polish     -> "Nazwa"@@ -126,7 +126,7 @@     Esperanto  -> "Nomo"     _          -> "Name" -version :: Language -> T.Text+version :: Language -> Text version = \case     Japanese   -> "バージョン"     Polish     -> "Wersja"@@ -144,7 +144,7 @@     Esperanto  -> "Versio"     _          -> "Version" -aurStatus :: Language -> T.Text+aurStatus :: Language -> Text aurStatus = \case     Japanese   -> "パッケージ状態"     Polish     -> "Status w AUR"@@ -161,7 +161,7 @@     _          -> "AUR Status"  -- NEEDS TRANSLATION-maintainer :: Language -> T.Text+maintainer :: Language -> Text maintainer = \case     Japanese   -> "管理者"     Spanish    -> "Mantenedor"@@ -173,7 +173,7 @@     Esperanto  -> "Daŭriganto"     _          -> "Maintainer" -projectUrl :: Language -> T.Text+projectUrl :: Language -> Text projectUrl = \case     Japanese   -> "プロジェクト"     Polish     -> "URL Projektu"@@ -191,7 +191,7 @@     Esperanto  -> "URL de Projekto"     _          -> "Project URL" -aurUrl :: Language -> T.Text+aurUrl :: Language -> Text aurUrl = \case     Japanese   -> "パッケージページ"     Polish     -> "URL w AUR"@@ -206,7 +206,7 @@     Esperanto  -> "URL en AUR"     _          -> "AUR URL" -license :: Language -> T.Text+license :: Language -> Text license = \case     Japanese   -> "ライセンス"     Polish     -> "Licencja"@@ -224,7 +224,7 @@     Esperanto  -> "Permesilo"     _          -> "License" -dependsOn :: Language -> T.Text+dependsOn :: Language -> Text dependsOn = \case     Japanese   -> "従属パッケージ"     Polish     -> "Zależności"@@ -240,7 +240,7 @@     Esperanto  -> "Dependi de"     _          -> "Depends On" -buildDeps :: Language -> T.Text+buildDeps :: Language -> Text buildDeps = \case     Japanese   -> "作成時従属パ"     German     -> "Build-Abhängigkeiten"@@ -252,7 +252,7 @@     Esperanto  -> "Muntaj Dependecoj"     _          -> "Build Deps" -votes :: Language -> T.Text+votes :: Language -> Text votes = \case     Japanese   -> "投票数"     Polish     -> "Głosy"@@ -270,7 +270,7 @@     Esperanto  -> "Balotiloj"     _          -> "Votes" -popularity :: Language -> T.Text+popularity :: Language -> Text popularity = \case     Japanese   -> "人気"     Spanish    -> "Popularidad"@@ -278,7 +278,7 @@     Esperanto  -> "Populareco"     _          -> "Popularity" -description :: Language -> T.Text+description :: Language -> Text description = \case     Japanese   -> "概要"     Polish     -> "Opis"@@ -296,7 +296,7 @@     Esperanto  -> "Priskribo"     _          -> "Description" -makeDeps :: Language -> T.Text+makeDeps :: Language -> Text makeDeps = \case     Polish     -> "Zależności Make"     Croatian   -> "Make Zavisnosti"
lib/Aura/Logo.hs view
@@ -15,32 +15,30 @@ import           Aura.Pacman (verMsgPad) import           Aura.Settings import           Aura.Utils-import           BasePrelude-import qualified Data.Text as T-import qualified Data.Text.IO as T import           Data.Text.Prettyprint.Doc-import           System.IO (hFlush, stdout)+import           RIO+import qualified RIO.Text as T  ---  -- | Show an animated version message, but only when the output target -- is a terminal.-animateVersionMsg :: Settings -> T.Text -> [T.Text] -> IO ()+animateVersionMsg :: Settings -> Text -> [Text] -> IO () animateVersionMsg ss auraVersion verMsg = do   when (isTerminal ss) $ do     hideCursor-    traverse_ (T.putStrLn . padString verMsgPad) verMsg  -- Version message+    traverse_ (putTextLn . padString verMsgPad) verMsg  -- Version message     raiseCursorBy 7  -- Initial reraising of the cursor.     drawPills 3-    traverse_ T.putStrLn $ renderPacmanHead ss 0 Open  -- Initial rendering of head.+    traverse_ putTextLn $ renderPacmanHead ss 0 Open  -- Initial rendering of head.     raiseCursorBy 4     takeABite ss 0  -- Initial bite animation.     traverse_ pillEating pillsAndWidths     clearGrid-  T.putStrLn auraLogo-  T.putStrLn $ "AURA Version " <> auraVersion-  T.putStrLn " by Colin Woodbury\n"-  traverse_ T.putStrLn . translatorMsg . langOf $ ss+  putTextLn auraLogo+  putTextLn $ "AURA Version " <> auraVersion+  putTextLn " by Colin Woodbury\n"+  traverse_ putTextLn . translatorMsg . langOf $ ss   when (isTerminal ss) showCursor     where pillEating (p, w) = clearGrid *> drawPills p *> takeABite ss w           pillsAndWidths    = [(2, 5), (1, 10), (0, 15)]@@ -48,12 +46,12 @@ data MouthState = Open | Closed deriving (Eq)  -- Taken from: figlet -f small "aura"-auraLogo :: T.Text+auraLogo :: Text auraLogo = " __ _ _  _ _ _ __ _ \n" <>            "/ _` | || | '_/ _` |\n" <>            "\\__,_|\\_,_|_| \\__,_|" -openMouth :: Settings -> [T.Text]+openMouth :: Settings -> [Text] openMouth ss = map f             [ " .--."             , "/ _.-'"@@ -62,7 +60,7 @@   where f | shared ss (Colour Never) = id           | otherwise = dtot . yellow . pretty -closedMouth :: Settings -> [T.Text]+closedMouth :: Settings -> [Text] closedMouth ss = map f               [ " .--."               , "/ _..\\"@@ -71,7 +69,7 @@   where f | shared ss (Colour Never) = id           | otherwise = dtot . yellow . pretty -pill :: [T.Text]+pill :: [Text] pill = [ ""        , ".-."        , "'-'"@@ -79,31 +77,33 @@  takeABite :: Settings -> Int -> IO () takeABite ss pad = drawMouth Closed *> drawMouth Open-    where drawMouth mouth = do-            traverse_ T.putStrLn $ renderPacmanHead ss pad mouth-            raiseCursorBy 4-            hFlush stdout-            threadDelay 125000+  where+    drawMouth :: MouthState -> IO ()+    drawMouth mouth = do+      traverse_ putTextLn $ renderPacmanHead ss pad mouth+      raiseCursorBy 4+      hFlush stdout+      threadDelay 125000  drawPills :: Int -> IO ()-drawPills numOfPills = traverse_ T.putStrLn pills-    where pills = renderPills numOfPills+drawPills numOfPills = traverse_ putTextLn pills+  where pills = renderPills numOfPills  clearGrid :: IO ()-clearGrid = T.putStr blankLines *> raiseCursorBy 4-    where blankLines = fold . replicate 4 . padString 23 $ "\n"+clearGrid = putText blankLines *> raiseCursorBy 4+  where blankLines = fold . replicate 4 . padString 23 $ "\n" -renderPill :: Int -> [T.Text]+renderPill :: Int -> [Text] renderPill pad = padString pad <$> pill -renderPills :: Int -> [T.Text]+renderPills :: Int -> [Text] renderPills numOfPills = take numOfPills pillPostitions >>= render-    where pillPostitions = [17, 12, 7]-          render pos = renderPill pos <> [ cursorUpLineCode 5 ]+  where pillPostitions = [17, 12, 7]+        render pos = renderPill pos <> [ decodeUtf8Lenient $ cursorUpLineCode 5 ] -renderPacmanHead :: Settings -> Int -> MouthState -> [T.Text]+renderPacmanHead :: Settings -> Int -> MouthState -> [Text] renderPacmanHead ss pad Open   = map (padString pad) $ openMouth ss renderPacmanHead ss pad Closed = map (padString pad) $ closedMouth ss -padString :: Int -> T.Text -> T.Text+padString :: Int -> Text -> Text padString pad cs = T.justifyRight (pad + T.length cs) ' ' cs
lib/Aura/MakePkg.hs view
@@ -18,15 +18,15 @@ import           Aura.Languages import           Aura.Settings import           Aura.Types-import           Aura.Utils (optionalPrompt, strictText)-import           BasePrelude+import           Aura.Utils (optionalPrompt) import           Control.Error.Util (note)-import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.List.NonEmpty as NEL import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T-import           Lens.Micro ((^.), _2)+import           Lens.Micro (_2)+import           RIO+import qualified RIO.ByteString.Lazy as BL+import qualified RIO.Text as T import           System.Path     (Absolute, Path, fromAbsoluteFilePath, toFilePath, (</>)) import           System.Path.IO (getCurrentDirectory, getDirectoryContents)@@ -64,7 +64,7 @@ make ss (User usr) pc = do   (ec, se) <- runIt ss pc   res <- readProcess $ proc "sudo" ["-u", T.unpack usr, toFilePath makepkgCmd, "--packagelist"]-  let fs = map (fromAbsoluteFilePath . T.unpack . strictText) . BL.lines $ res ^. _2+  let fs = map (fromAbsoluteFilePath . T.unpack) . T.lines . decodeUtf8Lenient . BL.toStrict $ res ^. _2   pure (ec, se, fs)  runIt :: MonadIO m => Settings -> ProcessConfig stdin stdout stderr -> m (ExitCode, BL.ByteString)
lib/Aura/Packages/AUR.hs view
@@ -32,36 +32,34 @@ import           Aura.Pkgbuild.Fetch import           Aura.Settings import           Aura.Types-import           BasePrelude hiding (head) import           Control.Compactable (fmapEither) import           Control.Concurrent.STM.TVar (modifyTVar')-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Error.Util (hush, note) import           Control.Monad.Trans.Class (lift) import           Control.Monad.Trans.Maybe import           Control.Scheduler (Comp(..), traverseConcurrently) import           Data.Generics.Product (field)+import           Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NEL-import qualified Data.Map.Strict as M-import qualified Data.Set as S import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Data.Versions (versioning)-import           Lens.Micro (each, non, to, (^.), (^..))+import           Lens.Micro (each, non, (^..)) import           Linux.Arch.Aur import           Network.HTTP.Client (Manager)+import           RIO+import           RIO.List (sortBy)+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path import           System.Path.IO (getCurrentDirectory) import           System.Process.Typed  --- --- | Attempt to retrieve info about a given `S.Set` of packages from the AUR.-aurLookup :: Manager -> NESet PkgName -> IO (Maybe (S.Set PkgName, S.Set Buildable))+-- | Attempt to retrieve info about a given `Set` of packages from the AUR.+aurLookup :: Manager -> NESet PkgName -> IO (Maybe (Set PkgName, Set Buildable)) aurLookup m names = runMaybeT $ do   infos <- MaybeT . fmap hush . info m $ foldr (\(PkgName pn) acc -> pn : acc) [] names   badsgoods <- lift $ traverseConcurrently Par' (buildable m) infos@@ -76,7 +74,7 @@    -- TODO Use `data-or` here to offer `Or (NESet PkgName) (NESet Package)`?   -- Yes that sounds like a good idea :)-  let f :: Settings -> NESet PkgName -> IO (Maybe (S.Set PkgName, S.Set Package))+  let f :: Settings -> NESet PkgName -> IO (Maybe (Set PkgName, Set Package))       f ss ps = do         --- Retrieve cached Packages ---         cache <- readTVarIO tv@@ -121,7 +119,7 @@ aurLink = fromUnrootedFilePath "https://aur.archlinux.org"  -- | A package's home URL on the AUR.-pkgUrl :: PkgName -> T.Text+pkgUrl :: PkgName -> Text pkgUrl (PkgName pkg) = T.pack . toUnrootedFilePath $ aurLink </> fromUnrootedFilePath "packages" </> fromUnrootedFilePath (T.unpack pkg)  -------------------@@ -148,17 +146,15 @@                      _ -> \x y -> compare (aurVotesOf y) (aurVotesOf x)  -- | Frontend to the `aur` library. For @-As@.-aurSearch :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  T.Text -> m [AurInfo]+aurSearch :: Text -> RIO Env [AurInfo] aurSearch regex = do   ss  <- asks settings-  res <- liftMaybeM (Failure connectionFailure_1) . fmap hush . sendM $ search (managerOf ss) regex+  res <- liftMaybeM (Failure connectionFailure_1) . fmap hush . liftIO $ search (managerOf ss) regex   pure $ sortAurInfo (bool Nothing (Just SortAlphabetically) $ switch ss SortAlphabetically) res  -- | Frontend to the `aur` library. For @-Ai@.-aurInfo :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  NonEmpty PkgName -> m [AurInfo]+aurInfo :: NonEmpty PkgName -> RIO Env [AurInfo] aurInfo pkgs = do   m   <- asks (managerOf . settings)-  res <- liftMaybeM (Failure connectionFailure_1) . fmap hush . sendM . info m . map (^. field @"name") $ toList pkgs+  res <- liftMaybeM (Failure connectionFailure_1) . fmap hush . liftIO . info m . map (^. field @"name") $ toList pkgs   pure $ sortAurInfo (Just SortAlphabetically) res
lib/Aura/Packages/Repository.hs view
@@ -22,20 +22,17 @@ import           Aura.Pacman (pacmanLines, pacmanOutput) import           Aura.Settings (CommonSwitch(..), Settings(..), shared) import           Aura.Types-import           Aura.Utils (getSelection, strictText)-import           BasePrelude hiding (try)-import           Control.Compactable (fmapEither)-import           Control.Compactable (traverseEither)-import           Control.Concurrent.STM.TVar (modifyTVar')+import           Aura.Utils (getSelection)+import           Control.Compactable (fmapEither, traverseEither) import           Control.Error.Util (hush, note) import           Control.Scheduler (Comp(..), traverseConcurrently) import           Data.Generics.Product (field)-import qualified Data.Map.Strict as M-import qualified Data.Set as S+import           Data.List.NonEmpty (NonEmpty(..)) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Data.Versions-import           Lens.Micro ((^.))+import           RIO hiding (try)+import qualified RIO.Map as M+import qualified RIO.Set as S import           Text.Megaparsec import           Text.Megaparsec.Char @@ -47,7 +44,7 @@ pacmanRepo = do   tv <- newTVarIO mempty -  let g :: Settings -> NES.NESet PkgName -> IO (Maybe (S.Set PkgName, S.Set Package))+  let g :: Settings -> NES.NESet PkgName -> IO (Maybe (Set PkgName, Set Package))       g ss names = do         --- Retrieve cached Packages ---         cache <- readTVarIO tv@@ -96,11 +93,11 @@  -- | The most recent version of a package, if it exists in the respositories. mostRecent :: PkgName -> IO (Either PkgName Versioning)-mostRecent p@(PkgName s) = note p . extractVersion . strictText <$> pacmanOutput ["-Si", s]+mostRecent p@(PkgName s) = note p . extractVersion . decodeUtf8Lenient <$> pacmanOutput ["-Si", s]  -- | Parses the version number of a package from the result of a -- @pacman -Si@ call.-extractVersion :: T.Text -> Maybe Versioning+extractVersion :: Text -> Maybe Versioning extractVersion = hush . parse p "extractVersion"   where p = do           void $ takeWhile1P Nothing (/= '\n') *> newline
lib/Aura/Pacman.hs view
@@ -35,21 +35,17 @@  import           Aura.Languages import           Aura.Types-import           Aura.Utils (strictText)-import           BasePrelude hiding (setEnv, some, try)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.Map.Strict as M-import           Data.Set (Set)-import qualified Data.Set as S+import           Data.Bifunctor (first) import           Data.Set.NonEmpty (NESet)-import qualified Data.Text as T-import           Data.Text.Encoding (decodeUtf8With)-import           Data.Text.Encoding.Error (lenientDecode)-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL-import           Lens.Micro+import           Lens.Micro (at, (^?), _2, _Just, _head) import           Lens.Micro.GHC ()+import           RIO hiding (first, some, try)+import qualified RIO.ByteString as BS+import qualified RIO.ByteString.Lazy as BL+import           RIO.List.Partial ((!!))+import qualified RIO.Map as M+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path (Absolute, Path, fromAbsoluteFilePath, toFilePath) import           System.Process.Typed import           Text.Megaparsec hiding (single)@@ -59,16 +55,16 @@ ---  -- | The (meaningful) contents of the Pacman config file.-newtype Config = Config (M.Map T.Text [T.Text]) deriving (Show)+newtype Config = Config (Map Text [Text]) deriving (Show)  -- | Parse a `Config`, the pacman configuration file.-config :: Parsec Void T.Text Config+config :: Parsec Void Text Config config = Config . M.fromList . rights <$> (garbage *> some (fmap Right (try pair) <|> fmap Left single) <* eof) -single :: Parsec Void T.Text ()+single :: Parsec Void Text () single = L.lexeme garbage . void $ manyTill letterChar newline -pair :: Parsec Void T.Text (T.Text, [T.Text])+pair :: Parsec Void Text (Text, [Text]) pair = L.lexeme garbage $ do   n <- takeWhile1P Nothing (/= ' ')   space@@ -78,7 +74,7 @@   pure (n, rest)  -- | Using `[]` as block comment markers is a trick to skip conf file "section" lines.-garbage :: Parsec Void T.Text ()+garbage :: Parsec Void Text () garbage = L.space space1 (L.skipLineComment "#") (L.skipBlockComment "[" "]")  -- | Default location of the pacman config file: \/etc\/pacman.conf@@ -96,7 +92,7 @@ -- | Given a filepath to the pacman config, try to parse its contents. getPacmanConf :: Path Absolute -> IO (Either Failure Config) getPacmanConf fp = do-  file <- decodeUtf8With lenientDecode <$> BS.readFile (toFilePath fp)+  file <- decodeUtf8Lenient <$> BS.readFile (toFilePath fp)   pure . first (const (Failure confParsing_1)) $ parse config "pacman config" file  -- | Fetches the @IgnorePkg@ entry from the config, if it's there.@@ -109,12 +105,10 @@  -- | Given a `Set` of package groups, yield all the packages they contain. groupPackages :: NESet PkgGroup -> IO (Set PkgName)-groupPackages igs-  | null igs  = pure S.empty-  | otherwise = fmap f . pacmanOutput $ "-Qg" : asFlag igs+groupPackages igs = fmap (f . decodeUtf8Lenient) . pacmanOutput $ "-Qg" : asFlag igs   where-    f :: BL.ByteString -> Set PkgName-    f = S.fromList . map (PkgName . strictText . (!! 1) . BL.words) . BL.lines+    f :: Text -> Set PkgName+    f = S.fromList . map (PkgName . (!! 1) . T.words) . T.lines  -- | Fetches the @CacheDir@ entry from the config, if it's there. getCachePath :: Config -> Maybe (Path Absolute)@@ -132,26 +126,26 @@ pacmanProc :: [String] -> ProcessConfig () () () pacmanProc args = setEnv [("LC_ALL", "C")] $ proc "pacman" args --- | Run a pacman action that may fail. Will never throw an IO exception.-pacman :: [T.Text] -> IO (Either Failure ())+-- | Run a pacman action that may fail.+pacman :: [Text] -> IO () pacman (map T.unpack -> args) = do   ec <- runProcess $ pacmanProc args-  pure . bool (Left $ Failure pacmanFailure_1) (Right ()) $ ec == ExitSuccess+  unless (ec == ExitSuccess) $ throwM (Failure pacmanFailure_1)  -- | Run some `pacman` process, but only care about whether it succeeded. pacmanSuccess :: [T.Text] -> IO Bool pacmanSuccess = fmap (== ExitSuccess) . runProcess . setStderr closed . setStdout closed . pacmanProc . map T.unpack  -- | Runs pacman silently and returns only the stdout.-pacmanOutput :: [T.Text] -> IO BL.ByteString-pacmanOutput = fmap (^. _2) . readProcess . pacmanProc . map T.unpack+pacmanOutput :: [Text] -> IO ByteString+pacmanOutput = fmap (^. _2 . to BL.toStrict) . readProcess . pacmanProc . map T.unpack  -- | Runs pacman silently and returns the stdout as UTF8-decoded `Text` lines.-pacmanLines :: [T.Text] -> IO [T.Text]-pacmanLines s = T.lines . TL.toStrict . TL.decodeUtf8With lenientDecode <$> pacmanOutput s+pacmanLines :: [Text] -> IO [Text]+pacmanLines s = T.lines . decodeUtf8Lenient <$> pacmanOutput s  -- | Yields the lines given by `pacman -V` with the pacman image stripped.-versionInfo :: IO [T.Text]+versionInfo :: IO [Text] versionInfo = map (T.drop verMsgPad) <$> pacmanLines ["-V"]  -- | The amount of whitespace before text in the lines given by `pacman -V`
lib/Aura/Pkgbuild/Base.hs view
@@ -13,10 +13,8 @@   ) where  import           Aura.Types-import qualified Data.Text as T+import qualified RIO.Text as T import           System.Path-    (Absolute, FileExt(..), Path, fromAbsoluteFilePath, fromUnrootedFilePath,-    (<.>), (</>))  --- 
lib/Aura/Pkgbuild/Editing.hs view
@@ -12,18 +12,17 @@  module Aura.Pkgbuild.Editing ( hotEdit ) where -import           Aura.Languages-import           Aura.Settings-import           Aura.Types-import           Aura.Utils-import           BasePrelude-import qualified Data.ByteString.Lazy.Char8 as BL-import           Data.Generics.Product (field)-import           Lens.Micro ((.~), (^.))-import           System.Directory (setCurrentDirectory)-import           System.Path (toFilePath)-import           System.Path.IO (getCurrentDirectory, getTemporaryDirectory)-import           System.Process.Typed (proc, runProcess)+import Aura.Languages+import Aura.Settings+import Aura.Types+import Aura.Utils+import Data.Generics.Product (field)+import Lens.Micro ((.~))+import RIO+import RIO.Directory (setCurrentDirectory)+import System.Path (toFilePath)+import System.Path.IO (getCurrentDirectory, getTemporaryDirectory)+import System.Process.Typed (proc, runProcess)  --- @@ -32,9 +31,9 @@ -- package building. edit :: (FilePath -> IO a) -> Buildable -> IO Buildable edit f p = do-  BL.writeFile filename $ p ^. field @"pkgbuild" . field @"pkgbuild"+  writeFileBinary filename $ p ^. field @"pkgbuild" . field @"pkgbuild"   void $ f filename-  newPB <- BL.readFile filename+  newPB <- readFileBinary filename   pure (p & field @"pkgbuild" .~ Pkgbuild newPB)     where filename = "PKGBUILD" 
lib/Aura/Pkgbuild/Fetch.hs view
@@ -18,19 +18,15 @@  import           Aura.Types (PkgName(..), Pkgbuild(..)) import           Aura.Utils (urlContents)-import           BasePrelude-import           Control.Exception (SomeException, catch) import           Data.Generics.Product (field)-import qualified Data.Text as T-import           Lens.Micro ((^.)) import           Network.HTTP.Client (Manager) import           Network.URI (escapeURIString, isUnescapedInURIComponent)-import           System.FilePath ((</>))+import           RIO+import           RIO.FilePath ((</>))+import qualified RIO.Text as T  --- -type E = SomeException- baseUrl :: String baseUrl = "https://aur.archlinux.org/" @@ -40,8 +36,11 @@   ++ escapeURIString isUnescapedInURIComponent p  -- | The PKGBUILD of a given package, retrieved from the AUR servers.-getPkgbuild :: MonadIO m => Manager -> PkgName -> m (Maybe Pkgbuild)+getPkgbuild :: Manager -> PkgName -> IO (Maybe Pkgbuild) getPkgbuild m p = e $ do   t <- urlContents m . pkgbuildUrl . T.unpack $ p ^. field @"name"   pure $ fmap Pkgbuild t-  where e f = liftIO $ f `catch` (\(_ :: E) -> return Nothing)+  where+    -- TODO Make this less "baby's first Haskell".+    e :: IO (Maybe a) -> IO (Maybe a)+    e f = f `catch` (\(_ :: SomeException) -> return Nothing)
lib/Aura/Pkgbuild/Records.hs view
@@ -14,15 +14,13 @@   , storePkgbuilds   ) where -import           Aura.Pkgbuild.Base-import           Aura.Types-import           BasePrelude-import qualified Data.ByteString.Lazy.Char8 as BL-import           Data.Generics.Product (field)-import           Data.Set.NonEmpty (NESet)-import           Lens.Micro ((^.))-import           System.Path (toFilePath)-import           System.Path.IO (createDirectoryIfMissing, doesFileExist)+import Aura.Pkgbuild.Base+import Aura.Types+import Data.Generics.Product (field)+import Data.Set.NonEmpty (NESet)+import RIO+import System.Path (toFilePath)+import System.Path.IO (createDirectoryIfMissing, doesFileExist)  --- @@ -38,4 +36,4 @@   traverse_ (\p -> writePkgbuild (p ^. field @"name") (p ^. field @"pkgbuild")) bs  writePkgbuild :: PkgName -> Pkgbuild -> IO ()-writePkgbuild pn (Pkgbuild pb) = BL.writeFile (toFilePath $ pkgbuildPath pn) pb+writePkgbuild pn (Pkgbuild pb) = writeFileBinary (toFilePath $ pkgbuildPath pn) pb
lib/Aura/Pkgbuild/Security.hs view
@@ -19,24 +19,23 @@  import           Aura.Languages import           Aura.Types (Language, Pkgbuild(..))-import           Aura.Utils (strictText)-import           BasePrelude hiding (Last, Word) import           Control.Error.Util (hush)-import           Data.Generics.Product-import qualified Data.Map.Strict as M-import qualified Data.Text as T+import           Data.Generics.Product (typed, types) import           Data.Text.Prettyprint.Doc (Doc) import           Data.Text.Prettyprint.Doc.Render.Terminal (AnsiStyle) import           Language.Bash.Parse (parse) import           Language.Bash.Syntax import           Language.Bash.Word (Span(..), Word, unquote)-import           Lens.Micro+import           Lens.Micro (each, (.~), (^..), _Just)+import           RIO hiding (Word)+import qualified RIO.Map as M+import qualified RIO.Text as T  ---  -- | A bash term which should never appear in a PKGBUILD. If one does, it's -- either a sign of maintainer negligence or malicious behaviour.-data BannedTerm = BannedTerm T.Text BanCategory deriving (Eq, Ord, Show, Generic)+data BannedTerm = BannedTerm Text BanCategory deriving (Eq, Ord, Show, Generic)  -- | The reason why the bash term is black-listed. data BanCategory = Downloading@@ -47,15 +46,17 @@                  | CleverRedirect                  deriving (Eq, Ord, Show) -blacklist :: M.Map T.Text BannedTerm+blacklist :: Map Text BannedTerm blacklist = M.fromList $ downloading <> running <> permissions-  where downloading = map (\t -> (t, BannedTerm t Downloading)) ["curl", "wget", "rsync", "scp"]-        running     = map (\t -> (t, BannedTerm t ScriptRunning)) ["sh", "bash", "eval", "zsh", "fish"]-        permissions = map (\t -> (t, BannedTerm t Permissions)) ["sudo", "ssh"]+  where+    downloading = map (\t -> (t, BannedTerm t Downloading)) ["curl", "wget", "rsync", "scp"]+    running     = map (\t -> (t, BannedTerm t ScriptRunning)) ["sh", "bash", "eval", "zsh", "fish"]+    permissions = map (\t -> (t, BannedTerm t Permissions)) ["sudo", "ssh"] +-- TODO wasteful conversion! -- | Attempt to parse a PKGBUILD. Should succeed for all reasonable PKGBUILDs. parsedPB :: Pkgbuild -> Maybe List-parsedPB (Pkgbuild pb) = hush . parse "PKGBUILD" . T.unpack $ strictText pb  -- TODO wasteful conversion!+parsedPB (Pkgbuild pb) = hush . parse "PKGBUILD" . T.unpack $ decodeUtf8Lenient pb  -- | Discover any banned terms lurking in a parsed PKGBUILD, paired with -- the surrounding context lines.
lib/Aura/Settings.hs view
@@ -25,10 +25,10 @@   ) where  import           Aura.Types-import           BasePrelude-import qualified Data.Set as S-import qualified Data.Text as T import           Network.HTTP.Client (Manager)+import           RIO+import qualified RIO.Set as S+import qualified RIO.Text as T import           System.Path (Absolute, Path, fromAbsoluteFilePath, toFilePath)  ---@@ -51,7 +51,7 @@   { cachePathOf      :: !(Either (Path Absolute) (Path Absolute))   , configPathOf     :: !(Either (Path Absolute) (Path Absolute))   , logPathOf        :: !(Either (Path Absolute) (Path Absolute))-  , commonSwitchesOf :: !(S.Set CommonSwitch) } deriving (Show, Generic)+  , commonSwitchesOf :: !(Set CommonSwitch) } deriving (Show, Generic)  instance Flagable CommonConfig where   asFlag (CommonConfig cap cop lfp cs) =@@ -81,11 +81,11 @@  -- | Settings unique to the AUR package building process. data BuildConfig = BuildConfig-  { makepkgFlagsOf  :: !(S.Set Makepkg)+  { makepkgFlagsOf  :: !(Set Makepkg)   , buildPathOf     :: !(Path Absolute)   , buildUserOf     :: !(Maybe User)   , truncationOf    :: !Truncation  -- For `-As`-  , buildSwitchesOf :: !(S.Set BuildSwitch) } deriving (Show)+  , buildSwitchesOf :: !(Set BuildSwitch) } deriving (Show)  -- | Extra options for customizing the build process. data BuildSwitch = DeleteMakeDeps@@ -116,7 +116,7 @@   , langOf         :: !Language   , editorOf       :: !FilePath   , isTerminal     :: !Bool-  , ignoresOf      :: !(S.Set PkgName)+  , ignoresOf      :: !(Set PkgName)   , commonConfigOf :: !CommonConfig   , buildConfigOf  :: !BuildConfig } 
lib/Aura/State.hs view
@@ -24,49 +24,52 @@  import           Aura.Cache import           Aura.Colour (red)-import           Aura.Core (Env(..), liftEitherM, notify, report, warn)+import           Aura.Core (Env(..), notify, report, warn) import           Aura.Languages-import           Aura.Pacman (pacman, pacmanOutput)+import           Aura.Pacman (pacman, pacmanLines) import           Aura.Settings import           Aura.Types import           Aura.Utils-import           BasePrelude hiding (Version) import           Control.Compactable (fmapMaybe)-import           Control.Effect (Carrier, Member)-import           Control.Effect.Error (Error, throwError)-import           Control.Effect.Lift (Lift, sendM)-import           Control.Effect.Reader (Reader, asks) import           Control.Error.Util (hush) import           Data.Aeson-import           Data.Aeson.Types (typeMismatch)-import qualified Data.ByteString.Lazy as BL-import qualified Data.ByteString.Lazy.Char8 as BL import           Data.Generics.Product (field)-import           Data.List.NonEmpty (nonEmpty)-import qualified Data.Map.Strict as M-import qualified Data.Text as T-import           Data.Time+import           Data.List.NonEmpty (NonEmpty, nonEmpty) import           Data.Versions import           Lens.Micro ((^.))+import           RIO+import qualified RIO.ByteString.Lazy as BL+import           RIO.List (intercalate, partition, sort)+import           RIO.List.Partial ((!!))+import qualified RIO.Map as M+import qualified RIO.Map.Unchecked as M+import qualified RIO.Text as T+import           RIO.Time import           System.Path import           System.Path.IO (createDirectoryIfMissing, getDirectoryContents)+import           Text.Printf (printf)  ---  -- | All packages installed at some specific `ZonedTime`. Any "pinned" PkgState will -- never be deleted by `-Bc`.-data PkgState = PkgState { timeOf :: ZonedTime, pinnedOf :: Bool, pkgsOf :: M.Map PkgName Versioning }+data PkgState = PkgState+  { timeOf   :: ZonedTime+  , pinnedOf :: Bool+  , pkgsOf   :: Map PkgName Versioning }  instance ToJSON PkgState where-  toJSON (PkgState t pnd ps) = object [ "time" .= t, "pinned" .= pnd, "packages" .= fmap prettyV ps ]+  toJSON (PkgState t pnd ps) = object+    [ "time" .= t+    , "pinned" .= pnd+    , "packages" .= fmap prettyV ps ]  instance FromJSON PkgState where-  parseJSON (Object v) = PkgState+  parseJSON = withObject "PkgState" $ \v -> PkgState     <$> v .: "time"     <*> v .: "pinned"     <*> fmap f (v .: "packages")     where f = fmapMaybe (hush . versioning)-  parseJSON invalid = typeMismatch "PkgState" invalid  data StateDiff = StateDiff { _toAlter :: [SimplePkg], _toRemove :: [PkgName] } @@ -79,7 +82,7 @@ inState (SimplePkg n v) s = maybe False (v ==) . M.lookup n $ pkgsOf s  rawCurrentState :: IO [SimplePkg]-rawCurrentState = mapMaybe (simplepkg' . strictText) . BL.lines <$> pacmanOutput ["-Q"]+rawCurrentState = mapMaybe simplepkg' <$> pacmanLines ["-Q"]  currentState :: IO PkgState currentState = do@@ -132,19 +135,19 @@           mnths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]  -- | Does its best to restore a state chosen by the user.-restoreState :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => m ()+restoreState :: RIO Env () restoreState =-  sendM getStateFiles >>= maybe (throwError $ Failure restoreState_2) f . nonEmpty-  where f :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) => NonEmpty (Path Absolute) -> m ()+  liftIO getStateFiles >>= maybe (throwM $ Failure restoreState_2) f . nonEmpty+  where f :: NonEmpty (Path Absolute) -> RIO Env ()         f sfs = do           ss  <- asks settings           let pth = either id id . cachePathOf $ commonConfigOf ss-          mpast  <- sendM $ selectState sfs >>= readState+          mpast  <- liftIO $ selectState sfs >>= readState           case mpast of-            Nothing   -> throwError $ Failure readState_1+            Nothing   -> throwM $ Failure readState_1             Just past -> do-              curr <- sendM currentState-              Cache cache <- sendM $ cacheContents pth+              curr <- liftIO currentState+              Cache cache <- liftIO $ cacheContents pth               let StateDiff rein remo = compareStates past curr                   (okay, nope)        = partition (`M.member` cache) rein               traverse_ (report red restoreState_1 . fmap (^. field @"name")) $ nonEmpty nope@@ -159,14 +162,13 @@ readState = fmap decode . BL.readFile . toFilePath  -- | `reinstalling` can mean true reinstalling, or just altering.-reinstallAndRemove :: (Carrier sig m, Member (Reader Env) sig, Member (Error Failure) sig, Member (Lift IO) sig) =>-  [PackagePath] -> [PkgName] -> m ()+reinstallAndRemove :: [PackagePath] -> [PkgName] -> RIO Env () reinstallAndRemove [] [] = asks settings >>= \ss ->-  sendM (warn ss . reinstallAndRemove_1 $ langOf ss)+  liftIO (warn ss . reinstallAndRemove_1 $ langOf ss) reinstallAndRemove down remo   | null remo = reinstall   | null down = remove   | otherwise = reinstall *> remove   where-    remove    = liftEitherM . sendM . pacman $ "-R" : asFlag remo-    reinstall = liftEitherM . sendM . pacman $ "-U" : map (T.pack . toFilePath . path) down+    remove    = liftIO . pacman $ "-R" : asFlag remo+    reinstall = liftIO . pacman $ "-U" : map (T.pack . toFilePath . path) down
lib/Aura/Types.hs view
@@ -46,23 +46,21 @@   , User(..)   ) where -import           BasePrelude hiding (try) import           Control.Error.Util (hush) import           Data.Aeson (FromJSONKey, ToJSONKey)+import           Data.Bifunctor (Bifunctor(..)) import           Data.Bitraversable-import qualified Data.ByteString.Lazy as BL import           Data.Generics.Product (field, super)-import qualified Data.Map.Strict as M import           Data.Semigroup.Foldable (Foldable1(..)) import           Data.Set.NonEmpty (NESet) import qualified Data.Set.NonEmpty as NES-import qualified Data.Text as T import           Data.Text.Prettyprint.Doc hiding (list, space) import           Data.Text.Prettyprint.Doc.Render.Terminal import           Data.These (These(..)) import           Data.Versions hiding (Traversal')-import           GHC.Generics (Generic) import           Lens.Micro+import           RIO hiding (try)+import qualified RIO.Text as T import           System.Path (Absolute, Path, takeFileName, toUnrootedFilePath) import           Text.Megaparsec import           Text.Megaparsec.Char@@ -71,9 +69,9 @@  -- | Types whose members can be converted to CLI flags. class Flagable a where-  asFlag :: a -> [T.Text]+  asFlag :: a -> [Text] -instance Flagable T.Text where+instance Flagable Text where   asFlag t = [t]  instance (Foldable f, Flagable a) => Flagable (f a) where@@ -141,7 +139,7 @@ -- >>> parseDep "pacman>1.2.3" -- Just (Dep {name = PkgName {name = "pacman"}, demand = >1.2.3}) -- @-parseDep :: T.Text -> Maybe Dep+parseDep :: Text -> Maybe Dep parseDep = hush . parse dep "dep"   where dep = Dep <$> n <*> v         n   = PkgName <$> takeWhile1P Nothing (\c -> c /= '<' && c /= '>' && c /= '=')@@ -156,10 +154,10 @@  -- | Renders the `Dep` into a form that @pacman -T@ understands. The dual of -- `parseDep`.-renderedDep :: Dep -> T.Text+renderedDep :: Dep -> Text renderedDep (Dep n ver) = (n ^. field @"name") <> asT ver   where-    asT :: VersionDemand -> T.Text+    asT :: VersionDemand -> Text     asT (LessThan v) = "<"  <> prettyV v     asT (AtLeast  v) = ">=" <> prettyV v     asT (MoreThan v) = ">"  <> prettyV v@@ -201,7 +199,7 @@ simplepkg (PackagePath t) = uncurry SimplePkg <$> bitraverse hush hush (parse n "name" t', parse v "version" t')   where t' = T.pack . toUnrootedFilePath $ takeFileName t -        n :: Parsec Void T.Text PkgName+        n :: Parsec Void Text PkgName         n = PkgName . T.pack <$> manyTill anySingle (try finished)          -- | Assumes that a version number will never start with a letter,@@ -214,7 +212,7 @@  -- | Attempt to create a `SimplePkg` from text like: --     xchat 2.8.8-19-simplepkg' :: T.Text -> Maybe SimplePkg+simplepkg' :: Text -> Maybe SimplePkg simplepkg' = hush . parse parser "name-and-version"   where parser = SimplePkg <$> (PkgName <$> takeWhile1P Nothing (/= ' ')) <*> (space *> versioning') @@ -235,7 +233,7 @@           f = ((^? _Just . field @"name") &&& (^? _Just . field @"version")) . simplepkg  -- | The contents of a PKGBUILD file.-newtype Pkgbuild = Pkgbuild { pkgbuild :: BL.ByteString } deriving (Eq, Ord, Show, Generic)+newtype Pkgbuild = Pkgbuild { pkgbuild :: ByteString } deriving (Eq, Ord, Show, Generic)  -- | All human languages available for text output. data Language = English@@ -266,19 +264,24 @@ -- will produce a human-friendly error. newtype Failure = Failure { failure :: Language -> Doc AnsiStyle } +instance Exception Failure++instance Show Failure where+  show (Failure _) = "There was some failure."+ -- | Shell environment variables.-type Environment = M.Map T.Text T.Text+type Environment = Map Text Text  -- | The name of a user account on a Linux system.-newtype User = User { user :: T.Text } deriving (Eq, Show, Generic)+newtype User = User { user :: Text } deriving (Eq, Show, Generic)  -- | The name of an Arch Linux package.-newtype PkgName = PkgName { name :: T.Text }+newtype PkgName = PkgName { name :: Text }   deriving stock (Eq, Ord, Show, Generic)   deriving newtype (Flagable, ToJSONKey, FromJSONKey, IsString)  -- | A group that a `Package` could belong too, like @base@, @base-devel@, etc.-newtype PkgGroup = PkgGroup { group :: T.Text }+newtype PkgGroup = PkgGroup { group :: Text }   deriving stock (Eq, Ord, Show, Generic)   deriving newtype (Flagable) 
lib/Aura/Utils.hs view
@@ -12,7 +12,6 @@   ( -- * Strings     Pattern(..)   , replaceByPatt, searchLines-  , strictText     -- * Network   , urlContents     -- * Shell@@ -24,6 +23,8 @@   , ifFile     -- * Output   , putStrLnA+  , putText+  , putTextLn   , colourCheck   , entrify     -- * User Input@@ -37,65 +38,58 @@ import           Aura.Languages (whitespace, yesNoMessage, yesPattern) import           Aura.Settings import           Aura.Types (Environment, Language, User(..))-import           BasePrelude hiding (Version, (<+>))-import qualified Data.ByteString.Lazy as BL-import qualified Data.ByteString.Lazy as L-import qualified Data.Map.Strict as M-import qualified Data.Text as T-import           Data.Text.Encoding.Error (lenientDecode)-import qualified Data.Text.IO as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL import           Data.Text.Prettyprint.Doc import           Data.Text.Prettyprint.Doc.Render.Terminal import           Network.HTTP.Client import           Network.HTTP.Types.Status (statusCode)-import           System.IO (hFlush, stdout)+import           RIO+import qualified RIO.ByteString as B+import qualified RIO.ByteString.Lazy as BL+import           RIO.List.Partial (maximum)+import qualified RIO.Map as M+import qualified RIO.Text as T+import           RIO.Text.Partial (breakOn) import           System.Path (Absolute, Path, toFilePath) import           System.Path.IO (doesFileExist) import           System.Process.Typed (proc, runProcess)+import           Text.Printf (printf)  ---  --------- -- STRING ------------- | For regex-like find-and-replace in some `T.Text`.-data Pattern = Pattern { _pattern :: T.Text, _target :: T.Text }+-- | For regex-like find-and-replace in some `Text`.+data Pattern = Pattern { _pattern :: Text, _target :: Text }  -- | Replaces a (p)attern with a (t)arget in a line if possible.-replaceByPatt :: [Pattern] -> T.Text -> T.Text+replaceByPatt :: [Pattern] -> Text -> Text replaceByPatt [] l = l-replaceByPatt (Pattern p t : ps) l = case T.breakOn p l of+replaceByPatt (Pattern p t : ps) l = case breakOn p l of   -- No match.   (_, "")    -> replaceByPatt ps l   -- Matched. The matched pattern is still present at the head of `rest`,   -- so we need to drop it first.   (cs, rest) -> replaceByPatt ps (cs <> t <> T.drop (T.length p) rest) --- | Find lines which contain some given `T.Text`.-searchLines :: T.Text -> [T.Text] -> [T.Text]+-- | Find lines which contain some given `Text`.+searchLines :: Text -> [Text] -> [Text] searchLines pat = filter (T.isInfixOf pat) --- | Get strict Text out of a lazy ByteString.-strictText :: BL.ByteString -> T.Text-strictText = TL.toStrict . TL.decodeUtf8With lenientDecode- ----- -- IO ----- -- | Given a number of selections, allows the user to choose one.-getSelection :: Foldable f => (a -> T.Text) -> f a -> IO a+getSelection :: Foldable f => (a -> Text) -> f a -> IO a getSelection f choiceLabels = do   let quantity = length choiceLabels-      valids   = show <$> [1..quantity]+      valids   = map tshow [1..quantity]       pad      = show . length . show $ quantity       choices  = zip valids $ toList choiceLabels   traverse_ (\(l,v) -> printf ("%" <> pad <> "s. %s\n") l (f v)) choices-  putStr ">> "+  BL.putStr ">> "   hFlush stdout-  userChoice <- getLine+  userChoice <- decodeUtf8Lenient <$> B.getLine   case userChoice `lookup` choices of     Just valid -> pure valid     Nothing    -> getSelection f choiceLabels  -- Ask again.@@ -109,20 +103,22 @@ -- NETWORK ---------- -- | Assumes the given URL is correctly formatted.-urlContents :: Manager -> String -> IO (Maybe L.ByteString)+urlContents :: Manager -> String -> IO (Maybe ByteString) urlContents m url = f <$> httpLbs (parseRequest_ url) m-  where f res | statusCode (responseStatus res) == 200 = Just $ responseBody res-              | otherwise = Nothing+  where+    f :: Response BL.ByteString -> Maybe ByteString+    f res | statusCode (responseStatus res) == 200 = Just . BL.toStrict $ responseBody res+          | otherwise = Nothing  -------- -- SHELL -------- -- | Code borrowed from `ansi-terminal` library by Max Bolingbroke.-csi :: [Int] -> T.Text -> T.Text-csi args code = "\ESC[" <> T.intercalate ";" (map (T.pack . show) args) <> code+csi :: [Int] -> ByteString -> ByteString+csi args code = "\ESC[" <> B.intercalate ";" (map (encodeUtf8 . textDisplay) args) <> code  -- | Terminal code for raising the cursor.-cursorUpLineCode :: Int -> T.Text+cursorUpLineCode :: Int -> ByteString cursorUpLineCode n = csi [n] "F"  -- | This will get the true user name regardless of sudo-ing.@@ -145,7 +141,7 @@ getEditor = maybe "vi" T.unpack . M.lookup "EDITOR"  -- | This will get the locale variable for translations from the environment-getLocale :: Environment -> T.Text+getLocale :: Environment -> Text getLocale env = fromMaybe "C" . asum $ map (`M.lookup` env) ["LC_ALL", "LC_MESSAGES", "LANG"]  -- | Mark some `Path` as being owned by a `User`.@@ -154,33 +150,32 @@  -- | Hide the cursor in a terminal. hideCursor :: IO ()-hideCursor = T.putStr hideCursorCode+hideCursor = B.putStr hideCursorCode  -- | Restore a cursor to visiblity in the terminal. showCursor :: IO ()-showCursor = T.putStr showCursorCode+showCursor = B.putStr showCursorCode -hideCursorCode :: T.Text+hideCursorCode :: ByteString hideCursorCode = csi [] "?25l" -showCursorCode :: T.Text+showCursorCode :: ByteString showCursorCode = csi [] "?25h"  -- | Raise the cursor by @n@ lines. raiseCursorBy :: Int -> IO ()-raiseCursorBy = T.putStr . cursorUpLineCode+raiseCursorBy = B.putStr . cursorUpLineCode  ---------------- -- CUSTOM OUTPUT ----------------- -- | Print a `Doc` with Aura flair after performing a `colourCheck`. putStrLnA :: Settings -> Doc AnsiStyle -> IO () putStrLnA ss d = putStrA ss $ d <> hardline  -- | Will remove all colour annotations if the user specified @--color=never@. putStrA :: Settings -> Doc AnsiStyle -> IO ()-putStrA ss d = T.putStr . dtot $ "aura >>=" <+> colourCheck ss d+putStrA ss d = B.putStr . encodeUtf8 . dtot $ "aura >>=" <+> colourCheck ss d  -- | Strip colours from a `Doc` if @--color=never@ is specified, -- or if the output target isn't a terminal.@@ -190,6 +185,12 @@                | isTerminal ss = id                | otherwise = unAnnotate +putText :: Text -> IO ()+putText = B.putStr . encodeUtf8++putTextLn :: Text -> IO ()+putTextLn = BL.putStrLn . BL.fromStrict . encodeUtf8+ ---------- -- PROMPTS ----------@@ -197,11 +198,11 @@ yesNoPrompt ss msg = do   putStrA ss . yellow $ msg <+> yesNoMessage (langOf ss) <> " "   hFlush stdout-  response <- T.getLine+  response <- decodeUtf8Lenient <$> B.getLine   pure $ isAffirmative (langOf ss) response  -- | An empty response emplies "yes".-isAffirmative :: Language -> T.Text -> Bool+isAffirmative :: Language -> Text -> Bool isAffirmative l t = T.null t || elem (T.toCaseFold t) (yesPattern l)  -- | Doesn't prompt when `--noconfirm` is used.@@ -213,16 +214,16 @@ -- MISC ------- -- | Format two lists into two nice rows a la `-Qi` or `-Si`.-entrify :: Settings -> [T.Text] -> [Doc AnsiStyle] -> Doc AnsiStyle+entrify :: Settings -> [Text] -> [Doc AnsiStyle] -> Doc AnsiStyle entrify ss fs es = vsep $ zipWith combine fs' es-    where fs' = padding ss fs-          combine f e = annotate bold (pretty f) <+> ":" <+> e+  where fs' = padding ss fs+        combine f e = annotate bold (pretty f) <+> ":" <+> e  -- | Right-pads strings according to the longest string in the group.-padding :: Settings -> [T.Text] -> [T.Text]+padding :: Settings -> [Text] -> [Text] padding ss fs = map (T.justifyLeft longest ws) fs-    where ws      = whitespace $ langOf ss-          longest = maximum $ map T.length fs+  where ws      = whitespace $ langOf ss+        longest = maximum $ map T.length fs  -- | `maybe` with the function at the end. maybe' :: b -> Maybe a -> (a -> b) -> b
test/Test.hs view
@@ -7,12 +7,9 @@ import           Aura.Pacman import           Aura.Pkgbuild.Security import           Aura.Types-import           BasePrelude-import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.Map.Strict as M-import qualified Data.Text as T-import qualified Data.Text.IO as T import           Data.Versions+import           RIO+import qualified RIO.Map as M -- import           Language.Bash.Pretty (prettyText) import           System.Path import           Test.Tasty@@ -24,11 +21,11 @@  main :: IO () main = do-  conf <- T.readFile "test/pacman.conf"-  pkb  <- Pkgbuild <$> BL.readFile "test/aura.PKGBUILD"+  conf <- readFileUtf8 "test/pacman.conf"+  pkb  <- Pkgbuild <$> readFileBinary "test/aura.PKGBUILD"   defaultMain $ suite conf pkb -suite :: T.Text -> Pkgbuild -> TestTree+suite :: Text -> Pkgbuild -> TestTree suite conf pb = testGroup "Unit Tests"   [ testGroup "Aura.Core"     [ testCase "parseDep - python2" $ parseDep "python2" @?= Just (Dep "python2" Anything)@@ -72,7 +69,7 @@           assertEqual ("Language name map for " ++ show lang ++ " has incorrect number of items") (length languages - 1) (M.size names)     ]   , testGroup "Aura.Pkgbuild.Security"-    [ testCase "Parsing - aura.PKGBUILD" $ do+    [ testCase "Parsing - aura.PKGBUILD" $         -- pPrintNoColor $ map (first prettyText) . bannedTerms <$> ppb         -- pPrintNoColor ppb         assertBool "Failed to parse" $ isJust ppb@@ -81,7 +78,7 @@   ]   where ppb = parsedPB pb -firefox :: T.Text+firefox :: Text firefox = "Repository      : extra\n\ \Name            : firefox\n\ \Version         : 60.0.2-1\n\