{- | Module : Cabal Description : Building an installer from your Cabal project. Copyright : (c) Sigbjorn Finne, 2009 License : BSD3 Generating an MSI installer from your Cabal-built Haskell library or application. This is an example of how to take the contents of your Cabal project and box it up in Windows Installer form. Along with details specifying the properties of your package (name, author, project web site etc.) you also list the files you want to include. Given those two pieces, the Bamse builder goes to work, outputting in the end a working MSI that's ready for distribution. -} module Main where import Bamse.Package import Bamse.PackageUtils ( dropDirPrefix ) import Bamse.Builder import Data.List ( isPrefixOf ) import System.FilePath --import Debug.Trace -- | @main@ kicks off the party. To see what command-line options -- it supports, invoke it with @--help@. -- -- Typical invocation: -- -- > foo$ genCabal --generate-guids -o myInstaller.msi c:/path/to/the/top/of/my/cabal/pkg -- > # if you want to re-generate the MSI (but not update its product etc. GUIDs.) -- > foo$ genCabal -u -o myInstaller.msi c:/path/to/the/top/of/my/cabal/pkg main :: IO () main = do genBuilder pkgCabal -- alternatively, supply the command-line arguments directly: -- (this is something you want to do when integrating the Bamse library -- into your application directly.) -- genBuilderArgs pkgCabal ["--generate-guids", "-o", "c:/public/deploy/myInst.msi"] -- | @pkgCabal@ is the toplevel 'Bamse.Package.PackageData' value, containing -- all the interesting bits of info that make up an MSI (as seen/supported by Bamse..) -- We /derive/ it from 'Bamse.Package.minimalPackageData', which supplies default -- values for most MSI package properties. Here we simply override with the portions -- relevant to our Cabal example. For more comprehensive and demanding installers, -- please consult 'Bamse.Package.PackageData' or see the @templates/@ directory for -- live examples of other installer specifications. pkgCabal :: PackageData pkgCabal = minimalPackageData { p_fileMap = dirTree , p_defOutFile = defaultOutputFile , p_pkgInfo = cabalPkgInfo , p_webSite = webSite , p_baseFeature = baseFeature , p_desktopShortcuts = \ _ienv -> [] -- Note: this needs to be a .rtf file holding your license. If you -- supply one (after having generated the RTF via wordpad or some such..), -- the installer will include in its UI a user-agreement form displaying -- the license text. , p_license = \ _ -> Nothing -- Somewhat confusing perhaps, but this field is used to control the -- on-install running of Cabal itself, letting you automatically install -- (and possibly) the Cabal package at install-time. (The user is given -- a choice whether or not to do this in the UI.) We want to do this, -- but only allow the @install@ step; no support for building from source. , p_cabalPackage = Just cabalPackage } -- -- The rest of this module supplies the definitions of the fields that we -- filled in for @pkgCabal' -- -- First, some overall package information: -- pkgName :: String pkgName = "MyPackage" pkgVersion :: String pkgVersion = "1.2.0" -- major.minor.build[.whatever] pkgAuthor :: String pkgAuthor = "Kap. Abel" cabalPkgInfo :: Package cabalPkgInfo = Package { name = pkgName , title = pkgName -- will show up in UI. , productVersion = pkgVersion , author = pkgAuthor , comment = "This is an example package" } -- | @dirTree@ is the function that walks over the directory -- you point the MSI generator at when running, returning the -- files and directories to include in the generated MSI. -- -- This particular one will include anything inside the build @dist/@ -- directory + the .cabal, LICENSE and Setup.hs files. We -- don't consider including the sources here, but doing so -- is an easy extension (see @templates/@ for examples of this.) -- dirTree :: InstallEnv -> IO DirTree dirTree ienv = findFiles ofInterest topDir where topDir = srcDir ienv ofInterest f = {-trace (show (f_local,res)) -}res where f_local = dropDirPrefix topDir f res = null f_local || "dist" `isPrefixOf` f_local || takeExtension f_local == ".cabal" || f_local `elem` package_files package_files = ["Setup.hs", "LICENSE", "README", "custWrap.exe"] -- | Extra Cabal specific information used to direct installation -- of the package on the user's machine. cabalPackage :: CabalPackage cabalPackage = CabalPackage { cabal_packageName = name cabalPkgInfo , cabal_forGhcVersion = "6.10.1" , cabal_packageFile = Just (name cabalPkgInfo ++ ".cabal") , cabal_pkgCmdLine = Nothing , cabal_fromSource = False -- don't support from source building via the MSI. } -- | When invoked the MSI generator can emit the MSI into a default output file. -- (the @-o@ option is what you would normally use to override this.) defaultOutputFile :: FilePath defaultOutputFile = name cabalPkgInfo ++ '-':map subst (productVersion cabalPkgInfo) ++ ".msi" where subst '.' = '-' subst ch = ch -- | @webSite@ contains the URL for the package itself. -- If that doesn't apply to you, its Hackage URL would be good. webSite :: {-URL-}String webSite = "http://www.haskell.org/cabal" -- | @baseFeature@ is a mostly-internal name, but you need to supply -- a name. Defaults to @cabalPkgInfo.name@ baseFeature :: Feature baseFeature = (name cabalPkgInfo, name cabalPkgInfo ++ " package for GHC")