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,36 @@ 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
+
184
+ indexFilePath :: Repo -> IndexFileType -> FilePath
185
+ indexFilePath repo idx_file =
186
+ case idx_file of
187
+ IndexTarGz -> repoLocalDir repo </> fn <.> " tar.gz"
188
+ IndexTar -> repoLocalDir repo </> fn <.> " tar"
189
+ IndexCache -> repoLocalDir repo </> (fn <.> " cache-" <> prettyShow cabalInstallVersion)
190
+ IndexTimestamp -> repoLocalDir repo </> fn <.> " timestamp"
191
+ OldIndexCache -> repoLocalDir repo </> fn <.> " cache"
181
192
where
182
193
fn = case repo of
183
194
RepoSecure {} -> " 01-index"
184
195
RepoRemote {} -> " 00-index"
185
196
RepoLocalNoIndex {} -> " noindex"
186
197
198
+ -- | The types of the files which are associated with a particular index.
199
+ data IndexFileType = IndexTarGz
200
+ | IndexTar
201
+ | IndexCache -- ^ The specific cache file, for this version of cabal-install
202
+ | IndexTimestamp -- ^ The timestamp file for the index
203
+ | OldIndexCache -- ^ The location that old versions (before 3.16) of cabal-install put the index cache
204
+
187
205
------------------------------------------------------------------------
188
206
-- Reading the source package index
189
207
--
@@ -495,15 +513,15 @@ readRepoIndex verbosity repoCtxt repo idxState =
495
513
496
514
-- | Return the age of the index file in days (as a Double).
497
515
getIndexFileAge :: Repo -> IO Double
498
- getIndexFileAge repo = getFileAge $ indexBaseName repo <.> " tar "
516
+ getIndexFileAge repo = getFileAge $ indexFilePath repo IndexTar
499
517
500
518
-- | A set of files (or directories) that can be monitored to detect when
501
519
-- there might have been a change in the source packages.
502
520
getSourcePackagesMonitorFiles :: [Repo ] -> [FilePath ]
503
521
getSourcePackagesMonitorFiles repos =
504
522
concat
505
- [ [ indexBaseName repo <.> " cache "
506
- , indexBaseName repo <.> " timestamp "
523
+ [ [ indexFilePath repo IndexCache
524
+ , indexFilePath repo IndexTimestamp
507
525
]
508
526
| repo <- repos
509
527
]
@@ -752,13 +770,13 @@ data Index
752
770
RepoIndex RepoContext Repo
753
771
754
772
indexFile :: Index -> FilePath
755
- indexFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " tar "
773
+ indexFile (RepoIndex _ctxt repo) = indexFilePath repo IndexTar
756
774
757
775
cacheFile :: Index -> FilePath
758
- cacheFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " cache "
776
+ cacheFile (RepoIndex _ctxt repo) = indexFilePath repo IndexCache
759
777
760
778
timestampFile :: Index -> FilePath
761
- timestampFile (RepoIndex _ctxt repo) = indexBaseName repo <.> " timestamp "
779
+ timestampFile (RepoIndex _ctxt repo) = indexFilePath repo IndexTimestamp
762
780
763
781
-- | Return 'True' if 'Index' uses 01-index format (aka secure repo)
764
782
is01Index :: Index -> Bool
@@ -767,6 +785,32 @@ is01Index (RepoIndex _ repo) = case repo of
767
785
RepoRemote {} -> False
768
786
RepoLocalNoIndex {} -> True
769
787
788
+
789
+ -- | Clear the cache files for old cabal-install versions which have a cache
790
+ -- for this index. The cache will be invalid now that we have downloaded a new
791
+ -- .tar.gz for the index.
792
+ --
793
+ -- Note that this invalidation logic only invalidates the old-style caches for
794
+ -- cabal-install < 3.16. For never versions, the check in `readIndexCache` that the
795
+ -- cache is older than the indexFile is sufficient to update the caches when required.
796
+ --
797
+ -- If the old version of cabal-install is used again, then this file will be generated
798
+ -- lazily.
799
+ clearPackageIndexCacheFiles :: Verbosity -> Index -> IO ()
800
+ clearPackageIndexCacheFiles verbosity (RepoIndex _ repo) = do
801
+ info verbosity (" Deleting caches if they exist for " ++ prettyShow (repoName repo))
802
+ let old_cache_path = indexFilePath repo OldIndexCache
803
+ -- Delete old-style non-versioned caches, if the file existed then replace
804
+ -- it with an empty file. Otherwise old versions of `cabal-install` will complain
805
+ -- about a missing package list.
806
+ (removeFile old_cache_path
807
+ >> writeFile old_cache_path " " ) `catch` handleExists
808
+
809
+ where
810
+ handleExists e
811
+ | isDoesNotExistError e = return ()
812
+ | otherwise = throwIO e
813
+
770
814
updatePackageIndexCacheFile :: Verbosity -> Index -> IO ()
771
815
updatePackageIndexCacheFile verbosity index = do
772
816
info verbosity (" Updating index cache file " ++ cacheFile index ++ " ..." )
@@ -1139,12 +1183,24 @@ packageListFromCache verbosity mkPkg hnd Cache{..} = accum mempty [] mempty cach
1139
1183
1140
1184
-- | Read a repository cache from the filesystem
1141
1185
--
1186
+ -- If an out-dated cache is detected, the cache is older than the .tar file corresponding
1187
+ -- to the cache, the cache is updated.
1188
+ --
1142
1189
-- If a corrupted index cache is detected this function regenerates
1143
1190
-- the index cache and then reattempt to read the index once (and
1144
1191
-- 'dieWithException's if it fails again).
1145
1192
readIndexCache :: Verbosity -> Index -> IO Cache
1146
1193
readIndexCache verbosity index = do
1194
+ -- 1. Update the cache, if it's out of date.
1195
+ -- This covers the case where
1196
+ -- - The index .tar.gz is downloaded, but the cache is missing.
1197
+ -- - The index .tar.gz is downloaded, but the cache is too old (ie updated by another cabal-install)
1198
+
1199
+ -- This also fails with a "does not exist" error is the .tar.gz is not downloaded. That's important for
1200
+ -- the control flow of functions which call this.
1201
+ updateRepoIndexCache verbosity index
1147
1202
cacheOrFail <- readIndexCache' index
1203
+ -- 2. Regenerate the cache if parsing failed.
1148
1204
case cacheOrFail of
1149
1205
Left msg -> do
1150
1206
warn verbosity $
0 commit comments