{-# LANGUAGE CPP #-}
import Control.Applicative (
#if !MIN_VERSION_simple_cmd_args(0,1,3)
(<|>),
#endif
#if !MIN_VERSION_simple_cmd_args(0,1,4)
some,
#endif
#if !MIN_VERSION_base(4,8,0)
(<$>), (<*>)
#endif
)
import Control.Monad.Extra
import Data.Graph.Inductive.Query.DFS (components)
import Data.List
#if !MIN_VERSION_simple_cmd_args(0,1,4)
import Options.Applicative (str)
#endif
import SimpleCmdArgs
import System.Directory (doesDirectoryExist,
#if MIN_VERSION_directory(1,2,5)
listDirectory
#else
getDirectoryContents
#endif
)
import Distribution.RPM.Build.Graph
import Distribution.RPM.Build.Order
import Paths_rpmbuild_order (version)
main :: IO ()
main =
simpleCmdArgs (Just version) "Order packages by build dependencies"
"Sort package sources (spec files) in build dependency order" $
subcommands
[ Subcommand "sort" "sort packages" $
sortPackages <$> verboseOpt <*> lenientOpt <*> componentsOpt <*> subdirOpt <*> pkgArgs
, Subcommand "deps" "sort dependencies" $
depsPackages False <$> verboseOpt <*> lenientOpt <*> combineOpt <*> subdirOpt <*> pkgArgs
, Subcommand "rdeps" "sort dependents" $
depsPackages True <$> verboseOpt <*> lenientOpt <*> combineOpt <*> subdirOpt <*> pkgArgs
, Subcommand "layers" "ordered output suitable for a chain-build" $
layerPackages <$> verboseOpt <*> lenientOpt <*> combineOpt <*> subdirOpt <*> pkgArgs
, Subcommand "chain" "ordered output suitable for a chain-build" $
chainPackages <$> verboseOpt <*> lenientOpt <*> combineOpt <*> subdirOpt <*> pkgArgs
, Subcommand "leaves" "List of the top leaves of package graph" $
leavesPackages <$> verboseOpt <*> lenientOpt <*> subdirOpt <*> pkgArgs
, Subcommand "roots" "List lowest root packages" $
rootPackages <$> verboseOpt <*> lenientOpt <*> subdirOpt <*> pkgArgs
]
where
verboseOpt = switchWith 'v' "verbose" "Verbose output for debugging"
lenientOpt = switchWith 'l' "lenient" "Ignore rpmspec errors"
combineOpt = switchWith 'c' "combine" "Combine independent packages"
subdirOpt = optional (strOptionWith 'd' "dir" "SUBDIR" "Branch directory")
pkgArgs = some (argumentWith str "PKG...")
componentsOpt =
flagWith' Connected 'C' "connected" "Only include connected packages" <|>
flagWith' Separate 'i' "independent" "Only list independent packages" <|>
flagWith Parallel Combine 'c' "combine" "Combine connected and independent packages"
sortPackages :: Bool -> Bool -> Components -> Maybe FilePath -> [FilePath] -> IO ()
sortPackages verbose lenient opts mdir pkgs = do
createGraph' verbose lenient True mdir pkgs >>= sortGraph opts
depsPackages :: Bool -> Bool -> Bool -> Bool -> Maybe FilePath -> [FilePath] -> IO ()
depsPackages rev verbose lenient parallel mdir pkgs = do
unlessM (and <$> mapM doesDirectoryExist pkgs) $
error "Please use package directory paths"
listDirectory "." >>=
-- filter out dotfiles
createGraph' verbose lenient (not rev) mdir . filter ((/= '.') . head) >>=
createGraph' verbose lenient True mdir . dependencyNodes pkgs >>=
sortGraph (if parallel then Parallel else Combine)
#if (defined(MIN_VERSION_directory) && MIN_VERSION_directory(1,2,5))
#else
listDirectory :: FilePath -> IO [FilePath]
listDirectory path =
filter f <$> getDirectoryContents path
where f filename = filename /= "." && filename /= ".."
#endif
layerPackages :: Bool -> Bool -> Bool -> Maybe FilePath -> [FilePath] -> IO ()
layerPackages verbose lenient combine mdir pkgs = do
graph <- createGraph' verbose lenient True mdir pkgs
if combine then printLayers graph
else mapM_ (printLayers . subgraph' graph) (components graph)
where
printLayers = putStrLn . unlines . map unwords . packageLayers
chainPackages :: Bool -> Bool -> Bool -> Maybe FilePath -> [FilePath] -> IO ()
chainPackages verbose lenient combine mdir pkgs = do
graph <- createGraph' verbose lenient True mdir pkgs
if combine then doChain graph
else mapM_ (doChain . subgraph' graph) (components graph)
where
doChain graph =
let chain = intercalate [":"] $ packageLayers graph
in putStrLn $ unwords chain
leavesPackages :: Bool -> Bool -> Maybe FilePath -> [FilePath] -> IO ()
leavesPackages verbose lenient mdir pkgs = do
graph <- createGraph' verbose lenient True mdir pkgs
mapM_ putStrLn $ packageLeaves graph
rootPackages :: Bool -> Bool -> Maybe FilePath -> [FilePath] -> IO ()
rootPackages verbose lenient mdir pkgs = do
graph <- createGraph' verbose lenient True mdir pkgs
mapM_ putStrLn $ lowestLayer graph