cblrepo 0.2.0 → 0.2.1
raw patch · 3 files changed
+437/−2 lines, 3 files
Files
- cblrepo.cabal +2/−2
- src/PkgBuild.hs +74/−0
- src/Util/Translation.hs +361/−0
cblrepo.cabal view
@@ -1,5 +1,5 @@ name: cblrepo-version: 0.2.0+version: 0.2.1 cabal-version: >= 1.6 license: OtherLicense license-file: LICENSE-2.0@@ -27,7 +27,7 @@ hs-source-dirs: src main-is: Main.hs other-modules: Util.Misc PkgDB AddBase AddCabal BumpPkgs BuildPkgs IdxSync- IdxVersion Updates ListPkgs Urls+ IdxVersion Updates ListPkgs Urls PkgBuild Util.Translation build-depends: base ==4.3.*, cmdargs ==0.7.*, filepath ==1.2.*, directory ==1.1.*, Cabal ==1.10.*, json ==0.4.*, bytestring ==0.9.*, tar ==0.3.*, zlib ==0.5.*, mtl ==2.0.*,
+ src/PkgBuild.hs view
@@ -0,0 +1,74 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module PkgBuild where++import PkgDB+import Util.Misc+import Util.Translation++import Control.Monad.Reader+import Data.Maybe+import Distribution.Text+import System.Exit+import System.Unix.Directory+import System.Directory+import System.IO(openFile)+import System.IO+import Text.PrettyPrint.ANSI.Leijen++-- TODO:+-- - patches:+-- .cabal patch - put into sources array, copied into package dir+-- PKGBUILD patch - applied+-- build patch - put into source array, copied into package dir+-- - flags+pkgBuild :: ReaderT Cmds IO ()+pkgBuild = let+ failFinalize _ = error "pkgBuild: unexpected failure to finalize a package"+ in do+ db <- cfgGet dbFile >>= liftIO . readDb+ pD <- cfgGet patchDir+ pkgs <- cfgGet pkgs+ unless (all isJust (map (lookupPkg db) pkgs)) $+ liftIO (mapM_ (printNotAPkg db) pkgs >> exitFailure)+ let cbls = map (appendPkgVer db) pkgs+ genPDs <- liftIO $ mapM (\ c -> withTemporaryDirectory "/tmp/cblrepo." (readCabal pD c)) cbls+ let pds = map (either failFinalize id . finalizePkg db) genPDs+ let aps = map (translate db . fst) pds+ apsP <- liftIO $ mapM (addPatches pD) aps+ apsF <- liftIO $ mapM (\ a -> withTemporaryDirectory "/tmp/cblrepo." (addHashes a)) apsP+ liftIO $ mapM_ (\ a -> createDirectoryIfMissing False (apPkgName a)) apsF+ liftIO $ mapM_ (\ a -> withWorkingDirectory (apPkgName a) $ do+ copyPatches "." a+ hF <- openFile "PKGBUILD" WriteMode + hPutDoc hF $ pretty a+ hClose hF+ maybe (return ()) (\ pfn -> applyPatch "PKGBUILD" pfn) (apPkgbuildPatch a)+ when (apHasLibrary a) $ do+ hFI <- openFile (apPkgName a ++ ".install") WriteMode+ let ai = aiFromAP a+ hPutDoc hFI $ pretty ai+ hClose hFI+ ) apsF++printNotAPkg db pkg = maybe doPrint (const $ return ()) (lookupPkg db pkg)+ where+ doPrint = putStrLn $ "Unknown package: " ++ pkg++appendPkgVer db pkg = let+ displayVer = display . pkgVersion . fromJust . lookupPkg db+ in pkg ++ "," ++ (displayVer pkg)
+ src/Util/Translation.hs view
@@ -0,0 +1,361 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Util.Translation where++--+import AddCabal+import Distribution.PackageDescription.Parse+import Distribution.Verbosity+--++import PkgDB as DB+import Util.Misc++import Data.Monoid+import Text.PrettyPrint.ANSI.Leijen hiding((</>))+import Data.Version+import Distribution.Text+import Distribution.Package as P+import Data.Char+import Distribution.PackageDescription+import Data.Maybe+import System.FilePath+import System.Unix.Directory+import System.Exit+import System.IO+import System.Process+import Data.List+import System.Directory+import Control.Monad++-- {{{1 ShQuotedString+newtype ShQuotedString = ShQuotedString String+ deriving (Eq, Show)++instance Pretty ShQuotedString where+ pretty (ShQuotedString s) = char '"' <> text s <> char '"'++-- {{{1 ShArray+newtype ShArray = ShArray [String]+ deriving (Eq, Show)++instance Monoid ShArray where+ mempty = ShArray []+ (ShArray a) `mappend` (ShArray b) = ShArray $ a ++ b++instance Pretty ShArray where+ pretty (ShArray a) = encloseSep (char '(') (char ')') (char ' ') (map (\ t -> char '"' <> text t <> char '"') a)++-- {{{1 ShVar+data ShVar a = ShVar String a+ deriving (Eq, Show)++shVarNewValue (ShVar n _) v = ShVar n v+shVarAppendValue (ShVar n v1) v2 = ShVar n (v1 `mappend` v2)+shVarValue (ShVar _ v) = v++instance Pretty a => Pretty (ShVar a) where+ pretty (ShVar n v) = text n <> char '=' <> pretty v++-- {{{1 ArchPkg+-- TODO: patches, flags+data ArchPkg = ArchPkg+ { apPkgName :: String+ , apHkgName :: String+ , apHasLibrary :: Bool+ , apLicenseFile :: Maybe FilePath+ , apCabalPatch :: Maybe FilePath+ , apPkgbuildPatch :: Maybe FilePath+ -- shell bits+ , apShHkgName :: ShVar String+ , apShPkgName :: ShVar String+ , apShPkgVer :: ShVar Version+ , apShPkgRel :: ShVar Int+ , apShPkgDesc :: ShVar ShQuotedString+ , apShUrl :: ShVar ShQuotedString+ , apShLicence :: ShVar ShArray+ , apShMakeDepends :: ShVar ShArray+ , apShDepends :: ShVar ShArray+ , apShSource :: ShVar ShArray+ , apShInstall :: Maybe (ShVar ShQuotedString)+ , apShSha256Sums :: ShVar ShArray+ } deriving (Eq, Show)++-- {{{2 baseArchPkg+baseArchPkg = ArchPkg+ { apPkgName = ""+ , apHkgName = ""+ , apHasLibrary = False+ , apLicenseFile = Nothing+ , apCabalPatch = Nothing+ , apPkgbuildPatch = Nothing+ , apShHkgName = ShVar "_hkgname" ""+ , apShPkgName = ShVar "pkgname" ""+ , apShPkgVer = ShVar "pkgver" (Version [] [])+ , apShPkgRel = ShVar "pkgrel" 0+ , apShPkgDesc = ShVar "pkgdesc" (ShQuotedString "")+ , apShUrl = ShVar "url" (ShQuotedString "http://hackage.haskell.org/package/${_hkgname}")+ , apShLicence = ShVar "license" (ShArray [])+ , apShMakeDepends = ShVar "makedepends" (ShArray [])+ , apShDepends = ShVar "depends" (ShArray [])+ , apShSource = ShVar "source" (ShArray ["http://hackage.haskell.org/packages/archive/${_hkgname}/${pkgver}/${_hkgname}-${pkgver}.tar.gz"])+ , apShInstall = Just $ ShVar "install" (ShQuotedString "${pkgname}.install")+ -- this is a trick to make sure that the user's setting for integrity+ -- checking in makepkg.conf isn't used, as long as this array contains+ -- something non-empty it will overrule+ , apShSha256Sums = ShVar "sha256sums" (ShArray ["0"])+ }++-- {{{2 Pretty instance+instance Pretty ArchPkg where+ pretty (ArchPkg+ { apHasLibrary = hasLib+ , apLicenseFile = licenseFile+ , apCabalPatch = cabalPatchFile+ , apShHkgName = hkgName+ , apShPkgName = pkgName+ , apShPkgVer = pkgVer+ , apShPkgRel = pkgRel+ , apShPkgDesc = pkgDesc+ , apShUrl = url+ , apShLicence = pkgLicense+ , apShMakeDepends = makeDepends+ , apShDepends = depends+ , apShSource = source+ , apShInstall = install+ , apShSha256Sums = sha256sums+ }) = vsep+ [ text "# custom variables"+ , pretty hkgName+ , maybe empty (\ fn -> pretty $ ShVar "_licensefile" fn) licenseFile+ , empty, text "# PKGBUILD options/directives"+ , pretty pkgName+ , pretty pkgVer+ , pretty pkgRel+ , pretty pkgDesc+ , pretty url+ , pretty pkgLicense+ , text "arch=('i686' 'x86_64')"+ , pretty makeDepends+ , pretty depends+ , text "options=('strip')"+ , pretty source+ , maybe empty pretty install+ , pretty sha256sums+ , empty, text "# PKGBUILD functions"+ , if hasLib then libBuildFunction else exeBuildFunction+ , empty+ , if hasLib then libPackageFunction else exePackageFunction+ , empty+ ]+ where+ libBuildFunction = text "build() {" <>+ nest 4 (empty <$>+ text "cd ${srcdir}/${_hkgname}-${pkgver}" <$>+ maybe empty (\ _ ->+ text $ "patch " ++ shVarValue hkgName ++ ".cabal ${srcdir}/cabal.patch ")+ cabalPatchFile <$>+ nest 4 (text "runhaskell Setup configure -O -p --enable-split-objs --enable-shared \\" <$>+ text "--prefix=/usr --docdir=/usr/share/doc/${pkgname} \\" <$>+ text "--libsubdir=\\$compiler/site-local/\\$pkgid") <$>+ text "runhaskell Setup build" <$>+ text "runhaskell Setup haddock" <$>+ text "runhaskell Setup register --gen-script" <$>+ text "runhaskell Setup unregister --gen-script" <$>+ text "sed -i -r -e \"s|ghc-pkg.*unregister[^ ]* |&'--force' |\" unregister.sh"+ ) <$>+ char '}'++ exeBuildFunction = text "build() {" <>+ nest 4 (empty <$> text "cd ${srcdir}/${_hkgname}-${pkgver}" <$>+ text "runhaskell Setup configure -O --prefix=/usr --docdir=/usr/share/doc/${pkgname}" <$>+ text "runhaskell Setup build"+ ) <$>+ char '}'++ libPackageFunction = text "package() {" <>+ nest 4 (empty <$>+ text "cd ${srcdir}/${_hkgname}-${pkgver}" <$>+ text "install -D -m744 register.sh ${pkgdir}/usr/share/haskell/${pkgname}/register.sh" <$>+ text "install -m744 unregister.sh ${pkgdir}/usr/share/haskell/${pkgname}/unregister.sh" <$>+ text "install -d -m755 ${pkgdir}/usr/share/doc/ghc/html/libraries" <$>+ text "ln -s /usr/share/doc/${pkgname}/html ${pkgdir}/usr/share/doc/ghc/html/libraries/${_hkgname}" <$>+ text "runhaskell Setup copy --destdir=${pkgdir}" <$>+ (maybe empty (\ _ -> text "install -D -m644 ${_licensefile} ${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" <$>+ text "rm -f ${pkgdir}/usr/share/doc/${pkgname}/${_licensefile}") licenseFile)+ ) <$>+ char '}'++ exePackageFunction = text "package() {" <>+ nest 4 (empty <$> text "cd ${srcdir}/${_hkgname}-${pkgver}" <$>+ text "runhaskell Setup copy --destdir=${pkgdir}"+ ) <$>+ char '}'++-- {{{1 ArchInstall+data ArchInstall = ArchInstall+ { aiShPkgName :: ShVar String+ } deriving (Eq, Show)++-- {{{2 baseArchInstall+baseArchInstall = ArchInstall+ { aiShPkgName = ShVar "pkgname" ""+ }++-- {{{2 ArchInstall from ArchPackage+aiFromAP (ArchPkg { apShPkgName = pkgName }) =+ ArchInstall { aiShPkgName = pkgName }++-- {{{2 Pretty instance+instance Pretty ArchInstall where+ pretty (ArchInstall+ { aiShPkgName = pkgName+ }) = vsep+ [ text "# custom variables"+ , pretty pkgName+ , pretty (ShVar "HS_DIR" "usr/share/haskell/${pkgname}")+ , empty, text "# functions"+ , postInstallFunction+ , empty, preUpgradeFunction+ , empty, postUpgradeFunction+ , empty, preRemoveFunction+ , empty, postRemoveFunction+ , empty+ ]+ where+ postInstallFunction = text "post_install() {" <>+ nest 4 (empty <$> text "${HS_DIR}/register.sh" <$>+ text "(cd usr/share/doc/ghc/html/libraries; ./gen_contents_index)") <$>+ char '}'+ preUpgradeFunction = text "pre_upgrade() {" <>+ nest 4 (empty <$> text "${HS_DIR}/unregister.sh") <$>+ char '}'+ postUpgradeFunction = text "post_upgrade() {" <>+ nest 4 (empty <$> text "${HS_DIR}/register.sh" <$>+ text "(cd usr/share/doc/ghc/html/libraries; ./gen_contents_index)") <$>+ char '}'+ preRemoveFunction = text "pre_remove() {" <>+ nest 4 (empty <$> text "${HS_DIR}/unregister.sh") <$>+ char '}'+ postRemoveFunction = text "post_remove() {" <>+ nest 4 (empty <$> text "(cd usr/share/doc/ghc/html/libraries; ./gen_contents_index)") <$>+ char '}'++-- {{{1 extra instances+instance Pretty Version where+ pretty (Version b _) = encloseSep empty empty (char '.') (map pretty b)++-- {{{1 translate+-- TODO:+-- • add flags+-- • add patches to sources+-- • translation of extraLibDepends-libs to Arch packages+translate db pd = let+ ap = baseArchPkg+ (PackageName hkgName) = packageName pd+ pkgVer = packageVersion pd+ pkgRel = maybe 1 pkgRelease (lookupPkg db hkgName)+ hasLib = maybe False (const True) (library pd)+ licFn = let l = licenseFile pd in if null l then Nothing else Just l+ archName = (if hasLib then "haskell-" else "") ++ (map toLower hkgName)+ pkgDesc = synopsis pd+ url = if null (homepage pd) then "http://hackage.haskell.org/package/${_hkgname}" else (homepage pd)+ lic = display (license pd)+ makeDepends = if hasLib then [] else ["ghc=7.0.2"] ++ calcExactDeps db pd+ depends = if hasLib then ["ghc=7.0.2"] ++ calcExactDeps db pd else []+ extraLibDepends = maybe [] (extraLibs . libBuildInfo) (library pd)+ install = if hasLib then (apShInstall ap) else Nothing+ in ap+ { apPkgName = archName+ , apHkgName = hkgName+ , apHasLibrary = hasLib+ , apLicenseFile = licFn+ , apShHkgName = shVarNewValue (apShHkgName ap) hkgName+ , apShPkgName = shVarNewValue (apShPkgName ap) archName+ , apShPkgVer = shVarNewValue (apShPkgVer ap) pkgVer+ , apShPkgRel = shVarNewValue (apShPkgRel ap) pkgRel+ , apShPkgDesc = shVarNewValue (apShPkgDesc ap) (ShQuotedString pkgDesc)+ , apShUrl = shVarNewValue (apShUrl ap) (ShQuotedString url)+ , apShLicence = shVarNewValue (apShLicence ap) (ShArray [lic])+ , apShMakeDepends = shVarNewValue (apShMakeDepends ap) (ShArray makeDepends)+ , apShDepends = shVarNewValue (apShDepends ap) (ShArray $ depends ++ extraLibDepends)+ , apShInstall = install+ }++-- Calculate exact dependencies based on the package in a CblDB. We assume the+-- same db has been used to finalise the package so it's all right to use+-- fromJust.+-- TODO:+-- • this is most likely too simplistic to create the Arch package names+-- correctly for all possible dependencies+calcExactDeps db pd = let+ deps = filter (not . flip elem ghcPkgs) (map depName (buildDepends pd))+ lookupPkgVer = display . DB.pkgVersion . fromJust . lookupPkg db+ in map (\ n -> "haskell-" ++ (map toLower n) ++ "=" ++ (lookupPkgVer n)) deps++-- {{{2 ghcPkgs+-- libraries included in GHC, but not marked as provided by the Arch package+ghcPkgs = ["base", "bin-package-db", "ffi", "ghc", "ghc-binary", "ghc-prim", "haskell2010", "integer-gmp", "rts"]++-- {{{1 stuff with patches+-- {{{2 addPatches+-- TODO:+-- • add build patch+addPatches patchDir ap = let+ hkgName = apHkgName ap+ sources = apShSource ap+ fi tF fF v = if v then tF else fF+ cabalPatchFn = patchDir </> hkgName <.> "cabal"+ pkgbuildPatchFn = patchDir </> hkgName <.> "pkgbuild"+ in do+ cabalPatch <- doesFileExist cabalPatchFn >>= fi (liftM Just $ canonicalizePath cabalPatchFn) (return Nothing)+ pkgBuildPatch <- doesFileExist pkgbuildPatchFn >>= fi (liftM Just $ canonicalizePath pkgbuildPatchFn) (return Nothing)+ let sources' = shVarAppendValue sources (ShArray $ maybe [] (const ["cabal.patch"]) cabalPatch)+ return ap+ { apCabalPatch = cabalPatch+ , apPkgbuildPatch = pkgBuildPatch+ , apShSource = sources'+ }++-- {{{2 copyPatches+-- TODO:+-- • add build patch+copyPatches destDir ap = let+ cabalPatch = apCabalPatch ap+ in maybe (return ()) (\ fn -> copyFile fn (destDir </> "cabal.patch")) cabalPatch++-- {{{1 addHashes+-- TODO:+-- • deal with errors better+addHashes ap tmpDir = let+ hashes = map (filter (`elem` "1234567890abcdef")) . lines . drop 11+ pkgbuildFn = tmpDir </> "PKGBUILD"+ pkgbuildPatch = apPkgbuildPatch ap+ in do+ copyPatches tmpDir ap+ writeFile pkgbuildFn (show $ pretty ap)+ maybe (return ()) (\ pfn -> applyPatch pkgbuildFn pfn) pkgbuildPatch+ (ec, out, er) <- withWorkingDirectory tmpDir (readProcessWithExitCode "makepkg" ["-g"] "")+ case ec of+ ExitFailure _ -> do+ hPutStrLn stderr er+ hPutStrLn stderr "makepkg: error while calculating the source hashes"+ return ap+ ExitSuccess -> do+ if "sha256sums=(" `isPrefixOf` out+ then return ap { apShSha256Sums = shVarNewValue (apShSha256Sums ap) (ShArray $ hashes out) }+ else return ap