cabal-install-3.12.1.0: src/Distribution/Client/DistDirLayout.hs
{-# LANGUAGE RecordWildCards #-}
-- |
--
-- The layout of the .\/dist\/ directory where cabal keeps all of its state
-- and build artifacts.
module Distribution.Client.DistDirLayout
( -- * 'DistDirLayout'
DistDirLayout (..)
, DistDirParams (..)
, defaultDistDirLayout
-- * 'ProjectRoot'
, ProjectRoot (..)
, defaultProjectFile
-- * 'StoreDirLayout'
, StoreDirLayout (..)
, defaultStoreDirLayout
-- * 'CabalDirLayout'
, CabalDirLayout (..)
, mkCabalDirLayout
, defaultCabalDirLayout
) where
import Distribution.Client.Compat.Prelude
import Prelude ()
import System.FilePath
import Distribution.Client.Config
( defaultLogsDir
, defaultStoreDir
)
import Distribution.Compiler
import Distribution.Package
( ComponentId
, PackageId
, PackageIdentifier
, UnitId
)
import Distribution.Simple.Compiler
( Compiler (..)
, OptimisationLevel (..)
, PackageDB (..)
, PackageDBStack
)
import Distribution.Simple.Configure (interpretPackageDbFlags)
import Distribution.System
import Distribution.Types.ComponentName
import Distribution.Types.LibraryName
-- | Information which can be used to construct the path to
-- the build directory of a build. This is LESS fine-grained
-- than what goes into the hashed 'InstalledPackageId',
-- and for good reason: we don't want this path to change if
-- the user, say, adds a dependency to their project.
data DistDirParams = DistDirParams
{ distParamUnitId :: UnitId
, distParamPackageId :: PackageId
, distParamComponentId :: ComponentId
, distParamComponentName :: Maybe ComponentName
, distParamCompilerId :: CompilerId
, distParamPlatform :: Platform
, distParamOptimization :: OptimisationLevel
-- TODO (see #3343):
-- Flag assignments
-- Optimization
}
-- | The layout of the project state directory. Traditionally this has been
-- called the @dist@ directory.
data DistDirLayout = DistDirLayout
{ distProjectRootDirectory :: FilePath
-- ^ The root directory of the project. Many other files are relative to
-- this location (e.g. the @cabal.project@ file).
, distProjectFile :: String -> FilePath
-- ^ The @cabal.project@ file and related like @cabal.project.freeze@.
-- The parameter is for the extension, like \"freeze\", or \"\" for the
-- main file.
, distDirectory :: FilePath
-- ^ The \"dist\" directory, which is the root of where cabal keeps all
-- its state including the build artifacts from each package we build.
, distBuildDirectory :: DistDirParams -> FilePath
-- ^ The directory under dist where we keep the build artifacts for a
-- package we're building from a local directory.
--
-- This uses a 'UnitId' not just a 'PackageName' because technically
-- we can have multiple instances of the same package in a solution
-- (e.g. setup deps).
, distBuildRootDirectory :: FilePath
, distDownloadSrcDirectory :: FilePath
-- ^ The directory under dist where we download tarballs and source
-- control repos to.
, distUnpackedSrcDirectory :: PackageId -> FilePath
-- ^ The directory under dist where we put the unpacked sources of
-- packages, in those cases where it makes sense to keep the build
-- artifacts to reduce rebuild times.
, distUnpackedSrcRootDirectory :: FilePath
, distProjectCacheFile :: String -> FilePath
-- ^ The location for project-wide cache files (e.g. state used in
-- incremental rebuilds).
, distProjectCacheDirectory :: FilePath
, distPackageCacheFile :: DistDirParams -> String -> FilePath
-- ^ The location for package-specific cache files (e.g. state used in
-- incremental rebuilds).
, distPackageCacheDirectory :: DistDirParams -> FilePath
, distSdistFile :: PackageId -> FilePath
-- ^ The location that sdists are placed by default.
, distSdistDirectory :: FilePath
, distTempDirectory :: FilePath
, distBinDirectory :: FilePath
, distPackageDB :: CompilerId -> PackageDB
, distHaddockOutputDir :: Maybe FilePath
-- ^ Is needed when `--haddock-output-dir` flag is used.
}
-- | The layout of a cabal nix-style store.
data StoreDirLayout = StoreDirLayout
{ storeDirectory :: Compiler -> FilePath
, storePackageDirectory :: Compiler -> UnitId -> FilePath
, storePackageDBPath :: Compiler -> FilePath
, storePackageDB :: Compiler -> PackageDB
, storePackageDBStack :: Compiler -> [Maybe PackageDB] -> PackageDBStack
, storeIncomingDirectory :: Compiler -> FilePath
, storeIncomingLock :: Compiler -> UnitId -> FilePath
}
-- TODO: move to another module, e.g. CabalDirLayout?
-- or perhaps rename this module to DirLayouts.
-- | The layout of the user-wide cabal directory, that is the @~/.cabal@ dir
-- on unix, and equivalents on other systems.
--
-- At the moment this is just a partial specification, but the idea is
-- eventually to cover it all.
data CabalDirLayout = CabalDirLayout
{ cabalStoreDirLayout :: StoreDirLayout
, cabalLogsDirectory :: FilePath
}
-- | Information about the root directory of the project.
--
-- It can either be an implicit project root in the current dir if no
-- @cabal.project@ file is found, or an explicit root if either
-- the file is found or the project root directory was specicied.
data ProjectRoot
= -- | An implicit project root. It contains the absolute project
-- root dir.
ProjectRootImplicit FilePath
| -- | An explicit project root. It contains the absolute project
-- root dir and the relative @cabal.project@ file (or explicit override)
ProjectRootExplicit FilePath FilePath
| -- | An explicit, absolute project root dir and an explicit, absolute
-- @cabal.project@ file.
ProjectRootExplicitAbsolute FilePath FilePath
deriving (Eq, Show)
defaultProjectFile :: FilePath
defaultProjectFile = "cabal.project"
-- | Make the default 'DistDirLayout' based on the project root dir and
-- optional overrides for the location of the @dist@ directory, the
-- @cabal.project@ file and the documentation directory.
defaultDistDirLayout
:: ProjectRoot
-- ^ the project root
-> Maybe FilePath
-- ^ the @dist@ directory or default
-- (absolute or relative to the root)
-> Maybe FilePath
-- ^ the documentation directory
-> DistDirLayout
defaultDistDirLayout projectRoot mdistDirectory haddockOutputDir =
DistDirLayout{..}
where
(projectRootDir, projectFile) = case projectRoot of
ProjectRootImplicit dir -> (dir, dir </> defaultProjectFile)
ProjectRootExplicit dir file -> (dir, dir </> file)
ProjectRootExplicitAbsolute dir file -> (dir, file)
distProjectRootDirectory :: FilePath
distProjectRootDirectory = projectRootDir
distProjectFile :: String -> FilePath
distProjectFile ext = projectFile <.> ext
distDirectory :: FilePath
distDirectory =
distProjectRootDirectory
</> fromMaybe "dist-newstyle" mdistDirectory
-- TODO: switch to just dist at some point, or some other new name
distBuildRootDirectory :: FilePath
distBuildRootDirectory = distDirectory </> "build"
distBuildDirectory :: DistDirParams -> FilePath
distBuildDirectory params =
distBuildRootDirectory
</> prettyShow (distParamPlatform params)
</> prettyShow (distParamCompilerId params)
</> prettyShow (distParamPackageId params)
</> ( case distParamComponentName params of
Nothing -> ""
Just (CLibName LMainLibName) -> ""
Just (CLibName (LSubLibName name)) -> "l" </> prettyShow name
Just (CFLibName name) -> "f" </> prettyShow name
Just (CExeName name) -> "x" </> prettyShow name
Just (CTestName name) -> "t" </> prettyShow name
Just (CBenchName name) -> "b" </> prettyShow name
)
</> ( case distParamOptimization params of
NoOptimisation -> "noopt"
NormalOptimisation -> ""
MaximumOptimisation -> "opt"
)
</> ( let uid_str = prettyShow (distParamUnitId params)
in if uid_str == prettyShow (distParamComponentId params)
then ""
else uid_str
)
distUnpackedSrcRootDirectory :: FilePath
distUnpackedSrcRootDirectory = distDirectory </> "src"
distUnpackedSrcDirectory :: PackageId -> FilePath
distUnpackedSrcDirectory pkgid =
distUnpackedSrcRootDirectory
</> prettyShow pkgid
-- we shouldn't get name clashes so this should be fine:
distDownloadSrcDirectory :: FilePath
distDownloadSrcDirectory = distUnpackedSrcRootDirectory
distProjectCacheDirectory :: FilePath
distProjectCacheDirectory = distDirectory </> "cache"
distProjectCacheFile :: FilePath -> FilePath
distProjectCacheFile name = distProjectCacheDirectory </> name
distPackageCacheDirectory :: DistDirParams -> FilePath
distPackageCacheDirectory params = distBuildDirectory params </> "cache"
distPackageCacheFile :: DistDirParams -> String -> FilePath
distPackageCacheFile params name = distPackageCacheDirectory params </> name
distSdistFile :: PackageIdentifier -> FilePath
distSdistFile pid = distSdistDirectory </> prettyShow pid <.> "tar.gz"
distSdistDirectory :: FilePath
distSdistDirectory = distDirectory </> "sdist"
distTempDirectory :: FilePath
distTempDirectory = distDirectory </> "tmp"
distBinDirectory :: FilePath
distBinDirectory = distDirectory </> "bin"
distPackageDBPath :: CompilerId -> FilePath
distPackageDBPath compid = distDirectory </> "packagedb" </> prettyShow compid
distPackageDB :: CompilerId -> PackageDB
distPackageDB = SpecificPackageDB . distPackageDBPath
distHaddockOutputDir :: Maybe FilePath
distHaddockOutputDir = haddockOutputDir
defaultStoreDirLayout :: FilePath -> StoreDirLayout
defaultStoreDirLayout storeRoot =
StoreDirLayout{..}
where
storeDirectory :: Compiler -> FilePath
storeDirectory compiler =
storeRoot </> case compilerAbiTag compiler of
NoAbiTag -> prettyShow (compilerId compiler)
AbiTag tag -> prettyShow (compilerId compiler) <> "-" <> tag
storePackageDirectory :: Compiler -> UnitId -> FilePath
storePackageDirectory compiler ipkgid =
storeDirectory compiler </> prettyShow ipkgid
storePackageDBPath :: Compiler -> FilePath
storePackageDBPath compiler =
storeDirectory compiler </> "package.db"
storePackageDB :: Compiler -> PackageDB
storePackageDB compiler =
SpecificPackageDB (storePackageDBPath compiler)
storePackageDBStack :: Compiler -> [Maybe PackageDB] -> PackageDBStack
storePackageDBStack compiler extraPackageDB =
(interpretPackageDbFlags False extraPackageDB)
++ [storePackageDB compiler]
storeIncomingDirectory :: Compiler -> FilePath
storeIncomingDirectory compiler =
storeDirectory compiler </> "incoming"
storeIncomingLock :: Compiler -> UnitId -> FilePath
storeIncomingLock compiler unitid =
storeIncomingDirectory compiler </> prettyShow unitid <.> "lock"
defaultCabalDirLayout :: IO CabalDirLayout
defaultCabalDirLayout =
mkCabalDirLayout Nothing Nothing
mkCabalDirLayout
:: Maybe FilePath
-- ^ Store directory. Must be absolute
-> Maybe FilePath
-- ^ Log directory
-> IO CabalDirLayout
mkCabalDirLayout mstoreDir mlogDir = do
cabalStoreDirLayout <-
defaultStoreDirLayout <$> maybe defaultStoreDir pure mstoreDir
cabalLogsDirectory <-
maybe defaultLogsDir pure mlogDir
pure $ CabalDirLayout{..}