koji-install 0.2.0 → 0.3
raw patch · 5 files changed
+112/−67 lines, 5 filesdep +http-commondep −optparse-applicative
Dependencies added: http-common
Dependencies removed: optparse-applicative
Files
- ChangeLog.md +5/−0
- README.md +8/−8
- koji-install.cabal +5/−4
- src/Main.hs +75/−46
- test/tests.hs +19/−9
ChangeLog.md view
@@ -1,5 +1,10 @@ # Release history for koji-install +## 0.3 (2021-12-03)+- add `--list` command to list recent builds+- fix bug in generating kojifiles url from short name+- workarounds for rpmfusion's older koji not supporting patterns+ ## 0.2.0 (2021-12-03) - initial Hackage release - `--hub` to select hub
README.md view
@@ -13,33 +13,32 @@ Will download the latest build for your Fedora version, and try to install it. -You can specify a different hub using `--hub`.+You can specify a different Koji hub service with `--hub`. ### Selecting subpackages -By default only installed subpackages are and downloaded and updated,+By default only installed subpackages are downloaded and updated, but the following options change the behavior: `--all`: install all subpackages `--ask`: ask about each subpackage -`--base-only`: only install base package+`--base-only`: only install the base package `--exclude-devel`: skip devel subpackages ### Help ```shellsession-$ koji-install-Install latest build from Koji+$ koji-install --help+Download and install latest package build from Koji tag. Usage: koji-install [--version] [-n|--dry-run] [-D|--debug] [-H|--hub HUB] [-P|--packages-url URL]- [(-a|--all) | (-A|--ask) | (-b|--base-only) |+ [(-l|--list) | (-a|--all) | (-A|--ask) | (-b|--base-only) | (-D|--exclude-devel)] [-d|--disttag DISTTAG] [(-R|--nvr) | (-V|--nv)] PACKAGE- Download and install latest package build from Koji tag.- HUB = fedora, stream, mbox, rpmfusion, URL+ HUB = fedora, stream, rpmfusion, or URL Available options: -h,--help Show this help text@@ -48,6 +47,7 @@ -D,--debug More detailed output -H,--hub HUB KojiHub shortname or url [default: fedora] -P,--packages-url URL KojiFiles packages url [default: fedora]+ -l,--list List builds -a,--all all subpackages -A,--ask ask for each subpackge -b,--base-only only base package
koji-install.cabal view
@@ -1,10 +1,10 @@ name: koji-install-version: 0.2.0+version: 0.3 synopsis: CLI tool for installing rpms directly from Fedora Koji description: koji-install can install the latest koji build of a package locally.- By default it only downloads newer binaries of the subpackages- already installed, but there are options to override that.+ By default it only downloads newer binaries of already-installed+ subpackages, but there are options to override that. license: BSD3 license-file: LICENSE author: Jens Petersen <juhpetersen@gmail.com>@@ -37,11 +37,12 @@ extra, filepath, koji >= 0.0.2,- optparse-applicative, rpm-nvr, simple-cmd, simple-cmd-args, xdg-userdirs+ if impl(ghc<8.4)+ build-depends: http-common < 0.8.3.4 default-language: Haskell2010 ghc-options: -Wall -threaded if impl(ghc >= 8.0)
src/Main.hs view
@@ -9,8 +9,6 @@ import Data.RPM import Distribution.Koji import qualified Distribution.Koji.API as Koji-import Options.Applicative (fullDesc, header, progDescDoc)-import qualified Options.Applicative.Help.Pretty as P import SimpleCmd import SimpleCmdArgs import System.Directory@@ -20,9 +18,15 @@ import DownloadDir import Paths_koji_install (version) +-- FIXME use subtype for listing vs installation+data Mode = List | InstMode InstallMode+ deriving Eq+ data InstallMode = Update | All | Ask | Base | NoDevel+ deriving Eq data Request = ReqName | ReqNV | ReqNVR+ deriving Eq -- FIXME --include devel, --exclude * -- FIXME specify tag or task@@ -33,13 +37,12 @@ main :: IO () main = do- sysdisttag <- cmd "rpm" ["--eval", "%{dist}"]- let pdoc = Just $ P.vcat- [ P.text "Download and install latest package build from Koji tag.",- P.text ("HUB = " <> intercalate ", " knownHubs)- ]- simpleCmdArgsWithMods (Just Paths_koji_install.version)- (fullDesc <> header "Install latest build from Koji" <> progDescDoc pdoc) $+ sysdisttag <- do+ dist <- cmd "rpm" ["--eval", "%{dist}"]+ return $ if dist == "%{dist}" then "" else dist+ simpleCmdArgs (Just Paths_koji_install.version)+ "Download and install latest package build from Koji tag."+ ("HUB = " ++ intercalate ", " knownHubs) $ program <$> switchWith 'n' "dry-run" "Don't actually download anything" <*> switchWith 'D' "debug" "More detailed output"@@ -53,13 +56,15 @@ <|> flagWith ReqName ReqNVR 'V' "nv" "Give an N-V instead of package name") <*> some (strArg "PACKAGE") where- modeOpt :: Parser InstallMode+ modeOpt :: Parser Mode modeOpt =- flagWith' All 'a' "all" "all subpackages" <|>+ flagWith' List 'l' "list" "List builds" <|>+ InstMode <$>+ (flagWith' All 'a' "all" "all subpackages" <|> flagWith' Ask 'A' "ask" "ask for each subpackge" <|> flagWith' Base 'b' "base-only" "only base package" <|> flagWith' NoDevel 'D' "exclude-devel" "Skip devel packages" <|>- pure Update+ pure Update) disttagOpt :: String -> Parser String disttagOpt disttag = startingDot <$> strOptionalWith 'd' "disttag" "DISTTAG" ("Use a different disttag [default: " ++ disttag ++ "]") disttag@@ -69,14 +74,15 @@ "" -> error' "empty disttag" (c:_) -> if c == '.' then cs else '.' : cs +-- mbox kojihub is locked knownHubs :: [String]-knownHubs = ["fedora","stream","mbox","rpmfusion", "URL"]+knownHubs = ["fedora","stream","rpmfusion", "or URL"] hubURL :: String -> String hubURL "fedora" = fedoraKojiHub -- later use centosKojiHub hubURL "stream" = "https://kojihub.stream.centos.org/kojihub"-hubURL "mbox" = "https://koji.mbox.centos.org/kojihub"+--hubURL "mbox" = "https://koji.mbox.centos.org/kojihub" hubURL "rpmfusion" = "https://koji.rpmfusion.org/kojihub" hubURL "fusion" = "https://koji.rpmfusion.org/kojihub" hubURL hub =@@ -84,23 +90,23 @@ then hub else error' $ "unknown hub: try " ++ show knownHubs -defaultPkgsURL :: Maybe String -> String-defaultPkgsURL Nothing =- "https://kojipkgs.fedoraproject.org/packages"-defaultPkgsURL (Just url) =- case url of+defaultPkgsURL :: String -> String+defaultPkgsURL url =+ case dropSuffix "/" url of+ "https://koji.fedoraproject.org/kojihub" ->+ "https://kojipkgs.fedoraproject.org/packages" "https://kojihub.stream.centos.org/kojihub" -> "https://kojihub.stream.centos.org/kojifiles/packages" _ -> if "kojihub" `isSuffixOf` url then replace "kojihub" "kojifiles" url- else error' "use --files-url to specify kojifiles url for this kojihub"+ else error' $ "use --files-url to specify kojifiles url for " ++ url -program :: Bool -> Bool -> Maybe String -> Maybe String -> InstallMode+program :: Bool -> Bool -> Maybe String -> Maybe String -> Mode -> String -> Request -> [String] -> IO () program dryrun debug mhuburl mpkgsurl mode disttag request pkgs = do let huburl = maybe fedoraKojiHub hubURL mhuburl- pkgsurl = fromMaybe (defaultPkgsURL mhuburl) mpkgsurl+ pkgsurl = fromMaybe (defaultPkgsURL huburl) mpkgsurl when debug $ do putStrLn huburl putStrLn pkgsurl@@ -109,22 +115,29 @@ when debug $ putStrLn dlDir setNoBuffering mapM (kojiLatestRPMs huburl pkgsurl dlDir) pkgs- >>= installRPMs dryrun . mconcat+ >>= case mode of+ List -> mapM_ putStrLn . mconcat+ _ -> installRPMs dryrun . mconcat where kojiLatestRPMs :: String -> String -> String -> String -> IO [String] kojiLatestRPMs huburl pkgsurl dlDir pkg = do- mnvr <- kojiLatestOSBuild huburl disttag request pkg- case mnvr of- Nothing -> error' $ "latest " ++ pkg ++ " not found"- Just nvr -> do- putStrLn $ nvr ++ "\n"- allRpms <- map (<.> "rpm") . sort . filter (not . debugPkg) <$> kojiGetBuildRPMs huburl nvr- dlRpms <- decideRpms mode allRpms- unless (dryrun || null dlRpms) $ do- mapM_ (downloadRpm pkgsurl (readNVR nvr)) dlRpms- -- FIXME once we check file size - can skip if no downloads- putStrLn $ "Packages downloaded to " ++ dlDir- return dlRpms+ nvrs <- kojiLatestOSBuilds debug huburl (mode == List) disttag request pkg+ case mode of+ List -> return nvrs+ InstMode instmode ->+ case nvrs of+ [] -> error' $ "latest " ++ pkg ++ " not found for " ++ disttag+ [nvr] -> do+ putStrLn $ nvr ++ "\n"+ allRpms <- map (<.> "rpm") . sort . filter (not . debugPkg) <$> kojiGetBuildRPMs huburl nvr+ dlRpms <- decideRpms instmode allRpms+ unless (dryrun || null dlRpms) $ do+ mapM_ (downloadRpm pkgsurl (readNVR nvr)) dlRpms+ -- FIXME once we check file size - can skip if no downloads+ putStrLn $ "Packages downloaded to " ++ dlDir+ return dlRpms+ _ -> error $ "multiple latest build founds for " ++ pkg ++ ": " +++ unwords nvrs where decideRpms :: InstallMode -> [String] -> IO [String] decideRpms mode' allRpms =@@ -155,23 +168,39 @@ debugPkg :: String -> Bool debugPkg p = "-debuginfo-" `isInfixOf` p || "-debugsource-" `isInfixOf` p -kojiLatestOSBuild :: String -> String -> Request -> String -> IO (Maybe String)-kojiLatestOSBuild hub disttag request pkgpat = do+kojiLatestOSBuilds :: Bool -> String -> Bool -> String -> Request -> String+ -> IO [String]+kojiLatestOSBuilds debug hub listmode disttag request pkgpat = do let (pkg,full) = packageOfPattern pkgpat+ oldkoji = "rpmfusion" `isInfixOf` hub+ when (oldkoji && ("*" `isInfixOf` pkgpat || request /= ReqName)) $+ error' "cannot use pattern with this kojihub" mpkgid <- Koji.getPackageID hub pkg case mpkgid of Nothing -> error $ "package not found: " ++ pkg Just pkgid -> do- let opts = [("packageID", ValueInt pkgid),+ -- strictly should getAPIVersion+ let opts = (if oldkoji+ then id+ else (("pattern", ValueString (if full then pkgpat else dropSuffix "*" pkgpat ++ "*" ++ disttag ++ "*")) :))+ [("packageID", ValueInt pkgid), ("state", ValueInt (fromEnum BuildComplete)),- ("queryOpts",ValueStruct [("limit",ValueInt 1),- ("order",ValueString "-build_id")])]- res <- Koji.listBuilds hub $- ("pattern", ValueString (if full then pkgpat else dropSuffix "*" pkgpat ++ "*" ++ disttag)) : opts- case res of- [] -> return Nothing- [bld] -> return $ lookupStruct "nvr" bld- _ -> error $ "more than one latest build found for " ++ pkg+ ("queryOpts",ValueStruct+ [("limit",ValueInt $ if listmode || oldkoji then 10 else 1),+ ("order",ValueString "-build_id")])]+ when debug $ print opts+ nvrs <- mapMaybe (lookupStruct "nvr") <$> Koji.listBuilds hub opts+ if null nvrs+ then error' $ "no builds found for " ++ disttag+ else+ return $+ if oldkoji+ then case filter (disttag `isInfixOf`) nvrs of+ [] -> error' $ "no builds found for " ++ disttag+ [res] -> [res]+ rs@(r:_) ->+ if listmode then rs else [r]+ else nvrs where packageOfPattern :: String -> (String, Bool) packageOfPattern pat =
test/tests.hs view
@@ -3,18 +3,28 @@ program :: [String] -> IO () program args =- putStrLn "" >> cmdLog "koji-install" ("-n" : "-b" : args)+ putStrLn "" >>+ cmdLog "koji-install" ("-n" : args) -tests :: [[String]]-tests =- [["podman"]- ,["-H", "https://kojihub.stream.centos.org/kojihub", "-d", "el9", "bash"]- ,["-H", "stream", "-d", "el9", "kernel"]--- ,["-H", "rpmfusion", "ffmpeg"]+tests :: Bool -> [[String]]+tests havedist =+ [["-b", "podman"] ++ sysdist+ ,["-l", "coreutils"] ++ sysdist+ ,["-b", "-H", "https://kojihub.stream.centos.org/kojihub", "-d", "el9", "bash"]+ ,["-b", "-H", "stream", "-d", "el9", "kernel"]+ ,["-l", "-H", "stream", "-d", "el9", "grep"]+ ,["-b", "-H", "rpmfusion", "ffmpeg"] ++ sysdist+ ,["-l", "-H", "rpmfusion", "ffmpeg"] ++ sysdist ]+ where+ sysdist = if havedist then [] else ["-d", "fc35"] main :: IO () main = do hSetBuffering stdout NoBuffering- mapM_ program tests- putStrLn $ show (length tests) ++ " tests run"+ havedist <- do+ dist <- cmd "rpm" ["--eval", "%{dist}"]+ return $ dist /= "%{dist}"+ let cases = tests havedist+ mapM_ program cases+ putStrLn $ show (length cases) ++ " tests run"