-- -- >>> Hub.hub <<< -- -- This module provdes the central Hub abstraction. As the primary purpose -- of a hub is to execute programs in a controlled environment it includes -- the 'exec' utilities for setting up the PATH, GHC_PACKAGE_PATH and munging -- cabal's command-line arguments, etc. -- -- (c) 2011-2012 Chris Dornan module Hub.Hub ( Hub(..) , UsrHub(..) , HubName , HubKind(..) , HubSource(..) , prettyHubKind , checkHubName , isHubName , hubUserPackageDBPath , usr_ghHUB , usr_dbHUB , lockedHUB , Mode(..) , execP , execProg , hub_ftr_env ) where import Data.Char import Text.Printf --import System.IO import System.Exit import System.FilePath import System.Environment import Hub.FilePaths import Hub.System import Hub.Directory.Allocate import Hub.Oops import Hub.Prog data Hub = HUB { sourceHUB :: HubSource , name__HUB :: HubName , kind__HUB :: HubKind , path__HUB :: FilePath , commntHUB :: String , hc_binHUB :: FilePath , tl_binHUB :: FilePath , ci_vrnHUB :: Maybe String , glb_dbHUB :: FilePath , usr___HUB :: Maybe UsrHub } deriving (Show) data UsrHub = UHB { dir___UHB :: FilePath , glb_hnUHB :: HubName , usr_dbUHB :: FilePath , lockedUHB :: Bool } deriving (Show) type HubName = String data HubKind = GlbHK -- global hub | UsrHK -- user hub deriving (Eq,Ord,Bounded,Enum,Show) data HubSource = ClHS -- hub sepcified on command line | EvHS -- hub specified by environment variable | DrHS -- hub specified by a directory marker | DsHS -- hub specified by system default deriving (Show) prettyHubKind :: HubKind -> String prettyHubKind GlbHK = "global" prettyHubKind UsrHK = "user" checkHubName :: [HubKind] -> HubName -> IO HubKind checkHubName hks hn = case isHubName hn of Nothing -> oops PrgO $ printf "%s is not a valid hub name" hn Just hk | hk `elem` hks -> return hk | otherwise -> oops PrgO $ printf "%s is a %s hub" hn $ prettyHubKind hk isHubName :: HubName -> Maybe HubKind isHubName hn = case hn of c:cs | all hubname_c cs -> fst_hubname_c c _ -> Nothing hubUserPackageDBPath :: Hub -> IO FilePath hubUserPackageDBPath hub = case usr___HUB hub of Nothing -> oops PrgO $ printf "%s: not a user hub" $ name__HUB hub Just uhb -> return $ usr_dbUHB uhb usr_ghHUB :: Hub -> Maybe FilePath usr_ghHUB = fmap glb_hnUHB . usr___HUB usr_dbHUB :: Hub -> Maybe FilePath usr_dbHUB = fmap usr_dbUHB . usr___HUB lockedHUB :: Hub -> Bool lockedHUB hub = maybe False lockedUHB $ usr___HUB hub data Mode = FullMDE | UserMDE execP :: Oops -> ExecEnv -> Mode -> Hub -> P -> [String] -> IO () execP o ee0 mde hub p args0 = execProg o ee0 mde hub (p2prog p) args0 execProg :: Oops -> ExecEnv -> Mode -> Hub -> Prog -> [String] -> IO () execProg o ee0 mde hub prog args0 = do case (mde,usr___HUB hub) of (UserMDE,Nothing) -> oops o "user hub expected" _ -> return () (exe,args,tdy) <- mk_prog hub prog args0 pth0 <- getEnv "PATH" let p = enmPROG prog ee = ee0 { extendEnvtEE = hub_env p mde hub pth0 ++ extendEnvtEE ee0 , filterEnvtEE = hub_ftr_env p ++ filterEnvtEE ee0 } -- h <- openFile "/hub/src/exec.log" AppendMode -- hPutStrLn h "----- ee -------------" -- hPutStrLn h $ show ee -- hPutStrLn h "----- exe ------------" -- hPutStrLn h $ show exe -- hPutStrLn h "----- args -----------" -- hPutStrLn h $ show args -- hPutStrLn h "----- tdy ------------" -- hPutStrLn h $ show tdy -- hPutStrLn h "----------------------" -- hPutStrLn h "" -- hClose h ec <- exec ee exe args case tdy of Nothing -> return () Just hd -> tidyDir hd case ec of ExitSuccess -> return () ExitFailure n -> oops o $ printf "%s failure (return code=%d)" exe n -- -- Executing Programmes -- mk_prog :: Hub -> Prog -> [String] -> IO (FilePath,[String],Maybe FilePath) mk_prog hub prog as0 = do (as,tdy) <- case (hk/=GlbHK,enmPROG prog,as0) of (True,CabalP,"configure":as') -> ci "configure" as' (True,CabalP,"install" :as') -> ci "install" as' (True,CabalP,"upgrade" :as') -> ci "upgrade" as' _ -> return (as0,Nothing) return (exe,as,tdy) where exe = case typPROG prog of HcPT -> hc_binHUB hub nmePROG prog TlPT -> tl_binHUB hub prog_name hub prog hk = kind__HUB hub ci cmd as' = do hd <- allocate db <- hubUserPackageDBPath hub let _ld = "--libdir=" ++ hd _pd = "--package-db=" ++ db _hc = "--with-hsc2hs=hsc2hs" return ( cmd : _ld : _pd : _hc : as', Just hd ) prog_name :: Hub -> Prog -> FilePath prog_name hub prog = case (enmPROG prog,ci_vrnHUB hub) of (CabalP,Just ci_vrn) -> nmePROG prog ++ "-" ++ ci_vrn _ -> nmePROG prog hub_env :: P -> Mode -> Hub -> String -> [(String,String)] hub_env p mde hub pth0 = concat [ [ (,) "HUB" hnm ] , [ (,) "PATH" pth | is_usr ] , [ (,) "GHC_PACKAGE_PATH" ppt | is_usr && p /= CabalP ] ] where is_usr = hk /= GlbHK pth = printf "%s:%s:%s" hubGccBin hubBinutilsBin pth0 ppt = case mb_usr of Nothing -> glb Just uhb -> case mde of UserMDE -> udb FullMDE -> printf "%s:%s" udb glb where udb = usr_dbUHB uhb hnm = name__HUB hub hk = kind__HUB hub mb_usr = usr___HUB hub glb = glb_dbHUB hub hub_ftr_env :: P -> [String] hub_ftr_env CabalP = ["GHC_PACKAGE_PATH"] hub_ftr_env _ = [] -- -- Validating Hub Names -- fst_hubname_c :: Char -> Maybe HubKind fst_hubname_c c | glb_first_hub_name_c c = Just GlbHK | usr_first_hub_name_c c = Just UsrHK | otherwise = Nothing hubname_c :: Char -> Bool hubname_c c = c `elem` "_-." || isAlpha c || isDigit c glb_first_hub_name_c, usr_first_hub_name_c :: Char -> Bool glb_first_hub_name_c c = isDigit c usr_first_hub_name_c c = c `elem` "_." || isAlpha c