diff --git a/cblrepo.cabal b/cblrepo.cabal
--- a/cblrepo.cabal
+++ b/cblrepo.cabal
@@ -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.*,
diff --git a/src/PkgBuild.hs b/src/PkgBuild.hs
new file mode 100644
--- /dev/null
+++ b/src/PkgBuild.hs
@@ -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)
diff --git a/src/Util/Translation.hs b/src/Util/Translation.hs
new file mode 100644
--- /dev/null
+++ b/src/Util/Translation.hs
@@ -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
