-- | Dealing with Cabal packages in Fay's own special way. module Language.Fay.Compiler.Packages where import Language.Fay.Types import Control.Monad import Data.List import GHC.Paths import System.Directory import System.FilePath import System.Process.Extra -- | Given a configuration, resolve any packages specified to their -- data file directories for importing the *.hs sources. resolvePackages :: CompileConfig -> IO CompileConfig resolvePackages config = do foldM resolvePackage config (configPackages config) -- | Resolve package. resolvePackage :: CompileConfig -> String -> IO CompileConfig resolvePackage config name = do desc <- describePackage (configPackageConf config) name case shareDirs desc of Nothing -> error $ "unable to find share dir of package: " ++ name Just dirs -> do mapM_ checkDirExists dirs return (addConfigDirectoryIncludes dirs config) -- | Describe package with ghc-pkg. -- -- Weinsworth : Why are you not using the GHC API which would -- provide you this information like in modules like -- Packages which has functions like -- -- collectIncludeDirs :: [PackageConfig] -> [FilePath] -- -- and awesome stuff like that. What are you, stupid? -- -- Batemen : Pretty much. I think this might be a little faster than -- initializing GHC, and using the GHC API adds a lot of -- link time when you use it. -- -- Weinsworth : Uh huh. -- -- Batemen: Yeah. Stop looking at me like that. -- describePackage :: Maybe FilePath -> String -> IO String describePackage db name = do result <- readAllFromProcess ghc_pkg args "" case result of Left err -> error $ "ghc-pkg describe error:\n" ++ err Right (_err,out) -> return out where args = concat [["describe",name] ,["-f" ++ db' | Just db' <- [db]]] -- | Get the share dirs of the package. -- -- Alright. -- Stop. -- Collaborate and listen. -- -- You're gonna have to stop scrolling and read this. -- -- I can't figure out how to get the data-dirs from the package -- description. -- -- * It doesn't seem to be in the Cabal API's PackageDescription type. -- * It doesn't seem to be in the ghc-pkg description. -- * I can't find out how to read the Cabal configuration. Yeah, I -- could probably find it eventually. Shut up. -- -- So what I'm doing is parsing the “import-dirs” flag, which -- appears in ghc-pkg's output like this: -- -- /home/chris/Projects/me/fay-jquery/cabal-dev//lib/fay-jquery-0.1.0.0/ghc-7.4.1 -- -- And I'm going to replace “lib” with “share” and drop the “ghc-*” -- and that, under a *normal* configuration, gives the share -- directory. -- -- Under an atypical situation, we're going to throw an error and -- you guys will just have to submit a pull request or some code to -- do this better, because I've got better things to be doing, like -- climbing trees, baking cookies and reading books about zombies. -- shareDirs :: String -> Maybe [FilePath] shareDirs desc = case find (isPrefixOf "import-dirs: ") (lines desc) of Nothing -> Nothing Just idirs -> case words idirs of -- I'm going to take the first one. If you've got more, just, -- I hate you. (_import_dirs:idir:_) -> Just $ [munge idir ,munge idir "src"] -- Yep. _ -> Nothing where munge = joinPath . reverse . swap . dropGhc . reverse . map dropTrailingPathSeparator . splitPath where dropGhc = drop 1 swap (name_version:"lib":rest) = name_version : "share" : rest swap paths = error $ "unable to complete munging of the lib dir\ \, see Language.Fay.Compiler.Packages.hs \ \for an explanation: " ++ "\npath was: " ++ joinPath paths -- | Might as well check the dir that we munged to death actually -- exists. -___ - checkDirExists :: FilePath -> IO () checkDirExists p = do don'tFlipOut <- doesDirectoryExist p unless don'tFlipOut $ error $ "so the directory we munged doesn't exist:\n " ++ p ++ "\nreport a bug, we screwed up."