packages feed

koji-tool-1.3: src/BuildlogSizes.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}

-- SPDX-License-Identifier: BSD-3-Clause

module BuildlogSizes (
  buildlogSizesCmd
  )
where

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*>))
#endif
import Control.Monad.Extra

import Data.Char (isDigit)
import Data.RPM.NVR
import Data.List.Extra (sortOn, splitOn)
--import Data.Maybe
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import qualified Data.Text as T
import Distribution.Koji (fedoraKojiHub)
import Distribution.Koji.API --(listBuilds)

import Formatting

#if !MIN_VERSION_http_directory(0,1,5)
import Network.HTTP.Client (Manager)
#endif
import Network.HTTP.Directory

import SimpleCmdArgs

import Common (commonBuildQueryOptions, getBuildState, Limit, lookupArch,
               maybeLimit, defaultBuildsLimit)
import Utils (buildlogUrlfromTaskId)

-- FIXME split off arch suffix
-- FIXME show build duration
-- FIXME allow buildid
-- FIXME only supports Fedora koji
buildlogSizesCmd :: Maybe Limit -> String -> IO ()
buildlogSizesCmd mlimit nvrpat = do
  if all isDigit nvrpat -- taskid
    then buildlogSizes (read nvrpat)
    else do -- find builds
    let pat =
          if '*' `notElem` nvrpat && length (splitOn "-" nvrpat) < 3
          then nvrpat ++ "*"
          else nvrpat
    results <- listBuilds fedoraKojiHub
               [("pattern", ValueString pat),
                commonBuildQueryOptions $
                maybeLimit defaultBuildsLimit mlimit]
    if null results
      then if '*' `notElem` pat
           then buildlogSizesCmd mlimit $ nvrpat ++ "*"
           else putStrLn $ "no NVRs found for pattern: " ++ pat
      else mapM_ getResult results
  where
    getResult :: Struct -> IO ()
    getResult bld = do
      putStrLn ""
      case lookupStruct "nvr" bld of
        Just nvr -> do
          putStrLn $ nvr ++
            maybe "" (\s -> " (" ++ show s ++ ")") (getBuildState bld)
          ok <- nvrBuildlogSizes nvr
          unless ok $ taskResult bld
        Nothing -> taskResult bld

    taskResult :: Struct -> IO ()
    taskResult bld = do
      let mtid =
            lookupStruct "task_id" bld <|>
            (lookupStruct "extra" bld >>= lookupStruct "task_id")
      case mtid :: Maybe Int of
        Nothing -> error "no taskid found!"
        Just tid -> buildlogSizes tid

nvrBuildlogSizes :: String -> IO Bool
nvrBuildlogSizes nvr = do
  let (NVR n (VerRel v r)) = readNVR nvr
      logsdir = "https://kojipkgs.fedoraproject.org/packages" +/+ n  +/+ v +/+ r +/+ "data/logs/"
  exists <- httpExists' logsdir
  if exists
    then do
    archs <- map (T.unpack . noTrailingSlash) <$> httpDirectory' logsdir
    forM_ archs $ \arch ->
      doGetBuildlogSize (logsdir +/+ arch +/+ "build.log") arch
    return True
    else
    return False

buildlogSizes :: Int -> IO ()
buildlogSizes tid = do
  children <- sortOn lookupArch <$>
              getTaskChildren fedoraKojiHub tid True
  mapM_ buildlogSize children

buildlogSize :: Struct -> IO ()
buildlogSize child = do
  case lookupStruct "id" child :: Maybe Int of
    Nothing -> error "child taskid not found"
    Just tid ->
      whenJust (lookupStruct "arch" child) $
        doGetBuildlogSize buildlog
      where
        buildlog = buildlogUrlfromTaskId tid

doGetBuildlogSize :: String -> String -> IO ()
doGetBuildlogSize buildlog arch = do
  exists <- httpExists' buildlog
  msize <- if exists then httpFileSize' buildlog else return Nothing
  whenJust msize $ \ size ->
    fprintLn (right 8 ' ' % lpadded 7 ' ' commas % "kB") arch (size `div` 1000)

#if !MIN_VERSION_http_directory(0,1,9)
infixr 5 +/+
(+/+) :: String -> String -> String
s +/+ t =
  case (s,t) of
    ("",_) -> t
    (_,"") -> s
    (_,_) -> dropWhileEnd (== '/') s ++ '/' : dropWhile (== '/') t
#endif