packages feed

bamse-0.9.4: Bamse/Builder.hs

--------------------------------------------------------------------
-- |
-- Module      : Bamse.Builder
-- Description : Toplevel module for a bamse library/app.
-- Copyright   : (c) Sigbjorn Finne, 2004-2009
-- License     : BSD3
--
-- Maintainer  : Sigbjorn Finne <sof@forkIO.com>
-- Stability   : provisional
-- Portability : portable
--
-- Toplevel module for the @Bamse@ library/app. Use @genBuilder@
-- to do the generation of an MSI; it taking a specification of the
-- installer you are wanting to create. That along with the command-line
-- settings are then used to kick off the creation of an MSI database,
-- which will incorporate not only the metadata (installer name, shortcuts etc.)
-- but also the file content and structure that makes up the tree of
-- files you want to install on the user's machine.
-- 
--------------------------------------------------------------------
module Bamse.Builder 
       ( genBuilder 
       , genBuilderArgs
       ) where

import Bamse.Package
import Bamse.Writer
import Bamse.IMonad
import Bamse.PackageGen
import Bamse.MSIExtra
import Bamse.PackageUtils
import Bamse.DialogUtils

import System.Win32.Com ( coRun )
import System.FilePath
import Bamse.Util.Dir
import Bamse.Util.List ( ifCons )

import System.Cmd
import System.IO
import Data.Maybe
import Bamse.Options
import System.Directory

-- ToDo:
--     - ability to organise installed bits into features/sub parts.
-- 

-- | @genBuilderArgs pkg argv@ constructs an MSI from the given package
-- description + a set of command-line of arguments @args@.
genBuilderArgs :: PackageData -> [String] -> IO ()
genBuilderArgs pkg args = do
  opts      <- getOptionsFrom args (p_defOutFile pkg)
  genBuilderOpts pkg opts

-- | @genBuilder pkg @ constructs an MSI from the given package
-- description, plus taking the command-line arguments from @getArgs@.
genBuilder :: PackageData -> IO ()
genBuilder pkg = do
  putStrLn ("Installer builder for: " ++ name (p_pkgInfo pkg)) >> hFlush stdout
  opts           <- getOptions (p_defOutFile pkg)
  genBuilderOpts pkg opts

genBuilderOpts :: PackageData -> Options -> IO ()
genBuilderOpts pkg opts = do
  ds             <- (p_fileMap pkg) (opt_ienv opts)
  (dsDist, _ienv) <- mkDistTree (opt_ienv opts)        
                                (normalise $ dropTrailingPathSeparator $ srcDir $ opt_ienv opts)
  			        (name $ p_pkgInfo pkg)
				(p_distFileMap pkg)
  			        ds
  let pkg' = pkg{ p_files   = dsDist
		, p_dialogs = 
		       ifCons (p_userInstall pkg) setupTypeDialog $
		         ifCons (isJust (p_cabalPackage pkg)) (cabalDialog (fromJust (p_cabalPackage pkg))) $
--retired:	         ifCons (isJust (p_ghcPackage pkg)) ghcPkgDialog $
			   -- add customization selection dialog only if the
			   -- builder supplies the relevant features.
			  case options_ (opt_ienv opts) of
			    [] -> []
			    os -> [customizeDialog os]
  		, p_productGUID  = fromJust (opt_productGUID opts)
		, p_revisionGUID = fromJust (opt_revisionGUID opts)
		, p_ienv         = opt_ienv opts
		, p_verbose      = opt_verbose opts
  		}
  let bamseDir = toolDir (p_ienv pkg')
  coRun $ do
    (_, ts, tabs, reps) <-  doInstall [] (genTables pkg')
    let wenv = 
         WriterEnv 
            { w_toolDir     = bamseDir
   	    , w_templateDir = lFile (lFile bamseDir "data") "msi"
	    , w_outFile     = outFile (p_ienv pkg')
	    , w_srcDir      = normalise (takeDirectory (srcDir $ p_ienv pkg'))
	    , w_package     = pkg'
	    }
    outputMSI wenv tabs ts reps
    return ()
 where
  options_ ienv
   = ifCons (not (null (p_extensions pkg ienv)))
   	    ("Register file extensions", "OptFileExt", True) $
       ifCons (not (null (p_desktopShortcuts pkg ienv)))
              ("Create desktop shortcuts", "OptDesktopShortcuts", True) $
	 ifCons (not (null (snd $ p_startMenu pkg ienv)))
	        ("Create start menu folder", "OptStartMenu", True)
		[]


mkDistTree :: InstallEnv
	   -> FilePath
	   -> String
	   -> Maybe (FilePath -> Maybe FilePath)
	   -> DirTree
	   -> IO (DirTree, InstallEnv)
mkDistTree ienv _      _  Nothing   ds = return (ds, ienv)
mkDistTree ienv topDir nm (Just fn) ds = do
     -- copy over directory tree into temporary 'outDir'
    fp <- getCurrentDirectory
    catch (createDirectory (appendP fp "out")) (\ _ -> return ())
    let outDir = appendP fp (appendP "out" nm)
    catch (createDirectory outDir) (\ _ -> return ())
    copyOver outDir ds
    ds1 <- allFiles outDir
    return (ds1, ienv{srcDir=outDir})
  where
    copyOver _ Empty         = return ()
    copyOver outDir (File f) = do
      case fn f of
        Nothing  -> return ()
	Just fnm -> do
          let cmd = ("copy /b \"" ++ fnm ++ "\" \"" ++ 
	             appendP outDir (dropDirPrefix topDir fnm) ++ "\" > nul")
          system cmd
          return ()
    copyOver outDir (Directory fp subs) = do
       maybe (return ())
             (\ f -> system ("mkdir " ++ appendP outDir (dropDirPrefix topDir f)) >> return ())
	     (fn fp)
       mapM_ (copyOver outDir) subs

    appendP a b = normalise (a </> b)