koji-tool 0.9.1 → 0.9.2
raw patch · 13 files changed
+311/−172 lines, 13 files
Files
- ChangeLog.md +11/−3
- README.md +41/−37
- TODO +3/−3
- koji-tool.cabal +1/−1
- src/Builds.hs +8/−10
- src/DownloadDir.hs +1/−1
- src/Install.hs +120/−68
- src/Main.hs +2/−1
- src/Progress.hs +58/−29
- src/Quick.hs +1/−1
- src/Tasks.hs +18/−15
- src/Time.hs +30/−3
- src/Utils.hs +17/−0
ChangeLog.md view
@@ -1,13 +1,21 @@ # Version history of koji-tool +## 0.9.2 (2022-06-12)+- progress: print build duration+- install: place rpms in a nvr subdirectory+- progress: show duration of build and finished tasks+- install: when downloading check if local files' timestamp within build time+- progress: no longer quit after srpm build+- tasks --install now takes install options string+ ## 0.9.1 (2022-05-29) - 'find': add "install", "tail", "notail", and archs support - 'install': --rpm option to install directly with rpm instead of dnf - 'tasks': add --install option - 'tasks': major rework of the log file handling-- 'tasks --tail': fix output when still running-- 'tasks': compact task output shows duration-- 'builds': now outputs packages/ archive url+- 'tasks --tail': fix output when task still running+- 'tasks': compact output shows duration+- 'builds': now outputs packages archive url ## 0.9 (2022-05-20) - rename 'quick' command to 'find'
README.md view
@@ -23,7 +23,7 @@ ## Commands ```shellsession $ koji-tool --version-0.9.1+0.9.2 $ koji-tool --help Query and track Koji tasks, and install rpms from Koji. @@ -134,7 +134,7 @@ [(-B|--before TIMESTAMP) | (-F|--from TIMESTAMP)] [-m|--method METHOD] [-d|--details] [-D|--debug] [(-P|--only-package PKG) | (-N|--only-nvr PREFIX)]- [-T|--tail] [-i|--install]+ [-T|--tail] [-i|--install INSTALLOPTS] [(-b|--build BUILD) | (-p|--pattern NVRPAT) | PACKAGE|TASKID] Query Koji tasks (by default lists most recent buildArch tasks)@@ -158,7 +158,7 @@ -P,--only-package PKG Filter task results to specified package -N,--only-nvr PREFIX Filter task results by NVR prefix -T,--tail Fetch the tail of build.log- -i,--install install the package+ -i,--install INSTALLOPTS Install the package with 'install' options -b,--build BUILD List child tasks of build -p,--pattern NVRPAT Build tasks of matching pattern -h,--help Show this help text@@ -194,36 +194,8 @@ https://kojipkgs.fedoraproject.org/work/tasks/5316/86685316/build.log (13kB) ``` -## koji-tool find-This provides shortcuts to a few select common searches--### Usage-`koji-tool find my builds` shows your 10 most recent koji builds (equivalent to `koji-tool builds --mine`)--`koji-tool find my last fail` shows your most recent task failure including the tail of the build.log (equivalent to `koji-tool tasks -MLT -s fail`).--`koji-tool find last complete build` shows the latest completed koji build (equivalent to `koji-tool builds -L -s complete`).--### Help-```shellsession-$ koji-tool find-koji-tool: find handles these words:--my mine-last latest-fail failure failed-complete completed completion close closed finish finished-current building open-build builds-detail details detailed-install-tail-notail-x86_64 aarch64 ppc64le s390x i686 armv7hl-PACKAGE-USER\'s--```+It is also possible to install packages from a task using `--install "..."`.+See the install command documentation below for more details. ## koji-tool install @@ -235,7 +207,7 @@ Note this command is intended for development and testing purposes and should not be necessary/used normally on production systems, but it can be very helpful for quickly testing an specific package build or-update.+update locally. ### Usage @@ -279,7 +251,7 @@ $ koji-tool install --help Usage: koji-tool install [-n|--dry-run] [-D|--debug] [-y|--yes] [-H|--hub HUB] [-P|--packages-url URL] [-l|--list] [-L|--latest]- [-r|--rpm] [-N|--no-reinstall]+ [-t|--check-remote-time] [-r|--rpm] [-N|--no-reinstall] [-b|--prefix SUBPKGPREFIX] [(-a|--all) | (-A|--ask) | [-p|--package SUBPKG] [-x|--exclude SUBPKG]] [-d|--disttag DISTTAG]@@ -296,6 +268,7 @@ -P,--packages-url URL KojiFiles packages url [default: Fedora] -l,--list List builds -L,--latest Latest build+ -t,--check-remote-time Check remote rpm timestamps -r,--rpm Use rpm instead of dnf -N,--no-reinstall Do not reinstall existing NVRs -b,--prefix SUBPKGPREFIX Prefix to use for subpackages [default: base package]@@ -303,12 +276,43 @@ -A,--ask ask for each subpackge [default if not installed] -p,--package SUBPKG Subpackage (glob) to install -x,--exclude SUBPKG Subpackage (glob) not to install- -d,--disttag DISTTAG Override the disttag+ -d,--disttag DISTTAG Select a disttag different to system -R,--nvr Give an N-V-R instead of package name -V,--nv Give an N-V instead of package name -h,--help Show this help text ``` +## koji-tool find+This provides shortcuts to a few select common searches++### Usage+`koji-tool find my builds` shows your 10 most recent koji builds (equivalent to `koji-tool builds --mine`)++`koji-tool find my last fail` shows your most recent task failure including the tail of the build.log (equivalent to `koji-tool tasks -MLT -s fail`).++`koji-tool find last complete build` shows the latest completed koji build (equivalent to `koji-tool builds -L -s complete`).++### Help+```shellsession+$ koji-tool find+koji-tool: find handles these words:++my mine+last latest+fail failure failed+complete completed completion close closed finish finished+current building open+build builds+detail details detailed+install+tail+notail+x86_64 aarch64 ppc64le s390x i686 armv7hl+PACKAGE+USER\'s++```+ ## koji-tool progress Shows the progress of active koji builds tasks by checking the size of their build.log files.@@ -334,7 +338,7 @@ The `buildlog-sizes` command is similar but runs once over nvr patterns. ## Installation-koji-tool is packaged in Fedora 35++koji-tool is packaged in Fedora ## Build `cabal-rpm builddep && cabal install || stack install`
TODO view
@@ -2,6 +2,9 @@ - hub configurations - determine urls for logs etc by parsing html +# misc+- api-version command+ # install - autodetect nvr - --nodeps@@ -47,10 +50,7 @@ - % of previous build (or finished tasks) - mbs urls? - average build times? (cache or separate tool?)-* quits after srpm build - show log sizes for old finished builds--- display buildtimes for completed tasks - pick up user's new builds
koji-tool.cabal view
@@ -1,5 +1,5 @@ name: koji-tool-version: 0.9.1+version: 0.9.2 synopsis: Koji CLI tool for querying tasks and installing builds description: koji-tool is a CLI interface to Koji with commands to query
src/Builds.hs view
@@ -95,12 +95,10 @@ nvr <- lookupStruct "nvr" bld state <- readBuildState <$> lookupStruct "state" bld let date =- case lookupTime "completion" bld of- Just t -> compactZonedTime tz t- Nothing ->- case lookupTime "start" bld of- Just t -> compactZonedTime tz t- Nothing -> ""+ case lookupTimes bld of+ Nothing -> ""+ Just (start,mend) ->+ compactZonedTime tz $ fromMaybe start mend mbid = lookupStruct "build_id" bld return $ nvr +-+ show state +-+ date +-+ maybe "" (buildinfoUrl hub) mbid @@ -139,7 +137,8 @@ pPrintCompact = #if MIN_VERSION_pretty_simple(4,0,0) pPrintOpt CheckColorTty- (defaultOutputOptionsDarkBg {outputOptionsCompact = True})+ (defaultOutputOptionsDarkBg {outputOptionsCompact = True,+ outputOptionsCompactParens = True}) #else pPrint #endif@@ -160,15 +159,14 @@ maybeBuildResult :: Struct -> Maybe BuildResult maybeBuildResult st = do- start_time <- lookupTime "start" st- let mend_time = lookupTime "completion" st+ (start,mend) <- lookupTimes st buildid <- lookupStruct "build_id" st -- buildContainer has no task_id let mtaskid = lookupStruct "task_id" st state <- getBuildState st nvr <- lookupStruct "nvr" st >>= maybeNVR return $- BuildResult nvr state buildid mtaskid start_time mend_time+ BuildResult nvr state buildid mtaskid start mend printBuild :: String -> TimeZone -> BuildResult -> IO () printBuild hub tz build = do
src/DownloadDir.hs view
@@ -38,7 +38,7 @@ return $ putStrLn $ "Packages downloaded to " ++- if isRelative path then "~" </> path else path+ (if isRelative path then "~" </> path else path) </> subdir where setCWD :: FilePath -> IO FilePath setCWD dir = do
src/Install.hs view
@@ -7,7 +7,8 @@ Request(..), installCmd, knownHubs,- Yes(..)+ Yes(..),+ installArgs ) where @@ -30,17 +31,39 @@ import Common import DownloadDir+import Time import Utils data Yes = No | Yes deriving Eq data Select = All- | Ask- -- distinguish except and exclude- | PkgsReq [String] [String] -- ^ include, except/exclude+ | Ask+ | PkgsReq [String] [String] -- ^ include, except/exclude deriving Eq +installArgs :: String -> Select+installArgs cs =+ case words cs of+ ["-a"] -> All+ ["--all"] -> All+ ["-A"] -> Ask+ ["--ask"] -> Ask+ ws -> installPairs [] [] ws+ where+ installPairs :: [String] -> [String] -> [String] -> Select+ installPairs pa xa [] = PkgsReq pa xa+ installPairs pa xa (w:ws)+ | w `elem` ["-p","--package"] =+ case ws of+ [] -> error' "--install-opts --package missing value"+ (w':ws') -> installPairs (w':pa) xa ws'+ | w `elem` ["-x","--exclude"] =+ case ws of+ [] -> error' "--install-opts --exclude missing value"+ (w':ws') -> installPairs pa (w':xa) ws'+ | otherwise = error' "invalid --install-opts"+ data Request = ReqName | ReqNV | ReqNVR deriving Eq @@ -52,10 +75,11 @@ -- FIXME --delete after installing -- FIXME --dnf to install selected packages using default dnf repo instead -- FIXME offer to download subpackage deps+-- FIXME is --check-remote-time really needed? installCmd :: Bool -> Bool -> Yes -> Maybe String -> Maybe String -> Bool- -> Bool -> Bool -> Bool -> Maybe String -> Select -> Maybe String- -> Request -> [String] -> IO ()-installCmd dryrun debug yes mhuburl mpkgsurl listmode latest userpm noreinstall mprefix select mdisttag request pkgbldtsks = do+ -> Bool -> Bool -> Bool -> Bool -> Maybe String -> Select+ -> Maybe String -> Request -> [String] -> IO ()+installCmd dryrun debug yes mhuburl mpkgsurl listmode latest checkremotetime useRpm noreinstall mprefix select mdisttag request pkgbldtsks = do let huburl = maybe fedoraKojiHub hubURL mhuburl pkgsurl = fromMaybe (hubToPkgsURL huburl) mpkgsurl when debug $ do@@ -64,17 +88,18 @@ printDlDir <- setDownloadDir dryrun "rpms" when debug printDlDir setNoBuffering- mapM (kojiRPMs huburl pkgsurl printDlDir) pkgbldtsks- >>= installRPMs dryrun userpm noreinstall yes . mconcat+ buildrpms <- mapM (kojiRPMs huburl pkgsurl printDlDir) pkgbldtsks+ installRPMs dryrun debug useRpm noreinstall yes buildrpms where- kojiRPMs :: String -> String -> IO () -> String -> IO [(Existence,NVRA)]+ kojiRPMs :: String -> String -> IO () -> String+ -> IO (FilePath, [(Existence,NVRA)]) kojiRPMs huburl pkgsurl printDlDir bldtask = case readMaybe bldtask of- Just taskid -> kojiTaskRPMs dryrun debug yes huburl pkgsurl listmode noreinstall mprefix select printDlDir taskid+ Just taskid -> kojiTaskRPMs dryrun debug yes huburl pkgsurl listmode noreinstall mprefix select checkremotetime printDlDir taskid Nothing -> kojiBuildRPMs huburl pkgsurl printDlDir bldtask kojiBuildRPMs :: String -> String -> IO () -> String- -> IO [(Existence,NVRA)]+ -> IO (FilePath, [(Existence,NVRA)]) kojiBuildRPMs huburl pkgsurl printDlDir pkgbld = do disttag <- case mdisttag of@@ -91,25 +116,30 @@ [nvr] -> do putStrLn (showNVR nvr) putStrLn ""- kojiGetBuildRPMs huburl nvr >>=+ bid <- kojiGetBuildID' huburl (showNVR nvr)+ kojiGetBuildRPMs huburl nvr bid >>= mapM_ putStrLn . sort . filter notDebugPkg _ -> mapM_ (putStrLn . showNVR) nvrs- return []+ return ("",[]) else case nvrs of [] -> error' $ pkgbld ++ " not found for " ++ disttag [nvr] -> do putStrLn $ showNVR nvr ++ "\n"- nvras <- sort . map readNVRA . filter notDebugPkg <$> kojiGetBuildRPMs huburl nvr+ bid <- kojiGetBuildID' huburl (showNVR nvr)+ nvras <- sort . map readNVRA . filter notDebugPkg <$> kojiGetBuildRPMs huburl nvr bid when debug $ mapM_ (putStrLn . showNVRA) nvras let prefix = fromMaybe (nvrName nvr) mprefix dlRpms <- decideRpms yes listmode noreinstall select prefix nvras when debug $ mapM_ printInstalled dlRpms+ let subdir = showNVR nvr unless (dryrun || null dlRpms) $ do- downloadRpms debug (buildURL nvr) dlRpms+ bld <- kojiGetBuild' huburl nvr+ -- FIXME should be NVRA ideally+ downloadRpms debug checkremotetime (lookupTimes' bld) subdir (buildURL nvr) dlRpms -- FIXME once we check file size - can skip if no downloads printDlDir- return dlRpms+ return (subdir,dlRpms) _ -> error $ "multiple build founds for " ++ pkgbld ++ ": " ++ unwords (map showNVR nvrs) where@@ -123,8 +153,9 @@ not ("-debuginfo-" `isInfixOf` p || "-debugsource-" `isInfixOf` p) kojiTaskRPMs :: Bool -> Bool -> Yes -> String -> String -> Bool -> Bool- -> Maybe String -> Select -> IO () -> Int -> IO [(Existence,NVRA)]-kojiTaskRPMs dryrun debug yes huburl pkgsurl listmode noreinstall mprefix select printDlDir taskid = do+ -> Maybe String -> Select -> Bool -> IO () -> Int+ -> IO (FilePath, [(Existence,NVRA)])+kojiTaskRPMs dryrun debug yes huburl pkgsurl listmode noreinstall mprefix select checkremotetime printDlDir taskid = do mtaskinfo <- Koji.getTaskInfo huburl taskid True tasks <- case mtaskinfo of Nothing -> error' "failed to get taskinfo"@@ -157,21 +188,25 @@ kojiTaskRequestPkgNVR $ fromMaybe archtask mtaskinfo if listmode- then decideRpms yes listmode noreinstall select prefix nvras+ then do+ drpms <- decideRpms yes listmode noreinstall select prefix nvras+ return ("",drpms) else if null nvras then do- kojiTaskRPMs dryrun debug yes huburl pkgsurl True noreinstall mprefix select printDlDir archtid >>= mapM_ printInstalled- return []+ (_, rpms) <- kojiTaskRPMs dryrun debug yes huburl pkgsurl True noreinstall mprefix select checkremotetime printDlDir archtid+ mapM_ printInstalled rpms+ return ("",[]) else do when debug $ print $ map showNVRA nvras dlRpms <- decideRpms yes listmode noreinstall select prefix $ filter ((/= "src") . rpmArch) nvras when debug $ mapM_ printInstalled dlRpms+ let subdir = show archtid unless (dryrun || null dlRpms) $ do- downloadRpms debug (taskRPMURL archtid) dlRpms+ downloadRpms debug checkremotetime (lookupTimes' archtask) subdir (taskRPMURL archtid) dlRpms printDlDir- return dlRpms+ return (subdir,dlRpms) where getTaskNVRAs :: Int -> IO [NVRA] getTaskNVRAs taskid' =@@ -298,6 +333,7 @@ kojiBuildOSBuilds debug hub listmode latest disttag request pkgpat = do when debug $ putStrLn pkgpat let (pkg,full) = packageOfPattern request pkgpat+ -- FIXME recheck koji version oldkoji = "rpmfusion" `isInfixOf` hub when debug $ print (pkg,full) when debug $ putStrLn pkg@@ -344,42 +380,39 @@ case readNVR pat of NVR n _ -> (n, True) -kojiGetBuildRPMs :: String -> NVR -> IO [String]-kojiGetBuildRPMs huburl nvr = do- mbid <- kojiGetBuildID huburl (showNVR nvr)- case mbid of- Nothing -> error $ "Build id not found for " ++ showNVR nvr- Just (BuildId bid) -> do- rpms <- Koji.listBuildRPMs huburl bid- sysarch <- cmd "rpm" ["--eval", "%{_arch}"]- return $ map getNVRA $ filter (forArch sysarch) rpms- where- forArch :: String -> Struct -> Bool- forArch sysarch st =- case lookupStruct "arch" st of- Just arch -> arch `elem` [sysarch, "noarch"]- Nothing -> error $ "No arch found for rpm for: " ++ showNVR nvr+kojiGetBuildRPMs :: String -> NVR -> BuildID -> IO [String]+kojiGetBuildRPMs huburl nvr (BuildId bid) = do+ rpms <- Koji.listBuildRPMs huburl bid+ sysarch <- cmd "rpm" ["--eval", "%{_arch}"]+ return $ map getNVRA $ filter (forArch sysarch) rpms+ where+ forArch :: String -> Struct -> Bool+ forArch sysarch st =+ case lookupStruct "arch" st of+ Just arch -> arch `elem` [sysarch, "noarch"]+ Nothing -> error $ "No arch found for rpm for: " ++ showNVR nvr - getNVRA :: Struct -> String- getNVRA st =- case lookupStruct "nvr" st of- Nothing -> error' "NVR not found"- Just pnvr ->- case lookupStruct "arch" st of- Nothing -> error "arch not found"- Just arch ->- pnvr <.> arch+ getNVRA :: Struct -> String+ getNVRA st =+ case lookupStruct "nvr" st of+ Nothing -> error' "NVR not found"+ Just pnvr ->+ case lookupStruct "arch" st of+ Nothing -> error "arch not found"+ Just arch ->+ pnvr <.> arch setNoBuffering :: IO () setNoBuffering = do hSetBuffering stdin NoBuffering hSetBuffering stdout NoBuffering -installRPMs :: Bool -> Bool -> Bool -> Yes -> [(Existence,NVRA)] -> IO ()-installRPMs _ _ _ _ [] = return ()-installRPMs dryrun rpm noreinstall yes classified =- forM_ (groupSort classified) $ \(cl,pkgs) ->- unless (null pkgs) $+installRPMs :: Bool -> Bool -> Bool -> Bool -> Yes -> [(FilePath,[(Existence,NVRA)])]+ -> IO ()+installRPMs _ _ _ _ _ [] = return ()+installRPMs dryrun debug rpm noreinstall yes classified =+ forM_ (groupClasses classified) $ \(cl,dirpkgs) ->+ unless (null dirpkgs) $ let pkgmgr = if rpm then "rpm" else "dnf" mcom = case cl of@@ -389,32 +422,51 @@ _ -> Just (if rpm then ["-ivh"] else ["localinstall"]) in whenJust mcom $ \com -> if dryrun- then mapM_ putStrLn $ ("would" +-+ unwords (pkgmgr : com) ++ ":") : map showRpmFile pkgs- else sudo_ pkgmgr $ com ++ map showRpmFile pkgs ++ ["--assumeyes" | yes == Yes && not rpm]+ then mapM_ putStrLn $ ("would" +-+ unwords (pkgmgr : com) ++ ":") : map showRpmFile dirpkgs+ else do+ when debug $ mapM_ (putStrLn . showRpmFile) dirpkgs+ sudo_ pkgmgr $ com ++ map showRpmFile dirpkgs ++ ["--assumeyes" | yes == Yes && not rpm]+ where+ groupClasses =+ groupSort . concatMap mapDir+ where+ mapDir :: (FilePath,[(Existence,NVRA)])+ -> [(Existence,(FilePath,NVRA))]+ mapDir (dir,cls) =+ map (\(e,n) -> (e,(dir,n))) cls -showRpmFile :: NVRA -> FilePath-showRpmFile nvra = showNVRA nvra <.> "rpm"+showRpm :: NVRA -> FilePath+showRpm nvra = showNVRA nvra <.> "rpm" -downloadRpms :: Bool -> (String -> String) -> [(Existence,NVRA)] -> IO ()-downloadRpms debug urlOf rpms = do+showRpmFile :: (FilePath,NVRA) -> FilePath+showRpmFile (dir,nvra) = dir </> showRpm nvra++downloadRpms :: Bool -> Bool -> (UTCTime, UTCTime) -> FilePath+ -> (String -> String) -> [(Existence,NVRA)] -> IO ()+downloadRpms debug checkremotetime (taskstart,taskend) subdir urlOf rpms = do urls <- fmap catMaybes <$>- forM (map snd rpms) $ \nvra -> do- let rpm = showRpmFile nvra- exists <- doesFileExist rpm+ forM (map (showRpm . snd) rpms) $ \rpm -> do+ let rpmfile = subdir </> rpm+ exists <- doesFileExist rpmfile let url = urlOf rpm notfile <- if exists then do- old <- outOfDate rpm url- when old $ removeFile rpm- return old+ if checkremotetime+ then do+ old <- outOfDate rpmfile url+ when old $ removeFile rpmfile+ return old+ else do+ localtime <- getModificationTime rpmfile+ return $ localtime < taskstart || localtime > taskend else return True- when notfile $ putStrLn $ if debug then url else rpm+ -- FIXME is this still useful?+ when (notfile && debug) $ putStrLn url return $ if notfile then Just url else Nothing unless (null urls) $ do- mapM_ putStrLn urls putStrLn "downloading..."- cmd_ "curl" $ ["--remote-time", "--fail", "-C-", "--show-error", "--remote-name-all", "--progress-bar"] ++ urls+ cmd_ "curl" $ ["--remote-time", "--fail", "-C-", "--show-error", "--create-dirs", "--output-dir", subdir, "--remote-name-all", "--progress-bar", "--write-out", "%{filename_effective}\n"] ++ urls where outOfDate :: String -> String -> IO Bool outOfDate file url = do
src/Main.hs view
@@ -60,7 +60,7 @@ <*> optional (TaskPackage <$> strOptionWith 'P' "only-package" "PKG" "Filter task results to specified package" <|> TaskNVR <$> strOptionWith 'N' "only-nvr" "PREFIX" "Filter task results by NVR prefix") <*> switchWith 'T' "tail" "Fetch the tail of build.log"- <*> switchWith 'i' "install" "install the package"+ <*> optional (installArgs <$> strOptionWith 'i' "install" "INSTALLOPTS" "Install the package with 'install' options") <*> (Build <$> strOptionWith 'b' "build" "BUILD" "List child tasks of build" <|> Pattern <$> strOptionWith 'p' "pattern" "NVRPAT" "Build tasks of matching pattern" <|> argumentWith (maybeReader readTaskReq) "PACKAGE|TASKID"@@ -85,6 +85,7 @@ "KojiFiles packages url [default: Fedora]") <*> switchWith 'l' "list" "List builds" <*> switchWith 'L' "latest" "Latest build"+ <*> switchWith 't' "check-remote-time" "Check remote rpm timestamps" <*> switchWith 'r' "rpm" "Use rpm instead of dnf" <*> switchWith 'N' "no-reinstall" "Do not reinstall existing NVRs" <*> optional (strOptionWith 'b' "prefix" "SUBPKGPREFIX" "Prefix to use for subpackages [default: base package]")
src/Progress.hs view
@@ -11,7 +11,7 @@ #else import Control.Applicative ((<$>), (<*>)) #endif-import Control.Monad+import Control.Monad.Extra (unless, when) import Formatting @@ -29,6 +29,7 @@ #if !MIN_VERSION_base(4,11,0) import Data.Monoid ((<>)) #endif+import Data.Time (diffUTCTime, getCurrentTime, NominalDiffTime) import Data.RPM.NVR import Data.Text (Text) import qualified Data.Text as T@@ -36,9 +37,9 @@ import SimpleCmd import System.FilePath ((</>)) +import Time import Utils --- FIXME quits after srpmbuild progressCmd :: Bool -> Int -> Bool -> [TaskID] -> IO () progressCmd debug waitdelay modules tids = do when (waitdelay < 1) $ error' "minimum interval is 1 min"@@ -57,22 +58,27 @@ case mtaskinfo of Nothing -> error' $ "taskinfo not found for " ++ displayID tid Just taskinfo -> do- parent <-- case lookupStruct "method" taskinfo :: Maybe String of- Nothing -> error' $ "no method found for " ++ displayID tid- Just method ->- case method of- "build" -> return tid- "buildArch" ->- case lookupStruct "parent" taskinfo of- Nothing -> error' $ "no parent found for " ++ displayID tid- Just parent -> return (TaskId parent)- _ -> error' $ "unsupport method: " ++ method+ let parent =+ case lookupStruct "method" taskinfo :: Maybe String of+ Nothing -> error' $ "no method found for " ++ displayID tid+ Just method ->+ case method of+ "build" -> tid+ "buildArch" ->+ case lookupStruct "parent" taskinfo of+ Nothing -> error' $ "no parent found for " ++ displayID tid+ Just par -> TaskId par+ _ -> error' $ "unsupported method: " ++ method children <- sortOn (\t -> lookupStruct "arch" t :: Maybe String) <$> kojiGetTaskChildren fedoraKojiHub parent True- return (tid, zip children (repeat Nothing))+ let start =+ case lookupTime False taskinfo of+ Nothing ->+ error' $ "task " ++ displayID tid ++ " has no start time"+ Just t -> t+ return (tid, start, zip children (repeat Nothing)) -type BuildTask = (TaskID, [TaskInfoSize])+type BuildTask = (TaskID, UTCTime, [TaskInfoSize]) -- FIXME change to (TaskID,Struct,Size) type TaskInfoSize = (Struct,Maybe Int)@@ -93,32 +99,37 @@ threadDelay (fromEnum (fromIntegral (m * 60) :: Micro)) runProgress :: BuildTask -> IO BuildTask- runProgress (tid,tasks) =+ runProgress (tid,start,tasks) = case tasks of [] -> do state <- kojiGetTaskState fedoraKojiHub tid- if state `elem` map Just openTaskStates then do+ if state `elem` map Just openTaskStates+ then do threadDelayMinutes waitdelay kojiTaskinfoRecursive tid- else return (tid,[])+ else return (tid, start, []) ((task,_):_) -> do- putStrLn "" when debug $ print task+ current <- getCurrentTime let mnvr = kojiTaskRequestNVR task- logMsg $ maybe "<unknown>" showNVR mnvr ++ " (" ++ displayID tid ++ ")"+ duration = diffUTCTime current start+ logMsg $ maybe "<unknown>" showNVR mnvr ++ " (" ++ displayID tid ++ ") " ++ renderDuration True duration sizes <- mapM buildlogSize tasks printLogSizes waitdelay sizes+ putStrLn "" let news = map (\(t,(s,_)) -> (t,s)) sizes open = filter (\ (t,_) -> getTaskState t `elem` map Just openTaskStates) news- return (tid, open)+ if null open+ then runProgress (tid,start,[])+ else return (tid, start, open) tasksOpen :: BuildTask -> Bool- tasksOpen (_,ts) = not (null ts)+ tasksOpen (_,_,ts) = not (null ts) updateBuildTask :: BuildTask -> IO BuildTask- updateBuildTask (tid, ts) = do+ updateBuildTask (tid,start,ts) = do news <- mapM updateTask ts- return (tid, news)+ return (tid, start, news) updateTask :: TaskInfoSize -> IO TaskInfoSize updateTask (task,size) = do@@ -141,7 +152,12 @@ let few = dropWhile (== '0') $ takeEnd 4 tid in if null few then "0" else few -data TaskOutput = TaskOut {_outArch :: Text, moutSize :: Maybe Int, moutSpeed :: Maybe Int, _outState :: Text, _method :: Text}+data TaskOutput = TaskOut {_outArch :: Text,+ moutSize :: Maybe Int,+ moutSpeed :: Maybe Int,+ _outState :: Text,+ _method :: Text,+ _mduration :: Maybe NominalDiffTime} printLogSizes :: Int -> [TaskInfoSizes] -> IO () printLogSizes waitdelay tss =@@ -149,8 +165,18 @@ in mapM_ (printTaskOut mxsi mxsp) taskoutputs where printTaskOut :: Int64 -> Int64 -> TaskOutput -> IO ()- printTaskOut mxsi mxsp (TaskOut a msi msp st mth) =- fprintLn (rpadded 8 ' ' stext % lpadded mxsi ' ' (optioned commas) % "kB" % " " % optioned ("[" % lpadded mxsp ' ' commas % " B/min]") % " " % stext % " " % stext) a ((`div` 1000) <$> msi) ((`div` waitdelay) <$> msp) st (abridgeMethod mth)+ printTaskOut mxsi mxsp (TaskOut a msi msp st mth mdur) =+ fprintLn (rpadded 8 ' ' stext %+ lpadded mxsi ' ' (optioned commas) % "kB" % " " %+ optioned ("[" % lpadded mxsp ' ' commas % " B/min]") % " " %+ stext % " " %+ optioned string % " " % stext)+ a+ ((`div` 1000) <$> msi)+ ((`div` waitdelay) <$> msp)+ st+ (renderDuration True <$> mdur)+ (abridgeMethod mth) formatSize :: [TaskOutput] -> (Int64, Int64,[TaskOutput]) formatSize ts =@@ -174,8 +200,11 @@ arch = maybeVal "arch not found" (lookupStruct "arch") task :: Text diff = (-) <$> size <*> old state = maybeVal "No state found" getTaskState task- state' = if state == TaskOpen then "" else T.pack (show state)- in TaskOut arch size diff state' method+ state' =+ if state == TaskOpen+ then ""+ else T.pack $ show state+ in TaskOut arch size diff state' method (durationOfTask task) kojiListBuildTasks :: Maybe String -> IO [TaskID] kojiListBuildTasks muser = do
src/Quick.hs view
@@ -87,7 +87,7 @@ let states = [TaskFailed|failure] ++ [TaskClosed|complete] ++ [TaskOpen|current] taskreq = maybe Tasks.TaskQuery Tasks.Package mpkg- in Tasks.tasksCmd mhub user limit states archs Nothing Nothing detail debug Nothing ((tail' || failure) && not notail) install taskreq+ in Tasks.tasksCmd mhub user limit states archs Nothing Nothing detail debug Nothing ((tail' || failure) && not notail) (if install then Just (Tasks.PkgsReq [] []) else Nothing) taskreq where hasWord :: Words -> Bool hasWord word = any (`elem` findWords word) args
src/Tasks.hs view
@@ -10,7 +10,8 @@ parseTaskState, kojiMethods, fedoraKojiHub,- taskinfoUrl+ taskinfoUrl,+ Select(PkgsReq) ) where @@ -72,8 +73,8 @@ -- FIXME --output-fields tasksCmd :: Maybe String -> Maybe UserOpt -> Int -> [TaskState] -> [String] -> Maybe BeforeAfter -> Maybe String -> Bool -> Bool- -> Maybe TaskFilter -> Bool -> Bool -> TaskReq -> IO ()-tasksCmd mhub museropt limit states archs mdate mmethod details debug mfilter' tail' install taskreq = do+ -> Maybe TaskFilter -> Bool -> Maybe Select -> TaskReq -> IO ()+tasksCmd mhub museropt limit states archs mdate mmethod details debug mfilter' tail' minstall taskreq = do when (hub /= fedoraKojiHub && museropt == Just UserSelf) $ error' "--mine currently only works with Fedora Koji: use --user instead" tz <- getCurrentTimeZone@@ -88,8 +89,9 @@ let hasparent = isJust $ mtaskParent res printTask hasparent tz res if hasparent- then when install $ installCmd False debug No mhub Nothing False False False False Nothing (PkgsReq [] []) Nothing ReqName [show taskid]- else tasksCmd (Just hub) museropt limit states archs mdate mmethod details debug mfilter' tail' install (Parent taskid)+ then whenJust minstall $ \installopts ->+ installCmd False debug No mhub Nothing False False False False False Nothing installopts Nothing ReqName [show taskid]+ else tasksCmd (Just hub) museropt limit states archs mdate mmethod details debug mfilter' tail' minstall (Parent taskid) Build bld -> do when (isJust mdate || isJust mfilter') $ error' "cannot use --build together with timedate or filter"@@ -97,7 +99,7 @@ then ((fmap TaskId . lookupStruct "task_id") =<<) <$> getBuild hub (InfoID (read bld)) else kojiGetBuildTaskID hub bld whenJust mtaskid $ \(TaskId taskid) ->- tasksCmd (Just hub) museropt limit states archs mdate mmethod details debug mfilter' tail' install (Parent taskid)+ tasksCmd (Just hub) museropt limit states archs mdate mmethod details debug mfilter' tail' minstall (Parent taskid) Package pkg -> do when (head pkg == '-') $ error' $ "bad combination: not a package " ++ pkg@@ -113,7 +115,7 @@ forM_ builds $ \bld -> do let mtaskid = (fmap TaskId . lookupStruct "task_id") bld whenJust mtaskid $ \(TaskId taskid) ->- tasksCmd (Just hub) museropt 10 states archs mdate mmethod details debug mfilter' tail' install (Parent taskid)+ tasksCmd (Just hub) museropt 10 states archs mdate mmethod details debug mfilter' tail' minstall (Parent taskid) Pattern pat -> do let buildquery = [("pattern", ValueString pat), commonBuildQueryOptions limit]@@ -123,7 +125,7 @@ forM_ builds $ \bld -> do let mtaskid = (fmap TaskId . lookupStruct "task_id") bld whenJust mtaskid $ \(TaskId taskid) ->- tasksCmd (Just hub) museropt 10 states archs mdate mmethod details debug mfilter' tail' install (Parent taskid)+ tasksCmd (Just hub) museropt 10 states archs mdate mmethod details debug mfilter' tail' minstall (Parent taskid) _ -> do query <- setupQuery let queryopts = commonQueryOptions limit "-id"@@ -133,9 +135,9 @@ let exact = length tasks == 1 detailed = details || exact (mapM_ (printTask detailed tz) . filterResults . mapMaybe maybeTaskResult) tasks- when install $+ whenJust minstall $ \args -> if exact- then installCmd False debug No mhub Nothing False False False False Nothing (PkgsReq [] []) Nothing ReqName [show (i :: Int) | i <- mapMaybe (lookupStruct "id") tasks]+ then installCmd False debug No mhub Nothing False False False False False Nothing args Nothing ReqName [show (i :: Int) | i <- mapMaybe (lookupStruct "id") tasks] else error' "cannot install more than one task" where hub = maybe fedoraKojiHub hubURL mhub@@ -191,8 +193,8 @@ maybeTaskResult :: Struct -> Maybe TaskResult maybeTaskResult st = do arch <- lookupStruct "arch" st- let mstart_time = lookupTime "start" st- mend_time = lookupTime "completion" st+ let mstart_time = lookupTime False st+ mend_time = lookupTime True st taskid <- lookupStruct "id" st method <- lookupStruct "method" st state <- getTaskState st@@ -234,7 +236,8 @@ pPrintCompact = #if MIN_VERSION_pretty_simple(4,0,0) pPrintOpt CheckColorTty- (defaultOutputOptionsDarkBg {outputOptionsCompact = True})+ (defaultOutputOptionsDarkBg {outputOptionsCompact = True,+ outputOptionsCompactParens = True}) #else pPrint #endif@@ -275,9 +278,9 @@ ++ case mtime of Just now ->- ["current duration: " ++ renderDuration False dur | Just start <- [mstart], let dur = diffUTCTime now start]+ ["current duration: " ++ renderDuration False dur | Just start <- [mstart], let dur = diffUTCTime now start] Nothing ->- ["duration: " ++ renderDuration False dur | Just start <- [mstart], Just end <- [mend], let dur = diffUTCTime end start]+ ["duration: " ++ renderDuration False dur | Just start <- [mstart], Just end <- [mend], let dur = diffUTCTime end start] #endif
src/Time.hs view
@@ -3,8 +3,12 @@ module Time ( compactZonedTime, lookupTime,+ lookupTimes,+ lookupTimes',+ durationOfTask, formatLocalTime,- renderDuration)+ renderDuration,+ UTCTime) where import Data.Time.Clock@@ -22,13 +26,36 @@ compactZonedTime tz = formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S%Z" . utcToZonedTime tz -lookupTime :: String -> Struct -> Maybe UTCTime-lookupTime prefix str = do+lookupTime :: Bool -> Struct -> Maybe UTCTime+lookupTime completion str = do case lookupStruct (prefix ++ "_ts") str of Just ts -> return $ readTime' ts Nothing -> lookupStruct (prefix ++ "_time") str >>= parseTimeM False defaultTimeLocale "%Y-%m-%d %H:%M:%S%Q%EZ"+ where+ prefix = if completion then "completion" else "start"++lookupTimes :: Struct -> Maybe (UTCTime, Maybe UTCTime)+lookupTimes str = do+ start <- lookupTime False str+ let mend = lookupTime True str+ return (start,mend)++lookupTimes' :: Struct -> (UTCTime, UTCTime)+lookupTimes' str =+ case lookupTimes str of+ Nothing -> error "no start time for task"+ Just (start,mend) ->+ case mend of+ Nothing -> error "no end time for task"+ Just end -> (start,end)++durationOfTask :: Struct -> Maybe NominalDiffTime+durationOfTask str = do+ (start,mend) <- lookupTimes str+ end <- mend+ return $ diffUTCTime end start formatLocalTime :: Bool -> TimeZone -> UTCTime -> String formatLocalTime start tz t =
src/Utils.hs view
@@ -1,6 +1,8 @@ module Utils ( kojiTaskRequestNVR, kojiTaskRequestPkgNVR,+ kojiGetBuildID',+ kojiGetBuild', showValue, buildOutputURL, hubToPkgsURL@@ -12,6 +14,7 @@ import Data.RPM.NVR import Data.RPM.NVRA import Distribution.Koji+import qualified Distribution.Koji.API as Koji import Network.HTTP.Directory ((+/+)) import SimpleCmd (error') import System.FilePath (takeBaseName)@@ -41,6 +44,20 @@ then tail $ dropWhile (/= ';') base else base _ -> error' "could determine package from build request"++kojiGetBuildID' :: String -> String -> IO BuildID+kojiGetBuildID' hub nvr = do+ mbid <- kojiGetBuildID hub nvr+ case mbid of+ Nothing -> error' $ "build id not found for " ++ nvr+ Just bid -> return bid++kojiGetBuild' :: String -> NVR -> IO Koji.Struct+kojiGetBuild' hub nvr = do+ mbld <- Koji.getBuild hub (Koji.InfoString (showNVR nvr))+ case mbld of+ Nothing -> error' $ "build not found for " ++ showNVR nvr+ Just bld -> return bld showValue :: Value -> String showValue (ValueString cs) = cs