packages feed

fbrnch-1.2: src/Cmd/Diff.hs

module Cmd.Diff (
  diffCmd,
  DiffFilter(..),
  DiffFormat(..),
  DiffWork(..)
  ) where

import Branches
import Common
import Common.System
import Git
import Package
import Patch

data DiffFormat =
  DiffDefault | DiffContext Int | DiffMinimal | DiffStatus | DiffStats |
  DiffQuiet
  deriving Eq

data DiffWork =
  DiffWorkAll | DiffWorkUnstage | DiffWorkStaged
  deriving Eq

data DiffFilter =
  DiffMatch String | DiffNotMatch String
  -- | DiffRegex String | DiffNotRegex String
  deriving Eq

-- FIXME diff other branches without switching
-- FIXME --older/--newer branch
diffCmd :: Bool -> DiffWork -> DiffFormat -> Bool -> Maybe DiffFilter
        -> Maybe AnyBranch -> (Maybe Branch,[String]) -> IO ()
diffCmd speconly work fmt ignorebumps mpatt mwbr =
  withPackagesMaybeBranch HeaderNone False dirtyGit diffPkg
  where
    diffPkg :: Package -> AnyBranch -> IO ()
    diffPkg pkg br = do
      gitSwitchBranch br
      speconlyNone <-
        if speconly
        then notM $ doesFileExist $ packageSpec pkg
        else return False
      if speconlyNone
        then do
        dead <- doesFileExist "dead.package"
        unless dead $ putStrLn $ "no " ++ packageSpec pkg
        else do
        let contxt = case fmt of
                       DiffContext n -> ["--unified=" ++ show n]
                       DiffMinimal -> ["--unified=0"]
                       DiffStatus -> ["--name-status"]
                       -- FIXME hide "files changed" and "insertions" summary
                       DiffStats -> ["--compact-summary"]
                       _ -> []
            (workOpts,workArgs) =
              case work of
                DiffWorkAll -> ([],["HEAD" | isNothing mwbr])
                DiffWorkUnstage -> ([],[])
                DiffWorkStaged -> (["--cached"],[])
            file = [packageSpec pkg | speconly]
        withBranch <-
          case mwbr of
            Nothing -> return []
            Just wbr ->
              let brn = show wbr in
                if '/' `elem` brn
                then return [brn]
                else do
                  localbrs <- gitLines "branch" ["--format=%(refname:short)"]
                  if brn `elem` localbrs
                    then return [brn]
                    else return ["origin/" ++ brn]
        let revdiff = case mwbr of
              Nothing -> []
              Just wbr -> case (wbr,br) of
                (RelBranch rwbr, RelBranch rbr) -> ["-R" | rwbr > rbr]
                _ -> []
        diff <- gitLines "diff" $ contxt ++ workOpts ++ revdiff ++ withBranch ++ workArgs ++ file
        let diffout = (maybe id filterPattern mpatt . simplifyDiff fmt) diff
        -- FIXME: sometimes we may want to list even if diff but no diffout
        unless (null diffout) $
          unless (ignorebumps && isTrivialRebuildCommit diffout) $
          if fmt == DiffQuiet
          then putStrLn $ unPackage pkg
          else do
            putPkgAnyBrnchHdr pkg br
            mapM_ putStrLn diffout
        where
          simplifyDiff :: DiffFormat -> [String] -> [String]
          simplifyDiff DiffMinimal ds = simplifyMinimalDiff ds
          -- drop "2 files changed, 113 insertions(+)"
          simplifyDiff DiffStats ds = if null ds then ds else init ds
          simplifyDiff _ ds = ds

          filterPattern :: DiffFilter -> [String] -> [String]
          filterPattern (DiffMatch patt) = filter (patt `isInfixOf`)
          filterPattern (DiffNotMatch patt) = filter (not . (patt `isInfixOf`))
            --  void $ runProcess $ setStderr nullStream $ proc "grep" [pat, file]