packages feed

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 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