module Debian.Package.Build.Sequence
( origArchive, nativeArchive, sourceDir
, withCurrentDir, withBaseCurrentDir
, getBuildDir, removeBuildDir
, findDebianChanges
, copyDebianDir
, rsyncGenOrigSources, rsyncGenNativeSources, rsyncGenSources
, cabalGenOrigSources, cabalGenSources, cabalAutogenSources
, genSources
, findGeneratedSourceDir, findGeneratedSource,
) where
import System.FilePath ((</>), takeFileName, takeDirectory, takeBaseName)
import System.Directory
(getDirectoryContents, doesDirectoryExist, doesFileExist)
import Control.Applicative (pure, (<$>), (<*>), (<|>))
import Control.Monad (when, guard, msum)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
import Data.List (isPrefixOf)
import Data.Maybe (catMaybes)
import Debian.Package.Data
(Hackage, hackageLongName, hackageArchive,
Source, origArchiveName, nativeArchiveName, sourceDirName, isNative,
PackageType, takeChangesType,
HaskellPackage, hackage, package, haskellPackageFromPackage)
import Debian.Package.Build.Monad
(Build, liftTrace, bracketBuild_, Config (..), askConfig, askBaseDir, askBuildDir)
import Debian.Package.Build.Command
(chdir, pwd, createDirectoryIfMissing, confirmPath, renameFile, renameDirectory,
unpack, packInDir', cabalDebian, dpkgParseChangeLog, rawSystem')
import qualified Debian.Package.Build.Cabal as Cabal
withCurrentDir :: FilePath -> Build a -> Build a
withCurrentDir dir act = do
saveDir <- liftIO pwd
bracketBuild_
(liftTrace $ chdir dir)
(liftTrace $ chdir saveDir)
act
withBaseCurrentDir :: Build a -> Build a
withBaseCurrentDir act = do
baseDir <- askBaseDir
withCurrentDir baseDir act
getBuildDir :: Build FilePath
getBuildDir = askBuildDir
withBuildDir :: (FilePath -> Build a) -> Build a
withBuildDir f = getBuildDir >>= f
removeBuildDir :: Build ()
removeBuildDir = do
bldDir <- getBuildDir
liftTrace $ do
found <- liftIO $ doesDirectoryExist bldDir
when found $ rawSystem' "rm" ["-r", bldDir]
debianDirName' :: Build FilePath
debianDirName' = debianDirName <$> askConfig
origArchive :: Source -> Build FilePath
origArchive pkg =
withBuildDir $ \w -> return $ w </> origArchiveName pkg
nativeArchive :: Source -> Build FilePath
nativeArchive pkg =
withBuildDir $ \w -> return $ w </> nativeArchiveName pkg
sourceDir :: Source -> Build FilePath
sourceDir pkg =
withBuildDir $ \w -> return $ w </> sourceDirName pkg
copyDebianDir :: FilePath -> Build ()
copyDebianDir srcDir = do
debDN <- debianDirName'
baseDir <- askBaseDir
liftTrace $ rawSystem' "cp" ["-a", baseDir </> debDN, srcDir </> "."]
rsyncGenOrigSourceDir :: Source -> Build FilePath
rsyncGenOrigSourceDir pkg = do
srcDir <- sourceDir pkg
debDN <- debianDirName'
baseDir <- askBaseDir
bldDir <- getBuildDir
confEXs <- sourceExcludes <$> askConfig
let excludes = [takeFileName d
| d <- [bldDir]
, baseDir `isPrefixOf` d ]
++ [debDN] ++ confEXs
liftTrace $ do
createDirectoryIfMissing srcDir
rawSystem' "rsync"
$ ["-auv"]
++ ["--exclude=" ++ e | e <- excludes]
++ [baseDir </> ".", srcDir </> "." ]
return srcDir
rsyncGenOrigSources :: Source -> Build (FilePath, FilePath)
rsyncGenOrigSources pkg = do
srcDir <- rsyncGenOrigSourceDir pkg
origPath <- origArchive pkg
withBuildDir $ liftTrace . packInDir' (takeFileName srcDir) origPath
copyDebianDir srcDir
liftTrace $ confirmPath srcDir
return (origPath, srcDir)
rsyncGenNativeSources :: Source -> Build (FilePath, FilePath)
rsyncGenNativeSources pkg = do
srcDir <- rsyncGenOrigSourceDir pkg
copyDebianDir srcDir
nativePath <- nativeArchive pkg
withBuildDir $ liftTrace . packInDir' (takeFileName srcDir) nativePath
liftTrace $ confirmPath srcDir
return (nativePath, srcDir)
rsyncGenSources :: Source -> Build (FilePath, FilePath)
rsyncGenSources pkg
| isNative pkg = rsyncGenNativeSources pkg
| otherwise = rsyncGenOrigSources pkg
cabalGenArchive :: Hackage -> Build FilePath
cabalGenArchive hkg = do
withBaseCurrentDir . liftTrace $ Cabal.sdist []
baseDir <- askBaseDir
let apath = baseDir </> hackageArchive hkg
liftTrace $ confirmPath apath
return apath
cabalGenOrigArchive :: HaskellPackage -> Build FilePath
cabalGenOrigArchive hpkg = do
origPath <- origArchive $ package hpkg
apath <- cabalGenArchive $ hackage hpkg
liftTrace $ do
createDirectoryIfMissing $ takeDirectory origPath
renameFile apath origPath
return origPath
cabalGenOrigSources :: HaskellPackage -> Build (FilePath, FilePath)
cabalGenOrigSources hpkg = do
origPath <- cabalGenOrigArchive hpkg
srcDir <- sourceDir $ package hpkg
liftTrace $ do
unpack origPath
renameDirectory
(takeDirectory origPath </> hackageLongName (hackage hpkg))
srcDir
confirmPath srcDir
return (origPath, srcDir)
cabalGenSources :: HaskellPackage -> Build (FilePath, FilePath)
cabalGenSources hpkg = do
pair@(_, srcDir) <- cabalGenOrigSources hpkg
copyDebianDir srcDir
return pair
cabalAutogenDebianDir :: Maybe String
-> [String]
-> Build FilePath
cabalAutogenDebianDir mayRev cdArgs = do
baseDir <- askBaseDir
let ddName = "debian"
tmpDD = baseDir </> ddName
exist <- liftIO $ doesDirectoryExist tmpDD
when exist (fail $ "Invalid state: directory already exist: " ++ tmpDD)
debDir <- (</> ddName) <$> getBuildDir
liftTrace $ do
cabalDebian baseDir mayRev cdArgs
createDirectoryIfMissing $ takeDirectory debDir
renameDirectory tmpDD debDir
return debDir
cabalAutogenSources :: String
-> Maybe String
-> [String]
-> Build ((FilePath, FilePath), HaskellPackage)
cabalAutogenSources hname mayRev cdArgs = do
liftIO . Cabal.fillSetupHs =<< askBaseDir
debDir <- cabalAutogenDebianDir mayRev cdArgs
pkg <- liftTrace . dpkgParseChangeLog $ debDir </> "changelog"
let hpkg = haskellPackageFromPackage hname pkg
pair@(_, srcDir) <- cabalGenOrigSources hpkg
liftTrace $ renameDirectory debDir (srcDir </> takeFileName debDir)
return (pair, hpkg)
findDebianChangeLog :: MaybeT Build FilePath
findDebianChangeLog = MaybeT $ do
baseDir <- askBaseDir
debDN <- debianDirName'
let changelog = baseDir </> debDN </> "changelog"
liftIO $ do
exist <- doesFileExist changelog
return $ if exist
then Just changelog
else Nothing
findDebianChanges :: Build [(FilePath, PackageType)]
findDebianChanges = do
bd <- getBuildDir
fs <- liftIO $ getDirectoryContents bd
return $ catMaybes
[ do ty <- takeChangesType path
Just (path, ty)
| path <- map (bd </>) fs
]
findCabalDescription :: MaybeT Build FilePath
findCabalDescription = MaybeT (askBaseDir >>= liftIO . Cabal.findDescriptionFile)
genSources :: Maybe String
-> [String]
-> Build (Maybe ((FilePath, FilePath), Source, Maybe Hackage))
genSources mayRev cdArgs = runMaybeT $
do clog <- findDebianChangeLog
src <- lift . liftTrace $ dpkgParseChangeLog clog
(do hname <- takeBaseName <$> findCabalDescription
let hpkg = haskellPackageFromPackage hname src
p <- lift $ cabalGenSources hpkg
return (p, src, Just $ hackage hpkg)
<|>
do lift $ (,,) <$> rsyncGenSources src <*> pure src <*> pure Nothing)
<|>
do hname <- takeBaseName <$> findCabalDescription
lift $ do
(p, hpkg) <- cabalAutogenSources hname mayRev cdArgs
return (p, package hpkg, Just $ hackage hpkg)
<|>
do fail "No source generate rule found."
findGeneratedSourceDir :: MaybeT Build FilePath
findGeneratedSourceDir = do
bd <- lift getBuildDir
fs <- liftIO $ getDirectoryContents bd
msum
[ do MaybeT . liftIO $ guard <$> doesFileExist (path </> "debian" </> "control")
pure path
| f <- fs
, f `notElem` [".", ".."]
, let path = bd </> f
]
findGeneratedSource :: MaybeT Build (FilePath, Source, Hackage)
findGeneratedSource = do
srcDir <- findGeneratedSourceDir
src <- lift . liftTrace $ dpkgParseChangeLog $ srcDir </> "debian" </> "changelog"
hname <- takeBaseName <$> findCabalDescription
return (srcDir, src, hackage $ haskellPackageFromPackage hname src)