diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Kei Hibino
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Kei Hibino nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/debian-build.cabal b/debian-build.cabal
new file mode 100644
--- /dev/null
+++ b/debian-build.cabal
@@ -0,0 +1,53 @@
+name:                debian-build
+version:             0.1.0.0
+synopsis:            Debian package build sequence tools
+description:         This package provides functions to build
+                     debian package from source tree.
+homepage:            http://twitter.com/khibino/
+license:             BSD3
+license-file:        LICENSE
+author:              Kei Hibino
+maintainer:          ex8k.hibino@gmail.com
+-- copyright:
+category:            Debian
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:
+                     Debian.Package.Data.Hackage
+                     Debian.Package.Data.Source
+                     Debian.Package.Data
+                     Debian.Package.Build.Monad
+                     Debian.Package.Build.Cabal
+                     Debian.Package.Build.Command
+                     Debian.Package.Build.Sequence
+                     Debian.Package.Build
+
+--  other-modules:
+
+  build-depends:       base <5
+                     , filepath
+                     , process
+                     , directory
+                     , transformers
+                     , Cabal
+
+  hs-source-dirs:      src
+  ghc-options:       -Wall
+
+executable odebuild
+  build-depends:       base <5
+                     , debian-build
+
+  main-is: odebuild.hs
+  hs-source-dirs:      mains
+  ghc-options:       -Wall
+
+source-repository head
+  type:       git
+  location:   https://github.com/khibino/haskell-debian-build
+
+source-repository head
+  type:       mercurial
+  location:   https://bitbucket.org/khibino/haskell-debian-build
diff --git a/mains/odebuild.hs b/mains/odebuild.hs
new file mode 100644
--- /dev/null
+++ b/mains/odebuild.hs
@@ -0,0 +1,62 @@
+import System.Environment (getProgName, getArgs)
+import Control.Monad (void)
+
+import Debian.Package.Data (Source, Hackage)
+import Debian.Package.Build
+  (BuildMode (All), buildPackage, debi,
+   baseDirCurrent, defaultConfig, Build, runBuild, liftTrace,
+   sourceDir, removeBuildDir, genSources, removeGhcLibrary)
+
+
+source' :: Build ((FilePath, FilePath), Source, Maybe Hackage)
+source' =
+  maybe (fail "Illegal state: genSources") return =<< genSources
+
+remove' :: Hackage -> Build ()
+remove' =  liftTrace . removeGhcLibrary All
+
+install' :: Source -> Build ()
+install' src = do
+  srcDir <- sourceDir src
+  liftTrace $ debi srcDir []
+
+
+help :: IO ()
+help =  do
+  prog <- getProgName
+  putStr . unlines $ map unwords
+    [[prog, "build"],
+     [prog, "install"],
+     [prog, "reinstall", "  -- Remove and install support only for Haskell"] ]
+
+build :: [String] -> Build (Source, Maybe Hackage)
+build opts = do
+  removeBuildDir
+  ((_, dir), src, mayH) <- source'
+  liftTrace $ buildPackage dir All opts
+  return (src, mayH)
+
+install :: [String] -> Build ()
+install args = do
+  (src, _mayH) <- build args
+  install' src
+
+reinstall :: [String] -> Build ()
+reinstall args = do
+  (src, mayH) <- build args
+  maybe (return ()) remove' mayH
+  install' src
+
+run :: Build a -> IO a
+run b = uncurry (runBuild b baseDirCurrent) defaultConfig
+
+main :: IO ()
+main =  do
+  as0 <- getArgs
+  case as0 of
+    "help" : _            ->  help
+    as1  ->  run $ case  as1  of
+      "build" : args      ->  void $ build args
+      "install" : args    ->  install args
+      "reinstall" : args  ->  reinstall args
+      args                ->  void $ build args
diff --git a/src/Debian/Package/Build.hs b/src/Debian/Package/Build.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Build.hs
@@ -0,0 +1,21 @@
+-- |
+-- Module      : Debian.Package.Build
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides build-tool namespace.
+module Debian.Package.Build
+       ( module Debian.Package.Build.Monad
+       , module Debian.Package.Build.Command
+       , module Debian.Package.Build.Cabal
+       , module Debian.Package.Build.Sequence
+       ) where
+
+import Debian.Package.Build.Monad
+import Debian.Package.Build.Command
+import Debian.Package.Build.Cabal hiding (hackageLongName, hackageName, hackageVersion)
+import Debian.Package.Build.Sequence
diff --git a/src/Debian/Package/Build/Cabal.hs b/src/Debian/Package/Build/Cabal.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Build/Cabal.hs
@@ -0,0 +1,103 @@
+-- |
+-- Module      : Debian.Package.Build.Cabal
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module wraps cabal library interfaces to keep sparse dependency to it.
+module Debian.Package.Build.Cabal
+       ( findDescriptionFile
+       , parsePackageDescription
+       , hackageLongName, hackageName, hackageVersion
+
+       , setupCmd, clean, sdist
+       , configure, build, install, register
+       )  where
+
+import Control.Applicative ((<$>))
+import Control.Monad (filterM)
+import Control.Monad.Trans.Class (lift)
+import Data.Maybe (listToMaybe)
+import Data.List (isSuffixOf)
+import System.FilePath ((</>))
+import System.Directory (getDirectoryContents, doesFileExist)
+import System.Environment (withArgs)
+
+import Distribution.Text (disp)
+import Distribution.Verbosity (silent)
+import Distribution.Package (pkgName, pkgVersion)
+import Distribution.PackageDescription
+  (GenericPackageDescription, packageDescription, PackageDescription, package)
+import Distribution.PackageDescription.Parse (readPackageDescription)
+
+import Distribution.Simple (defaultMain)
+
+import Debian.Package.Build.Monad (Trace, traceCommand)
+
+
+-- | Find .cabal file
+findDescriptionFile :: FilePath -> IO (Maybe FilePath)
+findDescriptionFile dir = do
+  fs  <-  getDirectoryContents dir
+  let find f
+        | length f > length suf  &&
+          suf `isSuffixOf` f           =  doesFileExist $ dir </> f
+        | otherwise                    =  return False
+        where suf = ".cabal"
+  fmap (dir </>) . listToMaybe <$> filterM find fs
+
+-- | Parse .cabal file
+parsePackageDescription :: FilePath -> IO PackageDescription
+parsePackageDescription =  (packageDescription `fmap`) . readPackageDescription silent
+
+-- | Hackage name and version string from 'PackageDescription'
+hackageLongName :: PackageDescription -> String
+hackageLongName =  show . disp . package
+
+-- | Hackage name string from 'PackageDescription'
+hackageName :: PackageDescription -> String
+hackageName =  show . disp . pkgName . package
+
+-- | Hackage version string from 'PackageDescription'
+hackageVersion :: PackageDescription -> String
+hackageVersion =  show . disp . pkgVersion . package
+
+_testDotCabal :: IO PackageDescription
+_testDotCabal =  do Just path <- findDescriptionFile "."
+                    parsePackageDescription path
+
+setup :: [String] -> Trace ()
+setup args =  do
+  traceCommand (unwords $ "<cabal>" : args)
+  lift $ args `withArgs` defaultMain
+
+-- | Call cabal library defaultMain like Setup.hs
+setupCmd :: String -> [String] -> Trace ()
+setupCmd cmd = setup . (cmd : )
+
+-- | Cabal library defaultMain with sub-command clean
+clean :: [String] -> Trace ()
+clean =  setupCmd "clean"
+
+-- | Cabal library defaultMain with sub-command configure
+configure :: [String] -> Trace ()
+configure =  setupCmd "configure"
+
+-- | Cabal library defaultMain with sub-command sdist
+sdist :: [String] -> Trace ()
+sdist =  setupCmd "sdist"
+
+-- | Cabal library defaultMain with sub-command build
+build :: [String] -> Trace ()
+build =  setupCmd "build"
+
+-- | Cabal library defaultMain with sub-command install
+install :: [String] -> Trace ()
+install =  setupCmd "install"
+
+-- | Cabal library defaultMain with sub-command register
+register :: [String] -> Trace ()
+register =  setupCmd "register"
diff --git a/src/Debian/Package/Build/Command.hs b/src/Debian/Package/Build/Command.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Build/Command.hs
@@ -0,0 +1,202 @@
+-- |
+-- Module      : Debian.Package.Build.Command
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides trace-able action instances like commands.
+module Debian.Package.Build.Command
+       ( chdir, pwd
+
+       , createDirectoryIfMissing, renameDirectory, renameFile
+
+       , confirmPath
+
+       , unpackInDir, unpack, packInDir', packInDir
+
+       , cabalDebian', cabalDebian, dpkgParseChangeLog
+
+       , debuild, debi
+
+       , BuildMode (..)
+
+       , buildPackage, rebuild
+
+       , removeGhcLibrary
+
+       , withCurrentDir'
+
+       , readProcess', rawSystem', system'
+       ) where
+
+import Data.Maybe (fromMaybe)
+import Control.Arrow ((&&&))
+import Control.Monad.Trans.Class (lift)
+import System.FilePath ((<.>), takeDirectory)
+import qualified System.Directory as D
+import qualified System.Process as Process
+import System.Exit (ExitCode (..))
+
+import Debian.Package.Data (Hackage, ghcLibraryBinPackages, ghcLibraryPackages, Source, parseChangeLog)
+import Debian.Package.Build.Monad (Trace, traceCommand, traceOut, bracketTrace_)
+
+
+splitCommand :: [a] -> (a, [a])
+splitCommand =  head &&& tail
+
+handleExit :: String -> ExitCode -> IO ()
+handleExit cmd = d  where
+  d (ExitFailure rv) = fail $ unwords ["Failed with", show rv ++ ":", cmd]
+  d  ExitSuccess     = return ()
+
+-- | Run command without shell and get standard output string.
+readProcess' :: [String] -> Trace String
+readProcess' cmd0 = do
+  traceCommand $ unwords cmd0
+  lift $ do
+    let (cmd, args) = splitCommand cmd0
+    Process.readProcess cmd args ""
+
+-- | Run command without shell
+rawSystem' :: [String] -> Trace ()
+rawSystem' cmd0 = do
+  traceCommand $ unwords cmd0
+  lift $ do
+    let (cmd, args) = splitCommand cmd0
+    Process.rawSystem cmd args >>= handleExit cmd
+
+-- | Run command with shell
+system' :: String -> Trace ()
+system' cmd = do
+  traceCommand cmd
+  lift $ Process.system cmd >>= handleExit cmd
+
+-- | Change directory action
+chdir :: String -> Trace ()
+chdir dir =  do
+  traceCommand $ "<setCurrentDirectory> " ++ dir
+  lift $ D.setCurrentDirectory dir
+
+-- | Action to get current working directory
+pwd :: IO String
+pwd =  D.getCurrentDirectory
+
+-- | Create directory if missing
+createDirectoryIfMissing :: String -> Trace ()
+createDirectoryIfMissing dir = do
+  traceCommand $ "<createDirectoryIfMissing True> " ++ dir
+  lift $ D.createDirectoryIfMissing True dir
+
+renameMsg :: String -> String -> String -> String
+renameMsg tag src dst = unwords ["<" ++ tag ++ "> ", src, "-->", dst]
+
+-- | Rename directory action. e.g. /renameDirectory from to/
+renameDirectory :: String -> String -> Trace ()
+renameDirectory src dst = do
+  traceCommand $ renameMsg "renameDirectory" src dst
+  lift $ D.renameDirectory src dst
+
+-- | Rename file action. e.g. /renameFile from to/
+renameFile :: String -> String -> Trace ()
+renameFile src dst = do
+  traceCommand $ renameMsg "renameFile" src dst
+  lift $ D.renameFile src dst
+
+-- | Confirm filepath using /ls/ command
+confirmPath :: String -> Trace ()
+confirmPath path =
+  readProcess' ["ls", "-ld", path] >>= traceOut
+
+
+-- | Unpack .tar.gz under directory.
+unpackInDir :: FilePath -> FilePath -> Trace ()
+apath `unpackInDir` dir = do
+  lift . putStrLn $ unwords ["Unpacking", apath, "in", dir, "."]
+  rawSystem' ["tar", "-C", dir, "-zxf", apath]
+
+-- | Unpack .tar.gz under archive place.
+unpack :: FilePath -> Trace ()
+unpack apath = apath `unpackInDir` takeDirectory apath
+
+-- | Pack directory into .tar.gz under working directory
+packInDir' :: FilePath -> FilePath -> FilePath -> Trace ()
+packInDir' pdir apath wdir = do
+  lift . putStrLn $ unwords ["Packing", pdir, "in", wdir, "into", apath, "."]
+  rawSystem' ["tar", "-C", wdir, "-zcf", apath, pdir]
+
+-- | Pack directory into same location .tar.gz under working directory
+packInDir :: FilePath -> FilePath -> Trace ()
+pdir `packInDir` wdir =
+  packInDir' pdir (pdir <.> "tar" <.> "gz") wdir
+
+
+-- | Run action under specified directory
+withCurrentDir' :: FilePath -> Trace a -> Trace a
+withCurrentDir' dir act = do
+  saveDir <- lift pwd
+  bracketTrace_
+    (chdir dir)
+    (chdir saveDir)
+    act
+
+-- | Just call /cabal-debian/ command
+cabalDebian' :: Maybe String -> Trace ()
+cabalDebian' mayRev =
+  rawSystem'
+  [ "cabal-debian"
+  , "--debianize" {- for cabal-debian 1.25 -}
+  , "--quilt"
+  , "--revision=" ++ fromMaybe "1~autogen1" mayRev
+  ]
+
+-- | Call /cabal-debian/ command under specified directory
+cabalDebian :: FilePath -> Maybe String -> Trace ()
+cabalDebian dir = withCurrentDir' dir . cabalDebian'
+
+-- | Read debian changelog file and try to parse into 'Source'
+dpkgParseChangeLog :: FilePath -> Trace Source
+dpkgParseChangeLog cpath =  do
+  str <- readProcess' ["dpkg-parsechangelog", "-l" ++ cpath]
+  maybe (fail $ "parseChangeLog: failed: " ++ str) return
+    $ parseChangeLog str
+
+
+run :: String -> [String] -> Trace ()
+run cmd = rawSystem' . (cmd :)
+
+debuild' :: [String] -> Trace ()
+debuild' =  run "debuild"
+
+-- | Call /debuild/ under specified directory, with command line options
+debuild :: FilePath -> [String] -> Trace ()
+debuild dir = withCurrentDir' dir . debuild'
+
+-- | Install packages under specified source package directory
+debi :: FilePath -> [String] -> Trace ()
+debi dir = withCurrentDir' dir . rawSystem' . (["sudo", "debi"] ++)
+
+-- | Build mode, all or binary only
+data BuildMode = All | Bin
+
+-- | Build package using /debuild/ under specified directory
+buildPackage :: FilePath -> BuildMode -> [String] -> Trace ()
+buildPackage dir mode opts = do
+  let modeOpt All = []
+      modeOpt Bin = ["-B"]
+  debuild dir $ ["-uc", "-us"] ++ modeOpt mode ++ opts
+
+-- | Clean and build package using /debuild/ under specified directory
+rebuild :: FilePath -> BuildMode -> [String] -> Trace ()
+rebuild dir mode opts = do
+  debuild dir ["clean"]
+  buildPackage dir mode opts
+
+-- | Remove ghc library packages under specified source package directory
+removeGhcLibrary :: BuildMode -> Hackage -> Trace ()
+removeGhcLibrary mode hkg = do
+  let pkgs All = ghcLibraryBinPackages
+      pkgs Bin = ghcLibraryPackages
+  system' $ unwords ["yes '' |", "sudo apt-get remove", unwords $ pkgs mode hkg, "|| true"]
diff --git a/src/Debian/Package/Build/Monad.hs b/src/Debian/Package/Build/Monad.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Build/Monad.hs
@@ -0,0 +1,168 @@
+-- |
+-- Module      : Debian.Package.Build.Monad
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides monad types to control build scripts.
+module Debian.Package.Build.Monad
+       ( Trace, runTrace, traceCommand, traceOut
+       , bracketTrace, bracketTrace_
+
+       , BaseDir, baseDirCurrent, baseDirSpecify
+
+       , askBaseDir, askBuildDir
+
+       , BuildDir, buildDirRelative, buildDirAbsolute
+
+       , Config, defaultConfig, buildDir, mayDebianDirName
+
+       , Build, liftTrace, runBuild, askConfig
+       , bracketBuild, bracketBuild_
+       ) where
+
+import System.FilePath ((</>))
+import System.IO (hPutStrLn, hFlush, stderr)
+import Data.Maybe (fromMaybe)
+import Control.Applicative ((<$>))
+import Control.Monad (when)
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)
+import Control.Exception (bracket)
+
+
+readerBracket :: Monad m
+             => (m a -> (a -> m b) -> (a -> m c) -> m c)
+             -> ReaderT r m a
+             -> (a -> ReaderT r m b)
+             -> (a -> ReaderT r m c)
+             -> ReaderT r m c
+readerBracket brkt open close body = do
+  r <- ask
+  lift $ brkt
+    (runReaderT open r)
+    (\a -> runReaderT (close a) r)
+    (\a -> runReaderT (body a) r)
+
+toBracket_ :: Monad m
+           => (m a -> (a -> m b) -> (a -> m c) -> m c)
+           -> m a
+           -> m b
+           -> m c
+           -> m c
+toBracket_ brkt start end body =
+  brkt start (const end) (const body)
+
+-- | Action type with trace flag
+type Trace = ReaderT Bool IO
+
+-- | Run 'Trace' monad
+runTrace :: Trace a -> Bool -> IO a
+runTrace =  runReaderT
+
+traceIO :: IO () -> Trace ()
+traceIO printIO = do
+  t <- ask
+  when t $ lift printIO
+
+-- | bracket for 'Trace' monad
+bracketTrace :: Trace a -> (a -> Trace b) -> (a -> Trace c) -> Trace c
+bracketTrace =  readerBracket bracket
+
+-- | bracket_ for 'Trace' monad
+bracketTrace_ :: Trace a -> Trace b -> Trace c -> Trace c
+bracketTrace_ =  toBracket_ bracketTrace
+
+tprint :: Char -> String -> IO ()
+tprint pc s = do
+  let fh = stderr
+  hPutStrLn fh $ pc : " " ++ s
+  hFlush fh
+
+-- | Command string trace print along with trace flag
+traceCommand :: String -> Trace ()
+traceCommand =  traceIO . tprint '+'
+
+-- | Output string trace print along with trace flag
+traceOut :: String -> Trace ()
+traceOut =  traceIO . tprint '>'
+
+
+-- | Type to specify base directory filepath
+newtype BaseDir = BaseDir { unBaseDir :: Maybe FilePath }
+
+-- | Use current directory as base directory
+baseDirCurrent :: BaseDir
+baseDirCurrent =  BaseDir Nothing
+
+-- | Use specified directory as base directory
+baseDirSpecify :: FilePath -> BaseDir
+baseDirSpecify =  BaseDir . Just
+
+-- | Type to specify build working directory
+newtype BuildDir = BuildDir (Either FilePath FilePath)
+
+-- | Use relative path from base-dir as build workding directory
+buildDirRelative :: FilePath -> BuildDir
+buildDirRelative = BuildDir . Left
+
+-- | Use absolute path as build workding directory
+buildDirAbsolute :: FilePath -> BuildDir
+buildDirAbsolute =  BuildDir . Right
+
+-- | Fold build dir
+unBuildDir :: FilePath -> BuildDir -> FilePath
+unBuildDir base (BuildDir b) = either (base </>) id b
+
+-- | Show 'BuildDir' is relative or absolute
+instance Show BuildDir where
+  show = d  where
+    d (BuildDir (Left  p)) = "Relative " ++ p
+    d (BuildDir (Right p)) = "Absolute " ++ p
+
+-- | Build configuration type
+data Config =
+  Config
+  { buildDir         :: BuildDir        -- ^ Specify build dir
+  , mayDebianDirName :: Maybe FilePath  -- ^ Name of debian directory
+  } deriving Show
+
+-- | Default configuration
+defaultConfig :: (Config, Bool)
+defaultConfig =  (Config (buildDirRelative ".debian-build") Nothing, True)
+
+-- | Monad type with build base directory and build configuration.
+type Build = ReaderT BaseDir (ReaderT Config Trace)
+
+-- | Lift from 'Trace' monad into monad with 'Build' configuration.
+liftTrace :: Trace a -> Build a
+liftTrace =  lift . lift
+
+-- | Run 'Build' configuration monad
+runBuild :: Build a -> BaseDir -> Config -> Bool -> IO a
+runBuild b bd = runTrace . (runReaderT $ runReaderT b bd)
+
+-- | bracket for 'Build' monad
+bracketBuild :: Build a -> (a -> Build b) -> (a -> Build c) -> Build c
+bracketBuild =  readerBracket $ readerBracket bracketTrace
+
+-- | bracket_ for 'Build' monad
+bracketBuild_ :: Build a -> Build b -> Build c -> Build c
+bracketBuild_ =  toBracket_ bracketBuild
+
+-- | Get base directory in 'Build' monad
+askBaseDir :: FilePath -> Build FilePath
+askBaseDir cur = fromMaybe cur . unBaseDir <$> ask
+
+-- | Get build configuration in 'Build' monad
+askConfig :: Build Config
+askConfig =  lift ask
+
+-- | Get build working directory in 'Build' monad
+askBuildDir :: FilePath -> Build FilePath
+askBuildDir cur = do
+  bd <- buildDir <$> askConfig
+  (`unBuildDir` bd) <$> askBaseDir cur
diff --git a/src/Debian/Package/Build/Sequence.hs b/src/Debian/Package/Build/Sequence.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Build/Sequence.hs
@@ -0,0 +1,258 @@
+-- |
+-- Module      : Debian.Package.Build.Command
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides build-sequence actions.
+module Debian.Package.Build.Sequence
+       ( origArchive, nativeArchive, sourceDir
+
+       , withCurrentDir, withBaseCurrentDir
+
+       , removeBuildDir
+
+       , copyDebianDir
+
+       , rsyncGenOrigSources, rsyncGenNativeSources, rsyncGenSources
+
+       , cabalGenOrigSources, cabalGenSources, cabalAutogenSources
+
+       , genSources
+       ) where
+
+import System.FilePath ((</>), takeFileName, takeDirectory, takeBaseName)
+import System.Directory
+  (doesDirectoryExist, doesFileExist)
+import Control.Applicative (pure, (<$>), (<*>), (<|>))
+import Control.Monad (when)
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
+import Data.Maybe (fromMaybe)
+import Data.List (isPrefixOf)
+
+import Debian.Package.Data
+  (Hackage, hackageLongName, hackageArchive,
+   Source, origArchiveName, nativeArchiveName, sourceDirName, isNative,
+   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
+
+
+-- | Run 'Bulid' action under specified directory.
+withCurrentDir :: FilePath -> Build a -> Build a
+withCurrentDir dir act = do
+  saveDir <- liftIO pwd
+  bracketBuild_
+    (liftTrace $ chdir dir)
+    (liftTrace $ chdir saveDir)
+    act
+
+-- Take base-directory from 'Build' action context.
+getBaseDir :: Build FilePath
+getBaseDir =  liftIO pwd >>= askBaseDir
+
+-- | Run 'Build' action under base-directory.
+withBaseCurrentDir :: Build a -> Build a
+withBaseCurrentDir act = do
+  baseDir <- getBaseDir
+  withCurrentDir baseDir act
+
+-- Take build-directory from 'Build' action context.
+getBuildDir :: Build FilePath
+getBuildDir =  liftIO pwd >>= askBuildDir
+
+-- Pass build-directory to 'Build' action.
+withBuildDir :: (FilePath -> Build a) -> Build a
+withBuildDir f = getBuildDir >>= f
+
+-- | Remove build-directory.
+removeBuildDir :: Build ()
+removeBuildDir = do
+  bldDir <- getBuildDir
+  liftTrace $ do
+    found <- liftIO $ doesDirectoryExist bldDir
+    when found $ rawSystem' ["rm", "-r", bldDir]
+
+-- | Take debian-directory name from 'Build' action context.
+debianDirName :: Build FilePath
+debianDirName =  do
+  mayD <- mayDebianDirName <$> askConfig
+  return $ fromMaybe "debian" mayD
+
+-- | Take original source archive name from 'Build' action context.
+origArchive :: Source -> Build FilePath
+origArchive pkg =
+  withBuildDir $ \w -> return $ w </> origArchiveName pkg
+
+-- | Take debian native source archive name from 'Build' action context.
+nativeArchive :: Source -> Build FilePath
+nativeArchive pkg =
+  withBuildDir $ \w -> return $ w </> nativeArchiveName pkg
+
+-- | Take source directory from 'Build' action context.
+sourceDir :: Source -> Build FilePath
+sourceDir pkg =
+  withBuildDir $ \w -> return $ w </> sourceDirName pkg
+
+-- | Action to copy debian directory from base-directory into specified directory.
+copyDebianDir :: FilePath -> Build ()
+copyDebianDir srcDir = do
+  debDN       <- debianDirName
+  baseDir     <- getBaseDir
+  liftTrace $ rawSystem' ["cp", "-a", baseDir </> debDN, srcDir </> "."]
+
+
+-- Setup source directory under build-directory using rsync.
+rsyncGenOrigSourceDir :: Source -> Build FilePath
+rsyncGenOrigSourceDir pkg = do
+  srcDir   <- sourceDir pkg
+  debDN    <- debianDirName
+  baseDir  <- getBaseDir
+  bldDir   <- getBuildDir
+  let excludes = [takeFileName d
+                 | d <- [bldDir]
+                 , baseDir `isPrefixOf` d ]
+                 ++ [debDN]
+  liftTrace $ do
+    createDirectoryIfMissing srcDir
+    rawSystem'
+      $  ["rsync", "-auv"]
+      ++ ["--exclude=" ++ e | e <- excludes]
+      ++ [baseDir </> ".", srcDir </> "." ]
+  return srcDir
+
+-- | Setup source directory and original source archive under
+--   build-directory using rsync.
+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)
+
+-- | Setup native source directory and native source archive under
+--   build-directory using rsync.
+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)
+
+-- | Setup debian source directory and source archive.
+rsyncGenSources :: Source -> Build (FilePath, FilePath)
+rsyncGenSources pkg
+  | isNative pkg = rsyncGenNativeSources pkg
+  | otherwise    = rsyncGenOrigSources   pkg
+
+
+-- Setup source archive using Cabal.
+cabalGenArchive :: Hackage -> Build FilePath
+cabalGenArchive hkg = do
+  withBaseCurrentDir . liftTrace $ Cabal.sdist []
+  baseDir <- getBaseDir
+  let apath = baseDir </> hackageArchive hkg
+  liftTrace $ confirmPath apath
+  return apath
+
+-- Setup original source archive using Cabal.
+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
+
+-- | Setup original source directory and archive using Cabal.
+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)
+
+-- | Setup source directory and archive using Cabal.
+cabalGenSources :: HaskellPackage -> Build (FilePath, FilePath)
+cabalGenSources hpkg = do
+  pair@(_, srcDir) <- cabalGenOrigSources hpkg
+  copyDebianDir srcDir
+  return pair
+
+cabalAutogenDebianDir :: Build FilePath
+cabalAutogenDebianDir = do
+  baseDir  <-  getBaseDir
+  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 Nothing
+    createDirectoryIfMissing $ takeDirectory debDir
+    renameDirectory tmpDD debDir
+  return debDir
+
+-- | Setup source directory and archive using Cabal and cabal-debian.
+cabalAutogenSources :: String -> Build ((FilePath, FilePath), HaskellPackage)
+cabalAutogenSources hname = do
+  debDir   <-  cabalAutogenDebianDir
+  pkg      <-  liftTrace . dpkgParseChangeLog $ debDir </> "changelog"
+  hpkg     <-  either fail return $ haskellPackageFromPackage hname pkg
+  pair@(_, srcDir)  <-  cabalGenOrigSources hpkg
+  liftTrace $ renameDirectory debDir (srcDir </> takeFileName debDir)
+  return (pair, hpkg)
+
+
+findDebianChangeLog :: MaybeT Build FilePath
+findDebianChangeLog =  MaybeT $ do
+  baseDir  <-  getBaseDir
+  debDN    <-  debianDirName
+  let changelog = baseDir </> debDN </> "changelog"
+  liftIO $ do
+    exist <- doesFileExist changelog
+    return $ if exist
+             then Just changelog
+             else Nothing
+
+findCabalDescription :: MaybeT Build FilePath
+findCabalDescription =  MaybeT (getBaseDir >>= liftIO . Cabal.findDescriptionFile)
+
+-- | On the fly setup of source directory and archive.
+genSources :: Build (Maybe ((FilePath, FilePath), Source, Maybe Hackage))
+genSources =  runMaybeT $
+  do clog <- findDebianChangeLog
+     src  <- lift . liftTrace $ dpkgParseChangeLog clog
+     (do hname <- takeBaseName <$> findCabalDescription
+         hpkg  <- either fail return $ 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
+       return (p, package hpkg, Just $ hackage hpkg)
+  <|>
+  do fail "No source generate rule found."
diff --git a/src/Debian/Package/Data.hs b/src/Debian/Package/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Data.hs
@@ -0,0 +1,17 @@
+-- |
+-- Module      : Debian.Package.Data
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides data-type namespace.
+module Debian.Package.Data
+       ( module Debian.Package.Data.Hackage
+       , module Debian.Package.Data.Source
+       ) where
+
+import Debian.Package.Data.Hackage
+import Debian.Package.Data.Source
diff --git a/src/Debian/Package/Data/Hackage.hs b/src/Debian/Package/Data/Hackage.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Data/Hackage.hs
@@ -0,0 +1,130 @@
+-- |
+-- Module      : Debian.Package.Data.Hackage
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides data types of hackage meta information.
+module Debian.Package.Data.Hackage
+       ( HackageVersion, mkHackageVersion, hackageVersionNumbers
+
+       , Hackage, mkHackage, hackageName, hackageVersion
+       , debianShortName, mkHackageDefault
+
+       , NameRule (..), debianNamesFromSourceName
+
+       , hackageLongName
+
+       , hackageArchiveName, hackageArchive
+
+       , ghcLibraryBinPackages, ghcLibraryDocPackage, ghcLibraryPackages
+       ) where
+
+import Data.List (stripPrefix)
+import Data.Char (toLower)
+import Data.Version (Version (Version), showVersion, parseVersion)
+import Text.ParserCombinators.ReadP (readP_to_S)
+import System.FilePath ((</>), (<.>))
+
+
+-- | Hackage version type
+newtype HackageVersion = HackageVersion (Version)
+
+-- | Make 'HackageVersion'
+mkHackageVersion :: Int -> Int -> Int -> Int -> HackageVersion
+mkHackageVersion v0 v1 v2 v3 = HackageVersion $ Version [v0, v1, v2, v3] []
+
+-- | Extract hackage version numbers.
+hackageVersionNumbers :: HackageVersion -> (Int, Int, Int, Int)
+hackageVersionNumbers = d  where
+  d (HackageVersion (Version [v0, v1, v2, v3] [])) = (v0, v1, v2, v3)
+  d hv                                             = error $ "HackageVersion: Invalid structure: " ++ show hv
+
+instance Show HackageVersion where
+  show (HackageVersion v) = showVersion v
+
+instance Read HackageVersion where
+  readsPrec _ = map toH . filter h . readP_to_S parseVersion  where
+    h (Version b t, _) = length b == 4 && null t
+    toH (v, s) = (HackageVersion v, s)
+
+-- | Hackage name and version type with debian short name. e.g. /src-ext/.
+data Hackage = Hackage String HackageVersion String  deriving Show
+
+-- | Make 'Hackage'
+mkHackage :: String -> HackageVersion -> String -> Hackage
+mkHackage =  Hackage
+
+-- | Get package name of 'Hackage'
+hackageName :: Hackage -> String
+hackageName (Hackage n _ _) = n
+
+-- | Get version of 'Hackage'
+hackageVersion :: Hackage -> HackageVersion
+hackageVersion (Hackage _ v _) = v
+
+-- | Get debian short name of 'Hackage'
+debianShortName :: Hackage -> String
+debianShortName (Hackage _ _ sn) = sn
+
+-- | Generate 'Hackage' type from package name and version
+--   using 'NameRule'
+mkHackageDefault :: NameRule       -- ^ Rule flag to generate names
+                 -> String         -- ^ Hackage name string
+                 -> HackageVersion -- ^ Version of hackage
+                 -> Hackage        -- ^ Result hackage meta info
+mkHackageDefault rule hname hver = mkHackage hname hver short  where
+  (_ , short) = debianNamesFromSourceName rule hname
+
+defaultHackageSrcPrefix :: String
+defaultHackageSrcPrefix =  "haskell-"
+
+-- | Debian short name generate rule
+data NameRule = Suggest | Simple deriving (Eq, Show)
+
+-- | Make debian short name from package name using 'NameRule'
+debianNamesFromSourceName :: NameRule          -- ^ Rule flag to generate name
+                          -> String            -- ^ Debian source name or Hackage name string
+                          -> (String, String)  -- ^ Debian source package name and short name like ("haskell-src-exts", "src-exts")
+debianNamesFromSourceName rule hname = d rule  where
+  lh = map toLower hname
+  d Suggest  =  rec' ["haskell-", "haskell"]
+  d Simple   =  (defaultHackageSrcPrefix ++ lh, lh)
+  rec' []     = (defaultHackageSrcPrefix ++ lh, lh)
+  rec' (p:ps) = case stripPrefix p lh of
+    Just s  -> (lh, s)
+    Nothing -> rec' ps
+
+-- | Package name string with version
+hackageLongName :: Hackage -> String
+hackageLongName hkg = hackageName hkg ++ '-' : show (hackageVersion hkg)
+
+-- | Package archive basename
+hackageArchiveName :: Hackage -> FilePath
+hackageArchiveName hkg = hackageLongName hkg <.> "tar" <.> "gz"
+
+distDir :: String
+distDir =  "dist"
+
+-- | Package archive pathname
+hackageArchive :: Hackage -> FilePath
+hackageArchive =  (distDir </>) . hackageArchiveName
+
+
+-- | Debian library binary package names for GHC
+ghcLibraryBinPackages :: Hackage -> [String]
+ghcLibraryBinPackages hkg =
+  [ concat ["libghc-", debianShortName hkg, '-' : suf]
+  | suf <- ["dev", "prof"]
+  ]
+
+-- | Debian library document package name for GHC
+ghcLibraryDocPackage :: Hackage -> String
+ghcLibraryDocPackage hkg = concat ["libghc-", debianShortName hkg, "-doc"]
+
+-- | Debian library package names for GHC
+ghcLibraryPackages :: Hackage -> [String]
+ghcLibraryPackages hkg = ghcLibraryDocPackage hkg : ghcLibraryBinPackages hkg
diff --git a/src/Debian/Package/Data/Source.hs b/src/Debian/Package/Data/Source.hs
new file mode 100644
--- /dev/null
+++ b/src/Debian/Package/Data/Source.hs
@@ -0,0 +1,218 @@
+-- |
+-- Module      : Debian.Package.Data.Source
+-- Copyright   : 2014 Kei Hibino
+-- License     : BSD3
+--
+-- Maintainer  : ex8k.hibino@gmail.com
+-- Stability   : experimental
+-- Portability : portable
+--
+-- This module provides data types of debian source package meta information.
+module Debian.Package.Data.Source
+       ( DebianVersion, versionFromHackageVersion
+
+       , Source, mkSource, sourceName, version, origVersion, isNative
+
+       , origArchiveName, nativeArchiveName, sourceDirName, deriveHackageVersion
+
+       , parseChangeLog
+
+       , HaskellPackage, hackage, package
+       , haskellPackageDefault, haskellPackageFromPackage
+       ) where
+
+import Data.Maybe (listToMaybe)
+import Control.Arrow (second)
+import Control.Monad (ap, MonadPlus, mplus)
+import Numeric (readDec)
+import Data.Char (isSpace)
+import Data.Version (Version (Version, versionBranch), showVersion, parseVersion)
+import Text.ParserCombinators.ReadP (ReadP, string, readP_to_S, readS_to_P)
+import System.FilePath ((<.>))
+
+import Debian.Package.Data.Hackage
+  (HackageVersion, mkHackageVersion, hackageVersionNumbers,
+   Hackage, mkHackageDefault, NameRule (Simple), debianNamesFromSourceName)
+
+
+-- Combinators like Applicative -- for base-4.5.0.0 - debian wheezy
+
+(<$>) :: Functor m => (a -> b) -> m a -> m b
+(<$>) =  fmap
+
+pure :: Monad m => a -> m a
+pure =  return
+
+(<*>) :: Monad m => m (a -> b) -> m a -> m b
+(<*>) =  ap
+
+(*>) :: Monad m => m a -> m b -> m b
+(*>) =  (>>)
+
+--  (<*) :: (Functor m, Monad m) => m a -> m b -> m a
+--  fa <* fb = const <$> fa <*> fb
+
+(<|>) :: MonadPlus m => m a -> m a -> m a
+(<|>) =  mplus
+
+infixl 3 <|>
+infixl 4 <$>, <*>, *>
+
+
+-- | Version type for Debian
+data DebianVersion
+  = DebianNative    Version (Maybe Int)
+  | DebianNonNative Version String
+
+debianNativeVersion :: [Int] -> Maybe Int -> DebianVersion
+debianNativeVersion v =  DebianNative (Version v [])
+
+debianNonNativeVersion :: [Int] -> String -> DebianVersion
+debianNonNativeVersion v = DebianNonNative (Version v [])
+
+-- | Make deebian version from hackage version
+versionFromHackageVersion :: HackageVersion -> Maybe String -> DebianVersion
+versionFromHackageVersion hv = d where
+  d (Just rev) = debianNonNativeVersion [v0, v1, v2, v3] rev
+  d Nothing    = debianNativeVersion    [v0, v1, v2, v3] Nothing
+  (v0, v1, v2, v3) = hackageVersionNumbers hv
+
+origVersion' :: DebianVersion -> Version
+origVersion' =  d  where
+  d (DebianNative    v _) = v
+  d (DebianNonNative v _) = v
+
+isNative' :: DebianVersion -> Bool
+isNative' = d where
+  d (DebianNative    _ _) = True
+  d (DebianNonNative _ _) = False
+
+lexWord :: String -> [(String, String)]
+lexWord =  (:[]) . break isSpace . dropWhile isSpace
+
+returnParsed :: ReadP a -> String -> ReadP a
+returnParsed p s = case [ x | (x, "") <- readP_to_S p s ] of
+  [x] -> return x
+  []  -> fail "ReadP: no parse"
+  _   -> fail "ReadP: ambiguous parse"
+
+returnParsedVersion :: String -> ReadP Version
+returnParsedVersion =  returnParsed parseVersion
+
+returnParsedNMU :: String -> ReadP (Maybe Int)
+returnParsedNMU = returnParsed $
+                  Just <$> (string "+nmu" *> readS_to_P readDec)  <|>
+                  pure Nothing
+
+parseDebianVersion :: ReadP DebianVersion
+parseDebianVersion =  do
+  vs0 <- readS_to_P lexWord
+  let (vs1, rtag) = break (== '-') vs0
+      (vs2, nmu)  = break (== '+') vs1
+  if rtag == ""
+    then DebianNative    <$> returnParsedVersion vs2 <*> returnParsedNMU nmu
+    else DebianNonNative <$> returnParsedVersion vs1 <*> return (tail rtag)
+
+instance Show DebianVersion where
+  show = d  where
+    d (DebianNative    v nr) = showVersion v ++ maybe "" (("+nmu" ++) . show) nr
+    d (DebianNonNative v r)  = showVersion v ++ '-': r
+
+instance Read DebianVersion where
+  readsPrec _ = readP_to_S parseDebianVersion
+
+readMaybe' :: Read a => String -> Maybe a
+readMaybe' =  fmap fst . listToMaybe . filter ((== "") . snd) . reads
+
+
+-- | Debian source package type, name with version
+data Source = Source String DebianVersion  deriving Show
+
+-- | Make 'Source'
+mkSource :: String -> DebianVersion -> Source
+mkSource =  Source
+
+-- | Source package name of 'Source'
+sourceName :: Source -> String
+sourceName (Source n _) = n
+
+-- | Debian version of 'Source'
+version :: Source -> DebianVersion
+version (Source _ v) = v
+
+-- | Version without debian revision
+origVersion :: Source -> Version
+origVersion =  origVersion' . version
+
+-- | Is debian-native or not
+isNative :: Source -> Bool
+isNative =  isNative' . version
+
+-- | Original source archive basename
+origArchiveName :: Source -> FilePath
+origArchiveName pkg = sourceName pkg ++ '_' : showVersion (origVersion pkg) <.> "orig" <.> "tar" <.> "gz"
+
+-- | Debian native archive basename
+nativeArchiveName :: Source -> String
+nativeArchiveName pkg = sourceName pkg ++ '_' : show (version pkg) <.> "tar" <.> "gz"
+
+-- | Source directory basename
+sourceDirName :: Source -> FilePath
+sourceDirName pkg = sourceName pkg ++ '-' : showVersion (origVersion pkg)
+
+-- | Try to make 'HackageVersion' from 'Source'
+deriveHackageVersion :: Source -> Maybe HackageVersion
+deriveHackageVersion =  d . versionBranch . origVersion where
+  d [v0, v1, v2, v3] = Just $ mkHackageVersion v0 v1 v2 v3
+  d _                = Nothing
+
+-- | Try to generate 'Source' from debian changelog string
+parseChangeLog :: String       -- ^ dpkg-parsechangelog result string
+               -> Maybe Source -- ^ Source structure
+parseChangeLog log' = do
+  deb  <- mayDebSrc
+  dver <- mayDebVer
+  return $ mkSource deb dver
+  where
+    pairs = map (second tail . break (== ' ')) . lines $ log'
+    lookup' = (`lookup` pairs)
+    mayDebSrc = lookup' "Source:"
+    mayDebVer = do
+      dverS <- lookup' "Version:"
+      readMaybe' dverS
+
+
+-- | Debian source package type for Haskell
+data HaskellPackage = HaskellPackage Hackage Source deriving Show
+
+-- | 'Hackage' meta-info of 'HaskellPackage'
+hackage :: HaskellPackage -> Hackage
+hackage (HaskellPackage h _) = h
+
+-- | Debian source package meta-info of 'HaskellPackage'
+package :: HaskellPackage -> Source
+package (HaskellPackage _ p) = p
+
+-- | Generate 'HaskellPackage' type from debian package name and version
+--   using 'NameRule'
+haskellPackageDefault :: NameRule
+                      -> String         -- ^ Hackage name string
+                      -> HackageVersion -- ^ Version of hackage
+                      -> Maybe String   -- ^ Debian revision String
+                      -> HaskellPackage -- ^ Result structure
+haskellPackageDefault rule hname hver mayDevRev =
+  HaskellPackage
+  (mkHackageDefault rule hname hver)
+  (mkSource sn (versionFromHackageVersion hver mayDevRev))
+  where
+    (sn, _) = debianNamesFromSourceName rule hname
+
+-- | Generate 'HaskellPackage' with hackage name and debian package meta-info
+haskellPackageFromPackage :: String                       -- ^ Hackage name string
+                          -> Source                       -- ^ Debian package meta info
+                          -> Either String HaskellPackage -- ^ Result
+haskellPackageFromPackage hname pkg = do
+  hv <- maybe (Left "Fail to derive hackage version") Right
+        $ deriveHackageVersion pkg
+  let hkg = mkHackageDefault Simple hname hv
+  return $ HaskellPackage hkg pkg
