cabal-rpm 0.8.10 → 0.8.11
raw patch · 11 files changed
+260/−176 lines, 11 filesdep −regex-compatdep ~Cabal
Dependencies removed: regex-compat
Dependency ranges changed: Cabal
Files
- ChangeLog +14/−0
- README.md +2/−1
- cabal-rpm.cabal +7/−8
- man/cblrpm.1 +2/−2
- man/cblrpm.1.md +2/−2
- src/Commands/RpmBuild.hs +16/−7
- src/Commands/Spec.hs +72/−30
- src/Dependencies.hs +26/−16
- src/Main.hs +10/−89
- src/PackageUtils.hs +104/−18
- src/Setup.hs +5/−3
ChangeLog view
@@ -1,3 +1,17 @@+* 0.8.11 (2014-05-17)+- build command renamed again from "rpm" to "local" (like fedpkg)+- use .spec file to determine pkg-ver when no .cabal file around+- automatically generate bcond for %check and add testsuite BRs+ when testsuites available+- disable debuginfo explicitly when no c-sources in preparation for+ ghc-rpm-macros no longer disabling debuginfo+- reset filemode of downloaded hackage tarballs to 0644:+ workaround for cabal-install setting 0600+- include release again in initial changelog+- also pull in Cabal and ghc-rpm-macros when yum installing deps+- no longer depends on regex-compat+- some refactorings+ * 0.8.10 (2014-03-03) - diff command replaces cblrpm-diff script - new missingdeps command
README.md view
@@ -1,4 +1,5 @@ [](https://travis-ci.org/juhp/cabal-rpm)+[](http://hackage.haskell.org/package/cabal-rpm) # cabal-rpm @@ -49,7 +50,7 @@ or - $ cblrpm rpm somepkg-0.1+ $ cblrpm local somepkg-0.1 will unpack the (latest) 'somepkg' package from hackage (if the dir does not exist, otherwise it uses the existing dir),
cabal-rpm.cabal view
@@ -1,16 +1,16 @@ Name: cabal-rpm-Version: 0.8.10+Version: 0.8.11 Synopsis: RPM packaging tool for Haskell Cabal-based packages Description: This package generates RPM packages from Haskell Cabal packages. .- * cblrpm spec: creates a .spec file from a hackage+ * cblrpm spec: create .spec file from a hackage .- * cblrpm srpm: creates an source rpm package+ * cblrpm srpm: create source rpm package .- * cblrpm rpm: build a binary rpm package, installing depends with yum+ * cblrpm local: build binary rpm package, installing depends with yum .- * cblrpm prep: unpacks package source+ * cblrpm prep: unpack package source . * cblrpm builddep: yum install depends .@@ -22,7 +22,7 @@ . * cblrpm missingdeps: list uninstalled dependencies .- * cblrpm diff: diff of current spec file with newly generated one+ * cblrpm diff: diff current spec file with newly generated one Homepage: https://github.com/juhp/cabal-rpm Bug-reports: https://github.com/juhp/cabal-rpm/issues License: GPL-3@@ -43,12 +43,11 @@ Executable cblrpm Main-is: Main.hs Build-depends: base < 5,- Cabal > 1.10,+ Cabal > 1.10 && < 1.19, directory, filepath, old-locale, process,- regex-compat, time, unix Other-modules:
man/cblrpm.1 view
@@ -5,7 +5,7 @@ .SH SYNOPSIS .PP cblrpm [\f[I]options\f[]] spec [\f[I]path\-or\-pkg\f[]] cblrpm-[\f[I]options\f[]] rpm [\f[I]path\-or\-pkg\f[]] cblrpm+[\f[I]options\f[]] local [\f[I]path\-or\-pkg\f[]] cblrpm [\f[I]options\f[]] srpm [\f[I]path\-or\-pkg\f[]] cblrpm [\f[I]options\f[]] prep [\f[I]path\-or\-pkg\f[]] cblrpm [\f[I]options\f[]] builddep [\f[I]path\-or\-pkg\f[]] cblrpm@@ -60,7 +60,7 @@ file. .SH EXAMPLES .PP-Below CMD can be one of: spec, srpm, rpm, install, and depends.+Below CMD can be one of: spec, srpm, prep, local, install, and depends. .PP Do CMD for the package in current directory: .IP
man/cblrpm.1.md view
@@ -7,7 +7,7 @@ # SYNOPSIS cblrpm [*options*] spec [*path-or-pkg*]-cblrpm [*options*] rpm [*path-or-pkg*]+cblrpm [*options*] local [*path-or-pkg*] cblrpm [*options*] srpm [*path-or-pkg*] cblrpm [*options*] prep [*path-or-pkg*] cblrpm [*options*] builddep [*path-or-pkg*]@@ -53,7 +53,7 @@ : Override the version number in the .spec file. # EXAMPLES-Below CMD can be one of: spec, srpm, rpm, install, and depends.+Below CMD can be one of: spec, srpm, prep, local, install, and depends. Do CMD for the package in current directory:
src/Commands/RpmBuild.hs view
@@ -20,7 +20,7 @@ ) where import Commands.Spec (createSpecFile)-import FileUtils (getDirectoryContents_)+import FileUtils (fileWithExtension, getDirectoryContents_) import PackageUtils (isScmDir, missingPackages, packageName, packageVersion) import Setup (RpmFlags (..)) import SysCmd (runSystem, yumInstall, (+-+))@@ -36,6 +36,7 @@ import System.Directory (copyFile, doesFileExist, getCurrentDirectory) import System.Environment (getEnv) import System.FilePath (takeDirectory, (</>))+import System.Posix.Files (setFileMode, getFileStatus, fileMode) -- autoreconf :: Verbosity -> PackageDescription -> IO () -- autoreconf verbose pkgDesc = do@@ -53,7 +54,10 @@ -- let verbose = rpmVerbosity flags -- bracket (setFileCreationMask 0o022) setFileCreationMask $ \ _ -> do -- autoreconf verbose pkgDesc- specFile <- specFileName pkgDesc flags+ mspcfile <- fileWithExtension "." ".spec"+ specFile <- case mspcfile of+ Just s -> return s+ Nothing -> specFileName pkgDesc flags specFileExists <- doesFileExist specFile if specFileExists then putStrLn $ "Using existing" +-+ specFile@@ -80,7 +84,7 @@ error "No tarball for source repo" cwd <- getCurrentDirectory- copyTarball name version False cwd+ copyTarball name version False runSystem ("rpmbuild -b" ++ rpmCmd +-+ (if stage == Prep then "--nodeps" else "") +-+ "--define \"_rpmdir" +-+ cwd ++ "\"" +-+@@ -88,8 +92,8 @@ "--define \"_sourcedir" +-+ cwd ++ "\"" +-+ specFile) where- copyTarball :: String -> String -> Bool -> FilePath -> IO ()- copyTarball n v ranFetch dest = do+ copyTarball :: String -> String -> Bool -> IO ()+ copyTarball n v ranFetch = do let tarfile = n ++ "-" ++ v ++ ".tar.gz" already <- doesFileExist tarfile unless already $ do@@ -105,8 +109,13 @@ then error $ "No" +-+ tarfile +-+ "found" else do runSystem ("cabal fetch -v0 --no-dependencies" +-+ n ++ "-" ++ v)- copyTarball n v True dest- else copyFile (head tarballs) (dest </> tarfile)+ copyTarball n v True+ else do+ copyFile (head tarballs) tarfile+ -- cabal fetch creates tarballs with mode 0600+ stat <- getFileStatus tarfile+ when (fileMode stat /= 0o100644) $+ setFileMode tarfile 0o0644 specFileName :: PackageDescription -- ^pkg description -> RpmFlags -- ^rpm flags
src/Commands/Spec.hs view
@@ -20,16 +20,17 @@ createSpecFile ) where -import Dependencies (packageDependencies, showDep)-import PackageUtils (isScmDir, packageName, packageVersion)+import Dependencies (packageDependencies, showDep, testsuiteDependencies)+import FileUtils (fileWithExtension)+import PackageUtils (isScmDir, notInstalled, packageName, packageVersion) import Setup (RpmFlags (..)) import SysCmd ((+-+)) --import Control.Exception (bracket)-import Control.Monad (unless, when)+import Control.Monad (filterM, when, unless) import Data.Char (toLower, toUpper)-import Data.List (groupBy, isPrefixOf, isSuffixOf, sort)-import Data.Maybe (fromMaybe)+import Data.List (groupBy, isPrefixOf, isSuffixOf, sort, (\\))+import Data.Maybe (fromMaybe, maybeToList) import Data.Time.Clock (UTCTime, getCurrentTime) import Data.Time.Format (formatTime) import Data.Version (showVersion)@@ -38,15 +39,16 @@ import Distribution.Simple.Utils (notice, warn) -import Distribution.PackageDescription (PackageDescription (..), exeName,- hasExes, hasLibs, withExe)+import Distribution.PackageDescription (PackageDescription (..), BuildInfo (..),+ Executable (..), Library (..),+ exeName, hasExes, hasLibs, withExe) --import Distribution.Version (VersionRange, foldVersionRange') import System.Directory (doesFileExist, getDirectoryContents) import System.IO (IOMode (..), hClose, hPutStrLn, openFile) import System.Locale (defaultTimeLocale)-import System.FilePath (dropFileName, takeDirectory, (</>))+import System.FilePath (dropFileName, takeBaseName, takeDirectory, (</>)) import qualified Paths_cabal_rpm (version) @@ -78,16 +80,23 @@ let verbose = rpmVerbosity flags now <- getCurrentTime defRelease <- defaultRelease cabalPath now- let pkg = package pkgDesc+ mspcfile <- if rpmForce flags then return Nothing+ else fileWithExtension "." ".spec"+ let mpkgname = fmap takeBaseName mspcfile+ pkg = package pkgDesc name = packageName pkg- pkgname = if isExec then name else "ghc-" ++ name- pkg_name = if isExec then "%{name}" else "%{pkg_name}"+ pkgname = fromMaybe (if hasExec then name else "ghc-" ++ name) mpkgname+ pkg_name = if pkgname == name then "%{name}" else "%{pkg_name}"+ basename | isBinLib = "%{pkg_name}"+ | hasExecPkg = name+ | otherwise = "ghc-%{pkg_name}" version = packageVersion pkg release = fromMaybe defRelease (rpmRelease flags)- specFile = (fromMaybe "" mdest) </> pkgname ++ ".spec"- isExec = not (rpmLibrary flags) && hasExes pkgDesc- isLib = hasLibs pkgDesc- isBinLib = isExec && isLib+ specFile = fromMaybe "" mdest </> pkgname ++ ".spec"+ hasExec = hasExes pkgDesc+ hasLib = hasLibs pkgDesc+ isBinLib = hasLib && not (rpmLibrary flags) && pkgname == name+ hasExecPkg = not (rpmLibrary flags) && (isBinLib || hasExes pkgDesc && not hasLib) specAlreadyExists <- doesFileExist specFile let specFilename = specFile ++ if not (rpmForce flags) && specAlreadyExists then ".cblrpm" else "" when specAlreadyExists $@@ -130,11 +139,24 @@ '\\' -> head cs: filterSymbols (tail cs) _ -> c: filterSymbols cs filterSymbols [] = []- when isLib $ do+ when hasLib $ do putDef "pkg_name" name putNewline - putHdr "Name" (if isExec then (if isLib then "%{pkg_name}" else pkgname) else "ghc-%{pkg_name}")+ let testsuiteDeps = testsuiteDependencies pkgDesc name+ missTestDeps <- filterM notInstalled testsuiteDeps+ unless (null testsuiteDeps) $ do+ put $ "%bcond_" ++ (if null missTestDeps then "without" else "with") +-+ "tests"+ putNewline++ let eCsources = concatMap (cSources . buildInfo) $ executables pkgDesc+ let lCsources = concatMap (cSources . libBuildInfo) $ maybeToList $ library pkgDesc+ when (null $ eCsources ++ lCsources) $ do+ put "# no useful debuginfo for Haskell packages without C sources"+ putDef "debug_package" "%{nil}"+ putNewline++ putHdr "Name" (if isBinLib then "%{pkg_name}" else basename) putHdr "Version" version putHdr "Release" $ release ++ "%{?dist}" putHdr "Summary" summary@@ -147,12 +169,17 @@ putHdr "BuildRequires" "ghc-rpm-macros" (deps, tools, clibs, pkgcfgs, selfdep) <- packageDependencies pkgDesc name- let alldeps = sort $ deps ++ tools ++ clibs ++ pkgcfgs- unless (null alldeps) $ do+ let alldeps = sort $ deps ++ tools ++ map (++ "%{?_isa}") clibs ++ pkgcfgs+ let extraTestDeps = sort $ testsuiteDeps \\ deps+ unless (null $ alldeps ++ extraTestDeps) $ do put "# Begin cabal-rpm deps:" mapM_ (putHdr "BuildRequires") alldeps when (any (\ d -> d `elem` map showDep ["template-haskell", "hamlet"]) deps) $ putHdr "ExclusiveArch" "%{ghc_arches_with_ghci}"+ unless (null extraTestDeps) $ do+ put "%if %{with tests}"+ mapM_ (putHdr "BuildRequires") extraTestDeps+ put "%endif" put "# End cabal-rpm deps" putNewline@@ -163,8 +190,8 @@ let wrapGenDesc = wordwrap (79 - max 0 (length pkgname - length pkg_name)) - when isLib $ do- when isExec $ do+ when hasLib $ do+ when isBinLib $ do put $ "%package" +-+ ghcPkg putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library" putNewline@@ -173,14 +200,14 @@ putNewline put $ "%package" +-+ ghcPkgDevel putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library development files"- putHdr "Provides" $ (if isExec then "ghc-%{name}" else "%{name}") ++ "-static = %{version}-%{release}"+ putHdr "Provides" $ (if isBinLib then "ghc-%{name}" else "%{name}") ++ "-static = %{version}-%{release}" putHdr "Requires" "ghc-compiler = %{ghc_version}" putHdr "Requires(post)" "ghc-compiler = %{ghc_version}" putHdr "Requires(postun)" "ghc-compiler = %{ghc_version}"- putHdr "Requires" $ (if isExec then "ghc-%{name}" else "%{name}") ++ "%{?_isa} = %{version}-%{release}"+ putHdr "Requires" $ (if isBinLib then "ghc-%{name}" else "%{name}") ++ "%{?_isa} = %{version}-%{release}" unless (null $ clibs ++ pkgcfgs) $ do put "# Begin cabal-rpm deps:"- mapM_ (putHdr "Requires") $ sort $ clibs ++ pkgcfgs+ mapM_ (putHdr "Requires") $ sort $ map (++ "%{?_isa}") clibs ++ pkgcfgs put "# End cabal-rpm deps" putNewline put $ "%description" +-+ ghcPkgDevel@@ -193,7 +220,7 @@ putNewline put "%build"- let pkgType = if isLib then "lib" else "bin"+ let pkgType = if hasLib then "lib" else "bin" put $ "%ghc_" ++ pkgType ++ "_build" putNewline putNewline@@ -206,7 +233,15 @@ putNewline putNewline - when isLib $ do+ unless (null testsuiteDeps) $ do+ put "%check"+ put "%if %{with tests}"+ put "%cabal test"+ put "%endif"+ putNewline+ putNewline++ when hasLib $ do let putInstallScript = do put "%ghc_pkg_recache" putNewline@@ -218,7 +253,7 @@ docs <- findDocs cabalPath pkgDesc - when isExec $ do+ when hasExecPkg $ do put "%files" -- Add the license file to the main package only if it wouldn't -- otherwise be empty.@@ -230,28 +265,35 @@ withExe pkgDesc $ \exe -> let program = exeName exe in put $ "%{_bindir}/" ++ (if program == name then "%{name}" else program)- unless (null (dataFiles pkgDesc) && isExec) $+ unless (null (dataFiles pkgDesc)) $ put "%{_datadir}/%{name}-%{version}" putNewline putNewline - when isLib $ do+ when hasLib $ do let baseFiles = if isBinLib then "-f ghc-%{name}.files" else "-f %{name}.files" develFiles = if isBinLib then "-f ghc-%{name}-devel.files" else "-f %{name}-devel.files" put $ "%files" +-+ ghcPkg +-+ baseFiles put $ "%doc" +-+ licenseFile pkgDesc+ -- be strict for now+-- unless (null (dataFiles pkgDesc) || isBinLib) $+-- put "%{_datadir}/%{pkg_name}-%{version}" putNewline putNewline put $ "%files" +-+ ghcPkgDevel +-+ develFiles unless (null docs) $ put $ "%doc" +-+ unwords docs+ when (not isBinLib && hasExec) $+ withExe pkgDesc $ \exe ->+ let program = exeName exe in+ put $ "%{_bindir}/" ++ (if program == name then "%{name}" else program) putNewline putNewline let date = formatTime defaultTimeLocale "%a %b %e %Y" now put "%changelog"- put $ "*" +-+ date +-+ "Fedora Haskell SIG <haskell@lists.fedoraproject.org> - " ++ version+ put $ "*" +-+ date +-+ "Fedora Haskell SIG <haskell@lists.fedoraproject.org> - " ++ version ++ "-" ++ release put $ "- spec file generated by cabal-rpm-" ++ showVersion Paths_cabal_rpm.version hClose h
src/Dependencies.hs view
@@ -14,24 +14,27 @@ -- (at your option) any later version. module Dependencies (- dependencies, packageDependencies, showDep+ dependencies, packageDependencies, showDep, testsuiteDependencies ) where import SysCmd (tryReadProcess) -import Data.List (nub)+import Data.List (delete, nub) import Distribution.Package (Dependency (..), PackageName (..)) import Distribution.PackageDescription (PackageDescription (..), allBuildInfo,- BuildInfo (..))+ BuildInfo (..),+ TestSuite (..)) +excludedPkgs :: String -> Bool+excludedPkgs = flip notElem ["Cabal", "base", "ghc-prim", "integer-gmp"]+ -- returns list of deps and whether package is self-dependent buildDependencies :: PackageDescription -> String -> ([String], Bool) buildDependencies pkgDesc self =- let deps = nub $ map depName (buildDepends pkgDesc)- excludedPkgs n = notElem n [self, "Cabal", "base", "ghc-prim", "integer-gmp"] in- (filter excludedPkgs deps, self `elem` deps)+ let deps = nub $ map depName (buildDepends pkgDesc) in+ (filter excludedPkgs (delete self deps), self `elem` deps) depName :: Dependency -> String depName (Dependency (PackageName n) _) = n@@ -52,6 +55,16 @@ clibs <- mapM repoqueryLib $ concatMap extraLibs buildinfo return (deps, tools, clibs, pkgcfgs, selfdep) +repoqueryLib :: String -> IO String+repoqueryLib lib = do+ let lib_path = "/usr/lib/lib" ++ lib ++ ".so"+ out <- tryReadProcess "repoquery" ["--qf=%{name}", "-qf", lib_path]+ let pkgs = nub $ words out+ case pkgs of+ [pkg] -> return pkg+ [] -> error $ "Could not resolve package that provides lib" ++ lib_path+ _ -> error $ "More than one package seems to provide lib" ++ lib_path ++ ": " ++ show pkgs+ packageDependencies :: PackageDescription -- ^pkg description -> String -- ^pkg name -> IO ([String], [String], [String], [String], Bool)@@ -67,14 +80,11 @@ tools = filter excludedTools $ nub $ map mapTools tools' ++ chrpath let showPkgCfg p = "pkgconfig(" ++ p ++ ")"- return (map showDep deps, tools, map (++ "%{?_isa}") clibs, map showPkgCfg pkgcfgs, selfdep)+ return (map showDep deps, tools, clibs, map showPkgCfg pkgcfgs, selfdep) -repoqueryLib :: String -> IO String-repoqueryLib lib = do- let lib_path = "/usr/lib/lib" ++ lib ++ ".so"- out <- tryReadProcess "repoquery" ["--qf=%{name}", "-qf", lib_path]- let pkgs = nub $ words out- case pkgs of- [pkg] -> return pkg- [] -> error $ "Could not resolve package that provides lib" ++ lib_path- _ -> error $ "More than one package seems to provide lib" ++ lib_path ++ ": " ++ show pkgs+testsuiteDependencies :: PackageDescription -- ^pkg description+ -> String -- ^self+ -> [String] -- ^depends+testsuiteDependencies pkgDesc self =+ map showDep . delete self . filter excludedPkgs . map depName . nub $ concatMap targetBuildDepends $ map testBuildInfo $ testSuites pkgDesc+
src/Main.hs view
@@ -22,39 +22,27 @@ import Commands.RpmBuild (rpmBuild, RpmStage (..)) import Commands.Spec (createSpecFile) -import FileUtils (fileWithExtension, fileWithExtension_,- getDirectoryContents_, mktempdir) import PackageUtils (simplePackageDescription)-import Setup (RpmFlags (..), parseArgs)-import SysCmd (runSystem, tryReadProcess)+import Setup (parseArgs) -import Control.Applicative ((<$>))-import Data.List (isSuffixOf, stripPrefix)-import Data.Maybe (isJust, listToMaybe, fromMaybe)-import Distribution.PackageDescription.Parse (readPackageDescription)-import Distribution.Simple.Utils (die, findPackageDesc)-import Distribution.Verbosity (Verbosity)-import System.Directory (doesDirectoryExist, doesFileExist, getCurrentDirectory,- removeDirectoryRecursive,- setCurrentDirectory)+import Data.Maybe (listToMaybe, fromMaybe)+import System.Directory (removeDirectoryRecursive) import System.Environment (getArgs)-import System.FilePath (takeExtension) -import Text.Regex (matchRegex, mkRegex)- main :: IO () main = do (opts, args) <- getArgs >>= parseArgs- let verbose = rpmVerbosity opts- (cmd:args') = args+ let (cmd:args') = args path = fromMaybe "." $ listToMaybe args'- (cabalPath, mtmp) <- findCabalFile verbose path- genPkgDesc <- readPackageDescription verbose cabalPath- pkgDesc <- simplePackageDescription genPkgDesc opts+ (cabalPath, pkgDesc, mtmp) <- simplePackageDescription path opts case cmd of "spec" -> createSpecFile cabalPath pkgDesc opts Nothing "srpm" -> rpmBuild cabalPath pkgDesc opts Source "prep" -> rpmBuild cabalPath pkgDesc opts Prep- "rpm" -> rpmBuild cabalPath pkgDesc opts Binary+ "local" -> rpmBuild cabalPath pkgDesc opts Binary+ "rpm" -> do+ putStrLn "* Warning the 'rpm' command has been renamed to 'local':"+ putStrLn "* this alias may be removed in a future release."+ rpmBuild cabalPath pkgDesc opts Binary "builddep" -> rpmBuild cabalPath pkgDesc opts BuildDep "install" -> install cabalPath pkgDesc "depends" -> depends pkgDesc@@ -77,70 +65,3 @@ -- } -- internalPackageSet = PackageIndex.fromList [internalPackage] --- returns path to .cabal file and possibly tmpdir to be removed-findCabalFile :: Verbosity -> FilePath -> IO (FilePath, Maybe FilePath)-findCabalFile vb path = do- isdir <- doesDirectoryExist path- if isdir- then do- cblfile <- fileWithExtension_ path ".cabal"- if cblfile- then do- file <- findPackageDesc path- return (file, Nothing)- else do- spcfile <- fileWithExtension path ".spec"- maybe (die "Cannot determine package in dir.")- (cabalFromSpec vb) spcfile- else do- isfile <- doesFileExist path- if not isfile- then if isJust $ matchRegex pkg_re path- then tryUnpack path- else error $ path ++ ": No such file or directory"- else if takeExtension path == ".cabal"- then return (path, Nothing)- else if takeExtension path == ".spec"- then cabalFromSpec vb path- else if ".tar.gz" `isSuffixOf` path- then do- tmpdir <- mktempdir- runSystem $ "tar zxf " ++ path ++ " -C " ++ tmpdir ++ " *.cabal"- subdir <- getDirectoryContents_ tmpdir- file <- findPackageDesc $ tmpdir ++ "/" ++ head subdir- return (file, Just tmpdir)- else error $ path ++ ": file should be a .cabal, .spec or .tar.gz file."- where pkg_re = mkRegex "^([A-Za-z0-9-]+)(-([0-9.]+))?$"--cabalFromSpec :: Verbosity -> FilePath -> IO (FilePath, Maybe FilePath)-cabalFromSpec vrb spcfile = do- -- no rpmspec command in RHEL 5 and 6- namever <- removePrefix "ghc-" <$> tryReadProcess "rpm" ["-q", "--qf", "%{name}-%{version}\n", "--specfile", spcfile]- findCabalFile vrb (head $ lines namever)--removePrefix :: String -> String-> String-removePrefix pref str =- fromMaybe str (stripPrefix pref str)--tryUnpack :: String -> IO (FilePath, Maybe FilePath)-tryUnpack pkg = do- pkgver <- if '.' `elem` pkg then return pkg- else do- contains_pkg <- tryReadProcess "cabal" ["list", "--simple-output", pkg]- let pkgs = filter ((== pkg) . takeWhile (not . (== ' '))) $ lines contains_pkg- if null pkgs- then error $ pkg ++ " hackage not found"- else return $ map (\c -> if c == ' ' then '-' else c) $ last pkgs- isdir <- doesDirectoryExist pkgver- if isdir- then do- pth <-findPackageDesc pkgver- return (pth, Nothing)- else do- cwd <- getCurrentDirectory- tmpdir <- mktempdir- setCurrentDirectory tmpdir- runSystem $ "cabal unpack -v0 " ++ pkgver- pth <- findPackageDesc pkgver- setCurrentDirectory cwd- return (tmpdir ++ "/" ++ pth, Just tmpdir)
src/PackageUtils.hs view
@@ -16,47 +16,132 @@ module PackageUtils ( isScmDir, missingPackages,+ notInstalled, packageName, packageVersion, simplePackageDescription ) where import Dependencies (packageDependencies)+import FileUtils (fileWithExtension, fileWithExtension_,+ getDirectoryContents_, mktempdir) import Setup (RpmFlags (..))-import SysCmd (systemBool, (+-+))+import SysCmd (runSystem, tryReadProcess, systemBool, (+-+)) +import Control.Applicative ((<$>)) import Control.Monad (filterM, liftM)++import Data.Char (isAlphaNum)+import Data.List (isSuffixOf, stripPrefix)+import Data.Maybe (fromMaybe) import Data.Version (showVersion) import Distribution.Compiler (CompilerFlavor (..)) import Distribution.Package (PackageIdentifier (..), PackageName (..))-import Distribution.PackageDescription (GenericPackageDescription (..),- PackageDescription (..))+import Distribution.PackageDescription (PackageDescription (..)) import Distribution.PackageDescription.Configuration (finalizePackageDescription)+import Distribution.PackageDescription.Parse (readPackageDescription) import Distribution.Simple.Compiler (Compiler (..)) import Distribution.Simple.Configure (configCompiler) import Distribution.Simple.Program (defaultProgramConfiguration)-import Distribution.Simple.Utils (die)+import Distribution.Simple.Utils (die, findPackageDesc) import Distribution.System (Platform (..), buildArch, buildOS)+import Distribution.Verbosity (Verbosity) -import System.Directory (doesDirectoryExist)-import System.FilePath ((</>))+import System.Directory (doesDirectoryExist, doesFileExist,+ getCurrentDirectory, setCurrentDirectory)+import System.FilePath ((</>), takeExtension) -simplePackageDescription :: GenericPackageDescription -> RpmFlags- -> IO PackageDescription-simplePackageDescription genPkgDesc flags = do- (compiler, _) <- configCompiler (Just GHC) Nothing Nothing- defaultProgramConfiguration- (rpmVerbosity flags)- case finalizePackageDescription (rpmConfigurationsFlags flags)- (const True) (Platform buildArch buildOS) (compilerId compiler)- [] genPkgDesc of- Left e -> die $ "finalize failed: " ++ show e- Right (pd, _) -> return pd +-- returns path to .cabal file and possibly tmpdir to be removed+findCabalFile :: Verbosity -> FilePath -> IO (FilePath, Maybe FilePath)+findCabalFile vb path = do+ isdir <- doesDirectoryExist path+ if isdir+ then do+ cblfile <- fileWithExtension_ path ".cabal"+ if cblfile+ then do+ file <- findPackageDesc path+ return (file, Nothing)+ else do+ spcfile <- fileWithExtension path ".spec"+ maybe (die "Cannot determine package in dir.")+ (cabalFromSpec vb) spcfile+ else do+ isfile <- doesFileExist path+ if not isfile+ then if isPackageId path+ then tryUnpack path+ else error $ path ++ ": No such file or directory"+ else if takeExtension path == ".cabal"+ then return (path, Nothing)+ else if takeExtension path == ".spec"+ then cabalFromSpec vb path+ else if ".tar.gz" `isSuffixOf` path+ then do+ tmpdir <- mktempdir+ runSystem $ "tar zxf " ++ path ++ " -C " ++ tmpdir ++ " *.cabal"+ subdir <- getDirectoryContents_ tmpdir+ file <- findPackageDesc $ tmpdir ++ "/" ++ head subdir+ return (file, Just tmpdir)+ else error $ path ++ ": file should be a .cabal, .spec or .tar.gz file."+ where+ isPackageId :: String -> Bool+ isPackageId (c:cs) | isAlphaNum c =+ all (\d -> isAlphaNum d || d `elem` "-." ) cs+ isPackageId _ = False++simplePackageDescription :: FilePath -> RpmFlags+ -> IO (FilePath, PackageDescription, Maybe FilePath)+simplePackageDescription path opts = do+ let verbose = rpmVerbosity opts+ (cabalPath, mtmp) <- findCabalFile verbose path+ genPkgDesc <- readPackageDescription verbose cabalPath+ (compiler, _) <- configCompiler (Just GHC) Nothing Nothing+ defaultProgramConfiguration verbose+ case finalizePackageDescription (rpmConfigurationsFlags opts)+ (const True) (Platform buildArch buildOS) (compilerId compiler)+ [] genPkgDesc of+ Left e -> die $ "finalize failed: " ++ show e+ Right (pd, _) -> return (cabalPath, pd, mtmp)++cabalFromSpec :: Verbosity -> FilePath -> IO (FilePath, Maybe FilePath)+cabalFromSpec vrb spcfile = do+ -- no rpmspec command in RHEL 5 and 6+ namever <- removePrefix "ghc-" <$> tryReadProcess "rpm" ["-q", "--qf", "%{name}-%{version}\n", "--specfile", spcfile]+ findCabalFile vrb (head $ lines namever)+ where+ removePrefix :: String -> String-> String+ removePrefix pref str =+ fromMaybe str (stripPrefix pref str)++tryUnpack :: String -> IO (FilePath, Maybe FilePath)+tryUnpack pkg = do+ pkgver <- if '.' `elem` pkg then return pkg+ else do+ contains_pkg <- tryReadProcess "cabal" ["list", "--simple-output", pkg]+ let pkgs = filter ((== pkg) . takeWhile (not . (== ' '))) $ lines contains_pkg+ if null pkgs+ then error $ pkg ++ " hackage not found"+ else return $ map (\c -> if c == ' ' then '-' else c) $ last pkgs+ isdir <- doesDirectoryExist pkgver+ if isdir+ then do+ pth <-findPackageDesc pkgver+ return (pth, Nothing)+ else do+ cwd <- getCurrentDirectory+ tmpdir <- mktempdir+ setCurrentDirectory tmpdir+ runSystem $ "cabal unpack -v0 " ++ pkgver+ pth <- findPackageDesc pkgver+ setCurrentDirectory cwd+ return (tmpdir ++ "/" ++ pth, Just tmpdir)+ packageName :: PackageIdentifier -> String packageName pkg = name where PackageName name = pkgName pkg@@ -84,4 +169,5 @@ missingPackages :: PackageDescription -> String -> IO [String] missingPackages pkgDesc name = do (deps, tools, clibs, pkgcfgs, _) <- packageDependencies pkgDesc name- filterM notInstalled $ deps ++ tools ++ clibs ++ pkgcfgs+ filterM notInstalled $ deps ++ ["ghc-Cabal-devel", "ghc-rpm-macros"] ++ tools ++ clibs ++ pkgcfgs+
src/Setup.hs view
@@ -88,13 +88,15 @@ printHelp h = do progName <- getProgName- let info = "Usage: " ++ progName ++ " [OPTION]... [COMMAND] [PKGDIR|PKG|PKG-VERSION|CABALFILE|TARBALL]\n"+ let info = "Usage: " ++ progName ++ " [OPTION]... COMMAND [PATH|PKG|PKG-VERSION]\n" ++ "\n"+ ++ "PATH can be to a .spec or .cabal file, pkg dir, or tarball.\n"+ ++ "\n" ++ "Commands:\n" ++ " spec\t\t- generate a spec file\n" ++ " srpm\t\t- generate a src rpm file\n" ++ " prep\t\t- unpack source\n"- ++ " rpm\t\t- build rpm package\n"+ ++ " local\t\t- build rpm package locally\n" ++ " builddep\t- install dependencies\n" ++ " install\t- user install package\n" ++ " depends\t- list Cabal depends\n"@@ -124,7 +126,7 @@ hPutStr stderr "Unrecognised options: " hPutStrLn stderr $ unwords unknown exitWith (ExitFailure 1)- when (null args' || notElem (head args') ["builddep", "depends", "diff", "install", "missingdeps", "prep", "requires", "spec", "srpm", "rpm"]) $ do+ when (null args' || notElem (head args') ["builddep", "depends", "diff", "install", "missingdeps", "prep", "requires", "spec", "srpm", "local", "rpm"]) $ do printHelp stderr exitWith (ExitFailure 1) when (length args' > 2) $ do