Skip to content

Commit ef9bf9e

Browse files
committed
Reject index states after last known timestamp
1 parent a191f0a commit ef9bf9e

File tree

2 files changed

+66
-40
lines changed

2 files changed

+66
-40
lines changed

cabal-install/src/Distribution/Client/IndexUtils.hs

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ import Data.Either
130130
import Data.List (stripPrefix)
131131
import qualified Data.Map as Map
132132
import qualified Data.Set as Set
133+
import Data.Time (diffUTCTime, getCurrentTime)
134+
import Data.Time.Clock.POSIX (posixDayLength)
133135
import Distribution.Client.GZipUtils (maybeDecompress)
134136
import Distribution.Client.Utils
135137
( byteStringToFilePath
@@ -321,37 +323,13 @@ getSourcePackagesAtIndexState verbosity repoCtxt mb_idxState mb_activeRepos = do
321323
return ()
322324
IndexStateTime ts0 -> do
323325
when (isiMaxTime isi /= ts0) $
324-
if ts0 > isiMaxTime isi
325-
then
326-
warn verbosity $
327-
"Requested index-state "
328-
++ prettyShow ts0
329-
++ " is newer than '"
330-
++ unRepoName rname
331-
++ "'!"
332-
++ " Falling back to older state ("
333-
++ prettyShow (isiMaxTime isi)
334-
++ ")."
335-
else
336-
info verbosity $
337-
"Requested index-state "
338-
++ prettyShow ts0
339-
++ " does not exist in '"
340-
++ unRepoName rname
341-
++ "'!"
342-
++ " Falling back to older state ("
343-
++ prettyShow (isiMaxTime isi)
344-
++ ")."
345-
info
346-
verbosity
347-
( "index-state("
326+
info verbosity $
327+
"There is no index-state for '"
348328
++ unRepoName rname
349-
++ ") = "
329+
++ "' exactly at the requested timestamp ("
330+
++ prettyShow ts0
331+
++ "). Falling back to the previous index-state that exists: "
350332
++ prettyShow (isiMaxTime isi)
351-
++ " (HEAD = "
352-
++ prettyShow (isiHeadTime isi)
353-
++ ")"
354-
)
355333

356334
pure
357335
RepoData
@@ -440,15 +418,19 @@ readRepoIndex
440418
-> IO (PackageIndex UnresolvedSourcePackage, [Dependency], IndexStateInfo)
441419
readRepoIndex verbosity repoCtxt repo idxState =
442420
handleNotFound $ do
443-
when (isRepoRemote repo) $ warnIfIndexIsOld =<< getIndexFileAge repo
444421
-- note that if this step fails due to a bad repo cache, the the procedure can still succeed by reading from the existing cache, which is updated regardless.
445422
updateRepoIndexCache verbosity (RepoIndex repoCtxt repo)
446423
`catchIO` (\e -> warn verbosity $ "unable to update the repo index cache -- " ++ displayException e)
447-
readPackageIndexCacheFile
448-
verbosity
449-
mkAvailablePackage
450-
(RepoIndex repoCtxt repo)
451-
idxState
424+
ret@(_, _, isi) <-
425+
readPackageIndexCacheFile
426+
verbosity
427+
mkAvailablePackage
428+
(RepoIndex repoCtxt repo)
429+
idxState
430+
when (isRepoRemote repo) $ do
431+
dieIfRequestedIdxIsNewer isi
432+
warnIfIndexIsOld isi
433+
pure ret
452434
where
453435
mkAvailablePackage pkgEntry =
454436
SourcePackage
@@ -480,12 +462,32 @@ readRepoIndex verbosity repoCtxt repo idxState =
480462
return (mempty, mempty, emptyStateInfo)
481463
else ioError e
482464

465+
isOldThreshold :: Double
483466
isOldThreshold = 15 -- days
484-
warnIfIndexIsOld dt = do
485-
when (dt >= isOldThreshold) $ case repo of
486-
RepoRemote{..} -> warn verbosity $ errOutdatedPackageList repoRemote dt
487-
RepoSecure{..} -> warn verbosity $ errOutdatedPackageList repoRemote dt
488-
RepoLocalNoIndex{} -> return ()
467+
warnIfIndexIsOld isi = do
468+
curTime <- getCurrentTime
469+
case timestampToUTCTime (isiHeadTime isi) of
470+
Nothing -> pure ()
471+
Just ts -> do
472+
let timeDiffInDays =
473+
realToFrac (curTime `diffUTCTime` ts) / realToFrac posixDayLength
474+
when (timeDiffInDays >= isOldThreshold) $ case repo of
475+
RepoRemote{..} ->
476+
warn verbosity $ errOutdatedPackageList repoRemote timeDiffInDays
477+
RepoSecure{..} ->
478+
warn verbosity $ errOutdatedPackageList repoRemote timeDiffInDays
479+
RepoLocalNoIndex{} -> return ()
480+
481+
dieIfRequestedIdxIsNewer isi =
482+
let latestTime = isiHeadTime isi
483+
in case idxState of
484+
IndexStateTime t -> when (t > latestTime) $ case repo of
485+
RepoRemote{..} ->
486+
die' verbosity $ errRequestedIdxIsNewer repoRemote latestTime t
487+
RepoSecure{..} ->
488+
die' verbosity $ errRequestedIdxIsNewer repoRemote latestTime t
489+
RepoLocalNoIndex{} -> return ()
490+
IndexStateHead -> pure ()
489491

490492
errMissingPackageList repoRemote =
491493
"The package list for '"
@@ -497,6 +499,16 @@ readRepoIndex verbosity repoCtxt repo idxState =
497499
++ "' is "
498500
++ shows (floor dt :: Int) " days old.\nRun "
499501
++ "'cabal update' to get the latest list of available packages."
502+
errRequestedIdxIsNewer repoRemote maxFound req =
503+
"Latest known index-state for '"
504+
++ unRepoName (remoteRepoName repoRemote)
505+
++ "' ("
506+
++ prettyShow maxFound
507+
++ ") is older than the requested index-state ("
508+
++ prettyShow req
509+
++ ").\nRun 'cabal update' or set the index-state to a value at or before "
510+
++ prettyShow maxFound
511+
++ "."
500512

501513
-- | Return the age of the index file in days (as a Double).
502514
getIndexFileAge :: Repo -> IO Double

changelog.d/index-state-cabal-update

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
synopsis: Reject index-state younger than cached index file
2+
packages: cabal-install
3+
prs: #8944
4+
5+
description: {
6+
7+
Requesting to use an index-state younger than the cached version will now fail,
8+
telling the user to use an index-state older or equal to the cached file, or to
9+
run `cabal update`.
10+
11+
The warning for a non-existing index-state has been also demoted to appear only
12+
on verbose logging.
13+
14+
}

0 commit comments

Comments
 (0)