cabal-rpm (empty) → 0.2
raw patch · 7 files changed
+1191/−0 lines, 7 filesdep +Cabaldep +basedep +filepathsetup-changed
Dependencies added: Cabal, base, filepath, time, unix
Files
- COPYING +340/−0
- Setup.lhs +8/−0
- cabal-rpm.cabal +26/−0
- src/CabalRpm.hs +20/−0
- src/Distribution/Package/Rpm.hs +640/−0
- src/Distribution/Package/Rpm/Main.hs +29/−0
- src/Distribution/Package/Rpm/Setup.hs +128/−0
+ COPYING view
@@ -0,0 +1,340 @@+ GNU GENERAL PUBLIC LICENSE+ Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The licenses for most software are designed to take away your+freedom to share and change it. By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users. This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it. (Some other Free Software Foundation software is covered by+the GNU Library General Public License instead.) You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++ To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have. You must make sure that they, too, receive or can get the+source code. And you must show them these terms so they know their+rights.++ We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++ Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software. If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++ Finally, any free program is threatened constantly by software+patents. We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary. To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++ The precise terms and conditions for copying, distribution and+modification follow.++ GNU GENERAL PUBLIC LICENSE+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++ 0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License. The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language. (Hereinafter, translation is included without limitation in+the term "modification".) Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope. The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++ 1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++ 2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++ a) You must cause the modified files to carry prominent notices+ stating that you changed the files and the date of any change.++ b) You must cause any work that you distribute or publish, that in+ whole or in part contains or is derived from the Program or any+ part thereof, to be licensed as a whole at no charge to all third+ parties under the terms of this License.++ c) If the modified program normally reads commands interactively+ when run, you must cause it, when started running for such+ interactive use in the most ordinary way, to print or display an+ announcement including an appropriate copyright notice and a+ notice that there is no warranty (or else, saying that you provide+ a warranty) and that users may redistribute the program under+ these conditions, and telling the user how to view a copy of this+ License. (Exception: if the Program itself is interactive but+ does not normally print such an announcement, your work based on+ the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole. If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works. But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++ 3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++ a) Accompany it with the complete corresponding machine-readable+ source code, which must be distributed under the terms of Sections+ 1 and 2 above on a medium customarily used for software interchange; or,++ b) Accompany it with a written offer, valid for at least three+ years, to give any third party, for a charge no more than your+ cost of physically performing source distribution, a complete+ machine-readable copy of the corresponding source code, to be+ distributed under the terms of Sections 1 and 2 above on a medium+ customarily used for software interchange; or,++ c) Accompany it with the information you received as to the offer+ to distribute corresponding source code. (This alternative is+ allowed only for noncommercial distribution and only if you+ received the program in object code or executable form with such+ an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it. For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable. However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++ 4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License. Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++ 5. You are not required to accept this License, since you have not+signed it. However, nothing else grants you permission to modify or+distribute the Program or its derivative works. These actions are+prohibited by law if you do not accept this License. Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++ 6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions. You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++ 7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all. For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices. Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++ 8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded. In such case, this License incorporates+the limitation as if written in the body of this License.++ 9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number. If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation. If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++ 10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission. For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this. Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++ NO WARRANTY++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software; you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation; either version 2 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program; if not, write to the Free Software+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA+++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++ Gnomovision version 69, Copyright (C) year name of author+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary. Here is a sample; alter the names:++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program+ `Gnomovision' (which makes passes at compilers) written by James Hacker.++ <signature of Ty Coon>, 1 April 1989+ Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs. If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library. If this is what you want to do, use the GNU Library General+Public License instead of this License.
+ Setup.lhs view
@@ -0,0 +1,8 @@+#!/usr/bin/env runghc++> module Main where++> import Distribution.Simple++> main :: IO ()+> main = defaultMain
+ cabal-rpm.cabal view
@@ -0,0 +1,26 @@+Name: cabal-rpm+Version: 0.2+License: GPL+License-File: COPYING+Author: Bryan O'Sullivan <bos@serpentine.com>+Maintainer: Bryan O'Sullivan <bos@serpentine.com>+Copyright: 2007 Bryan O'Sullivan <bos@serpentine.com>+Homepage: http://www.serpentine.com/software/cabal-rpm/+Stability: Experimental+Category: Distribution+Build-type: Simple+Build-depends: base, Cabal >= 1.1.7, filepath, time >= 1.1, unix+Synopsis: RPM package builder for Haskell Cabal source packages.+Description:+ This package turns Haskell Cabal source packages into source and+ binary RPM packages.++Executable: cabal-rpm+Main-Is: CabalRpm.hs+Other-Modules:+ Distribution.Package.Rpm,+ Distribution.Package.Rpm.Main,+ Distribution.Package.Rpm.Setup+Hs-Source-Dirs: src+Extensions: CPP+GHC-options: -fwarn-missing-signatures
+ src/CabalRpm.hs view
@@ -0,0 +1,20 @@+-- |+-- Module : CabalRpm+-- Copyright : Bryan O'Sullivan 2007+--+-- Maintainer : Bryan O'Sullivan <bos@serpentine.com>+-- Stability : alpha+-- Portability : portable+--+-- Explanation: Main entry point for building RPM packages.++-- This software may be used and distributed according to the terms of+-- the GNU General Public License, incorporated herein by reference.++module Main where++import qualified Distribution.Package.Rpm.Main as Rpm++main :: IO ()++main = Rpm.main
+ src/Distribution/Package/Rpm.hs view
@@ -0,0 +1,640 @@+-- |+-- Module : Distribution.Package.Rpm+-- Copyright : Bryan O'Sullivan 2007+--+-- Maintainer : Bryan O'Sullivan <bos@serpentine.com>+-- Stability : alpha+-- Portability : portable+--+-- Explanation: Support for building RPM packages. Can also generate+-- an RPM spec file if you need a basic one to hand-customize.++-- This software may be used and distributed according to the terms of+-- the GNU General Public License, incorporated herein by reference.++module Distribution.Package.Rpm (+ createSpecFile+ , rpm+ , rpmBuild+ ) where++import Control.Exception (bracket)+import Control.Monad (filterM, liftM, mapM, when, unless)+import Data.Char (toLower)+import Data.List (find, intersperse, isPrefixOf, sort)+import Data.Maybe+import Data.Time.Clock (UTCTime, getCurrentTime)+import Data.Time.Format (formatTime)+import Data.Version (Version(..), showVersion)+import System.Cmd (system)+import System.Directory (canonicalizePath, createDirectoryIfMissing,+ doesDirectoryExist, doesFileExist,+ getDirectoryContents)+import System.Environment (getProgName)+import System.Exit (ExitCode(..))+import System.IO+import System.Locale (defaultTimeLocale)+import System.Process (runInteractiveCommand, waitForProcess)++import System.FilePath ((</>))+import Distribution.Compiler (CompilerFlavor(..), Compiler(..),+ compilerVersion)+import Distribution.License+import Distribution.Package (PackageIdentifier(..))+import Distribution.PreProcess (knownSuffixHandlers)+import Distribution.Simple.Configure (configCompiler)+import Distribution.Simple.LocalBuildInfo (distPref)+import Distribution.Simple.SrcDist (createArchive, prepareTree, tarBallName)+import Distribution.Simple.Utils (copyDirectoryRecursiveVerbose,+ copyFileVerbose, die, warn)+import Distribution.PackageDescription (BuildInfo(..), Library(..),+ PackageDescription(..), exeName,+ hasLibs, setupMessage, withExe,+ withLib)+import Distribution.Verbosity (Verbosity(..))+import Distribution.Version (Dependency(..), VersionRange(..), withinRange)+import Distribution.Package.Rpm.Setup (RpmFlags(..))+import System.Posix.Files (setFileCreationMask)++rpm :: PackageDescription -- ^info from the .cabal file+ -> RpmFlags -- ^rpm flags+ -> IO ()++rpm pkgDesc flags = do+ case rpmCompiler flags of+ Just GHC -> return ()+ Just c -> die ("the " ++ show c ++ " compiler is not yet supported")+ if rpmGenSpec flags+ then do+ (name, extraDocs) <- createSpecFile False pkgDesc flags "."+ putStrLn $ "Spec file created: " ++ name+ when ((not . null) extraDocs) $ do+ putStrLn "NOTE: docs packaged, but not in .cabal file:"+ mapM_ putStrLn $ sort extraDocs+ return ()+ else rpmBuild pkgDesc flags++-- | Copy a file or directory (recursively, in the latter case) to the+-- same name in the target directory. Arguments flipped from the+-- conventional order.++copyTo :: Verbosity -> FilePath -> FilePath -> IO ()++copyTo verbose dest src = do+ isFile <- doesFileExist src+ let destDir = dest </> src+ if isFile+ then copyFileVerbose verbose src destDir+ else copyDirectoryRecursiveVerbose verbose src destDir++autoreconf :: Verbosity -> PackageDescription -> IO ()++autoreconf verbose pkgDesc = do+ ac <- doesFileExist "configure.ac"+ when ac $ do+ c <- doesFileExist "configure"+ when (not c) $ do+ setupMessage verbose "Running autoreconf" pkgDesc+ ret <- system "autoreconf"+ case ret of+ ExitSuccess -> return ()+ ExitFailure n -> die ("autoreconf failed with status " ++ show n)++rpmBuild :: PackageDescription+ -> RpmFlags+ -> IO ()++rpmBuild pkgDesc flags = do+ tgtPfx <- canonicalizePath (maybe distPref id $ rpmTopDir flags)+ let verbose = rpmVerbosity flags+ tmpDir = tgtPfx </> "src"+ flip mapM_ ["BUILD", "RPMS", "SOURCES", "SPECS", "SRPMS"] $ \ subDir -> do+ createDirectoryIfMissing True (tgtPfx </> subDir)+ let specsDir = tgtPfx </> "SPECS"+ bracket (setFileCreationMask 0o022) setFileCreationMask $ \ _ -> do+ autoreconf verbose pkgDesc+ (specFile, extraDocs) <- createSpecFile True pkgDesc flags specsDir+ tree <- prepareTree pkgDesc verbose Nothing False tmpDir+ knownSuffixHandlers 0+ mapM_ (copyTo verbose tree) extraDocs+ tarball <- createArchive pkgDesc verbose Nothing tmpDir+ (tgtPfx </> "SOURCES")+ ret <- system ("rpmbuild -ba --define \"_topdir " ++ tgtPfx ++ "\" " +++ specFile)+ case ret of+ ExitSuccess -> return ()+ ExitFailure n -> die ("rpmbuild failed with status " ++ show n)++defaultRelease :: UTCTime -> IO String++defaultRelease now = do+ darcsRepo <- doesDirectoryExist "_darcs"+ return $ if darcsRepo+ then formatTime defaultTimeLocale "0.%Y%m%d" now+ else "1"++rstrip :: (Char -> Bool) -> String -> String++rstrip p = reverse . dropWhile p . reverse++createSpecFile :: Bool -- ^whether to forcibly create file+ -> PackageDescription -- ^info from the .cabal file+ -> RpmFlags -- ^rpm flags+ -> FilePath -- ^directory in which to create file+ -> IO (FilePath, [FilePath])++createSpecFile force pkgDesc flags tgtPfx = do+ compiler <- configCompiler (rpmCompiler flags) Nothing Nothing+ (rpmVerbosity flags)+ now <- getCurrentTime+ defRelease <- defaultRelease now+ let pkg = package pkgDesc+ verbose = rpmVerbosity flags+ origName = pkgName pkg+ name = maybe (map toLower origName) id (rpmName flags)+ version = maybe ((showVersion . pkgVersion) pkg) id (rpmVersion flags)+ release = maybe defRelease id (rpmRelease flags)+ specPath = tgtPfx </> name ++ ".spec"+ group = "Development/Languages"+ buildRoot = "%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)"+ cmplrVersion = compilerVersion compiler+ doHaddock = rpmHaddock flags && hasLibs pkgDesc+ (cmplr, runner) = case compilerFlavor compiler of+ GHC -> ("ghc", "runghc")+ Hugs -> ("hugs", "runhugs")+ JHC -> ("jhc", "runjhc")+ NHC -> ("nhc", "runnhc")+ (OtherCompiler s) -> (s, "run" ++ s)+ unless force $ do+ specAlreadyExists <- doesFileExist specPath+ when specAlreadyExists $+ die $ "spec file already exists: " ++ specPath+ h <- openFile specPath WriteMode+ buildReq <- showBuildReq verbose doHaddock compiler pkgDesc+ runtimeReq <- showRuntimeReq verbose compiler pkgDesc+ progName <- getProgName+ let putHdr hdr val = hPutStrLn h (hdr ++ ": " ++ val)+ putHdr_ hdr val = when (not $ null val) $+ hPutStrLn h (hdr ++ ": " ++ val)+ putHdrD hdr val dfl = hPutStrLn h (hdr ++ ": " +++ if null val then dfl else val)+ putNewline = hPutStrLn h ""+ put s = hPutStrLn h s+ putDef v s = put $ "%define " ++ v ++ ' ' : s+ putSetup s = put $ runner ++ " Setup " ++ s+ date = formatTime defaultTimeLocale "%a %b %d %Y" now+ putDef "hsc_name" cmplr+ putDef "hsc_version" $ showVersion cmplrVersion+ putDef "hsc_namever" $ compilerNameVersion compiler+ putDef "pkg_name" origName+ putDef "pkg_libdir" "%{_libdir}/%{hsc_name}-%{hsc_version}/%{pkg_name}-%{version}"+ putNewline++ putHdr "Name" name+ putHdr "Version" version+ putHdr "Release" $ release ++ "%{?dist}"+ putHdr "License" $ (showLicense . license) pkgDesc+ putHdr "Group" group+ putHdr_ "URL" $ homepage pkgDesc+ putHdr "Source" $ tarBallName pkgDesc+ -- Some packages conflate the synopsis and description fields. Ugh.+ let syn = synopsis pkgDesc+ syn' = (head . lines) syn+ synTooLong = syn /= syn'+ summary = if synTooLong+ then syn' ++ " [...]"+ else rstrip (== '.') syn'+ when synTooLong $+ warn verbose "The synopsis for this package spans multiple lines."+ putHdrD "Summary" summary "This package has no summary"+ putHdr "BuildRoot" buildRoot+ putHdr "BuildRequires" buildReq+ -- External libraries incur both build-time and runtime+ -- dependencies. The latter only need to be made explicit for the+ -- built library, as RPM is smart enough to ferret out good+ -- dependencies for binaries.+ extDeps <- withLib pkgDesc [] (findLibDeps .libBuildInfo)+ let extraReq = concat $ intersperse ", " extDeps+ putHdr_ "BuildRequires" extraReq+ putNewline+ putNewline++ let putDesc = do+ put $ if (null . description) pkgDesc+ then if synTooLong+ then syn+ else "This package does not have a description."+ else description pkgDesc+ put "%description"+ putDesc+ putNewline+ putNewline++ {- Compiler-specific library data goes into a package of its own.<++ Unlike a library for a traditional language, the library+ packagen depends on the compiler, because when installed, it+ has to register itself with the compiler's own package+ management system. -}++ withLib pkgDesc () $ \_ -> do+ put "%package -n %{hsc_namever}-%{name}"+ putHdrD "Summary" summary "This library package has no summary"+ putHdr "Group" "Development/Libraries"+ putHdr "Requires" "%{hsc_name} = %{hsc_version}"+ putHdr_ "Requires" extraReq+ putHdr_ "Requires" runtimeReq+ putHdr "Provides" "%{pkg_name}-%{hsc_namever} = %{version}"+ putNewline+ putNewline++ put "%description -n %{hsc_namever}-%{name}"+ putDesc+ putNewline+ put "This package contains libraries for %{hsc_name} %{hsc_version}."+ putNewline+ putNewline++ when (rpmLibProf flags) $ do+ put "%package -n %{hsc_namever}-%{name}-prof"+ putHdr "Summary" "Profiling libraries for %{hsc_namever}-%{name}"+ putHdr "Group" "Development/Libraries"+ putHdr "Requires" "%{hsc_namever}-%{name} = %{version}"+ putHdr "Provides" "%{pkg_name}-%{hsc_namever}-prof = %{version}"+ putNewline+ putNewline++ put "%description -n %{hsc_namever}-%{name}-prof"+ putDesc+ putNewline+ put "This package contains profiling libraries for %{hsc_name} %{hsc_version}."+ putNewline+ putNewline++ put "%prep"+ put $ "%setup -q -n %{pkg_name}-%{version}"+ putNewline+ putNewline++ put "%build"+ put "if [ -f configure.ac -a ! -f configure ]; then autoreconf; fi"+ putSetup ("configure --prefix=%{_prefix} --libdir=%{_libdir} " +++ "--libsubdir='$compiler/$pkgid' " +++ (if (rpmLibProf flags) then "--enable" else "--disable") +++ "-library-profiling --" ++ cmplr)+ withLib pkgDesc () $ \_ -> do+ hPutStr h "if "+ putSetup "makefile -f cabal-rpm.mk"+ put "then"+ put " make -f cabal-rpm.mk %{_smp_mflags} || :"+ put "fi"+ putSetup "build"+ withLib pkgDesc () $ \_ -> do+ when doHaddock $+ putSetup "haddock || :"+ putSetup "register --gen-script"+ putSetup "unregister --gen-script"+ putNewline+ putNewline++ put "%install"+ put "rm -rf ${RPM_BUILD_ROOT}"+ putSetup "copy --destdir=${RPM_BUILD_ROOT}"+ withLib pkgDesc () $ \_ -> do+ put "install -m 755 register.sh unregister.sh ${RPM_BUILD_ROOT}%{pkg_libdir}"+ put "cd ${RPM_BUILD_ROOT}"+ put "echo '%defattr(-,root,root,-)' > %{_builddir}/%{?buildsubdir}/%{name}-files.prof"+ put "find .%{pkg_libdir} \\( -name '*_p.a' -o -name '*.p_hi' \\) | sed s/^.// >> %{_builddir}/%{?buildsubdir}/%{name}-files.prof"+ put "echo '%defattr(-,root,root,-)' > %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"+ put "find .%{pkg_libdir} ! \\( -name '*_p.a' -o -name '*.p_hi' \\) | sed s/^.// >> %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"+ put "sed 's,^/,%exclude /,' %{_builddir}/%{?buildsubdir}/%{name}-files.prof >> %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"+ put "rm -rf ${RPM_BUILD_ROOT}/%{_datadir}/%{pkg_name}-%{version}/doc"+ putNewline+ putNewline++ put "%clean"+ put "rm -rf ${RPM_BUILD_ROOT}"+ putNewline+ putNewline++ docs <- findDocs pkgDesc+ withLib pkgDesc () $ \_ -> do+ {- If we're upgrading to a library with the same Cabal+ name+version as the currently installed library (i.e. we've+ just bumped the release number), we need to unregister the+ old library first, so that the register script in %post may+ succeed.++ Note that this command runs *before* the new package's+ files are installed, and thus will execute the *previous*+ version's unregister script, if the script exists in the+ same location as the about-to-be-installed library's+ script. -}++ put "%pre -n %{hsc_namever}-%{name}"+ put "[ \"$1\" = 2 ] && %{pkg_libdir}/unregister.sh >&/dev/null || :"+ putNewline+ putNewline++ put "%post -n %{hsc_namever}-%{name}"+ put "%{pkg_libdir}/register.sh >&/dev/null"+ putNewline+ putNewline++ {- We must unregister an old version during an upgrade as+ well as during a normal removal, otherwise the Haskell+ runtime's package system will be left with a phantom record+ for a package it can no longer use. -}++ put "%preun -n %{hsc_namever}-%{name}"+ put "%{pkg_libdir}/unregister.sh >&/dev/null"+ putNewline+ putNewline++ {- If we're upgrading, the %preun step may have unregistered+ the *new* version of the library (if it had an identical+ Cabal name+version, even though the RPM release differs);+ therefore, we must attempt to re-register it. -}++ put "%postun -n %{hsc_namever}-%{name}"+ put "[ \"$1\" = 1 ] && %{pkg_libdir}/register.sh >& /dev/null || :"+ putNewline+ putNewline++ put "%files -n %{hsc_namever}-%{name} -f %{name}-files.nonprof"+ when doHaddock $+ put "%doc dist/doc/html"+ when ((not . null) docs) $+ put $ "%doc " ++ concat (intersperse " " docs)+ putNewline+ putNewline++ when (rpmLibProf flags) $ do+ put "%files -n %{hsc_namever}-%{name}-prof -f %{name}-files.prof"+ putNewline+ putNewline++ put "%files"+ put "%defattr(-,root,root,-)"+ withExe pkgDesc $ \exe -> put $ "%{_bindir}/" ++ exeName exe+ when ((not . null . dataFiles) pkgDesc) $+ put "%{_datadir}/%{pkg_name}-%{version}"++ -- Add the license file to the main package only if it wouldn't+ -- otherwise be empty.+ when ((not . null . licenseFile) pkgDesc &&+ ((not . null . executables) pkgDesc ||+ (not . null . dataFiles) pkgDesc)) $+ put $ "%doc " ++ licenseFile pkgDesc+ putNewline+ putNewline++ put "%changelog"+ put ("* " ++ date ++ " cabal-rpm <cabal-devel@haskell.org> - " +++ version ++ "-" ++ release)+ put "- spec file autogenerated by cabal-rpm"+ hClose h+ return (specPath, filter (`notElem` (extraSrcFiles pkgDesc)) docs)++findDocs :: PackageDescription -> IO [FilePath]++findDocs pkgDesc = do+ contents <- getDirectoryContents "."+ let docs = filter likely contents+ return $ if (null . licenseFile) pkgDesc+ then docs+ else let license = licenseFile pkgDesc+ in license : filter (/= license) docs+ where names = ["author", "copying", "doc", "example", "licence", "license",+ "readme", "todo"]+ likely name = let lowerName = map toLower name+ in any (`isPrefixOf` lowerName) names++-- | Take a Haskell package name, and turn it into a "virtual package"+-- that encodes the compiler name and version used.++virtualPackage :: Compiler -> String -> String+virtualPackage compiler name = name ++ '-' : compilerNameVersion compiler++compilerNameVersion :: Compiler -> String+compilerNameVersion (Compiler flavour (PackageIdentifier _ version) _ _ _) = name ++ squishedVersion+ where name = case flavour of+ GHC -> "ghc"+ Hugs -> "hugs"+ JHC -> "jhc"+ NHC -> "nhc"+ squishedVersion = (concat . map show . versionBranch) version++-- | Convert from license to RPM-friendly description. The strings are+-- taken from TagsCheck.py in the rpmlint distribution.++showLicense :: License -> String+showLicense GPL = "GPL"+showLicense LGPL = "LGPL"+showLicense BSD3 = "BSD"+showLicense BSD4 = "BSD-like"+showLicense PublicDomain = "Public Domain"+showLicense AllRightsReserved = "Proprietary"+showLicense OtherLicense = "Non-distributable"++-- | Determine whether a specific version of a Haskell package is "built+-- into" this particular version of the given compiler.++isBuiltIn :: CompilerFlavor+ -> Version+ -> Dependency+ -> Bool+isBuiltIn cn cv (Dependency pkg version) = maybe False checkVersion $ do+ (_, _, cb) <- find (\(n, v, _) -> (n,v) == (cn,cv)) builtIns+ (_, pv) <- find (\(pn, _) -> pn == pkg) cb+ return pv+ where checkVersion = flip withinRange version+ builtIns = [(GHC, Version [6,6,1] [], ghc661BuiltIns),+ (GHC, Version [6,6] [], ghc66BuiltIns)]+ v n x = (n, Version x [])+ ghc661BuiltIns = [+ v "base" [2,1,1],+ v "Cabal" [1,1,6,2],+ v "cgi" [3001,1,1],+ v "fgl" [5,4,1],+ v "filepath" [1,0],+ v "ghc" [6,6,1],+ v "GLUT" [2,1,1],+ v "haskell98" [1,0],+ v "haskell-src" [1,0,1],+ v "HGL" [3,1,1],+ v "html" [1,0,1],+ v "HUnit" [1,1,1],+ v "mtl" [1,0,1],+ v "network" [2,0,1],+ v "OpenAL" [1,3,1],+ v "OpenGL" [2,2,1],+ v "parsec" [2,0],+ v "QuickCheck" [1,0,1],+ v "readline" [1,0],+ v "regex-base" [0,72],+ v "regex-compat" [0,71],+ v "regex-posix" [0,71],+ v "rts" [1,0],+ v "stm" [2,0],+ v "template-haskell" [2,1],+ v "time" [1,1,1],+ v "unix" [2,1],+ v "X11" [1,2,1],+ v "xhtml" [3000,0,2]+ ]+ ghc66BuiltIns = [+ v "base" [2,0],+ v "Cabal" [1,1,6],+ v "cgi" [2006,9,6],+ v "fgl" [5,2],+ v "ghc" [6,6],+ v "GLUT" [2,0],+ v "haskell98" [1,0],+ v "haskell-src" [1,0],+ v "HGL" [3,1],+ v "html" [1,0],+ v "HTTP" [2006,7,7],+ v "HUnit" [1,1],+ v "mtl" [1,0],+ v "network" [2,0],+ v "OpenAL" [1,3],+ v "OpenGL" [2,1],+ v "parsec" [2,0],+ v "QuickCheck" [1,0],+ v "readline" [1,0],+ v "regex-base" [0,71],+ v "regex-compat" [0,71],+ v "regex-posix" [0,71],+ v "rts" [1,0],+ v "stm" [2,0],+ v "template-haskell" [2,0],+ v "time" [1,0],+ v "unix" [1,0],+ v "X11" [1,1],+ v "xhtml" [2006,9,13]+ ]++-- | Generate a string expressing runtime dependencies, but only+-- on package/version pairs not already "built into" a compiler+-- distribution.++showRuntimeReq :: Verbosity -> Compiler -> PackageDescription -> IO String++showRuntimeReq verbose c@(Compiler cFlav (PackageIdentifier _ cVersion) _ _ _)+ pkgDesc = do+ let externalDeps = filter (not . isBuiltIn cFlav cVersion)+ (buildDepends pkgDesc)+ clauses <- mapM (showRpmReq verbose (virtualPackage c)) externalDeps+ return $ (concat . intersperse ", " . concat) clauses++-- | Generate a string expressing package build dependencies, but only+-- on package/version pairs not already "built into" a compiler+-- distribution.++showBuildReq :: Verbosity -> Bool -> Compiler -> PackageDescription+ -> IO String++showBuildReq verbose haddock+ c@(Compiler cFlav (PackageIdentifier _ cVersion) _ _ _) pkgDesc =+ do+ cPkg <- case cFlav of+ GHC -> return "ghc"+ Hugs -> return "hugs98"+ _ -> die $ "unknown compiler " ++ show cFlav+ let myDeps = [Dependency cPkg (ThisVersion cVersion)] +++ if haddock then [Dependency "haddock" AnyVersion] else []+ externalDeps = filter (not . isBuiltIn cFlav cVersion)+ (buildDepends pkgDesc)+ exReqs <- mapM (showRpmReq verbose (virtualPackage c)) externalDeps+ myReqs <- mapM (showRpmReq verbose id) myDeps+ return $ (concat . intersperse ", " . concat) (myReqs ++ exReqs)++-- | Represent a dependency in a form suitable for an RPM spec file.++showRpmReq :: Verbosity -> (String -> String) -> Dependency -> IO [String]++showRpmReq verbose f (Dependency pkg AnyVersion) =+ return [f pkg]+showRpmReq verbose f (Dependency pkg (ThisVersion v)) =+ return [f pkg ++ " = " ++ showVersion v]+showRpmReq verbose f (Dependency pkg (EarlierVersion v)) =+ return [f pkg ++ " < " ++ showVersion v]+showRpmReq verbose f (Dependency pkg (LaterVersion v)) =+ return [f pkg ++ " > " ++ showVersion v]+showRpmReq verbose f (Dependency pkg (UnionVersionRanges+ (ThisVersion v1)+ (LaterVersion v2)))+ | v1 == v2 = return [f pkg ++ " >= " ++ showVersion v1]+showRpmReq verbose f (Dependency pkg (UnionVersionRanges+ (ThisVersion v1)+ (EarlierVersion v2)))+ | v1 == v2 = return [f pkg ++ " <= " ++ showVersion v1]+showRpmReq verbose f (Dependency pkg (UnionVersionRanges _ _)) = do+ warn verbose ("Cannot accurately represent " +++ "dependency on package " ++ f pkg)+ warn verbose " (uses version union, which RPM can't handle)"+ return [f pkg]+showRpmReq verbose f (Dependency pkg (IntersectVersionRanges r1 r2)) = do+ d1 <- showRpmReq verbose f (Dependency pkg r1)+ d2 <- showRpmReq verbose f (Dependency pkg r2)+ return (d1 ++ d2)++-- | Find the paths to all "extra" libraries specified in the package+-- config. Prefer shared libraries, since that's what gcc prefers.+findLibPaths :: BuildInfo -> IO [FilePath]++findLibPaths buildInfo = mapM findLib (extraLibs buildInfo)+ where findLib :: String -> IO FilePath+ findLib lib = do+ so <- findLibPath ("lib" ++ lib ++ ".so")+ if isJust so+ then return (fromJust so)+ else findLibPath ("lib" ++ lib ++ ".a") >>=+ maybe (die $ "could not find library: lib" ++ lib)+ return+ findLibPath extraLib = do+ loc <- findInExtraLibs (extraLibDirs buildInfo)+ if isJust loc+ then return loc+ else findWithGcc extraLib+ where findInExtraLibs (d:ds) = do+ let path = d </> extraLib+ exists <- doesFileExist path+ if exists+ then return (Just path)+ else findInExtraLibs ds+ findInExtraLibs [] = return Nothing++-- | Return the full path to a file (usually an object file) that gcc+-- knows about.++findWithGcc :: FilePath -> IO (Maybe FilePath)++findWithGcc lib = do+ (i,o,e,p) <- runInteractiveCommand $ "gcc -print-file-name=" ++ lib+ loc <- hGetLine o+ mapM_ hClose [i,o,e]+ waitForProcess p+ return $ if loc == lib then Nothing else Just loc++-- | Return the RPM that owns a particular file or directory. Die if+-- not owned.++findRpmOwner :: FilePath -> IO String+findRpmOwner path = do+ (i,o,e,p) <- runInteractiveCommand (rpmQuery ++ path)+ pkg <- hGetLine o+ mapM_ hClose [i,o,e]+ ret <- waitForProcess p+ case ret of+ ExitSuccess -> return pkg+ _ -> die $ "not owned by any package: " ++ path+ where rpmQuery = "rpm --queryformat='%{NAME}' -qf "++-- | Find all RPMs on which the build of this package depends. Die if+-- a dependency is not present, or not owned by an RPM.++findLibDeps :: BuildInfo -> IO [String]++findLibDeps buildInfo = findLibPaths buildInfo >>= mapM findRpmOwner
+ src/Distribution/Package/Rpm/Main.hs view
@@ -0,0 +1,29 @@+-- |+-- Module : Distribution.Package.Rpm.Main+-- Copyright : Bryan O'Sullivan 2007+--+-- Maintainer : Bryan O'Sullivan <bos@serpentine.com>+-- Stability : alpha+-- Portability : portable+--+-- Explanation: Main entry point for building RPM packages.++-- This software may be used and distributed according to the terms of+-- the GNU General Public License, incorporated herein by reference.++module Distribution.Package.Rpm.Main where++import Distribution.PackageDescription (packageDescription,+ readPackageDescription)+import Distribution.Package.Rpm (rpm)+import Distribution.Package.Rpm.Setup (RpmFlags (..), parseArgs)+import Distribution.Simple.Utils (defaultPackageDesc)+import System.Environment (getArgs)++main :: IO ()++main = do opts <- getArgs >>= parseArgs+ let verbosity = rpmVerbosity opts+ descPath <- defaultPackageDesc verbosity+ pkgDesc <- readPackageDescription verbosity descPath+ rpm (packageDescription pkgDesc) opts
+ src/Distribution/Package/Rpm/Setup.hs view
@@ -0,0 +1,128 @@+-- |+-- Module : Distribution.Package.Rpm.Setup+-- Copyright : Bryan O'Sullivan 2007+--+-- Maintainer : Bryan O'Sullivan <bos@serpentine.com>+-- Stability : alpha+-- Portability : portable+--+-- Explanation: Command line option processing for building RPM+-- packages.++-- This software may be used and distributed according to the terms of+-- the GNU General Public License, incorporated herein by reference.++module Distribution.Package.Rpm.Setup (+ RpmFlags(..)+ , parseArgs+ ) where++import Control.Monad (when)+import Distribution.Setup (defaultCompilerFlavor, CompilerFlavor(..))+import Distribution.Verbosity (Verbosity(..), flagToVerbosity, normal)+import System.Console.GetOpt (ArgDescr (..), ArgOrder (..), OptDescr (..),+ usageInfo, getOpt')+import System.Environment (getProgName)+import System.Exit (exitWith, ExitCode (..))+import System.IO (Handle, hPutStrLn, stderr, stdout)++data RpmFlags = RpmFlags+ {+ rpmCompiler :: Maybe CompilerFlavor+ , rpmGenSpec :: Bool+ , rpmHaddock :: Bool+ , rpmHelp :: Bool+ , rpmLibProf :: Bool+ , rpmName :: Maybe String+ , rpmOptimisation :: Bool+ , rpmRelease :: Maybe String+ , rpmSplitObjs :: Bool+ , rpmTopDir :: Maybe FilePath+ , rpmVerbosity :: Verbosity+ , rpmVersion :: Maybe String+ }+ deriving (Eq, Show)++emptyRpmFlags :: RpmFlags++emptyRpmFlags = RpmFlags+ {+ rpmCompiler = defaultCompilerFlavor+ , rpmGenSpec = False+ , rpmHaddock = True+ , rpmHelp = False+ , rpmLibProf = True+ , rpmName = Nothing+ , rpmOptimisation = True+ , rpmRelease = Nothing+ , rpmSplitObjs = True+ , rpmTopDir = Nothing+ , rpmVerbosity = normal+ , rpmVersion = Nothing+ }++options :: [OptDescr (RpmFlags -> RpmFlags)]++options =+ [+ Option "" ["ghc"] (NoArg (\x -> x { rpmCompiler = Just GHC }))+ "Compile with GHC",+ Option "" ["hugs"] (NoArg (\x -> x { rpmCompiler = Just Hugs }))+ "Compile with Hugs",+ Option "" ["jhc"] (NoArg (\x -> x { rpmCompiler = Just JHC }))+ "Compile with JHC",+ Option "" ["nhc"] (NoArg (\x -> x { rpmCompiler = Just NHC }))+ "Compile with NHC",+ Option "" ["gen-spec"] (NoArg (\x -> x { rpmGenSpec = True }))+ "Generate a spec file, nothing more",+ Option "h?" ["help"] (NoArg (\x -> x { rpmHelp = True }))+ "Show this help text",+ Option "" ["name"] (ReqArg (\name x -> x { rpmName = Just name }) "NAME")+ "Override the default package name",+ Option "" ["disable-haddock"] (NoArg (\x -> x { rpmHaddock = False }))+ "Don't generate API docs",+ Option "" ["disable-library-profiling"] (NoArg (\x -> x { rpmLibProf = False }))+ "Don't generate profiling libraries",+ Option "" ["disable-optimisation"] (NoArg (\x -> x { rpmOptimisation = False }))+ "Don't generate optimised code",+ Option "" ["disable-optimization"] (NoArg (\x -> x { rpmOptimisation = False }))+ "Don't generate optimised code",+ Option "" ["disable-split-objs"] (NoArg (\x -> x { rpmSplitObjs = False }))+ "Don't split object files up to save space",+ Option "" ["release"] (ReqArg (\rel x -> x { rpmRelease = Just rel }) "RELEASE")+ "Override the default package release",+ Option "" ["topdir"] (ReqArg (\path x -> x { rpmTopDir = Just path }) "TOPDIR")+ "Override the default build directory",+ Option "v" ["verbose"] (ReqArg (\verb x -> x { rpmVerbosity = flagToVerbosity (Just verb) }) "n")+ "Override the default build directory",+ Option "" ["version"] (ReqArg (\vers x -> x { rpmVersion = Just vers }) "VERSION")+ "Override the default package version"+ ]++printHelp :: Handle -> IO ()++printHelp h = do+ progName <- getProgName+ hPutStrLn h (usageInfo "Usage:" options)++parseArgs :: [String] -> IO RpmFlags++parseArgs args = do+ let (os, args', unknown, errs) = getOpt' RequireOrder options args+ opts = foldl (flip ($)) emptyRpmFlags os+ when (rpmHelp opts) $ do+ printHelp stdout+ exitWith ExitSuccess+ when (not (null errs)) $ do+ hPutStrLn stderr "Errors:"+ mapM_ (hPutStrLn stderr) errs+ exitWith (ExitFailure 1)+ when (not (null unknown)) $ do+ hPutStrLn stderr "Unrecognised options:"+ mapM_ (hPutStrLn stderr) unknown+ exitWith (ExitFailure 1)+ when (not (null args')) $ do+ hPutStrLn stderr "Unrecognised arguments:"+ mapM_ (hPutStrLn stderr) args'+ exitWith (ExitFailure 1)+ return opts