rpmbuild-order 0.2.1 → 0.3
raw patch · 8 files changed
+257/−368 lines, 8 filesdep +bytestringdep +optparse-applicativedep +simple-cmd-argsdep −explicit-exceptiondep −transformers
Dependencies added: bytestring, optparse-applicative, simple-cmd-args
Dependencies removed: explicit-exception, transformers
Files
- ChangeLog +0/−9
- ChangeLog.md +15/−0
- Main.hs +198/−0
- README.md +8/−2
- RpmbuildOrder.hs +0/−324
- TODO +2/−1
- rpmbuild-order.1 +18/−16
- rpmbuild-order.cabal +16/−16
− ChangeLog
@@ -1,9 +0,0 @@-* 0.2 (2018-08-17)-- error if no spec file-- filter out hidden files from deps search-- add --version-- generate manpage with help2man--* 0.1 (2018-07-18)-- initial release with sort, deps and rdeps (reverse dependencies) commands-
+ ChangeLog.md view
@@ -0,0 +1,15 @@+# 0.3 (2019-10-10)+- check package provides instead of rpms+- use ByteString for packages (provides)+- move to simple-cmd-args (optparse-applicative)+- add --lenient for rpmspec failures++# 0.2 (2018-08-17)+- error if no spec file+- filter out hidden files from deps search+- add --version+- generate manpage with help2man++# 0.1 (2018-07-18)+- initial release with sort, deps and rdeps (reverse dependencies) commands+
+ Main.hs view
@@ -0,0 +1,198 @@+import Data.Graph.Inductive.Query.DFS (xdfsWith, topsort', scc, components)+import Data.Graph.Inductive.Tree (Gr)+import qualified Data.Graph.Inductive.Graph as Graph++import qualified Data.Set as Set+import Control.Applicative (some,+#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))+#else+ (<$>), (<*>)+#endif+ )+import Control.Monad (guard, when, unless)+import qualified Data.ByteString.Char8 as B+import Data.Maybe (catMaybes, fromMaybe, mapMaybe)+import Data.List (delete)+import Options.Applicative (str)+import System.Directory (doesDirectoryExist, doesFileExist,+#if (defined(MIN_VERSION_directory) && MIN_VERSION_directory(1,2,5))+ listDirectory+#else+ getDirectoryContents+#endif+ )+import System.Exit (ExitCode (..), exitFailure)+import System.FilePath+-- replace with warning+import System.IO (hPutStrLn, stderr)+import System.Process (readProcessWithExitCode)++import SimpleCmdArgs+import Paths_rpmbuild_order (version)++#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++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" $+ sortSpecFiles <$> verboseOpt <*> lenientOpt <*> parallelOpt <*> subdirOpt <*> pkgArgs+ , Subcommand "deps" "sort dependencies" $+ depsSpecFiles False <$> verboseOpt <*> lenientOpt <*> parallelOpt <*> subdirOpt <*> pkgArgs+ , Subcommand "rdeps" "sort dependents" $+ depsSpecFiles True <$> verboseOpt <*> lenientOpt <*> parallelOpt <*> subdirOpt <*> pkgArgs+ ]+ where+ verboseOpt = switchWith 'v' "verbose" "Verbose output for debugging"+ lenientOpt = switchWith 'l' "lenient" "Ignore rpmspec errors"+ parallelOpt = switchWith 'p' "parallel" "Separate independent packages"+ subdirOpt = optional (strOptionWith 'd' "dir" "SUBDIR" "Branch directory")+ pkgArgs = some (argumentWith str "PKG...")++findSpec :: Maybe FilePath -> FilePath -> IO (Maybe FilePath)+findSpec mdir file =+ if takeExtension file == ".spec"+ then checkFile file+ else do+ dirp <- doesDirectoryExist file+ if dirp+ then+ let dir = maybe file (file </>) mdir+ pkg = takeBaseName file in+ checkFile $ dir </> pkg ++ ".spec"+ else error $ "No spec file found for " ++ file+ where+ checkFile :: FilePath -> IO (Maybe FilePath)+ checkFile f = do+ e <- doesFileExist f+ if e+ then return $ Just f+ else return Nothing++type Package = B.ByteString++data SourcePackage =+ SourcePackage {+ location :: FilePath,+ package :: Package,+ dependencies :: [Package]+ }+ deriving (Show, Eq)++createGraphNodes :: Bool -> Bool -> Maybe FilePath -> [Package] -> [Package] ->+ IO (Gr SourcePackage (), [Graph.Node])+createGraphNodes verbose lenient mdir pkgs subset = do+ unless (all (`elem` pkgs) subset) $+ error "Packages must be in the current directory"+ specPaths <- catMaybes <$> mapM (findSpec mdir . B.unpack) pkgs+ let names = map (B.pack . takeBaseName) specPaths+ resolves <- catMaybes <$> mapM (readProvides verbose lenient) specPaths+ deps <- catMaybes <$> mapM (getDepsSrcResolved verbose lenient resolves) specPaths+ let spkgs = zipWith3 SourcePackage specPaths names deps+ graph = getBuildGraph spkgs+ checkForCycles graph+ let nodes = Graph.labNodes graph+ subnodes = mapMaybe (pkgNode nodes) subset+ return (graph, subnodes)+ where+ pkgNode [] _ = Nothing+ pkgNode ((i,l):ns) p = if p == package l then Just i else pkgNode ns p++sortSpecFiles :: Bool -> Bool -> Bool -> Maybe FilePath -> [Package] -> IO ()+sortSpecFiles verbose lenient parallel mdir pkgs = do+ (graph, _) <- createGraphNodes verbose lenient mdir pkgs []+ if parallel then+ mapM_ ((B.putStrLn . B.cons '\n' . B.unwords . map package) . topsort' . subgraph graph) (components graph)+ else mapM_ (B.putStrLn . package) $ topsort' graph+ +depsSpecFiles :: Bool -> Bool -> Bool -> Bool -> Maybe FilePath -> [Package] -> IO ()+depsSpecFiles rev verbose lenient parallel mdir pkgs = do+ allpkgs <- map B.pack . filter (\ f -> head f /= '.') <$> listDirectory "."+ (graph, nodes) <- createGraphNodes verbose lenient mdir allpkgs pkgs+ let direction = if rev then Graph.suc' else Graph.pre'+ sortSpecFiles verbose lenient parallel mdir $ map package $ xdfsWith direction third nodes graph+ where+ third (_, _, c, _) = c++readProvides :: Bool -> Bool -> FilePath -> IO (Maybe (Package,[Package]))+readProvides verbose lenient file = do+ when verbose $ hPutStrLn stderr file+ mpkgs <- rpmspecQuery lenient ["-q", "--provides", "--define", "ghc_version any"] file+ case mpkgs of+ Nothing -> return Nothing+ Just pkgs ->+ let pkg = B.pack $ takeBaseName file in+ return $ Just (pkg, delete pkg pkgs)++getDepsSrcResolved :: Bool -> Bool -> [(Package,[Package])] -> FilePath -> IO (Maybe [Package])+getDepsSrcResolved verbose lenient provides file = do+ when verbose $ hPutStrLn stderr file+ fmap (map resolveBase) <$>+ rpmspecQuery lenient ["--buildrequires", "--define", "ghc_version any"] file+ where+ resolveBase :: Package -> Package+ resolveBase br =+ case mapMaybe (\ (pkg,subs) -> if br `elem` subs then Just pkg else Nothing) provides of+ [] -> br+ [p] -> p+ ps -> error $ B.unpack br ++ " is provided by: " ++ (B.unpack . B.unwords) ps++getBuildGraph :: [SourcePackage] -> Gr SourcePackage ()+getBuildGraph srcPkgs =+ let nodes = zip [0..] srcPkgs+ nodeDict = zip (map package srcPkgs) [0..]+ edges = do+ (srcNode,srcPkg) <- nodes+ dstNode <- mapMaybe (`lookup` nodeDict) (dependencies srcPkg)+ guard (dstNode /= srcNode)+ return (dstNode, srcNode, ())+ in Graph.mkGraph nodes edges++checkForCycles :: Monad m => Gr SourcePackage () -> m ()+checkForCycles graph =+ case getCycles graph of+ [] -> return ()+ cycles ->+ error $ unlines $+ "Cycles in dependencies:" :+ map (unwords . map location . nodeLabels graph) cycles++nodeLabels :: Gr a b -> [Graph.Node] -> [a]+nodeLabels graph =+ map (fromMaybe (error "node not found in graph") .+ Graph.lab graph)++subgraph :: Gr a b -> [Graph.Node] -> Gr a b+subgraph graph nodes =+ let nodeSet = Set.fromList nodes+ edges = do+ from <- nodes+ (to, lab) <- Graph.lsuc graph from+ guard $ Set.member from nodeSet && Set.member to nodeSet+ return (from,to,lab)+ in Graph.mkGraph (zip nodes $ nodeLabels graph nodes) edges++getCycles :: Gr a b -> [[Graph.Node]]+getCycles =+ filter (\ x -> length x == 3) . scc++-- returns the first word for each line+rpmspecQuery :: Bool -> [String] -> FilePath -> IO (Maybe [B.ByteString])+rpmspecQuery lenient args spec = do+ (res, out, err) <- readProcessWithExitCode "rpmspec" (["-q"] ++ args ++ [spec]) ""+ unless (null err) $ hPutStrLn stderr err+ case res of+ ExitFailure _ -> if lenient then return Nothing else exitFailure+ ExitSuccess -> return $ Just $ map takeFirst $ B.lines (B.pack out)+ where+ -- ignore version bounds+ takeFirst :: B.ByteString -> B.ByteString+ takeFirst = head . B.words
README.md view
@@ -22,13 +22,19 @@ from the current set of checked out package sources. ## Known problems-Given packages A, B, C, where C depends on B, and B depends on A,+1. Given packages A, B, C, where C depends on B, and B depends on A, and you call - rpmbuild-order C.spec A.spec+ rpmbuild-order sort C.spec A.spec then the output may be wrong if C does not have a direct dependency on A. Even if the order is correct, B is missing in the output and thus in this case the list of packages cannot be reliably used for a sequence of builds. +However `rpmbuild-order deps` and `rpmbuild-order rdeps` take+other neighbouring package directories into account.++2. repoquery is not used to resolve Requires or filelists for Provides.+So if a package BuildRequires: /usr/bin/sometool it will not be resolved.+This may get addressed in a future version.
− RpmbuildOrder.hs
@@ -1,324 +0,0 @@-{-# LANGUAGE LambdaCase #-}--module Main where--import System.Console.GetOpt- (getOpt, ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo)-import System.Exit (exitSuccess, exitFailure)-import qualified System.Environment as Env-import System.FilePath--import System.Directory (doesDirectoryExist, doesFileExist,-#if (defined(MIN_VERSION_directory) && MIN_VERSION_directory(1,2,5))- listDirectory-#else- getDirectoryContents-#endif- )-import System.IO (hPutStrLn, stderr)-import System.Process (readProcess)--import Data.Graph.Inductive.Query.DFS (xdfsWith, topsort', scc, components)-import Data.Graph.Inductive.Tree (Gr)-import qualified Data.Graph.Inductive.Graph as Graph--import qualified Control.Monad.Exception.Synchronous as E-import qualified Control.Monad.Trans.Class as T--import qualified Data.Set as Set-import Control.Monad (guard, when, unless)-import Data.Maybe (catMaybes, fromMaybe, mapMaybe)-import Data.List (delete, intersperse, stripPrefix)-import Data.Version (showVersion)--import Paths_rpmbuild_order (version)--#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,2))-#else-import Control.Applicative ((<$>))-#endif--#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--main :: IO ()-main =- E.resolveT handleException $ do- argv <- T.lift Env.getArgs- let (opts, args, errors) = getOpt Permute options argv- flags <-- E.ExceptionalT $ return $- foldr (=<<)- (return- Flags {optHelp = False,- optVersion = False,- optVerbosity = False,- optFormat = package,- optParallel = Nothing,- optBranch = Nothing})- opts- if optHelp flags- then T.lift $ help >> exitSuccess- else- if optVersion flags- then T.lift $ putStrLn $ showVersion version- else- if length args < 2- then T.lift $ help >> exitFailure- else do- let (com:pkgs) = args- unless (null errors) $ E.throwT $ concat errors- unless (com `elem` ["sort", "deps", "rdeps"]) $- E.throwT $ "Unknown command " ++ com- runCommand flags com $ map (removeSuffix "/") pkgs- where- help =- Env.getProgName >>= \programName ->- putStrLn- (usageInfo ("Usage: " ++ programName ++- " [OPTIONS] [sort|deps|rdeps] PKG-SPEC-OR-DIR ...") options)--handleException :: String -> IO ()-handleException msg = do- putStrLn $ "Aborted: " ++ msg- exitFailure--findSpec :: Maybe FilePath -> FilePath -> IO (Maybe FilePath)-findSpec mdir file =- if takeExtension file == ".spec"- then checkFile file- else do- dirp <- doesDirectoryExist file- if dirp- then- let dir = maybe file (file </>) mdir- pkg = takeBaseName file in- checkFile $ dir </> pkg ++ ".spec"- else error $ "No spec file found for " ++ file- where- checkFile :: FilePath -> IO (Maybe FilePath)- checkFile f = do- e <- doesFileExist f- if e- then return $ Just f- else return Nothing--data Flags =- Flags {- optHelp :: Bool,- optVersion :: Bool,- optVerbosity :: Bool,- optFormat :: SourcePackage -> String,- optParallel :: Maybe String,- optBranch :: Maybe FilePath- }--options :: [OptDescr (Flags -> E.Exceptional String Flags)]-options =- [- Option ['h'] ["help"]- (NoArg (\flags -> return $ flags{optHelp = True}))- "Show options"- , Option ['V'] ["version"]- (NoArg (\flags -> return $ flags{optVersion = True}))- "Show version"- , Option ['p'] ["parallel"]- (OptArg- (\mstr flags ->- fmap (\cs -> flags{optParallel = Just cs})- (E.Success (fromMaybe "" mstr)))- "SEPARATOR")- "Display independently buildable groups of packages, optionally with separator"- , Option ['b'] ["branch"]- (ReqArg- (\str flags ->- fmap (\mb -> flags{optBranch = mb})- (E.Success (Just str)))- "BRANCHDIR")- "branch directory"- , Option ['f'] ["format"]- (ReqArg- (\str flags ->- fmap (\select -> flags{optFormat = select}) $- case str of- "package" -> E.Success package- "spec" -> E.Success location- "dir" -> E.Success (takeDirectory . location)- _ ->- E.Exception $- "unknown info type " ++ str)- "KIND")- "output format: 'package' (default), 'spec', or 'dir'"- , Option ['v'] ["verbose"]- (NoArg- (\flags ->- return flags{optVerbosity = True}))- "verbose output"- ]--type Package = String--data SourcePackage =- SourcePackage {- location :: FilePath,- package :: Package,- dependencies :: [Package]- }- deriving (Show, Eq)--type Command = String--runCommand :: Flags -> Command -> [Package] -> E.ExceptionalT String IO ()-runCommand flags "sort" pkgs = sortSpecFiles flags pkgs-runCommand flags "deps" pkgs = depsSpecFiles False flags pkgs-runCommand flags "rdeps" pkgs = depsSpecFiles True flags pkgs-runCommand _ _ _ = E.throwT "impossible happened"--createGraphNodes :: Flags -> [Package] -> [Package] ->- E.ExceptionalT String IO (Gr SourcePackage (), [Graph.Node])-createGraphNodes flags pkgs subset = do- unless (all (`elem` pkgs) subset) $- E.throwT "Packages must be in the current directory"- specPaths <- T.lift $ catMaybes <$> mapM (findSpec (optBranch flags)) (filter (/= fromMaybe "" (optParallel flags)) pkgs)- let names = map takeBaseName specPaths- provs <-- T.lift $- mapM (readProvides (optVerbosity flags)) specPaths- let resolves = zip names provs- deps <-- T.lift $- mapM (getDepsSrcResolved (optVerbosity flags) resolves) specPaths- let spkgs = zipWith3 SourcePackage specPaths names deps- graph = getBuildGraph spkgs- checkForCycles graph- let nodes = Graph.labNodes graph- subnodes = mapMaybe (pkgNode nodes) subset- return (graph, subnodes)- where- pkgNode [] _ = Nothing- pkgNode ((i,l):ns) p = if p == package l then Just i else pkgNode ns p--sortSpecFiles :: Flags -> [Package] -> E.ExceptionalT String IO ()-sortSpecFiles flags pkgs = do- (graph, _) <- createGraphNodes flags pkgs []- T.lift $- case optParallel flags of- Just s ->- mapM_ ((putStrLn . unwords . (if null s then id else intersperse s) . map (optFormat flags)) . topsort' . subgraph graph)- (components graph)- Nothing ->- mapM_ (putStrLn . optFormat flags) $ topsort' graph- -depsSpecFiles :: Bool -> Flags -> [Package] -> E.ExceptionalT String IO ()-depsSpecFiles rev flags pkgs = do- allpkgs <- T.lift $ filter (\ f -> head f /= '.') <$> listDirectory "."- (graph, nodes) <- createGraphNodes flags allpkgs pkgs- let dir = if rev then Graph.suc' else Graph.pre'- sortSpecFiles flags $ map package $ xdfsWith dir third nodes graph- where- third (_, _, c, _) = c--readProvides :: Bool -> FilePath -> IO [String]-readProvides verbose file = do- when verbose $ hPutStrLn stderr file- pkgs <- lines <$>- rpmspec ["--rpms", "--qf=%{name}\n", "--define", "ghc_version any"] Nothing file- let pkg = takeBaseName file- return $ delete pkg pkgs--getDepsSrcResolved :: Bool -> [(String,[String])] -> FilePath -> IO [String]-getDepsSrcResolved verbose provides file =- map (resolveBase provides) <$> do- when verbose $ hPutStrLn stderr file- -- ignore version bounds- map (head . words) . lines <$>- rpmspec ["--buildrequires", "--define", "ghc_version any"] Nothing file- where- resolveBase :: [(String,[String])] -> String -> String- resolveBase provs br =- case mapMaybe (\ (pkg,subs) -> if br `elem` subs then Just pkg else Nothing) provs of- [] -> br- [p] -> p- ps -> error $ br ++ "is provided by: " ++ unwords ps--removeSuffix :: String -> String -> String-removeSuffix suffix orig =- fromMaybe orig $ stripSuffix suffix orig- where- stripSuffix sf str = reverse <$> stripPrefix (reverse sf) (reverse str)--cmdStdIn :: String -> [String] -> String -> IO String-cmdStdIn c as inp = removeTrailingNewline <$> readProcess c as inp- where- removeTrailingNewline :: String -> String- removeTrailingNewline "" = ""- removeTrailingNewline str =- if last str == '\n'- then init str- else str--cmd :: String -> [String] -> IO String-cmd c as = cmdStdIn c as ""--rpmspec :: [String] -> Maybe String -> FilePath -> IO String-rpmspec args mqf spec = do- let qf = maybe [] (\ q -> ["--queryformat", q]) mqf- cmd "rpmspec" (["-q"] ++ args ++ qf ++ [spec])--getDeps :: Gr SourcePackage () -> [(SourcePackage, [SourcePackage])]-getDeps gr =- let c2dep :: Graph.Context SourcePackage () -> (SourcePackage, [SourcePackage])- c2dep ctx =- (Graph.lab' ctx,- map (Graph.lab' . Graph.context gr) (Graph.pre gr . Graph.node' $ ctx))- in Graph.ufold (\ctx ds -> c2dep ctx : ds) [] gr--getBuildGraph :: [SourcePackage] -> Gr SourcePackage ()-getBuildGraph srcPkgs =- let nodes = zip [0..] srcPkgs- nodeDict = zip (map package srcPkgs) [0..]- edges = do- (srcNode,srcPkg) <- nodes- dstNode <- mapMaybe (`lookup` nodeDict) (dependencies srcPkg)- guard (dstNode /= srcNode)- return (dstNode, srcNode, ())- in Graph.mkGraph nodes edges--checkForCycles ::- Monad m =>- Gr SourcePackage () ->- E.ExceptionalT String m ()-checkForCycles graph =- case getCycles graph of- [] -> return ()- cycles ->- E.throwT $ unlines $- "Cycles in dependencies:" :- map (unwords . map location . nodeLabels graph) cycles--nodeLabels :: Gr a b -> [Graph.Node] -> [a]-nodeLabels graph =- map (fromMaybe (error "node not found in graph") .- Graph.lab graph)--subgraph :: Gr a b -> [Graph.Node] -> Gr a b-subgraph graph nodes =- let nodeSet = Set.fromList nodes- edges = do- from <- nodes- (to, lab) <- Graph.lsuc graph from- guard $ Set.member from nodeSet && Set.member to nodeSet- return (from,to,lab)- in Graph.mkGraph (zip nodes $ nodeLabels graph nodes) edges--getCycles :: Gr a b -> [[Graph.Node]]-getCycles =- filter (\case- _:_:_ -> True- _ -> False)- . scc
TODO view
@@ -1,1 +1,2 @@-add leaf command+- add leaf command+- better graph output
rpmbuild-order.1 view
@@ -1,26 +1,28 @@-.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.-.TH RPMBUILD-ORDER "1" "August 2018" "rpmbuild-order 0.2" "User Commands"+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.11.+.TH RPMBUILD-ORDER "1" "October 2019" "rpmbuild-order 0.3" "User Commands" .SH NAME-rpmbuild-order \- manual page for rpmbuild-order 0.2+rpmbuild-order \- manual page for rpmbuild-order 0.3 .SH SYNOPSIS .B rpmbuild-order-[\fI\,OPTIONS\/\fR] [\fI\,sort|deps|rdeps\/\fR] \fI\,PKG-SPEC-OR-DIR \/\fR...+[\fI\,--version\/\fR] \fI\,COMMAND\/\fR .SH DESCRIPTION+Order packages by build dependencies+.IP+Sort package sources (spec files) in build dependency order+.SS "Available options:" .TP-\fB\-h\fR \fB\-\-help\fR-Show options+\fB\-h\fR,\-\-help+Show this help text .TP-\fB\-V\fR \fB\-\-version\fR+\fB\-\-version\fR Show version-.TP-\fB\-p[SEPARATOR]\fR \fB\-\-parallel\fR[=\fI\,SEPARATOR\/\fR]-Display independently buildable groups of packages, optionally with separator+.SS "Available commands:" .TP-\fB\-b\fR BRANCHDIR \fB\-\-branch\fR=\fI\,BRANCHDIR\/\fR-branch directory+sort+sort packages .TP-\fB\-f\fR KIND \fB\-\-format\fR=\fI\,KIND\/\fR-output format: 'package' (default), 'spec', or 'dir'+deps+sort dependencies .TP-\fB\-v\fR \fB\-\-verbose\fR-verbose output+rdeps+sort dependents
rpmbuild-order.cabal view
@@ -1,11 +1,11 @@ Name: rpmbuild-order-Version: 0.2.1+Version: 0.3 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de> Maintainer: Jens Petersen <petersen@redhat.com> Copyright: 2010-2018 Henning Thielemann,- 2018 Jens Petersen <petersen@redhat.com>+ 2018-2019 Jens Petersen <petersen@redhat.com> Category: Distribution Homepage: https://github.com/juhp/rpmbuild-order Bug-reports: https://github.com/juhp/rpmbuild-order/issues@@ -17,32 +17,32 @@ The code originates from cabal-sort by Henning Thielemann. It can also output the ordered dependencies or reverse depends for one or more packages, provided all the packages are checked out- in neighbouring directories. This is also useful to see what packages+ in neighboring directories. This is also useful to see what packages are affected when a low-level package changes. Tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2,- GHC == 8.4.3+ GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.1 Cabal-Version: >=1.6 Build-Type: Simple-Extra-source-files: README.md TODO ChangeLog rpmbuild-order.1+Extra-source-files: README.md TODO ChangeLog.md rpmbuild-order.1 source-repository head type: git location: https://github.com/juhp/rpmbuild-order Executable rpmbuild-order- Build-Depends:- base < 5,- Cabal,- containers,- directory,- explicit-exception,- filepath,- fgl, - process,- transformers+ Build-Depends: base < 5,+ bytestring,+ Cabal,+ containers,+ directory,+ filepath,+ fgl,+ optparse-applicative,+ process,+ simple-cmd-args GHC-Options: -Wall- Main-Is: RpmbuildOrder.hs+ Main-Is: Main.hs Extensions: CPP Other-modules: Paths_rpmbuild_order