20
20
module Distribution.Client.IndexUtils
21
21
( getIndexFileAge
22
22
, getInstalledPackages
23
- , indexBaseName
23
+ , indexFilePath
24
+ , IndexFileType (.. )
24
25
, Configure. getInstalledPackagesMonitorFiles
25
26
, getSourcePackages
26
27
, getSourcePackagesMonitorFiles
@@ -34,6 +35,7 @@ module Distribution.Client.IndexUtils
34
35
, parsePackageIndex
35
36
, updateRepoIndexCache
36
37
, updatePackageIndexCacheFile
38
+ , clearPackageIndexCacheFiles
37
39
, writeIndexTimestamp
38
40
, currentIndexTimestamp
39
41
, BuildTreeRefType (.. )
@@ -61,6 +63,8 @@ import Distribution.Client.Types
61
63
import Distribution.Parsec (simpleParsecBS )
62
64
import Distribution.Verbosity
63
65
66
+ import Distribution.Client.Version
67
+
64
68
import Distribution.Client.ProjectConfig
65
69
( CabalFileParseError
66
70
, readSourcePackageCabalFile'
@@ -137,7 +141,7 @@ import Distribution.Compat.Directory (listDirectory)
137
141
import Distribution.Compat.Time (getFileAge , getModTime )
138
142
import Distribution.Utils.Generic (fstOf3 )
139
143
import Distribution.Utils.Structured (Structured (.. ), nominalStructure , structuredDecodeFileOrFail , structuredEncodeFile )
140
- import System.Directory (doesDirectoryExist , doesFileExist )
144
+ import System.Directory (doesDirectoryExist , doesFileExist , removeFile )
141
145
import System.FilePath
142
146
( normalise
143
147
, splitDirectories
@@ -168,22 +172,39 @@ getInstalledPackages verbosity comp packageDbs progdb =
168
172
where
169
173
verbosity' = lessVerbose verbosity
170
174
171
- -- | Get filename base (i.e. without file extension) for index-related files
175
+ -- | Get filenames for index-related files
172
176
--
173
177
-- /Secure/ cabal repositories use a new extended & incremental
174
178
-- @01-index.tar@. In order to avoid issues resulting from clobbering
175
179
-- new/old-style index data, we save them locally to different names.
176
180
--
177
- -- Example: Use @indexBaseName repo <.> "tar.gz" @ to compute the 'FilePath' of the
181
+ -- Example: Use @indexFilePath repo IndexTarGz @ to compute the 'FilePath' of the
178
182
-- @00-index.tar.gz@/@01-index.tar.gz@ file.
179
- indexBaseName :: Repo -> FilePath
180
- indexBaseName repo = repoLocalDir repo </> fn
183
+ indexFilePath :: Repo -> IndexFileType -> FilePath
184
+ indexFilePath repo idx_file =
185
+ case idx_file of
186
+ IndexTarGz -> repoLocalDir repo </> fn <.> " tar.gz"
187
+ IndexTar -> repoLocalDir repo </> fn <.> " tar"
188
+ IndexCache -> repoLocalDir repo </> (fn <.> " cache-" <> prettyShow cabalInstallVersion)
189
+ IndexTimestamp -> repoLocalDir repo </> fn <.> " timestamp"
190
+ OldIndexCache -> repoLocalDir repo </> fn <.> " cache"
181
191
where
182
192
fn = case repo of
183
193
RepoSecure {} -> " 01-index"
184
194
RepoRemote {} -> " 00-index"
185
195
RepoLocalNoIndex {} -> " noindex"
186
196
197
+ -- | The types of the files which are associated with a particular index.
198
+ data IndexFileType
199
+ = IndexTarGz
200
+ | IndexTar
201
+ | -- | The specific cache file, for this version of cabal-install
202
+ IndexCache
203
+ | -- | The timestamp file for the index
204
+ IndexTimestamp
205
+ | -- | The location that old versions (before 3.16) of cabal-install put the index cache
206
+ OldIndexCache
207
+
187
208
------------------------------------------------------------------------
188
209
-- Reading the source package index
189
210
--
@@ -495,15 +516,15 @@ readRepoIndex verbosity repoCtxt repo idxState =
495
516
496
517
-- | Return the age of the index file in days (as a Double).
497
518
getIndexFileAge :: Repo -> IO Double
498
- getIndexFileAge repo = getFileAge $ indexBaseName repo <.> " tar "
519
+ getIndexFileAge repo = getFileAge $ indexFilePath repo IndexTar
499
520
500
521
-- | A set of files (or directories) that can be monitored to detect when
501
522
-- there might have been a change in the source packages.
502
523
getSourcePackagesMonitorFiles :: [Repo ] -> [FilePath ]
503
524
getSourcePackagesMonitorFiles repos =
504
525
concat
505
- [ [ indexBaseName repo <.> " cache "
506
- , indexBaseName repo <.> " timestamp "
526
+ [ [ indexFilePath repo IndexCache
527
+ , indexFilePath repo IndexTimestamp
507
528
]
508
529
| repo <- repos
509
530
]
@@ -752,13 +773,13 @@ data Index
752
773
RepoIndex RepoContext Repo
753
774
754
775
indexFile :: Index -> FilePath
755
- indexFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " tar "
776
+ indexFile (RepoIndex _ctxt repo) = indexFilePath repo IndexTar
756
777
757
778
cacheFile :: Index -> FilePath
758
- cacheFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " cache "
779
+ cacheFile (RepoIndex _ctxt repo) = indexFilePath repo IndexCache
759
780
760
781
timestampFile :: Index -> FilePath
761
- timestampFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " timestamp "
782
+ timestampFile (RepoIndex _ctxt repo) = indexFilePath repo IndexTimestamp
762
783
763
784
-- | Return 'True' if 'Index' uses 01-index format (aka secure repo)
764
785
is01Index :: Index -> Bool
@@ -767,6 +788,32 @@ is01Index (RepoIndex _ repo) = case repo of
767
788
RepoRemote {} -> False
768
789
RepoLocalNoIndex {} -> True
769
790
791
+ -- | Clear the cache files for old cabal-install versions which have a cache
792
+ -- for this index. The cache will be invalid now that we have downloaded a new
793
+ -- .tar.gz for the index.
794
+ --
795
+ -- Note that this invalidation logic only invalidates the old-style caches for
796
+ -- cabal-install < 3.16. For never versions, the check in `readIndexCache` that the
797
+ -- cache is older than the indexFile is sufficient to update the caches when required.
798
+ --
799
+ -- If the old version of cabal-install is used again, then this file will be generated
800
+ -- lazily.
801
+ clearPackageIndexCacheFiles :: Verbosity -> Index -> IO ()
802
+ clearPackageIndexCacheFiles verbosity (RepoIndex _ repo) = do
803
+ info verbosity (" Deleting caches if they exist for " ++ prettyShow (repoName repo))
804
+ let old_cache_path = indexFilePath repo OldIndexCache
805
+ -- Delete old-style non-versioned caches, if the file existed then replace
806
+ -- it with an empty file. Otherwise old versions of `cabal-install` will complain
807
+ -- about a missing package list.
808
+ ( removeFile old_cache_path
809
+ >> writeFile old_cache_path " "
810
+ )
811
+ `catch` handleExists
812
+ where
813
+ handleExists e
814
+ | isDoesNotExistError e = return ()
815
+ | otherwise = throwIO e
816
+
770
817
updatePackageIndexCacheFile :: Verbosity -> Index -> IO ()
771
818
updatePackageIndexCacheFile verbosity index = do
772
819
info verbosity (" Updating index cache file " ++ cacheFile index ++ " ..." )
@@ -1139,12 +1186,24 @@ packageListFromCache verbosity mkPkg hnd Cache{..} = accum mempty [] mempty cach
1139
1186
1140
1187
-- | Read a repository cache from the filesystem
1141
1188
--
1189
+ -- If an out-dated cache is detected, the cache is older than the .tar file corresponding
1190
+ -- to the cache, the cache is updated.
1191
+ --
1142
1192
-- If a corrupted index cache is detected this function regenerates
1143
1193
-- the index cache and then reattempt to read the index once (and
1144
1194
-- 'dieWithException's if it fails again).
1145
1195
readIndexCache :: Verbosity -> Index -> IO Cache
1146
1196
readIndexCache verbosity index = do
1197
+ -- 1. Update the cache, if it's out of date.
1198
+ -- This covers the case where
1199
+ -- - The index .tar.gz is downloaded, but the cache is missing.
1200
+ -- - The index .tar.gz is downloaded, but the cache is too old (ie updated by another cabal-install)
1201
+
1202
+ -- This also fails with a "does not exist" error is the .tar.gz is not downloaded. That's important for
1203
+ -- the control flow of functions which call this.
1204
+ updateRepoIndexCache verbosity index
1147
1205
cacheOrFail <- readIndexCache' index
1206
+ -- 2. Regenerate the cache if parsing failed.
1148
1207
case cacheOrFail of
1149
1208
Left msg -> do
1150
1209
warn verbosity $
0 commit comments