packages feed

happstack-0.3.1: commands/happstack.hs

-- happstack command
module Main (main) where

import Control.Monad (filterM, liftM, mapM, mapM_)
import Paths_happstack (getDataDir)
import System.Environment (getArgs)
import System.Directory
    ( canonicalizePath
    , createDirectoryIfMissing
    , doesFileExist
    , doesDirectoryExist
    , copyFile
    )
import System.FilePath ((</>), makeRelative)
import Happstack.Util.AutoBuild (autoBuild)
import Happstack.Util.FileManip (always, find)

data Command
  = NewProjectCmd FilePath
  | BuildAutoCmd String String [String]
  | HelpCmd

main :: IO ()
main = do
  args <- getArgs
  case processArgs args of
    NewProjectCmd dir -> newProject dir
    BuildAutoCmd buildCmd binPath binArgs -> buildAuto buildCmd binPath binArgs
    HelpCmd -> do
      putStrLn "Usage: happstack <command>"
      putStrLn "Possible commands:"
      putStrLn "  build auto <buildCmd> <binPath> <binArgs>...: invoke the auto-builder"
      putStrLn "  new project <dir>: create a new happstack project"
  
processArgs :: [String] -> Command
processArgs ("build" : "auto" : buildCmd : binPath : binArgs) =
    BuildAutoCmd buildCmd binPath binArgs
processArgs ["new", "project", dir] = NewProjectCmd dir
processArgs ["help"]                = HelpCmd
processArgs _                       = HelpCmd
    
buildAuto :: String -> String -> [String] -> IO ()
buildAuto = autoBuild

newProject :: FilePath -> IO ()
newProject destDir' = do
    dataDir <- liftM (</> "templates" </> "project") getDataDir
    destDir <- canonicalizePath destDir'
    
    -- create destDir if needed
    createDir destDir

    -- create dirs
    srcDirs <- getSourceDirs dataDir
    let destDirs = map ((destDir </>) . makeRelative dataDir) srcDirs
    mapM_ createDir destDirs

    -- create files
    srcFiles <- getSourceFiles dataDir
    let destFiles = map ((destDir </>) . makeRelative dataDir) srcFiles
    mapM_ cp $ zip srcFiles destFiles
    where createDir = createDirectoryIfMissing True
      
-- only source dirs
getSourceDirs :: FilePath -> IO [FilePath]
getSourceDirs dataDir = filterM doesDirectoryExist =<< getSourceData dataDir

-- only source files
getSourceFiles :: FilePath -> IO [FilePath]
getSourceFiles dataDir = filterM doesFileExist =<< getSourceData dataDir

-- source data for project skeleton
getSourceData :: FilePath -> IO [FilePath]
getSourceData rawDataDir = do
    dataDir <- canonicalizePath rawDataDir
    all <- mapM canonicalizePath =<< (find always always dataDir)
    return $ filter (/= dataDir) all

-- does not work for folders
cp :: (FilePath, FilePath) -> IO ()
cp (src, dest) = do
  exists <- doesFileExist dest
  if exists
    then putStrLn $ "File exists already, skipping: " ++ dest
    else copyFile src dest