@@ -81,14 +81,13 @@ getPackageAvailableVersionsR (PathPackageName pkgName) =
8181getPackageVersionR :: PathPackageName -> PathVersion -> Handler Html
8282getPackageVersionR (PathPackageName pkgName) (PathVersion version) =
8383 cacheHtmlConditional $
84- findPackageWithLatest pkgName version $ \ pkg@ D. Package {.. } latestPkg -> do
84+ findPackageWithDeprecation pkgName version $ \ pkg@ D. Package {.. } deprecated -> do
8585 moduleList <- renderModuleList pkg
8686 ereadme <- tryGetReadme pkg
8787 let cacheStatus = either (const NotOkToCache ) (const OkToCache ) ereadme
8888 content <- defaultLayout $ do
8989 setTitle (toHtml (runPackageName pkgName))
9090 let dependencies = bowerDependencies pkgMeta
91- let deprecated = isDeprecated latestPkg
9291 $ (widgetFile " packageVersion" )
9392 return (cacheStatus, content)
9493
@@ -159,15 +158,14 @@ getPackageVersionDocsR (PathPackageName pkgName) (PathVersion version) =
159158
160159getPackageVersionModuleDocsR :: PathPackageName -> PathVersion -> Text -> Handler Html
161160getPackageVersionModuleDocsR (PathPackageName pkgName) (PathVersion version) mnString =
162- cacheHtml $ findPackageWithLatest pkgName version $ \ pkg@ D. Package {.. } latestPkg -> do
161+ cacheHtml $ findPackageWithDeprecation pkgName version $ \ pkg@ D. Package {.. } deprecated -> do
163162 moduleList <- renderModuleList pkg
164163 mhtmlDocs <- renderHtmlDocs pkg mnString
165164 case mhtmlDocs of
166165 Nothing -> notFound
167166 Just htmlDocs ->
168167 defaultLayout $ do
169168 let mn = P. moduleNameFromString mnString
170- let deprecated = isDeprecated latestPkg
171169 setTitle (toHtml (mnString <> " - " <> runPackageName pkgName))
172170 $ (widgetFile " packageVersionModuleDocs" )
173171
@@ -211,21 +209,82 @@ findPackage pkgName version cont = do
211209 Left NoSuchPackage -> packageNotFound pkgName
212210 Left NoSuchPackageVersion -> packageVersionNotFound pkgName version
213211
214- findPackageWithLatest ::
212+ findPackageWithDeprecation ::
215213 PackageName ->
216214 Version ->
217- (D. VerifiedPackage -> D. VerifiedPackage -> Handler r ) ->
215+ (D. VerifiedPackage -> Bool -> Handler r ) ->
218216 Handler r
219- findPackageWithLatest pkgName version cont = do
217+ findPackageWithDeprecation pkgName version cont = do
220218 findPackage pkgName version $ \ pkg -> do
221219 latestVersion <- fromMaybe version <$> getLatestVersionFor pkgName
222- -- Avoid decoding the same package file twice when the requested version
223- -- is the latest one; for large packages a decode is expensive.
224- latestPkg <-
220+ deprecated <-
225221 if latestVersion == version
226- then return pkg
227- else fromMaybe pkg . hush <$> lookupPackage pkgName latestVersion
228- cont pkg latestPkg
222+ then return (isDeprecated pkg)
223+ else getLatestDeprecation pkgName latestVersion (isDeprecated pkg)
224+ cont pkg deprecated
225+
226+ data DeprecationMarker = DeprecationMarker
227+ { markerLatestVersion :: Text
228+ , markerDeprecated :: Bool
229+ }
230+ deriving (Show , Eq , Generic )
231+
232+ instance ToJSON DeprecationMarker where
233+ toJSON DeprecationMarker {.. } =
234+ object
235+ [ " latest" .= markerLatestVersion
236+ , " deprecated" .= markerDeprecated
237+ ]
238+
239+ instance FromJSON DeprecationMarker where
240+ parseJSON = Aeson. withObject " DeprecationMarker" $ \ obj ->
241+ DeprecationMarker
242+ <$> obj .: " latest"
243+ <*> obj .: " deprecated"
244+
245+ getLatestDeprecation :: PackageName -> Version -> Bool -> Handler Bool
246+ getLatestDeprecation pkgName latestVersion fallbackDeprecated = do
247+ path <- deprecationMarkerFileFor pkgName
248+ emarker <- tryAny (liftIO (readFileMay path))
249+ case emarker of
250+ Right mmarker ->
251+ case mmarker >>= Aeson. decodeStrict of
252+ Just DeprecationMarker {.. }
253+ | markerLatestVersion == latestVersionText ->
254+ return markerDeprecated
255+ _ ->
256+ recompute path
257+ _ -> recompute path
258+ where
259+ latestVersionText = pack (showVersion latestVersion)
260+
261+ recompute path = do
262+ latestPkg <- hush <$> lookupPackage pkgName latestVersion
263+ let deprecated = maybe fallbackDeprecated isDeprecated latestPkg
264+ writeDeprecationMarker path deprecated
265+ return deprecated
266+
267+ writeDeprecationMarker path deprecated = do
268+ let marker =
269+ DeprecationMarker
270+ { markerLatestVersion = latestVersionText
271+ , markerDeprecated = deprecated
272+ }
273+ result <- tryAny (writeFileWithParents path (toStrict (Aeson. encode marker)))
274+ case result of
275+ Right () -> return ()
276+ Left err ->
277+ $ logError
278+ ( " Failed to write deprecation marker for "
279+ <> runPackageName pkgName <> " : " <> tshow err
280+ )
281+
282+ deprecationMarkerFileFor :: PackageName -> Handler FilePath
283+ deprecationMarkerFileFor pkgName = do
284+ dir <- getDataDir
285+ return $
286+ dir </> " cache" </> " packages" </>
287+ unpack (runPackageName pkgName) </> " deprecation-marker.json"
229288
230289packageNotFound :: PackageName -> Handler a
231290packageNotFound pkgName = do
0 commit comments