packages feed

select-rpms 0.3.0 → 0.3.1

raw patch · 3 files changed

+105/−51 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ SelectRPMs: installRPMsAllowErasing :: Bool -> Bool -> Maybe PkgMgr -> Bool -> Yes -> [(FilePath, [ExistNVRA])] -> IO ()
+ SelectRPMs: pkgMgrOpt :: Parser PkgMgr

Files

ChangeLog.md view
@@ -1,5 +1,14 @@ # Release history for select-rpms +## 0.3.1 (2025-09-13)+- selections that do not match any RPMs no longer error+- installing debuginfo/debugsource now possible if requested+- default presets for certain package prefixes (currently only ghc*)+- add pkgMgrOpt (from koji-tool)+- add installRPMsAllowErasing which extends installRPMs+- installRPMs (installCommand): use rpm -U since package may exist+- checkSelection: now used directly by decideRPMs+ ## 0.3.0 (2025-06-04) - ExistingStrategy: add ExistingError which aborts for existing installed pkg 
select-rpms.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                select-rpms-version:             0.3.0+version:             0.3.1 synopsis:            Select a subset of RPM packages description:         A library for selecting a subset of RPM (sub)packages.@@ -22,6 +22,7 @@                       || == 9.6.7                       || == 9.8.4                       || == 9.10.2+                      || == 9.12.2  source-repository head   type:                git
src/SelectRPMs.hs view
@@ -16,13 +16,15 @@   nvraToRPM,   groupOnArch,   PkgMgr(..),-  installRPMs+  pkgMgrOpt,+  installRPMs,+  installRPMsAllowErasing   ) where  import Control.Monad.Extra (forM_, mapMaybeM, unless, when) import Data.Either (partitionEithers)-import Data.List.Extra (isInfixOf, nubOrd, nubSort, sort,+import Data.List.Extra (isPrefixOf, isSuffixOf, nubOrd, nubSort, sort, #if !MIN_VERSION_base(4,20,0)                         foldl', #endif@@ -45,6 +47,8 @@ import System.FilePath.Glob (compile, isLiteral, match)  -- | The Select type specifies the subpackage selection+--+-- Can use name globs: eg "*-devel" or "lib*" data Select = All -- ^ all packages             | Ask -- ^ interactive prompting             | PkgsReq@@ -54,11 +58,11 @@               [String] -- ^ added   deriving Eq --- | default package selection+-- | Default package selection selectDefault :: Select selectDefault = PkgsReq [] [] [] [] --- | optparse-applicative Parser for Select+-- | An optparse-applicative Parser for Select selectRpmsOptions :: Parser Select selectRpmsOptions =   flagLongWith' All "all" "all subpackages [default if not installed]" <|>@@ -69,7 +73,7 @@   <*> many (strOptionWith 'x' "exclude" "SUBPKG" "deselect subpackage (glob): overrides -p and -e")   <*> many (strOptionWith 'i' "include" "SUBPKG" "additional subpackage (glob) to install: overrides -x") --- | alternative CLI args option parsing to Select packages+-- | An alternative CLI args option to parse String to Select of rpm packages installArgs :: String -> Select installArgs cs =   case words cs of@@ -110,28 +114,36 @@       then error' "empty pattern!"       else f --- FIXME explain if/why this is actually needed (used by koji-tool install)--- | check package Select is not empty+-- FIXME check allowed characters+-- | Check package Select options have no empty strings+--+-- (deprecated export) checkSelection :: Monad m => Select -> m () checkSelection (PkgsReq ps es xs is) =   forM_ (ps ++ es ++ xs ++ is) $ \s ->   when (null s) $ error' "empty package pattern not allowed" checkSelection _ = return () --- | converts a list of RPM files to NVRA's, filtering out debug subpackages+-- | Converts a list of RPM files to sorted NVRA's+--+-- (since 0.3.1 no longer excludes debuginfo and debugsource packages) rpmsToNVRAs :: [String] -> [NVRA]-rpmsToNVRAs = sort . map readNVRA . filter notDebugPkg+rpmsToNVRAs = sort . map readNVRA --- | how to handle already installed packages: re-install, skip, or+-- | How to handle already installed subpackages: re-install, skip, or -- default update -- -- The default strategy is to select existing subpackages, otherwise all. -- -- The constructors are only really needed internally but exported for -- documentation.-data ExistingStrategy = ExistingNoReinstall | ExistingSkip | ExistingOnly | ExistingError+data ExistingStrategy = ExistingNoReinstall -- ^ skip reinstall of same NVRs+                      | ExistingSkip        -- ^ skip installed subpkgs+                      | ExistingOnly        -- ^ only update existing subpkgs+                      | ExistingError       -- ^ abort for existing subpkg   deriving Eq +-- | An optparse-applicative Parser for ExistingStrategy existingStrategyOption :: Parser ExistingStrategy existingStrategyOption =   flagWith' ExistingNoReinstall 'N' "no-reinstall" "Do not reinstall existing NVRs" <|>@@ -139,37 +151,38 @@   flagWith' ExistingOnly 'O' "only-existing" "Only update existing installed subpackages" <|>   flagWith' ExistingError 'E' "error-existing" "Abort for existing installed subpackages" --- | sets prompt default behaviour for yes/no questions+-- | Sets prompt default behaviour for yes/no questions data Yes = No | Yes   deriving Eq --- | current state of a package NVR+-- | Current state of a package NVR data Existence = ExistingNVR -- ^ NVR is already installed                | ChangedNVR -- ^ NVR is different to installed package                | NotInstalled -- ^ package is not currently installed   deriving (Eq, Ord, Show) --- | combines Existence state with an NVRA+-- | Combines Existence state with an NVRA type ExistNVRA = (Existence, NVRA)  -- FIXME determine and add missing internal deps--- | decide list of NVRs based on a Select selection (using a package prefix)+-- | Decide list of NVRs based on a Select selection (using a package prefix) decideRPMs :: Yes -- ^ prompt default choice-           -> Bool -- ^ enable list mode which just display the package list+           -> Bool -- ^ enable list mode which just displays the package list            -> Maybe ExistingStrategy -- ^ optional existing install strategy            -> Select -- ^ specifies package Select choices-           -> String -- ^ package set prefix: allows abbreviated Select-           -> [NVRA] -- ^ list of packages to select from-           -> IO [ExistNVRA] -- ^ returns list of selected packages+           -> String -- ^ package set prefix: allows Select'ing without prefix+           -> [NVRA] -- ^ list of rpm packages to select from+           -> IO [ExistNVRA] -- ^ returns list of selected rpm packages decideRPMs yes listmode mstrategy select prefix nvras = do+  checkSelection select   classified <- mapMaybeM installExists (filter isBinaryRpm nvras)   if listmode     then do-    case select of-      PkgsReq subpkgs exceptpkgs exclpkgs addpkgs ->-        mapM_ printInstalled $-        selectRPMs prefix (subpkgs,exceptpkgs,exclpkgs,addpkgs) classified-      _ -> mapM_ printInstalled classified+    mapM_ printInstalled $+      case select of+        PkgsReq subpkgs exceptpkgs exclpkgs addpkgs ->+          selectRPMs prefix (subpkgs,exceptpkgs,exclpkgs,addpkgs) classified+        _ -> classified     return []     else     case select of@@ -209,7 +222,7 @@       included = matchingRPMs prefix addpkgs rpms       matching =         if null subpkgs && null exceptpkgs-        then defaultRPMs rpms+        then defaultRPMs prefix rpms         else matchingRPMs prefix subpkgs rpms       nonmatching = nonMatchingRPMs prefix exceptpkgs rpms   in nubSort $ ((matching ++ nonmatching) \\ excluded) ++ included@@ -252,24 +265,36 @@     then Just epn     else Nothing -defaultRPMs :: [ExistNVRA] -> [ExistNVRA]-defaultRPMs rpms =+defaultRPMs :: String -> [ExistNVRA] -> [ExistNVRA]+defaultRPMs prefix rpms =   let installed = filter ((/= NotInstalled) . fst) rpms   in if null installed-     then rpms+     then filter (wantedSubpackage . rpmName . snd) rpms      else installed+  where+    wantedSubpackage :: String -> Bool+    wantedSubpackage p =+      notDebugPkg p && defaultSubpackage p +    notDebugPkg :: String -> Bool+    notDebugPkg p =+      not ("-debuginfo" `isSuffixOf` p || "-debugsource" `isSuffixOf` p)++    defaultSubpackage :: String -> Bool+    defaultSubpackage p =+      not ("ghc" `isPrefixOf` prefix)+      ||+      not ("-doc" `isSuffixOf` p || "-prof" `isSuffixOf` p || "compiler-default" `isSuffixOf` p)++-- FIXME add --strict (must match) switch matchingRPMs :: String -> [String] -> [ExistNVRA] -> [ExistNVRA] matchingRPMs prefix subpkgs rpms =   nubSort . mconcat $-  flip map (nubOrd subpkgs) $ \ pkgpat ->+  flip map (nubOrd subpkgs) $ \pkgpat ->   case getMatches pkgpat of     [] -> if headMay pkgpat /= Just '*'-          then-            case getMatches (prefix ++ '-' : pkgpat) of-              [] -> error' $ "no subpackage match for " ++ pkgpat-              result -> result-          else error' $ "no subpackage match for " ++ pkgpat+          then getMatches (prefix ++ '-' : pkgpat)+          else []     result -> result   where     getMatches :: String -> [ExistNVRA]@@ -301,29 +326,48 @@                   (prefix ++ '-' : pat) == rpmname              else match comppat rpmname -notDebugPkg :: String -> Bool-notDebugPkg p =-  not ("-debuginfo-" `isInfixOf` p || "-debugsource-" `isInfixOf` p)---- | whether a package needs to be reinstalled or installed+-- | Whether a package needs to be reinstalled or installed data InstallType = ReInstall                  | Install --- | package manager+-- | Package manager data PkgMgr = DNF3 | DNF5 | RPM | OSTREE   deriving Eq --- FIXME support options per build: install ibus imsettings -i plasma--- (or don't error if multiple packages)--- | do installation of packages+-- | An optparse-applicative Parser for PkgMgr+--+-- (since 0.3.1)+pkgMgrOpt :: Parser PkgMgr+pkgMgrOpt =+  flagLongWith' RPM "rpm" "Use rpm instead of dnf" <|>+  flagLongWith' OSTREE "rpm-ostree" "Use rpm-ostree instead of dnf" <|>+  flagLongWith' DNF5 "dnf5" "Use dnf5 to install" <|>+  flagLongWith' DNF3 "dnf3" "Use dnf-3 to install [default dnf unless ostree]"++-- | Do installation of selected rpm packages installRPMs :: Bool -- ^ dry-run             -> Bool -- ^ debug output             -> Maybe PkgMgr -- ^ optional specify package manager             -> Yes -- ^ prompt default choice             -> [(FilePath,[ExistNVRA])] -- ^ list of rpms to install with path             -> IO ()-installRPMs _ _ _ _ [] = return ()-installRPMs dryrun debug mmgr yes classifieds = do+installRPMs dryrun debug mmgr =+  installRPMsAllowErasing dryrun debug mmgr False++-- FIXME support options per build: install ibus imsettings -i plasma+-- (or don't error if multiple packages)+-- | Do installation of packages (with allowerasing switch)+--+-- (since 0.3.1)+installRPMsAllowErasing :: Bool -- ^ dry-run+                        -> Bool -- ^ debug output+                        -> Maybe PkgMgr -- ^ optional specify package manager+                        -> Bool -- ^ use dnf --allowerasing+                        -> Yes -- ^ prompt default choice+                        -> [(FilePath,[ExistNVRA])] -- ^ list of rpms to install with path+                        -> IO ()+installRPMsAllowErasing _ _ _ _ _ [] = return ()+installRPMsAllowErasing dryrun debug mmgr allowerasing yes classifieds =   case installTypes (concatMap zipDir classifieds) of     ([],is) -> doInstall Install is     (ris,is) -> do@@ -372,7 +416,7 @@           (case mgr of             OSTREE -> cmd_             _ -> if debug then sudoLog else sudo_) pkgmgr $-            com ++ map showRpmFile dirpkgs ++ ["--assumeyes" | yes == Yes && mgr `elem` [DNF3,DNF5]]+            com ++ map showRpmFile dirpkgs ++ ["--allowerasing" | allowerasing] ++ ["--assumeyes" | yes == Yes && mgr `elem` [DNF3,DNF5]]      reinstallCommand :: PkgMgr -> [String]     reinstallCommand mgr =@@ -387,19 +431,19 @@       case mgr of         DNF3 -> ["localinstall"]         DNF5 -> ["install"]-        RPM -> ["-ivh"]+        RPM -> ["-Uvh"]         OSTREE -> ["install"]  -- FIXME replace with export from rpm-nvr (once released)--- | render a NVRA as rpm file+-- | Render a NVRA as rpm file nvraToRPM :: NVRA -> FilePath nvraToRPM nvra = showNVRA nvra <.> "rpm" --- | render path and NVRA are rpm filepath+-- | Render path and NVRA are rpm filepath showRpmFile :: (FilePath,NVRA) -> FilePath showRpmFile (dir,nvra) = dir </> nvraToRPM nvra --- | group rpms by arch (subdirs)+-- | Group rpms by arch (subdirs) groupOnArch :: FilePath -- ^ prefix directory (eg "RPMS")             -> [ExistNVRA]             -> [(FilePath,[ExistNVRA])]