archlinux-1.3: Distribution/ArchLinux/CabalTranslation.hs
-- |
-- Module : Distribution.ArchLinux.CabalTranslation
-- Copyright : (c) Don Stewart, 2008-2010, Rémy Oudompheng 2010
-- License : BSD3
--
-- Maintainer: Arch Haskell Team <arch-haskell@haskell.org>
--
module Distribution.ArchLinux.CabalTranslation (
preprocessCabal,
cabal2pkg, cabal2pkg',
oldCabal2Arch,
install_hook_name
) where
-- Cabal modules
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Configuration
import Distribution.License
import Distribution.Version
import Distribution.Compiler
import Distribution.System
-- Archlinux modules
import Distribution.ArchLinux.PkgBuild
import Distribution.ArchLinux.SystemProvides
-- Standard types
import Distribution.Text
import Data.Char
import Data.List
import qualified Data.Map as M
import Data.Maybe
import Data.Monoid
import System.FilePath
-- Debugging
import Debug.Trace
--
-- | Configure package for system
--
preprocessCabal :: GenericPackageDescription -> SystemProvides -> Maybe PackageDescription
preprocessCabal cabalsrc systemContext =
case finalizePackageDescription
[]
(const True) -- could check against prefered pkgs....
(Platform X86_64 buildOS) -- linux/x86_64
(CompilerId GHC (Version [7,0,3] []))
-- now constrain it to solve in the context of a modern ghc only
(corePackages systemContext ++ platformPackages systemContext)
cabalsrc
of
Left deps -> trace ("Unresolved dependencies: " ++show deps) Nothing
Right (pkg,_) -> Just pkg { buildDepends = removeCoreFrom (buildDepends pkg) systemContext }
-- attempt to filter out core packages we've already satisified
-- not actually 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] -> SystemProvides -> [Dependency]
removeCoreFrom [] _ = []
removeCoreFrom (x@(Dependency n vr):xs) systemContext =
case find (\(Dependency k _) -> n == k) $ corePackages systemContext of
-- haskell-parsec, haskell-quickcheck
Just (Dependency (PackageName "base") _)
-> removeCoreFrom xs systemContext
Just (Dependency _ corevr)
| isAnyVersion corevr -> removeCoreFrom xs systemContext
| isJust isspef && (withinRange (fromJust isspef) vr)
-> removeCoreFrom xs systemContext
where isspef = isSpecificVersion corevr
_ -> x : removeCoreFrom xs systemContext
------------------------------------------------------------------------------------
--
-- | Translate a generic cabal file into a PKGBUILD (using default
-- values for pkgname and pkgrel).
--
cabal2pkg :: PackageDescription -> SystemProvides -> (AnnotatedPkgBuild, Maybe String)
cabal2pkg cabal systemContext = cabal2pkg' cabal archName 1 systemContext
where
archName = map toLower (if isLibrary then "haskell-" ++ display name else display name)
name = pkgName (package cabal)
isLibrary = isJust (library cabal) && map toLower (display name) `notElem` shouldNotBeLibraries
--
-- | Translate a generic cabal file into a PKGBUILD, using the specified
-- ArchLinux package name and package release.
--
cabal2pkg' :: PackageDescription -> String -> Int -> SystemProvides -> (AnnotatedPkgBuild, Maybe String)
cabal2pkg' cabal archName release systemContext
-- TODO decide if it's a library or an executable,
-- handle multipackages
-- extract C dependencies
-- = trace (show cabal) $
= ( emptyPkg {
pkgHeader = []
, hkgName = display name
, pkgBody = stub {
arch_pkgname = archName
, arch_pkgver = vers
, arch_pkgrel = release
, 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)
, arch_package = (arch_package stub) ++
(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"
, "rm -f ${pkgdir}/usr/share/doc/${pkgname}/LICENSE"
]
else []) }
}, if hasLibrary
then Just (install_hook archName)
else Nothing
)
where
stub = if hasLibrary
then (stubPackageLibrary $ display name) {
arch_depends = (
if not (isLibrary)
then ArchList [ArchDep (Dependency (PackageName "gmp") anyVersion)]
`mappend` anyClibraries
-- libraries have 'register-time' dependencies on
-- their dependent Haskell libraries.
--
else ArchList []) `mappend` my_makedepends
}
else (stubPackageProgram $ display name) {
-- isLibrary = False automatically
arch_makedepends = my_makedepends
, arch_depends = ArchList [ArchDep (Dependency (PackageName "gmp") anyVersion)]
`mappend` anyClibraries
}
name = pkgName (package cabal)
vers = pkgVersion (package cabal)
-- build time dependencies
my_makedepends =
-- everything depends on ghc and Cabal 1.4.x
ArchList
[(ArchDep (Dependency (PackageName "ghc") anyVersion))]
`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 systemContext) ]
(<->) :: String -> String -> String
x <-> y = x ++ "-" ++ y
--
-- | A PKGBUILD skeleton for Haskell libraries (hasLibrary = True)
--
stubPackageLibrary :: String -> PkgBuild
stubPackageLibrary _ = emptyPkgBuild {
arch_url = "http://hackage.haskell.org/package/${_hkgname}"
-- All Hackage packages depend on GHC at build time
-- All Haskell libraries are prefixed with "haskell-"
, arch_makedepends = ArchList [] -- makedepends should not duplicate depends
-- Hackage programs only need their own source to build
, arch_source = ArchList . return $
"http://hackage.haskell.org/packages/archive/${_hkgname}/${pkgver}/${_hkgname}-${pkgver}.tar.gz"
, arch_build =
[ "cd ${srcdir}/${_hkgname}-${pkgver}"
, "runhaskell Setup configure -O ${PKGBUILD_HASKELL_ENABLE_PROFILING:+-p } --enable-split-objs --enable-shared \\"
, " --prefix=/usr --docdir=/usr/share/doc/${pkgname} --libsubdir=\\$compiler/site-local/\\$pkgid"
, "runhaskell Setup build"
, "runhaskell Setup haddock"
, "runhaskell Setup register --gen-script"
, "runhaskell Setup unregister --gen-script"
, "sed -i -r -e \"s|ghc-pkg.*unregister[^ ]* |&'--force' |\" unregister.sh"
]
, arch_package =
[ "cd ${srcdir}/${_hkgname}-${pkgver}"
, "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/${_hkgname}"
, "runhaskell Setup copy --destdir=${pkgdir}"
]
-- if its a library:
, arch_install = Just "${pkgname}.install"
}
--
-- | A PKGBUILD skeleton for Haskell programs (hasLibrary = False)
--
stubPackageProgram :: String -> PkgBuild
stubPackageProgram _ = emptyPkgBuild {
arch_url = "http://hackage.haskell.org/package/${_hkgname}"
-- Hackage programs only need their own source to build
, arch_source = ArchList . return $
"http://hackage.haskell.org/packages/archive/${_hkgname}/${pkgver}/${_hkgname}-${pkgver}.tar.gz"
, arch_build =
[ "cd ${srcdir}/${_hkgname}-${pkgver}"
, "runhaskell Setup configure --prefix=/usr --docdir=/usr/share/doc/${pkgname} -O"
, "runhaskell Setup build"
]
, arch_package =
[ "cd ${srcdir}/${_hkgname}-${pkgver}"
, "runhaskell Setup copy --destdir=${pkgdir}"]
, arch_install = Nothing
}
--
-- 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)"
, "}" ]
findCLibs :: PackageDescription -> SystemProvides -> [String]
findCLibs (PackageDescription { library = lib, executables = exe }) sysContext =
-- 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 sysContext) 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
shouldNotBeLibraries :: [String]
shouldNotBeLibraries =
["xmonad"
,"gitit"
,"yavie"
,"berp"
,"l-seed"
,"hspresent"
,"haskell-platform"
,"xmonad-contrib"
,"xmonad-extras"
,"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
-}
------------------------------------------------------------------------
-- Checker
--
-- 2010-10-29: This code is unused. Do we still need it?
-- type Warnings = String
-- Hard code the cabal2arch version
recentCabal2ArchVersion :: Maybe Version
recentCabal2ArchVersion = case simpleParse "0.7" of -- XXX
Nothing -> error "Unable to parse cabal2arch version"
Just v -> Just v
-- | Look for problems in the PKGBUILD
oldCabal2Arch :: AnnotatedPkgBuild -> Bool
oldCabal2Arch s
| isNothing (pkgBuiltWith s)
= True
| pkgBuiltWith s < recentCabal2ArchVersion
= True -- ["Old version of cabal2arch: " ++ display (fromJust (pkgBuiltWith s))]
| otherwise = False