packages feed

cabal2spec (empty) → 1.0

raw patch · 4 files changed

+356/−0 lines, 4 filesdep +Cabaldep +Unixutilsdep +basesetup-changed

Dependencies added: Cabal, Unixutils, base, bytestring, directory, filepath, haskell98, old-locale, process, tar, time, unix, zlib

Files

+ LICENSE view
@@ -0,0 +1,13 @@+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 3 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, see <http://www.gnu.org/licenses/>.+
+ Main.hs view
@@ -0,0 +1,322 @@+{- c2shs - Generate a .spec file from a cabalised source tarball+ - Copyright (C) 2009 Conrad Meyer <cemeyer@u.washington.edu>+ -+ - 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 3 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, see <http://www.gnu.org/licenses/>.+ -}++import qualified Codec.Archive.Tar as Tar+import qualified Codec.Compression.GZip as GZip+import Control.Monad+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.Char8 as C+import Data.List+import Data.Time.Clock+import Data.Time.Format+import qualified Data.Version as DV+import qualified Distribution.ModuleName as DMN+import qualified Distribution.Package as DP+import qualified Distribution.PackageDescription as DPD+import Distribution.PackageDescription.Parse+import qualified Distribution.Verbosity as Verbosity+import IO+import System+import System.Console.GetOpt+import System.Directory+import System.Exit+import System.FilePath+import qualified System.Locale as SL+import qualified System.IO as IO+import qualified System.Posix.Directory as PD+import System.Posix.Files+import System.Unix.Directory+import System.Process++version = "c2shs 0.01"++data Options = Options { optPackager :: Maybe String+                       , stdout :: Maybe IO.Handle }++startOptions :: Options+startOptions = Options { optPackager = Nothing+                       , Main.stdout = Nothing }++options :: [ OptDescr (Options -> IO Options) ]+options =+  [ Option "p" ["packager"]+      (ReqArg+          (\arg opt -> return opt { optPackager = Just arg })+          "PACKAGER")+      "Packager and email tag for ChangeLog"++  , Option "s" ["stdout"]+      (NoArg+          (\opt -> return opt { Main.stdout = Just IO.stdout } ))+      "Print version"++  , Option "v" ["version"]+      (NoArg+          (\_ -> do+              hPutStrLn stderr version+              exitWith ExitSuccess))+      "Print version"++  , Option "h" ["help"]+      (NoArg+          (\_ -> do+              prg <- getProgName+              hPutStrLn stderr (usageInfo prg options)+              exitWith ExitSuccess))+      "Show help"+  ]++main :: IO ()+main = do+  args <- getArgs+  let (actions, nonOptions, errors) = getOpt RequireOrder options args+  opts <- foldl (>>=) (return startOptions) actions+  let Options { optPackager = author } = opts+  let Options { Main.stdout = stdoutMaybe } =  opts+  authorStr <- case author of+                 Just str -> return str+                 Nothing -> do+                             putStrLn "No packager supplied!"+                             exitFailure+  if (length nonOptions) /= 1+     then do prg <- getProgName+             hPutStrLn stderr (usageInfo prg options)+             exitSuccess+     else do let cabalFile = head nonOptions+             if ".cabal" `isSuffixOf` cabalFile+                then genSpec cabalFile authorStr stdoutMaybe+                else do cabalFile <- extractCabal cabalFile+                        genSpec cabalFile authorStr stdoutMaybe++-- Used to be in tar, but now we had to recreate it+extractTarData :: FilePath -> B.ByteString -> IO ()+extractTarData dir bytes = Tar.unpack dir . Tar.read =<< return bytes++extractCabal :: FilePath -> IO FilePath+extractCabal file = do+  fileContents <- B.readFile file+  let tarContents = GZip.decompress fileContents+  cwd <- getCurrentDirectory+  tmpdir <- getTemporaryDirectory+  PD.changeWorkingDirectory tmpdir+  -- make temporary working directory+  dirname <- mkdtemp "c2shs-XXXXXX"+  PD.changeWorkingDirectory dirname+  extractTarData "." tarContents+  dirContents <- getDirectoryContents "."+  let normalFiles = filter (\x -> and [x /= ".", x /= ".."]) dirContents+  PD.changeWorkingDirectory (head normalFiles)+  subdirContents <- getDirectoryContents "."+  cabalFile <- canonicalizePath $ head (filter (\x -> ".cabal" `isSuffixOf` x) subdirContents)+  PD.changeWorkingDirectory cwd+  return $ cabalFile++genSpec :: FilePath -> String -> Maybe IO.Handle -> IO ()+genSpec cabalFile author stdoutMaybe = do+  pd <- readPackageDescription Verbosity.normal cabalFile+  processCabal pd author stdoutMaybe++licenseTab :: [(String,String)]+licenseTab = [("BSD3", "BSD")+             ,("BSD4", "BSD")+             ,("PublicDomain", "Public Domain")+             ]++licenseLookup :: String -> String+licenseLookup str = licenseLookupHelper str licenseTab++licenseLookupHelper :: String -> [(String,String)] -> String+licenseLookupHelper str [] = str+licenseLookupHelper str ((key,x) : xs) | str == key = x+                                       | otherwise  = licenseLookupHelper str xs++processCabal :: DPD.GenericPackageDescription -> String -> Maybe IO.Handle -> IO ()+processCabal gpd author stdoutMaybe = do+  let pd = DPD.packageDescription gpd+  let pflags = DPD.genPackageFlags gpd+  let lib = DPD.condLibrary gpd+  let exe = DPD.condExecutables gpd+  let copy = DPD.copyright pd+  let licenseTmp = licenseLookup (show (DPD.license pd))+  license <- if or [licenseTmp == "GPL", licenseTmp == "LGPL"]+               then licenseLookupFile licenseTmp (DPD.licenseFile pd)+               else return licenseTmp+  let pkgid = DPD.package pd+  let DP.PackageName pkgname = DP.pkgName pkgid+  let pkgversion = DP.pkgVersion pkgid+  let pkgversionlist = (DV.versionBranch pkgversion)+  let pkgversionstr = foldl (\s i -> s ++ "." ++ (show i)) (show (head pkgversionlist)) (tail pkgversionlist)+  let urlTmp = DPD.homepage pd+  let url = if null urlTmp+              then "http://hackage.haskell.org/cgi-bin/hackage-scripts/package/" ++ pkgname+              else urlTmp+  --let pkgurl = DPD.pkgUrl pd -- nothing uses these+  {- we print in a separate action+  putStr "Name: "+  print pkgname+  putStr "Version: "+  print pkgversionstr+  -}+  --print (DV.versionTags pkgversion) -- nothing uses these+  {- we print in a separate action+  putStr "License: "+  print license+  putStr "URL: "+  print url+  -}+  let summary = DPD.synopsis pd+  {- we print in a separate action+  putStr "Summary: "+  print summary+  -}+  let description = DPD.description pd+  {- we print in a separate action+  putStrLn "\n%description"+  putStrLn description+  putStrLn ""+  -}+  --print (DPD.category pd) -- not useful, I think+  let builddeps = map (\d -> let DP.Dependency (DP.PackageName s) _ = d in s) (DPD.buildDepends pd)+  {- we print in a separate action+  putStr "Build-Depends: "+  print builddeps+  -}+  --putStr "Librar(y|ies): "+  --print lib+  --putStr "Executable(s): "+  --print exe+  let has_lib = case (DPD.condLibrary gpd) of+                  Nothing -> False+                  Just _  -> True+  let has_bin = not (null (DPD.condExecutables gpd))+  --putStrLn $ "HAS_LIB: " ++ (show has_lib)+  --putStrLn $ "HAS_BIN: " ++ (show has_bin)+  stdout <- maybe (IO.openFile ((if has_lib && not has_bin then "ghc-" else "") ++ pkgname `replaceExtension` ".spec") IO.WriteMode) return stdoutMaybe+  if has_lib+    then if has_bin+      then renderBinLib stdout author pkgname pkgversionstr summary description builddeps url license+      else renderLib stdout author pkgname pkgversionstr summary description builddeps url license+    else if has_bin+      then renderBin stdout author pkgname pkgversionstr summary description builddeps url license+      else do+        putStrLn "Error: pkg is neither a library nor binary!"+        exitFailure+  IO.hClose stdout++licenseLookupFile :: String -> FilePath -> IO String+licenseLookupFile guess fn = do+  contents <- readFile fn+  {-+    Haskell packages rarely include licensing information inside their+    source files, so the best picture we can get is to use the LICENSE /+    COPYING files and guess the closest version (for things that need a+    specific version, i.e. LGPL and GPL).++    If GPL and no other information is present, return GPL+.+    If LGPL and no other info is present, return LGPLv2+.+  -}+  let contains x = x `isInfixOf` contents+  let license = licenseLookupFileHelper contains+  if license == "None"+    then if guess == "LGPL"+      then return "LGPLv2+"+      else return "GPL+"+    else if guess == "LGPL"+      then return ('L' : license)+      else return license++licenseLookupFileHelper :: (String -> Bool) -> String+licenseLookupFileHelper contains+  | contains "Version 1, February 1989"   = "GPLv1"+  | contains "Version 2, June 1991"       = "GPLv2"+  | contains "Version 3, 29 June 2007"    = "GPLv3"+  | contains "Version 2.1, February 1999" = "GPLv2"+  | contains+    "version 2.1 of the License, or (at your option) any later version." =+    "GPLv2+"+  | and [contains "either version 2"+        ,contains "or (at your option) any later version."] =+    "GPLv2+"+  | and [contains "either version 1, or"+        ,contains "any later version."] =+    "GPL+"+  | and [contains "either version 3 of the License"+        ,contains "any later version."] =+    "GPLv3+"+  | otherwise                             = "None"++replaceString :: B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString+replaceString str old new+    | B.null str = B.empty+    | otherwise = if old `B.isPrefixOf` str+                  then B.append new (replaceString (B.drop (B.length old) str) old new)+                  else B.cons (B.head str) (replaceString (B.tail str) old new)++replaceStringT :: B.ByteString -> (B.ByteString, B.ByteString) -> B.ByteString+replaceStringT str (old, new) = replaceString str old new++replaceStrings :: B.ByteString -> [(B.ByteString, B.ByteString)] -> B.ByteString+replaceStrings str oldnews = foldl replaceStringT str oldnews++packStrings :: [(String, String)] -> [(B.ByteString, B.ByteString)]+packStrings = map (\(x, y) -> (C.pack x, C.pack y))++fixDescription :: String -> String+fixDescription description =+  if null description+    then "This package provides the Haskell %{pkg_name} library/nbuilt for ghc-%{ghc_version}."+    else description+++replacements :: String -> String -> String -> String -> String -> [String] -> String -> String -> [(String, String)]+replacements author pkgname pkgversionstr summary description builddeps url license =+    [ ("@AUTHOR@", author)+    , ("@PACKAGE@", pkgname)+    , ("@VERSION@", pkgversionstr)+    , ("@SUMMARY@", summary)+    , ("@DESCRIPTION@", description)+    , ("@URL@", url)+    , ("@LICENSE@", license)]+++replacementsAndDate :: [(String, String)] -> IO [(String, String)]+replacementsAndDate replacement =+    do date <- getCurrentTime+       return $ ("@DATE@", (formatTime SL.defaultTimeLocale "%a %b %e %Y" date)):replacement++replacementsAndGhcVersion :: [(String, String)] -> IO [(String, String)]+replacementsAndGhcVersion replacement =+    do ghcversion <- readProcess "ghc" ["--numeric-version"] ""+       return $ ("@GHC_VERSION@", ghcversion):replacement++renderTemplate :: FilePath -> Handle -> String -> String -> String -> String -> String -> [String] -> String -> String -> IO ()+renderTemplate fp stdout author pkgname pkgversionstr summary description builddeps url license =+    do template <- B.readFile fp+       let desc = fixDescription description+       reps <- replacementsAndDate $ replacements author pkgname pkgversionstr summary desc builddeps url license+       reps <- replacementsAndGhcVersion reps+       B.hPut stdout $ replaceStrings template $ packStrings reps+       return ()++renderBin :: Handle -> String -> String -> String -> String -> String -> [String] -> String -> String -> IO ()+renderBin = renderTemplate "/etc/rpmdevtools/spectemplate-ghc-bin.spec"++renderLib :: Handle -> String -> String -> String -> String -> String -> [String] -> String -> String -> IO ()+renderLib = renderTemplate "/etc/rpmdevtools/spectemplate-ghc-lib.spec"++renderBinLib :: Handle -> String -> String -> String -> String -> String -> [String] -> String -> String -> IO ()+renderBinLib = renderTemplate "/etc/rpmdevtools/spectemplate-ghc-lib.spec"
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ cabal2spec.cabal view
@@ -0,0 +1,18 @@+name:               cabal2spec+version:            1.0+synopsis:           Generates RPM Spec files from cabal files+description:        This package provides specfile templates and a script cabal2spec for easy+		    packaging of Haskell Cabal packages (hackages) for ghc following+           	    the Fedora Haskell Packaging Guidelines and associated RPM macros.+category:           System+license:            GPL+license-file:       LICENSE+author:             Conrad Meyer, Yaakov M. Nemoy+homepage:           https://fedorahosted.org/cabal2spec/+maintainer:         konrad@tylerc.org+cabal-version:      >= 1.2+build-type:         Simple++executable cabal2spec+    main-is:            Main.hs+    build-depends:      base < 5, process, Unixutils, unix, old-locale, filepath, directory, haskell98, Cabal, time, bytestring, zlib, tar