summaryrefslogtreecommitdiff
path: root/libraries/ghc-boot/GHC/EnvironmentFiles.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ghc-boot/GHC/EnvironmentFiles.hs')
-rw-r--r--libraries/ghc-boot/GHC/EnvironmentFiles.hs193
1 files changed, 193 insertions, 0 deletions
diff --git a/libraries/ghc-boot/GHC/EnvironmentFiles.hs b/libraries/ghc-boot/GHC/EnvironmentFiles.hs
new file mode 100644
index 0000000000..947d5089fd
--- /dev/null
+++ b/libraries/ghc-boot/GHC/EnvironmentFiles.hs
@@ -0,0 +1,193 @@
+-- | Logic for finding and parsing environemnt files
+module GHC.EnvironmentFiles where
+
+import GHC.Platform.ArchOS
+import GHC.AppDir
+import Prelude
+import Control.Monad.Trans.Maybe
+import Control.Monad.IO.Class
+import Control.Monad
+import System.Directory
+import System.FilePath
+import Control.Exception
+import Data.Maybe
+import System.IO.Error
+import System.Environment
+
+data PackageEnvironment = PackageEnvironment [PackageFlag] deriving Show
+
+
+-- -----------------------------------------------------------------------------
+-- | Find the package environment (if one exists)
+--
+-- We interpret the package environment as a set of package flags; to be
+-- specific, if we find a package environment file like
+--
+-- > clear-package-db
+-- > global-package-db
+-- > package-db blah/package.conf.d
+-- > package-id id1
+-- > package-id id2
+--
+-- we interpret this as
+--
+-- > [ -hide-all-packages
+-- > , -clear-package-db
+-- > , -global-package-db
+-- > , -package-db blah/package.conf.d
+-- > , -package-id id1
+-- > , -package-id id2
+-- > ]
+--
+-- There's also an older syntax alias for package-id, which is just an
+-- unadorned package id
+--
+-- > id1
+-- > id2
+--
+findPackageEnv :: (String -> IO ()) -> Maybe String -> Bool -> String -> ArchOS -> IO (Maybe PackageEnvironment)
+findPackageEnv logger packageEnv hide_all_packages prog_name archOS = do
+ mPkgEnv <- runMaybeT $ msum $ [
+ getCmdLineArg >>= \env -> msum [
+ probeNullEnv env
+ , probeEnvFile env
+ , probeEnvName env
+ , cmdLineError env
+ ]
+ , getEnvVar >>= \env -> msum [
+ probeNullEnv env
+ , probeEnvFile env
+ , probeEnvName env
+ , envError env
+ ]
+ , notIfHideAllPackages >> msum [
+ findLocalEnvFile >>= probeEnvFile
+ , probeEnvName defaultEnvName
+ ]
+ ]
+ case mPkgEnv of
+ Nothing ->
+ -- No environment found. Leave DynFlags unchanged.
+ return Nothing
+ Just "-" -> do
+ -- Explicitly disabled environment file. Leave DynFlags unchanged.
+ return Nothing
+ Just envfile -> do
+ content <- readFile envfile
+ logger ("Loaded package environment from " ++ envfile)
+ let res = parseEnvFile envfile content
+ case res of
+ Left err -> error err
+ Right p_e -> return (Just p_e)
+-- let (_, dflags') = runCmdLine (runEwM (setFlagsFromEnvFile envfile content)) dflags
+
+ -- return dflags'
+ where
+ -- Loading environments (by name or by location)
+
+-- archOS = platformArchOS (targetPlatform dflags)
+
+ namedEnvPath :: String -> MaybeT IO FilePath
+ namedEnvPath name = do
+ appdir <- versionedAppDir prog_name archOS
+ return $ appdir </> "environments" </> name
+
+ probeEnvName :: String -> MaybeT IO FilePath
+ probeEnvName name = probeEnvFile =<< namedEnvPath name
+
+ probeEnvFile :: FilePath -> MaybeT IO FilePath
+ probeEnvFile path = do
+ guard =<< liftIO (doesFileExist path)
+ return path
+
+ probeNullEnv :: FilePath -> MaybeT IO FilePath
+ probeNullEnv "-" = return "-"
+ probeNullEnv _ = mzero
+ -- Various ways to define which environment to use
+
+ getCmdLineArg :: MaybeT IO String
+ getCmdLineArg = MaybeT $ return packageEnv
+
+ getEnvVar :: MaybeT IO String
+ getEnvVar = do
+ mvar <- liftIO $ try $ getEnv "GHC_ENVIRONMENT"
+ case mvar of
+ Right var -> return var
+ Left err -> if isDoesNotExistError err then mzero
+ else liftIO $ throwIO err
+
+ notIfHideAllPackages :: MaybeT IO ()
+ notIfHideAllPackages =
+ guard (not hide_all_packages)
+
+ defaultEnvName :: String
+ defaultEnvName = "default"
+
+ -- e.g. .ghc.environment.x86_64-linux-7.6.3
+ localEnvFileName :: FilePath
+ localEnvFileName = ".ghc.environment" <.> versionedFilePath archOS
+
+ -- Search for an env file, starting in the current dir and looking upwards.
+ -- Fail if we get to the users home dir or the filesystem root. That is,
+ -- we don't look for an env file in the user's home dir. The user-wide
+ -- env lives in ghc's versionedAppDir/environments/default
+ findLocalEnvFile :: MaybeT IO FilePath
+ findLocalEnvFile = do
+ curdir <- liftIO getCurrentDirectory
+ homedir <- tryMaybeT getHomeDirectory
+ let probe dir | isDrive dir || dir == homedir
+ = mzero
+ probe dir = do
+ let file = dir </> localEnvFileName
+ exists <- liftIO (doesFileExist file)
+ if exists
+ then return file
+ else probe (takeDirectory dir)
+ probe curdir
+
+ -- Error reporting
+
+ cmdLineError :: String -> MaybeT IO a
+ cmdLineError env = liftIO . ioError $
+ mkIOError doesNotExistErrorType
+ ("Package environment " ++ show env ++ " not found")
+ Nothing
+ (Just env)
+
+ envError :: String -> MaybeT IO a
+ envError env = liftIO . ioError $
+ mkIOError doesNotExistErrorType
+ ( ("Package environment "
+ ++ show env
+ ++ " (specified in GHC_ENVIRONMENT) not found") )
+ Nothing
+ (Just env)
+
+data PackageFlag = PackageDb String
+ | ClearPackageDb
+ | HidePackage String
+ | GlobalPackageDb
+ | UserPackageDb
+ | PackageId String
+ deriving Show
+
+parseEnvFile :: FilePath -> String -> Either String PackageEnvironment
+parseEnvFile envfile = fmap (PackageEnvironment . catMaybes) . mapM parseEntry . lines
+ where
+ parseEntry str = case words str of
+ ("package-db": _) -> return (Just (PackageDb (envdir </> db)))
+ -- relative package dbs are interpreted relative to the env file
+ where envdir = takeDirectory envfile
+ db = drop 11 str
+ ["clear-package-db"] -> return (Just ClearPackageDb)
+ ["hide-package", pkg] -> return (Just (HidePackage pkg))
+ ["global-package-db"] -> return (Just GlobalPackageDb)
+ ["user-package-db"] -> return (Just UserPackageDb)
+ ["package-id", pkgid] -> return (Just (PackageId pkgid))
+ (('-':'-':_):_) -> return Nothing -- comments
+ -- and the original syntax introduced in 7.10:
+ [pkgid] -> return (Just (PackageId pkgid))
+ [] -> return Nothing
+ _ -> Left $
+ "Can't parse environment file entry: "
+ ++ envfile ++ ": " ++ str