cabal2arch 0.7.4 → 0.7.5
raw patch · 3 files changed
+187/−579 lines, 3 filesdep −pureMD5dep ~archlinuxdep ~basenew-component:exe:manycabal2archnew-uploader
Dependencies removed: pureMD5
Dependency ranges changed: archlinux, base
Files
- Main.hs +36/−568
- cabal2arch.cabal +23/−11
- scripts/manycabal2arch.hs +128/−0
Main.hs view
@@ -16,39 +16,23 @@ -- TODO: if build-type: Configure, accurate C library dependecies -- require downloading the source, and running configure ----- C libraries are dynamicall linked, should be listed in depends,+-- C libraries are dynamically linked, should be listed in depends, -- rather than makedepends -import Distribution.Package-import Distribution.PackageDescription import Distribution.PackageDescription.Parse-import Distribution.PackageDescription.Configuration import Distribution.Simple.Utils hiding (die) import Distribution.Verbosity-import Distribution.Version-import Distribution.Package-import Distribution.License import Distribution.Text-import Distribution.Compiler-import Distribution.System-import Distribution.Simple.PackageIndex -- from the archlinux package: import Distribution.ArchLinux.PkgBuild--import Data.Digest.Pure.MD5-import qualified Data.ByteString.Lazy as B+import Distribution.ArchLinux.CabalTranslation import Control.Monad import Control.Concurrent import qualified Control.OldException as C import Data.List-import Data.Maybe-import qualified Data.Map as M-import Data.Monoid-import Data.Char-import Debug.Trace import Text.PrettyPrint @@ -59,8 +43,15 @@ import System.Exit import System.FilePath import System.IO-import System.Process+import System.Process hiding(cwd) +comment :: String+comment = render $ vcat+ [ text "# Note: we list all package dependencies."+ , text "# Your package tool should understand 'provides' syntax"+ , text "#"+ , text "# Keep up to date on http://archhaskell.wordpress.com/"+ , text "#"] main :: IO () main =@@ -101,26 +92,15 @@ cabalsrc <- readPackageDescription normal cabalfile -- Create a package description with all configurations resolved.- let e_finalcabalsrc = finalizePackageDescription- []- (const True) -- could check against prefered pkgs....- (Platform X86_64 buildOS) -- linux/x86_64- (CompilerId GHC (Version [6,10,3] []))-- -- now constrain it to solve in the context of a modern ghc only- corePackages- cabalsrc-- finalcabal <- case e_finalcabalsrc of- Left deps -> die $ "Unresolved dependencies: " ++show deps- Right (pkg,_) ->- return $ pkg { buildDepends = removeCoreFrom (buildDepends pkg) }-- let (pkgbuild', hooks) = cabal2pkg finalcabal+ let finalcabal = preprocessCabal cabalsrc+ finalcabal' <- case finalcabal of+ Nothing -> die "Aborting..."+ Just f -> return f+ let (pkgbuild', hooks) = cabal2pkg finalcabal' pkgbuild <- getMD5 pkgbuild'- let doc = pkg2doc email pkgbuild-+ let apkgbuild = AnnotatedPkgBuild { pkgBuiltWith = Just version, pkgHeader = comment, pkgBody = pkgbuild }+ doc = pkg2doc email apkgbuild dir = arch_pkgname pkgbuild setCurrentDirectory cwd@@ -163,132 +143,31 @@ ------------------------------------------------------------------------ --- | Given an abstract pkgbuild, download the source bundle,--- and compute its md5, returning a modified PkgBuild with--- the md5 set.------ TODO we may want to use a local package.+-- | Given an abstract pkgbuild, run "makepkg -g" to compute md5+-- of source files (possibly cached locally), and modify the PkgBuild+-- accordingly. -- getMD5 :: PkgBuild -> IO PkgBuild-getMD5 pkg@(PkgBuild { arch_source = ArchList [url] }) = do- hPutStrLn stderr $ "Fetching " ++ url- hFlush stderr- eres <- myReadProcess "wget" [url] []+getMD5 pkg = do+ putStrLn "Feeding the PKGBUILD to `makepkg -g`..."+ eres <- readProcessWithExitCode "makepkg" ["-g"] (render $ disp pkg) case eres of- Left (_,s,_) -> do- hPutStrLn stderr s- hPutStrLn stderr $ "Couldn't download package: " ++ show url+ (ExitFailure _,_,err) -> do+ hPutStrLn stderr err+ hPutStrLn stderr $ "makepkg encountered an error while calculating MD5." return pkg- Right _ -> do- src <- B.readFile (takeBaseName url <.> "gz")- let !md5sum = show (md5 src)- return pkg { arch_md5sum = ArchList [md5sum] }+ (ExitSuccess,out,err) -> do+ -- s should be "md5sums=(' ... ')"+ hPutStrLn stderr err+ if "md5sums=('" `isPrefixOf` out+ then+ let md5sum = takeWhile (\x -> x `elem` "0123456789abcdef") $ drop 10 out+ in return pkg { arch_md5sum = ArchList [md5sum] }+ else do+ hPutStrLn stderr $ "Incorrect output from makepkg."+ return pkg getMD5 _ = die "Malformed PkgBuild" --- attempt to filter out core packages we've already satisified--- not actuall correct, since it doesn't take any version--- info into account.------ TODO this should use configDependency to find the precise--- versions we have available on Arch.----removeCoreFrom :: [Dependency] -> [Dependency]-removeCoreFrom [] = []-removeCoreFrom (x@(Dependency n vr):xs) =- case find (\(Dependency k _) -> n == k) corePackages of- -- haskell-parsec, haskell-quickcheck- Just (Dependency _ (ThisVersion v'))- | withinRange v' vr -> removeCoreFrom xs-- Just (Dependency (PackageName "base") _)- -> removeCoreFrom xs-- Just (Dependency _ AnyVersion) -> removeCoreFrom xs- _ -> x : removeCoreFrom xs------- Core packages and their versions. These come with--- ghc, so we should be right.------ http://haskell.org/haskellwiki/Libraries_released_with_GHC------ And what Arch Linux thinks GHC provides:------ http://repos.archlinux.org/wsvn/packages/ghc/repos/extra-x86_64/PKGBUILD------ Note: we could just list these directly, and have yaourt solve them.------ NEW POLICY:--- We rely on all "provides" from the GHC library to be listed explicitly.----corePackages :: [Dependency]-corePackages =- [---- Magic packages we have to remove- Dependency (PackageName "base") (ThisVersion (Version [4,1,0,0] []))- ,Dependency (PackageName "dph-base") (AnyVersion)- ,Dependency (PackageName "dph-par" ) (AnyVersion)- ,Dependency (PackageName "dph-prim-interface") (AnyVersion)- ,Dependency (PackageName "dph-prim-par" ) (AnyVersion)- ,Dependency (PackageName "dph-prim-seq" ) (AnyVersion)- ,Dependency (PackageName "dph-seq" ) (AnyVersion)- ,Dependency (PackageName "ghc") (AnyVersion)- ,Dependency (PackageName "ghc-prim") (AnyVersion)- ,Dependency (PackageName "integer") (AnyVersion)- ,Dependency (PackageName "integer-gmp") (AnyVersion)- ,Dependency (PackageName "ghc-binary") (AnyVersion)---- Official Provides: http://repos.archlinux.org/wsvn/packages/ghc/repos/extra-x86_64/PKGBUILD--- ,Dependency (PackageName "array") (ThisVersion (Version [0,3,0,0] []))--- ,Dependency (PackageName "bytestring") (ThisVersion (Version [0,9,1,5] []))--- ,Dependency (PackageName "Cabal") (ThisVersion (Version [1,8,0,2] []))--- ,Dependency (PackageName "containers") (ThisVersion (Version [0,3,0,0] []))--- ,Dependency (PackageName "directory") (ThisVersion (Version [1,0,1,0] []))--- ,Dependency (PackageName "extensible-exceptions") (AnyVersion)--- ,Dependency (PackageName "filepath") (ThisVersion (Version [1,1,0,3] []))--- ,Dependency (PackageName "haskell98") (ThisVersion (Version [1,0,1,1] []))--- ,Dependency (PackageName "hpc") (ThisVersion (Version [0,5,0,4] []))--- ,Dependency (PackageName "old-locale") (ThisVersion (Version [1,0,0,2] []))--- ,Dependency (PackageName "old-time") (ThisVersion (Version [1,0,0,1] []))--- ,Dependency (PackageName "pretty") (ThisVersion (Version [1,0,1,1] []))--- ,Dependency (PackageName "process") (ThisVersion (Version [1,0,1,2] []))--- ,Dependency (PackageName "random") (ThisVersion (Version [1,0,0,2] []))--- ,Dependency (PackageName "syb") (ThisVersion (Version [0,1,0,2] []))--- ,Dependency (PackageName "template-haskell") (ThisVersion (Version [2,4,0,0] []))--- ,Dependency (PackageName "time") (ThisVersion (Version [1,1,4] []))--- ,Dependency (PackageName "unix") (ThisVersion (Version [2,4,0,0] []))--- utf8-string----- Removed in 6.12.x--- ,Dependency (PackageName "html") (ThisVersion (Version [1,0,1,2] []))--- ,Dependency (PackageName "integer") (ThisVersion (Version [0,1,0,0] []))--- ,Dependency (PackageName "QuickCheck") (ThisVersion (Version [1,2,0,0] []))--- ,Dependency (PackageName "haskell-src") (ThisVersion (Version [1,0,1,3] []))--- ,Dependency (PackageName "parsec") (ThisVersion (Version [2,1,0,0] []))--- ,Dependency (PackageName "packedstring") (ThisVersion (Version [0,1,0,1] []))--- ,Dependency (PackageName "parallel") (ThisVersion (Version [1,1,0,0] []))--- ,Dependency (PackageName "network") (ThisVersion (Version [2,2,0,1] []))--- ,Dependency (PackageName "mtl") (ThisVersion (Version [1,1,0,2] []))--- ,Dependency (PackageName "stm") (ThisVersion (Version [2,1,1,2] []))--- ,Dependency (PackageName "HUnit") (ThisVersion (Version [1,2,0,3] []))--- ,Dependency (PackageName "xhtml") (ThisVersion (Version [3000,2,0,1] []))--- ,Dependency (PackageName "regex-base") (ThisVersion (Version [0,72,0,2] []))--- ,Dependency (PackageName "regex-compat") (ThisVersion (Version [0,71,0,1] []))--- ,Dependency (PackageName "regex-posix") (ThisVersion (Version [0,72,0,2] []))---- Removed in 6.10.x--- ,Dependency (PackageName "editline") (AnyVersion)--- Dependency (PackageName "ALUT") (ThisVersion (Version [2,1,0,0] []))--- ,Dependency (PackageName "cgi") (ThisVersion (Version [3001,1,5,1] []))--- ,Dependency (PackageName "fgl") (ThisVersion (Version [5,4,1,1] [])) -- gone--- ,Dependency (PackageName "GLUT") (ThisVersion (Version [2,1,1,1] []))--- ,Dependency (PackageName "OpenAL") (ThisVersion (Version [1,3,1,1] [])) -- gone--- ,Dependency (PackageName "readline") (ThisVersion (Version [1,0,1,0] []))-- ]- -- Return the path to a .cabal file. -- If not arguments are specified, use ".", -- if the argument looks like a url, download that@@ -333,412 +212,7 @@ then die $ "directory doesn't exist: " ++ show dir else findPackageDesc dir -findCLibs :: PackageDescription -> [String]-findCLibs (PackageDescription { library = lib, executables = exe }) =- -- warn for packages not in list.- filter (not . null) $ map (canonicalise . map toLower) (some ++ rest)- where- some = concatMap (extraLibs.buildInfo) exe- rest = case lib of- Nothing -> []- Just l -> extraLibs (libBuildInfo l) ++- map (\(Dependency (PackageName n) _) ->- if '-' `elem` n - then reverse . drop 1 . dropWhile (/= '-') . reverse $ n- else n)- (pkgconfigDepends (libBuildInfo l))-- canonicalise k = case M.lookup k translationTable of- Nothing -> trace ("WARNING: this library depends on a C library we do not know the pacman name for (" ++ map toLower k ++ ") . Check the C library names in the generated PKGBUILD File") $ map toLower k- Just s -> s-- -- known pacman packages for C libraries we use:- translationTable = M.fromList- [("Imlib2", "imlib2")- ,("SDL", "sdl")- ,("alut", "freealut")- ,("bz2", "bzip2")- ,("cblas", "blas")- ,("crack", "cracklib")- ,("crypto", "openssl")- ,("curl", "curl")- ,("freetype", "freetype2")- ,("glib", "glib2")- ,("wmflite", "libwmf")- ,("il", "devil")-- ,("jpeg", "libjpeg")- ,("ldap", "libldap")- ,("pcap", "libpcap")- ,("png", "libpng")- ,("x11", "libx11")- ,("xrandr", "libxrandr")- ,("xml2", "libxml2")- ,("exif", "libexif")- ,("tiff", "libtiff")- ,("sndfile", "libsndfile")- ,("gcrypt", "libgcrypt")- ,("fftw3", "fftw")-- ,("pq", "postgresql")- ,("ssl", "openssl")- ,("wx", "wxgtk")- ,("xenctrl", "xen")- ,("odbc", "unixodbc")- ,("z", "zlib")- ,("curses", "ncurses")- ,("xslt", "libxslt")- ,("csound64", "csound5")- ,("uuid", "e2fsprogs")- ,("doublefann", "fann")- ,("ev", "libev")-- ,("pthread", "")- ,("m", "")- ,("gl", "")- ,("glu", "")- ,("db_cxx", "")- ,("db_cxx", "")- ,("xdamage", "")-- ,("icui18n", "icu")- ,("icuuc", "icu")- ,("icudata", "icu")-- ,("netsnmp", "net-snmp")- ,("asound", "alsa-lib")- ,("ffi", "libffi")- ,("ogg", "libogg")- ,("theora", "libtheora")- ,("mtp", "libmtp")- ,("zmq", "zeromq")- ,("cv", "opencv")- ,("highgui", "opencv")- ,("xss", "libxss")- ,("idn", "libidn")- ,("libgsasl", "gsasl")- ,("event", "libevent")- ,("gcc_s", "gcc-libs")--- -- subsumed into glib-- ,("gobject", "")- ,("gmodule", "glib2")- ,("gio", "")- ,("gthread", "")- ,("gnome-vfs-module", "")- ,("gstreamer-audio", "")- ,("gstreamer-base", "")- ,("gstreamer-controller", "")- ,("gstreamer-dataprotocol", "")- ,("gstreamer-net", "")- ,("ogremain", "")- ,("gnutls-extra", "")- ,("pangocairo", "pango")-- ,("webkit", "libwebkit")- ,("gtk+", "gtkglext")- ,("gdk", "gtk")- ,("gdk-x11-2.0", "gtk")- ,("gtk-x11-2.0", "gtk")- ,("xine", "xine-lib")- ,("ncursesw", "ncurses")- ,("panel", "ncurses")-- ,("gstreamer", "gstreamer0.10")- ,("gstreamer-plugins-base", "gstreamer0.10-base")- ]- -- atlas--shouldNotBeLibraries :: [String]-shouldNotBeLibraries =- ["xmonad"- ,"gitit"- ,"yavie"- ,"berp"- ,"l-seed"- ,"hspresent"- ,"haskell-platform"- ,"xmonad-contrib"- ,"lambdabot"- ,"piet"- ,"hsffig"- ,"yi"- ,"haddock"- ,"hscolour"- ,"line2pdf"- ,"distract"- ,"derive"- ,"Hedi"- ,"conjure"- ,"clevercss"- ,"cpphs"- ,"backdropper"- ,"darcs-beta"- ,"gtk2hs"- ,"darcs"- ,"greencard"--- the pandoc package doesnt' ship haskell-pandoc--- ,"pandoc"- ,"pugs-drift"- ,"wol"- ,"timepiece"- ,"hledger"- ,"hp2any-graph"- ,"hp2any-manager"- ]---- translate some library dependencies to gtk names----gtk2hsIfy :: [Dependency] -> [Dependency]-gtk2hsIfy = id--{--gtk2hsIfy [] = []-gtk2hsIfy xs | foundSome = Dependency (PackageName "gtk2hs") AnyVersion :- [ v | v@(Dependency n _) <- xs- , n `notElem` gtkLibs ]- | otherwise = xs-- where- foundSome = not . null $ filter (`elem` gtkLibs) (map unDep xs)- unDep (Dependency n _) = n--}---- TODO: will need to remove this:-gtkLibs :: [PackageName]-gtkLibs = map PackageName- []- {-- ["glade" -- guihaskell- ,"cairo"- ,"glib"- ,"gtk"- ,"gconf"- ,"gtkglext"- ,"gtksourceview2"- ,"mozembed"- ,"svgcairo"- ]- -}-- --------------------------------------------------------------------------- Parsing and pretty printing:------- | Translate an abstract PkgBuild file into a document structure----pkg2doc :: String -> PkgBuild -> Doc-pkg2doc email pkg = vcat- [ text "# Contributor:"- <+> text email- , text "# Package generated by cabal2arch" <+> disp version- , text "# Note: we list all package dependencies."- , text "# Your package tool should understand 'provides' syntax"- , text "#"- , text "# Keep up to date on http://archhaskell.wordpress.com/"- , text "#"- , text "pkgname"- <=> text (arch_pkgname pkg)- , text "pkgrel"- <=> int (arch_pkgrel pkg)- , text "pkgver"- <=> disp (arch_pkgver pkg)- , text "pkgdesc"- <=> text (show (arch_pkgdesc pkg))- , text "url"- <=> doubleQuotes (text (arch_url pkg))- , text "license"- <=> disp (arch_license pkg)- , text "arch"- <=> disp (arch_arch pkg)- , text "makedepends"- <=> disp (arch_makedepends pkg)- , case arch_depends pkg of- ArchList [] -> empty- _ -> text "depends" <=> disp (arch_depends pkg)- , text "options" <=> disp (arch_options pkg)- , text "source"- <=> dispNoQuotes (arch_source pkg)- , case arch_install pkg of- Nothing -> empty- Just p -> text "install" <=> disp p- , text "md5sums"- <=> disp (arch_md5sum pkg)- , hang- (text "build() {") 4- (vcat $ (map text) (arch_build pkg))- $$ char '}'- ]------- | Tranlsate a generic cabal file into a PGKBUILD----cabal2pkg :: PackageDescription -> (PkgBuild, Maybe String)-cabal2pkg cabal---- TODO decide if its a library or an executable,--- handle mullltipackages--- extract C dependencies---- = trace (show cabal) $- =- (emptyPkgBuild- { arch_pkgname = archName- , arch_pkgver = vers- , arch_url = "http://hackage.haskell.org/package/"++display name- -- else homepage cabal- , arch_pkgdesc = case synopsis cabal of- [] -> take 80 (description cabal)- s -> s- , arch_license =- ArchList . return $- case license cabal of- x@GPL {} -> x- x@LGPL {} -> x- l -> UnknownLicense ("custom:"++ show l)-- -- All Hackage packages depend on GHC at build time- -- All Haskell libraries are prefixed with "haskell-"- , arch_makedepends = if not hasLibrary- then my_makedepends- else ArchList [] -- makedepends should not duplicate depends-- , arch_depends =- (if not (isLibrary)- then- ArchList [ArchDep (Dependency (PackageName "gmp") AnyVersion)]- `mappend`- anyClibraries- else ArchList [])- `mappend`- -- libraries have 'register-time' dependencies on- -- their dependent Haskell libraries.- --- (if hasLibrary then my_makedepends- else ArchList [])-- -- need the dependencies of all flags that are on by default, for all libraries and executables-- -- Hackage programs only need their own source to build- , arch_source = ArchList . return $- "http://hackage.haskell.org/packages/archive/"- ++ (display name </> display vers </> display name <-> display vers <.> "tar.gz")-- , arch_build =- [ "cd ${srcdir}/" </> display name <-> display vers- , "runhaskell Setup configure --prefix=/usr --docdir=/usr/share/doc/${pkgname} || return 1"- , "runhaskell Setup build || return 1"- ] ++-- -- Only needed for libraries:- (if hasLibrary- then- [ "runhaskell Setup haddock || return 1"- , "runhaskell Setup register --gen-script || return 1"- , "runhaskell Setup unregister --gen-script || return 1"- , "install -D -m744 register.sh ${pkgdir}/usr/share/haskell/$pkgname/register.sh"- , "install -m744 unregister.sh ${pkgdir}/usr/share/haskell/$pkgname/unregister.sh"- , "install -d -m755 $pkgdir/usr/share/doc/ghc/html/libraries"- , "ln -s /usr/share/doc/${pkgname}/html ${pkgdir}/usr/share/doc/ghc/html/libraries/" ++ (display name)- ]- else [])- ++- ["runhaskell Setup copy --destdir=${pkgdir} || return 1"]- ++- (if not (null (licenseFile cabal)) && (case license cabal of GPL {} -> False; LGPL {} -> False; _ -> True)- then- [ "install -D -m644 " ++ licenseFile cabal ++ " ${pkgdir}/usr/share/licenses/$pkgname/LICENSE || return 1"- , "rm -f ${pkgdir}/usr/share/doc/${pkgname}/LICENSE"- ]- else [])-- -- if its a library:- , arch_install = if hasLibrary then Just $ install_hook_name archName- else Nothing-- }, if hasLibrary- then Just (install_hook archName)- else Nothing- )-- where- archName = map toLower (if isLibrary then "haskell-" ++ display name else display name)- name = pkgName (package cabal)- vers = pkgVersion (package cabal)-- -- build time dependencies- my_makedepends =- (arch_makedepends emptyPkgBuild)- `mappend`- -- Haskell libraries- -- TODO: use a real package spec to compute these names- -- based on what is in Arch.- ArchList- [ ArchDep (Dependency (PackageName $- if d `notElem` shouldNotBeLibraries- then "haskell" <-> map toLower (display d) else display d) v)- | Dependency (PackageName d) v <- gtk2hsIfy (buildDepends cabal) ]- `mappend`- anyClibraries- `mappend`- ArchList [ ArchDep d' | b <- allBuildInfo cabal- , d@(Dependency n _) <- buildTools b- , n /= PackageName "hsc2hs"- , let d' | n `elem` gtkTools- = Dependency (PackageName "gtk2hs-buildtools") AnyVersion- | otherwise = d- ]-- gtkTools = map PackageName ["gtk2hsTypeGen" , "gtk2hsHookGenerator", "gtk2hsC2hs"]-- -- TODO: need a 'nub' in here.-- hasLibrary = isJust (library cabal)- isLibrary = isJust (library cabal) -- && null (executables cabal)- && map toLower (display name) `notElem` shouldNotBeLibraries-- anyClibraries | null libs = ArchList []- | otherwise = ArchList libs- where- libs = [ ArchDep (Dependency (PackageName s) AnyVersion) | s <- nub (findCLibs cabal) ]---- quickcheck 2.--- parsec 3------- post install, and pre-remove hooks to run, to sync up ghc-pkg----install_hook_name :: String -> String-install_hook_name pkgname = pkgname <.> "install"--install_hook :: String -> String-install_hook pkgname = unlines- [ "HS_DIR=/usr/share/haskell/" ++ pkgname- , "post_install() {"- , " ${HS_DIR}/register.sh"- , " (cd /usr/share/doc/ghc/html/libraries; ./gen_contents_index)"- , "}"- , "pre_upgrade() {"- , " ${HS_DIR}/unregister.sh"- , "}"- , "post_upgrade() {"- , " ${HS_DIR}/register.sh"- , " (cd /usr/share/doc/ghc/html/libraries; ./gen_contents_index)"- , "}"- , "pre_remove() {"- , " ${HS_DIR}/unregister.sh"- , "}"- , "post_remove() {"- , " (cd /usr/share/doc/ghc/html/libraries; ./gen_contents_index)"- , "}"- , "op=$1"- , "shift"- , "$op $*" ]-------------------------------------------------------------------------- -- Some extras -- @@ -768,12 +242,6 @@ die s = do hPutStrLn stderr $ "cabal2pkg:\n" ++ s exitWith (ExitFailure 1)--(<=>) :: Doc -> Doc -> Doc-x <=> y = x <> char '=' <> y--(<->) :: String -> String -> String-x <-> y = x ++ "-" ++ y -- Safe wrapper for getEnv getEnvMaybe :: String -> IO (Maybe String)
cabal2arch.cabal view
@@ -1,29 +1,41 @@ name: cabal2arch-version: 0.7.4-homepage: http://code.haskell.org/~dons/code/cabal2arch-synopsis: Create Arch Linux packages from Cabal packages-description: Create Arch Linux packages from Cabal packages+version: 0.7.5+homepage: http://github.com/archhaskell/+synopsis: Create Arch Linux packages from Cabal packages.+description: Create Arch Linux packages from Cabal packages. category: Distribution license: BSD3 license-file: LICENSE-author: Don Stewart-maintainer: dons@galois.com-cabal-version: >= 1.2+author: Don Stewart <dons@galois.com>+maintainer: ArchHaskell Team <arch-haskell@haskell.org>+cabal-version: >= 1.6 build-type: Simple +source-repository head+ type: git+ location: git://github.com/archhaskell/cabal2arch.git+ executable cabal2arch main-is: Main.hs ghc-options: -Wall - build-depends: + build-depends: base >= 4 && <= 6, pretty, process, directory, containers, bytestring,- Cabal > 1.8,- pureMD5 >= 0.2.1,+ Cabal > 1.8, filepath,- archlinux > 0.1+ archlinux >= 0.3.3 +executable manycabal2arch+ main-is: scripts/manycabal2arch.hs+ ghc-options: -Wall++ build-depends:+ base >=4 && <6,+ directory,+ filepath,+ archlinux >= 0.3.3
+ scripts/manycabal2arch.hs view
@@ -0,0 +1,128 @@+-- |+-- Module : manycabal2arch: batch creation of PKGBUILDs from Hackage tarball+-- Copyright : (c) Rémy Oudompheng 2010+-- License : BSD3+--+-- Maintainer: Arch Haskell Team <arch-haskell@haskell.org>+-- Stability : provisional+-- Portability:+--++import Distribution.ArchLinux.PkgBuild+import Distribution.ArchLinux.CabalTranslation+import Distribution.ArchLinux.HackageTranslation++import Distribution.PackageDescription+import Distribution.Text+import Text.PrettyPrint++import Data.List+import qualified Data.ByteString.Lazy as Bytes+import System.Directory+import System.FilePath++-- Input/output+import System.Environment+import System.IO+import System.Process+import System.Exit++import qualified Control.OldException as C++import Debug.Trace++import Paths_cabal2arch++exportPackage :: FilePath -> String -> GenericPackageDescription -> IO ()+exportPackage dot email p = do+ let q = preprocessCabal p+ case q of+ Nothing -> return ()+ Just p' -> do+ let (pkg, script) = cabal2pkg p'+ pkgname = trace ("Converting package " ++ arch_pkgname pkg) (arch_pkgname pkg)+ pkgbuild <- getMD5 pkg+ let apkgbuild = AnnotatedPkgBuild { pkgBuiltWith = Just version, pkgHeader = comment, pkgBody = pkgbuild }+ rawpkgbuild = (render $ pkg2doc email apkgbuild) ++ "\n"++ createDirectoryIfMissing True (dot </> pkgname)+ writeFile (dot </> pkgname </> "PKGBUILD") rawpkgbuild+ case script of+ Nothing -> return ()+ Just s -> writeFile (dot </> pkgname </> pkgname ++ ".install") s++main :: IO ()+main = do+ argv <- getArgs+ x <- case argv of+ _:_:_:_ -> return ()+ _ -> help+ pkglist <- readFile (argv !! 0)+ tarball <- Bytes.readFile (argv !! 1)+ repo <- canonicalizePath (argv !! 2)+ email <- do+ r <- getEnvMaybe "ARCH_HASKELL"+ case r of+ Nothing -> do hPutStrLn stderr "Warning: ARCH_HASKELL environment variable not set. Set this to the maintainer contact you wish to use. \n E.g. 'Arch Haskell Team <arch-haskell@haskell.org>'"+ return []+ Just s -> return s+ let cabals = getSpecifiedCabalsFromTarball tarball (lines pkglist)+ mapM (exportPackage repo email) cabals+ return ()++-- Safe wrapper for getEnv +getEnvMaybe :: String -> IO (Maybe String)+getEnvMaybe name = C.handle (const $ return Nothing) (Just `fmap` getEnv name)++comment :: String+comment = render $ vcat+ [ text "# Note: we list all package dependencies."+ , text "# Your package tool should understand 'provides' syntax"+ , text "#"+ , text "# Keep up to date on http://archhaskell.wordpress.com/"+ , text "#"]++-- | Given an abstract pkgbuild, run "makepkg -g" to compute md5+-- of source files (possibly cached locally), and modify the PkgBuild+-- accordingly.+--+getMD5 :: PkgBuild -> IO PkgBuild+getMD5 pkg = do+ putStrLn "Feeding the PKGBUILD to `makepkg -g`..."+ eres <- readProcessWithExitCode "makepkg" ["-g"] (render $ disp pkg)+ case eres of+ (ExitFailure _,_,err) -> do+ hPutStrLn stderr err+ hPutStrLn stderr $ "makepkg encountered an error while calculating MD5."+ return pkg+ (ExitSuccess,out,err) -> do+ -- s should be "md5sums=(' ... ')"+ hPutStrLn stderr err+ if "md5sums=('" `isPrefixOf` out+ then+ let md5sum = takeWhile (\x -> x `elem` "0123456789abcdef") $ drop 10 out+ in return pkg { arch_md5sum = ArchList [md5sum] }+ else do+ hPutStrLn stderr $ "Incorrect output from makepkg."+ return pkg++--+-- | Help file+--+help :: IO a+help = do+ hPutStrLn stderr $ unlines+ [ "Usage: manycabal2arch pkglist tarball destination"+ , ""+ , " Generate a ABS-like tree from a list of packages and the"+ , " uncompressed Hackage tarball"+ , ""+ , "Arguments: pkglist"+ , " A file with lines of the form \"<package-name> <version-number>\""+ , " tarball"+ , " The path to 00-index.tar, for example"+ , " $HOME/.cabal/packages/hackage.haskell.org/00-index.tar"+ , " destination"+ , " The directory where the repository will be created"+ ]+ exitWith ExitSuccess