{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -- | Handy path information. module Stack.Path ( path , pathParser ) where import Data.List ( intercalate ) import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Options.Applicative as OA import Path ( (), parent ) import Path.Extra ( toFilePathNoTrailingSep ) import RIO.Process ( HasProcessContext (..), exeSearchPathL ) import Stack.Constants import Stack.Constants.Config import Stack.GhcPkg as GhcPkg import Stack.Prelude import Stack.Runners import Stack.Types.Config import qualified System.FilePath as FP -- | Print out useful path information in a human-readable format (and -- support others later). path :: [Text] -> RIO Runner () path keys = do let deprecated = filter ((`elem` keys) . fst) deprecatedPathKeys forM_ deprecated $ \(oldOption, newOption) -> logWarn $ "\n" <> "'--" <> display oldOption <> "' will be removed in a future release.\n" <> "Please use '--" <> display newOption <> "' instead.\n" <> "\n" let -- filter the chosen paths in flags (keys), -- or show all of them if no specific paths chosen. goodPaths = filter ( \(_, key, _) -> (null keys && key /= T.pack deprecatedStackRootOptionName) || elem key keys ) paths singlePath = length goodPaths == 1 toEither (_, k, UseHaddocks p) = Left (k, p) toEither (_, k, WithoutHaddocks p) = Right (k, p) (with, without) = partitionEithers $ map toEither goodPaths runHaddock True $ printKeys with singlePath runHaddock False $ printKeys without singlePath printKeys :: HasEnvConfig env => [(Text, PathInfo -> Text)] -> Bool -> RIO env () printKeys extractors single = do pathInfo <- fillPathInfo liftIO $ forM_ extractors $ \(key, extractPath) -> do let prefix = if single then "" else key <> ": " T.putStrLn $ prefix <> extractPath pathInfo runHaddock :: Bool -> RIO EnvConfig () -> RIO Runner () runHaddock x action = local modifyConfig $ withConfig YesReexec $ withDefaultEnvConfig action where modifyConfig = set (globalOptsL.globalOptsBuildOptsMonoidL.buildOptsMonoidHaddockL) (Just x) fillPathInfo :: HasEnvConfig env => RIO env PathInfo fillPathInfo = do -- We must use a BuildConfig from an EnvConfig to ensure that it contains the -- full environment info including GHC paths etc. piBuildConfig <- view $ envConfigL.buildConfigL -- This is the modified 'bin-path', -- including the local GHC or MSYS if not configured to operate on -- global GHC. -- It was set up in 'withBuildConfigAndLock -> withBuildConfigExt -> setupEnv'. -- So it's not the *minimal* override path. piSnapDb <- packageDatabaseDeps piLocalDb <- packageDatabaseLocal piExtraDbs <- packageDatabaseExtra piGlobalDb <- view $ compilerPathsL.to cpGlobalDB piSnapRoot <- installationRootDeps piLocalRoot <- installationRootLocal piToolsDir <- bindirCompilerTools piHoogleRoot <- hoogleRoot piDistDir <- distRelativeDir piHpcDir <- hpcReportDir piCompiler <- getCompilerPath pure PathInfo {..} pathParser :: OA.Parser [Text] pathParser = mapMaybeA ( \(desc,name,_) -> OA.flag Nothing (Just name) ( OA.long (T.unpack name) <> OA.help desc ) ) paths -- | Passed to all the path printers as a source of info. data PathInfo = PathInfo { piBuildConfig :: !BuildConfig , piSnapDb :: !(Path Abs Dir) , piLocalDb :: !(Path Abs Dir) , piGlobalDb :: !(Path Abs Dir) , piSnapRoot :: !(Path Abs Dir) , piLocalRoot :: !(Path Abs Dir) , piToolsDir :: !(Path Abs Dir) , piHoogleRoot :: !(Path Abs Dir) , piDistDir :: Path Rel Dir , piHpcDir :: !(Path Abs Dir) , piExtraDbs :: ![Path Abs Dir] , piCompiler :: !(Path Abs File) } instance HasPlatform PathInfo instance HasLogFunc PathInfo where logFuncL = configL.logFuncL instance HasRunner PathInfo where runnerL = configL.runnerL instance HasStylesUpdate PathInfo where stylesUpdateL = runnerL.stylesUpdateL instance HasTerm PathInfo where useColorL = runnerL.useColorL termWidthL = runnerL.termWidthL instance HasGHCVariant PathInfo instance HasConfig PathInfo instance HasPantryConfig PathInfo where pantryConfigL = configL.pantryConfigL instance HasProcessContext PathInfo where processContextL = configL.processContextL instance HasBuildConfig PathInfo where buildConfigL = lens piBuildConfig (\x y -> x { piBuildConfig = y }) . buildConfigL data UseHaddocks a = UseHaddocks a | WithoutHaddocks a -- | The paths of interest to a user. The first tuple string is used -- for a description that the optparse flag uses, and the second -- string as a machine-readable key and also for @--foo@ flags. The user -- can choose a specific path to list like @--stack-root@. But -- really it's mainly for the documentation aspect. -- -- When printing output we generate @PathInfo@ and pass it to the -- function to generate an appropriate string. Trailing slashes are -- removed, see #506 paths :: [(String, Text, UseHaddocks (PathInfo -> Text))] paths = [ ( "Global Stack root directory" , T.pack stackRootOptionName , WithoutHaddocks $ view (stackRootL.to toFilePathNoTrailingSep.to T.pack)) , ( "Global Stack configuration file" , T.pack stackGlobalConfigOptionName , WithoutHaddocks $ view (stackGlobalConfigL.to toFilePath.to T.pack)) , ( "Project root (derived from stack.yaml file)" , "project-root" , WithoutHaddocks $ view (projectRootL.to toFilePathNoTrailingSep.to T.pack)) , ( "Configuration location (where the stack.yaml file is)" , "config-location" , WithoutHaddocks $ view (stackYamlL.to toFilePath.to T.pack)) , ( "PATH environment variable" , "bin-path" , WithoutHaddocks $ T.pack . intercalate [FP.searchPathSeparator] . view exeSearchPathL) , ( "Install location for GHC and other core tools (see 'stack ls tools' command)" , "programs" , WithoutHaddocks $ view (configL.to configLocalPrograms.to toFilePathNoTrailingSep.to T.pack)) , ( "Compiler binary (e.g. ghc)" , "compiler-exe" , WithoutHaddocks $ T.pack . toFilePath . piCompiler ) , ( "Directory containing the compiler binary (e.g. ghc)" , "compiler-bin" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . parent . piCompiler ) , ( "Directory containing binaries specific to a particular compiler (e.g. intero)" , "compiler-tools-bin" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piToolsDir ) , ( "Directory where Stack installs executables (e.g. ~/.local/bin (Unix-like OSs) or %APPDATA%\\local\\bin (Windows))" , "local-bin" , WithoutHaddocks $ view $ configL.to configLocalBin.to toFilePathNoTrailingSep.to T.pack) , ( "Extra include directories" , "extra-include-dirs" , WithoutHaddocks $ T.intercalate ", " . map T.pack . configExtraIncludeDirs . view configL ) , ( "Extra library directories" , "extra-library-dirs" , WithoutHaddocks $ T.intercalate ", " . map T.pack . configExtraLibDirs . view configL ) , ( "Snapshot package database" , "snapshot-pkg-db" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piSnapDb ) , ( "Local project package database" , "local-pkg-db" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piLocalDb ) , ( "Global package database" , "global-pkg-db" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piGlobalDb ) , ( "GHC_PACKAGE_PATH environment variable" , "ghc-package-path" , WithoutHaddocks $ \pi' -> mkGhcPackagePath True (piLocalDb pi') (piSnapDb pi') (piExtraDbs pi') (piGlobalDb pi') ) , ( "Snapshot installation root" , "snapshot-install-root" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piSnapRoot ) , ( "Local project installation root" , "local-install-root" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piLocalRoot ) , ( "Snapshot documentation root" , "snapshot-doc-root" , UseHaddocks $ \pi' -> T.pack (toFilePathNoTrailingSep (piSnapRoot pi' docDirSuffix)) ) , ( "Local project documentation root" , "local-doc-root" , UseHaddocks $ \pi' -> T.pack (toFilePathNoTrailingSep (piLocalRoot pi' docDirSuffix)) ) , ( "Local project documentation root" , "local-hoogle-root" , UseHaddocks $ T.pack . toFilePathNoTrailingSep . piHoogleRoot) , ( "Dist work directory, relative to package directory" , "dist-dir" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piDistDir ) , ( "Where HPC reports and tix files are stored" , "local-hpc-root" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . piHpcDir ) , ( "DEPRECATED: Use '--local-bin' instead" , "local-bin-path" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . configLocalBin . view configL ) , ( "DEPRECATED: Use '--programs' instead" , "ghc-paths" , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . configLocalPrograms . view configL ) , ( "DEPRECATED: Use '--" <> stackRootOptionName <> "' instead" , T.pack deprecatedStackRootOptionName , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . view stackRootL ) ] deprecatedPathKeys :: [(Text, Text)] deprecatedPathKeys = [ (T.pack deprecatedStackRootOptionName, T.pack stackRootOptionName) , ("ghc-paths", "programs") , ("local-bin-path", "local-bin") ]