never executed always true always false
1 {-# LANGUAGE RecordWildCards #-}
2
3 -- |
4 --
5 -- The layout of the .\/dist\/ directory where cabal keeps all of its state
6 -- and build artifacts.
7 --
8 module Distribution.Client.DistDirLayout (
9 -- * 'DistDirLayout'
10 DistDirLayout(..),
11 DistDirParams(..),
12 defaultDistDirLayout,
13 ProjectRoot(..),
14
15 -- * 'StoreDirLayout'
16 StoreDirLayout(..),
17 defaultStoreDirLayout,
18
19 -- * 'CabalDirLayout'
20 CabalDirLayout(..),
21 mkCabalDirLayout,
22 defaultCabalDirLayout
23 ) where
24
25 import Distribution.Client.Compat.Prelude
26 import Prelude ()
27
28 import System.FilePath
29
30 import Distribution.Package
31 ( PackageId, ComponentId, UnitId )
32 import Distribution.Compiler
33 import Distribution.Simple.Compiler
34 ( PackageDB(..), PackageDBStack, OptimisationLevel(..) )
35 import Distribution.Types.ComponentName
36 import Distribution.Types.LibraryName
37 import Distribution.System
38
39
40 -- | Information which can be used to construct the path to
41 -- the build directory of a build. This is LESS fine-grained
42 -- than what goes into the hashed 'InstalledPackageId',
43 -- and for good reason: we don't want this path to change if
44 -- the user, say, adds a dependency to their project.
45 data DistDirParams = DistDirParams {
46 distParamUnitId :: UnitId,
47 distParamPackageId :: PackageId,
48 distParamComponentId :: ComponentId,
49 distParamComponentName :: Maybe ComponentName,
50 distParamCompilerId :: CompilerId,
51 distParamPlatform :: Platform,
52 distParamOptimization :: OptimisationLevel
53 -- TODO (see #3343):
54 -- Flag assignments
55 -- Optimization
56 }
57
58
59 -- | The layout of the project state directory. Traditionally this has been
60 -- called the @dist@ directory.
61 --
62 data DistDirLayout = DistDirLayout {
63
64 -- | The root directory of the project. Many other files are relative to
65 -- this location. In particular, the @cabal.project@ lives here.
66 --
67 distProjectRootDirectory :: FilePath,
68
69 -- | The @cabal.project@ file and related like @cabal.project.freeze@.
70 -- The parameter is for the extension, like \"freeze\", or \"\" for the
71 -- main file.
72 --
73 distProjectFile :: String -> FilePath,
74
75 -- | The \"dist\" directory, which is the root of where cabal keeps all
76 -- its state including the build artifacts from each package we build.
77 --
78 distDirectory :: FilePath,
79
80 -- | The directory under dist where we keep the build artifacts for a
81 -- package we're building from a local directory.
82 --
83 -- This uses a 'UnitId' not just a 'PackageName' because technically
84 -- we can have multiple instances of the same package in a solution
85 -- (e.g. setup deps).
86 --
87 distBuildDirectory :: DistDirParams -> FilePath,
88 distBuildRootDirectory :: FilePath,
89
90 -- | The directory under dist where we download tarballs and source
91 -- control repos to.
92 --
93 distDownloadSrcDirectory :: FilePath,
94
95 -- | The directory under dist where we put the unpacked sources of
96 -- packages, in those cases where it makes sense to keep the build
97 -- artifacts to reduce rebuild times.
98 --
99 distUnpackedSrcDirectory :: PackageId -> FilePath,
100 distUnpackedSrcRootDirectory :: FilePath,
101
102 -- | The location for project-wide cache files (e.g. state used in
103 -- incremental rebuilds).
104 --
105 distProjectCacheFile :: String -> FilePath,
106 distProjectCacheDirectory :: FilePath,
107
108 -- | The location for package-specific cache files (e.g. state used in
109 -- incremental rebuilds).
110 --
111 distPackageCacheFile :: DistDirParams -> String -> FilePath,
112 distPackageCacheDirectory :: DistDirParams -> FilePath,
113
114 -- | The location that sdists are placed by default.
115 distSdistFile :: PackageId -> FilePath,
116 distSdistDirectory :: FilePath,
117
118 distTempDirectory :: FilePath,
119 distBinDirectory :: FilePath,
120
121 distPackageDB :: CompilerId -> PackageDB
122 }
123
124
125 -- | The layout of a cabal nix-style store.
126 --
127 data StoreDirLayout = StoreDirLayout {
128 storeDirectory :: CompilerId -> FilePath,
129 storePackageDirectory :: CompilerId -> UnitId -> FilePath,
130 storePackageDBPath :: CompilerId -> FilePath,
131 storePackageDB :: CompilerId -> PackageDB,
132 storePackageDBStack :: CompilerId -> PackageDBStack,
133 storeIncomingDirectory :: CompilerId -> FilePath,
134 storeIncomingLock :: CompilerId -> UnitId -> FilePath
135 }
136
137
138 --TODO: move to another module, e.g. CabalDirLayout?
139 -- or perhaps rename this module to DirLayouts.
140
141 -- | The layout of the user-wide cabal directory, that is the @~/.cabal@ dir
142 -- on unix, and equivalents on other systems.
143 --
144 -- At the moment this is just a partial specification, but the idea is
145 -- eventually to cover it all.
146 --
147 data CabalDirLayout = CabalDirLayout {
148 cabalStoreDirLayout :: StoreDirLayout,
149
150 cabalLogsDirectory :: FilePath,
151 cabalWorldFile :: FilePath
152 }
153
154
155 -- | Information about the root directory of the project.
156 --
157 -- It can either be an implicit project root in the current dir if no
158 -- @cabal.project@ file is found, or an explicit root if the file is found.
159 --
160 data ProjectRoot =
161 -- | -- ^ An implicit project root. It contains the absolute project
162 -- root dir.
163 ProjectRootImplicit FilePath
164
165 -- | -- ^ An explicit project root. It contains the absolute project
166 -- root dir and the relative @cabal.project@ file (or explicit override)
167 | ProjectRootExplicit FilePath FilePath
168 deriving (Eq, Show)
169
170 -- | Make the default 'DistDirLayout' based on the project root dir and
171 -- optional overrides for the location of the @dist@ directory and the
172 -- @cabal.project@ file.
173 --
174 defaultDistDirLayout :: ProjectRoot -- ^ the project root
175 -> Maybe FilePath -- ^ the @dist@ directory or default
176 -- (absolute or relative to the root)
177 -> DistDirLayout
178 defaultDistDirLayout projectRoot mdistDirectory =
179 DistDirLayout {..}
180 where
181 (projectRootDir, projectFile) = case projectRoot of
182 ProjectRootImplicit dir -> (dir, dir </> "cabal.project")
183 ProjectRootExplicit dir file -> (dir, dir </> file)
184
185 distProjectRootDirectory = projectRootDir
186 distProjectFile ext = projectFile <.> ext
187
188 distDirectory = distProjectRootDirectory
189 </> fromMaybe "dist-newstyle" mdistDirectory
190 --TODO: switch to just dist at some point, or some other new name
191
192 distBuildRootDirectory = distDirectory </> "build"
193 distBuildDirectory params =
194 distBuildRootDirectory </>
195 prettyShow (distParamPlatform params) </>
196 prettyShow (distParamCompilerId params) </>
197 prettyShow (distParamPackageId params) </>
198 (case distParamComponentName params of
199 Nothing -> ""
200 Just (CLibName LMainLibName) -> ""
201 Just (CLibName (LSubLibName name)) -> "l" </> prettyShow name
202 Just (CFLibName name) -> "f" </> prettyShow name
203 Just (CExeName name) -> "x" </> prettyShow name
204 Just (CTestName name) -> "t" </> prettyShow name
205 Just (CBenchName name) -> "b" </> prettyShow name) </>
206 (case distParamOptimization params of
207 NoOptimisation -> "noopt"
208 NormalOptimisation -> ""
209 MaximumOptimisation -> "opt") </>
210 (let uid_str = prettyShow (distParamUnitId params)
211 in if uid_str == prettyShow (distParamComponentId params)
212 then ""
213 else uid_str)
214
215 distUnpackedSrcRootDirectory = distDirectory </> "src"
216 distUnpackedSrcDirectory pkgid = distUnpackedSrcRootDirectory
217 </> prettyShow pkgid
218 -- we shouldn't get name clashes so this should be fine:
219 distDownloadSrcDirectory = distUnpackedSrcRootDirectory
220
221 distProjectCacheDirectory = distDirectory </> "cache"
222 distProjectCacheFile name = distProjectCacheDirectory </> name
223
224 distPackageCacheDirectory params = distBuildDirectory params </> "cache"
225 distPackageCacheFile params name = distPackageCacheDirectory params </> name
226
227 distSdistFile pid = distSdistDirectory </> prettyShow pid <.> "tar.gz"
228
229 distSdistDirectory = distDirectory </> "sdist"
230
231 distTempDirectory = distDirectory </> "tmp"
232
233 distBinDirectory = distDirectory </> "bin"
234
235 distPackageDBPath compid = distDirectory </> "packagedb" </> prettyShow compid
236 distPackageDB = SpecificPackageDB . distPackageDBPath
237
238
239 defaultStoreDirLayout :: FilePath -> StoreDirLayout
240 defaultStoreDirLayout storeRoot =
241 StoreDirLayout {..}
242 where
243 storeDirectory compid =
244 storeRoot </> prettyShow compid
245
246 storePackageDirectory compid ipkgid =
247 storeDirectory compid </> prettyShow ipkgid
248
249 storePackageDBPath compid =
250 storeDirectory compid </> "package.db"
251
252 storePackageDB compid =
253 SpecificPackageDB (storePackageDBPath compid)
254
255 storePackageDBStack compid =
256 [GlobalPackageDB, storePackageDB compid]
257
258 storeIncomingDirectory compid =
259 storeDirectory compid </> "incoming"
260
261 storeIncomingLock compid unitid =
262 storeIncomingDirectory compid </> prettyShow unitid <.> "lock"
263
264
265 defaultCabalDirLayout :: FilePath -> CabalDirLayout
266 defaultCabalDirLayout cabalDir =
267 mkCabalDirLayout cabalDir Nothing Nothing
268
269 mkCabalDirLayout :: FilePath -- ^ Cabal directory
270 -> Maybe FilePath -- ^ Store directory. Must be absolute
271 -> Maybe FilePath -- ^ Log directory
272 -> CabalDirLayout
273 mkCabalDirLayout cabalDir mstoreDir mlogDir =
274 CabalDirLayout {..}
275 where
276 cabalStoreDirLayout =
277 defaultStoreDirLayout (fromMaybe (cabalDir </> "store") mstoreDir)
278 cabalLogsDirectory = fromMaybe (cabalDir </> "logs") mlogDir
279 cabalWorldFile = cabalDir </> "world"