packages feed

fbrnch-1.3.2: src/Cmd/Update.hs

module Cmd.Update
  ( updateCmd
  )
where

import Branches
import Common
import Common.System
import Git
import InterleaveOutput (cmdSilent')
import Krb
import Package

import Data.RPM.VerCmp
import SimplePrompt (promptEnter)

-- FIXME if autorelease, drop -b baserelease
-- FIXME --no-prep to avoid overwriting ongoing build
-- FIXME don't bump release if already bumped
-- FIXME check EVR increased
-- FIXME if multiple sources might need to bump release
-- FIXME Haskell subpackages require release bump even with version bump
updateCmd :: Bool -> Bool -> Bool -> (Maybe Branch,[String]) -> IO ()
updateCmd onlysources force allowHEAD (mbr,args) = do
  pkgGit <- isPkgGitSshRepo
  (mver,pkgs) <-
    case args of
      [a] -> do
        if pkgGit
          then return (Just a,[])
          else do
          mspec <- maybeFindSpecfile
          return $ if isJust mspec
                   then (Just a,[])
                   else (Nothing,[a])
      _ -> return (Nothing,args)
  let mgitops =
        let dirty = if allowHEAD then dirtyGitHEAD else dirtyGitFetch
        in if pkgGit
           then dirty
           else if null pkgs then Nothing else dirty
  withPackagesMaybeBranch HeaderMay False mgitops (updatePkg mver) (mbr, pkgs)
  where
    updatePkg :: Maybe String -> Package -> AnyBranch -> IO ()
    updatePkg mver pkg br = do
      when (br /= RelBranch Rawhide) $
        promptEnter $ "Are you sure you want to update" +-+ show br +-+ "branch?!"
      spec <- if allowHEAD
              then findSpecfile
              else localBranchSpecFile pkg br
      (curver,_) <- pkgVerRel spec
      vdiff <- filter ("Version:" `isInfixOf`) . filter (not . ("@@ " `isPrefixOf`)) <$> gitLines "diff" ["-U0", "HEAD", spec]
      unless (length vdiff `elem` [0,2]) $
        error' $ "diff contains complex version change:\n" ++ unlines vdiff
      case mver of
        Nothing -> do
          when (null vdiff && not onlysources) $
            error' "specify or edit version to update"
          putStrLn $ "current version:" +-+ curver
        Just nver -> do
          when (length vdiff == 2) $
            error' $ "spec version already bumped to" +-+ curver
          when (curver == nver) $
            putStrLn $ "already new version" +-+ curver
      let moldnewver =
            case mver of
              Just nver -> Just (curver,nver)
              Nothing ->
                case map (last . words) vdiff of
                  [old,new] -> Just (old,new)
                  _ -> Nothing
      unless onlysources $ do
        let (oldver,newver) =
              fromMaybe (error' "complex version change") moldnewver
        -- FIXME take epoch into account
        when (rpmVerCompare oldver newver == GT) $
          putStrLn $ "current" +-+ oldver +-+ "is newer!"
        putStrLn $ oldver +-+ "->\n" ++ newver
        when (curver /= newver) $ do
          editSpecField "Version" newver spec
          editSpecField "Release" "0%{?dist}" spec
          -- FIXME should be sure sources exists for distgit
          whenM (doesFileExist "sources") $
            cmd_ "sed" ["-i", "/" ++ unPackage pkg ++ "-" ++ oldver ++ "./d", "sources"]
      whenM isPkgGitSshRepo $ do
        -- FIXME forM_
        sources <- map sourceFieldFile <$> cmdLines "spectool" ["-S", spec]
        existing <- filterM doesFileExist sources
        unless (existing == sources) $ do
          cmd_ "fedpkg" ["sources"]
          unless force $
            -- FIXME only if not all exist
            cmd_ "spectool" ["-g", "-S", spec]
        patches <- map sourceFieldFile <$> cmdLines "spectool" ["-P", spec]
        forM_ patches $ \patch ->
          unlessM (doesFileExist patch) $
          cmd_ "spectool" ["-g", "-P", spec]
        when force $ do
          let archives = filter isArchiveFile existing
          forM_ archives removeFile
          cmd_ "spectool" ["-g", "-S", spec]
        krbTicket
        cmd_ "fedpkg" $ "new-sources" : filter isArchiveFile sources
      whenJust moldnewver $ \(_old,newver) -> do
        versions <- changelogVersions spec
        let missing = null versions || not ((newver ++ "-") `isPrefixOf` head versions)
        when missing $ do
          cmd_ "rpmdev-bumpspec" ["-c", "update to" +-+ newver, spec]
          git_ "commit" ["-a", "-m", "update to" +-+ newver]
      putStr "Prepping... "
      cmdSilent' "rpmbuild" ["-bp", spec]
      putStrLn "done"
      -- FIXME git amend (if previous commit was update)

    sourceFieldFile :: String -> FilePath
    sourceFieldFile field =
      if null field then
        -- should be impossible
        error "empty source field!"
      else (takeFileName . last . words) field

    -- FIXME handle .tgz?
    isArchiveFile :: FilePath -> Bool
    isArchiveFile f =
      ".tar." `isInfixOf` f || ".zip" `isSuffixOf` f

pkgVerRel :: FilePath -> IO (String,String)
pkgVerRel spec = do
  --dist <- branchDist br
  -- workaround dist with bootstrap
  --hostdist <- cmd "rpm" ["--eval", "%{dist}"]
  mvr <- cmdMaybe "rpmspec" ["-q", "--srpm", "--qf", "%{version}-%{release}", spec]
  case mvr of
    Nothing -> error' $ "Failed to read package ver-rel:" +-+ spec
    Just vr -> return $ splitBy "-" vr

splitBy :: String -> String -> (String,String)
splitBy sep xs =
  let ws = splitOn sep xs in
    case ws of
      [f,v] -> (f,v)
      _ -> error $ "inconsistent field:" +-+ xs

changelogVersions :: FilePath -> IO [String]
changelogVersions spec = do
  ns <- cmdLines "rpmspec" ["-q", "--srpm", "--qf", "%{changelogname}", spec]
  return $ map (removePrefix "- " . dropWhile (/= '-')) ns