implements query parameter for prioritizing lower versions

This commit is contained in:
Keagan McClelland
2022-01-26 14:46:41 -07:00
parent 796128d78a
commit b43d85ea63
5 changed files with 43 additions and 22 deletions

View File

@@ -50,6 +50,7 @@ import Lib.Types.Emver ( Version )
import Util.Shared ( addPackageHeader import Util.Shared ( addPackageHeader
, getVersionSpecFromQuery , getVersionSpecFromQuery
, orThrow , orThrow
, versionPriorityFromQueryIsMin
) )
data FileExtension = FileExtension FilePath (Maybe String) data FileExtension = FileExtension FilePath (Maybe String)
@@ -60,7 +61,8 @@ instance Show FileExtension where
getAppManifestR :: PkgId -> Handler TypedContent getAppManifestR :: PkgId -> Handler TypedContent
getAppManifestR pkg = do getAppManifestR pkg = do
versionSpec <- getVersionSpecFromQuery versionSpec <- getVersionSpecFromQuery
version <- getBestVersion pkg versionSpec preferMin <- versionPriorityFromQueryIsMin
version <- getBestVersion pkg versionSpec preferMin
`orThrow` sendResponseStatus status404 (NotFoundE [i|#{pkg} satisfying #{versionSpec}|]) `orThrow` sendResponseStatus status404 (NotFoundE [i|#{pkg} satisfying #{versionSpec}|])
addPackageHeader pkg version addPackageHeader pkg version
(len, src) <- getManifest pkg version (len, src) <- getManifest pkg version
@@ -71,7 +73,8 @@ getAppR :: S9PK -> Handler TypedContent
getAppR file = do getAppR file = do
let pkg = PkgId . T.pack $ takeBaseName (show file) let pkg = PkgId . T.pack $ takeBaseName (show file)
versionSpec <- getVersionSpecFromQuery versionSpec <- getVersionSpecFromQuery
version <- getBestVersion pkg versionSpec preferMin <- versionPriorityFromQueryIsMin
version <- getBestVersion pkg versionSpec preferMin
`orThrow` sendResponseStatus status404 (NotFoundE [i|#{pkg} satisfying #{versionSpec}|]) `orThrow` sendResponseStatus status404 (NotFoundE [i|#{pkg} satisfying #{versionSpec}|])
addPackageHeader pkg version addPackageHeader pkg version
void $ recordMetrics pkg version void $ recordMetrics pkg version

View File

@@ -34,8 +34,9 @@ instance FromJSON IconType
getIconsR :: PkgId -> Handler TypedContent getIconsR :: PkgId -> Handler TypedContent
getIconsR pkg = do getIconsR pkg = do
spec <- getVersionSpecFromQuery spec <- getVersionSpecFromQuery
version <- getBestVersion pkg spec preferMin <- versionPriorityFromQueryIsMin
version <- getBestVersion pkg spec preferMin
`orThrow` sendResponseStatus status400 (NotFoundE [i|Icon for #{pkg} satisfying #{spec}|]) `orThrow` sendResponseStatus status400 (NotFoundE [i|Icon for #{pkg} satisfying #{spec}|])
(ct, len, src) <- getIcon pkg version (ct, len, src) <- getIcon pkg version
addHeader "Content-Length" (show len) addHeader "Content-Length" (show len)
@@ -43,8 +44,9 @@ getIconsR pkg = do
getLicenseR :: PkgId -> Handler TypedContent getLicenseR :: PkgId -> Handler TypedContent
getLicenseR pkg = do getLicenseR pkg = do
spec <- getVersionSpecFromQuery spec <- getVersionSpecFromQuery
version <- getBestVersion pkg spec preferMin <- versionPriorityFromQueryIsMin
version <- getBestVersion pkg spec preferMin
`orThrow` sendResponseStatus status400 (NotFoundE [i|License for #{pkg} satisfying #{spec}|]) `orThrow` sendResponseStatus status400 (NotFoundE [i|License for #{pkg} satisfying #{spec}|])
(len, src) <- getLicense pkg version (len, src) <- getLicense pkg version
addHeader "Content-Length" (show len) addHeader "Content-Length" (show len)
@@ -52,8 +54,9 @@ getLicenseR pkg = do
getInstructionsR :: PkgId -> Handler TypedContent getInstructionsR :: PkgId -> Handler TypedContent
getInstructionsR pkg = do getInstructionsR pkg = do
spec <- getVersionSpecFromQuery spec <- getVersionSpecFromQuery
version <- getBestVersion pkg spec preferMin <- versionPriorityFromQueryIsMin
version <- getBestVersion pkg spec preferMin
`orThrow` sendResponseStatus status400 (NotFoundE [i|Instructions for #{pkg} satisfying #{spec}|]) `orThrow` sendResponseStatus status400 (NotFoundE [i|Instructions for #{pkg} satisfying #{spec}|])
(len, src) <- getInstructions pkg version (len, src) <- getInstructions pkg version
addHeader "Content-Length" (show len) addHeader "Content-Length" (show len)

View File

@@ -21,11 +21,13 @@ import Lib.Types.AppIndex ( PkgId )
import Network.HTTP.Types.Status ( status404 ) import Network.HTTP.Types.Status ( status404 )
import Util.Shared ( getVersionSpecFromQuery import Util.Shared ( getVersionSpecFromQuery
, orThrow , orThrow
, versionPriorityFromQueryIsMin
) )
getPkgVersionR :: PkgId -> Handler AppVersionRes getPkgVersionR :: PkgId -> Handler AppVersionRes
getPkgVersionR pkg = do getPkgVersionR pkg = do
spec <- getVersionSpecFromQuery spec <- getVersionSpecFromQuery
AppVersionRes <$> getBestVersion pkg spec `orThrow` sendResponseStatus preferMin <- versionPriorityFromQueryIsMin
AppVersionRes <$> getBestVersion pkg spec preferMin `orThrow` sendResponseStatus
status404 status404
(NotFoundE [i|Version for #{pkg} satisfying #{spec}|]) (NotFoundE [i|Version for #{pkg} satisfying #{spec}|])

View File

@@ -1,11 +1,12 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-} {-# OPTIONS_GHC -Wno-name-shadowing #-}
module Lib.PkgRepository where module Lib.PkgRepository where
import Conduit ( (.|) import Conduit ( (.|)
@@ -70,6 +71,7 @@ import Startlude ( ($)
, Maybe(..) , Maybe(..)
, MonadIO(liftIO) , MonadIO(liftIO)
, MonadReader , MonadReader
, Ord(compare)
, Show , Show
, SomeException(..) , SomeException(..)
, filter , filter
@@ -79,11 +81,12 @@ import Startlude ( ($)
, fst , fst
, headMay , headMay
, not , not
, on
, partitionEithers , partitionEithers
, pure , pure
, show , show
, snd , snd
, sortOn , sortBy
, throwIO , throwIO
, void , void
) )
@@ -105,9 +108,9 @@ import UnliftIO ( MonadUnliftIO
, mapConcurrently_ , mapConcurrently_
, newEmptyMVar , newEmptyMVar
, takeMVar , takeMVar
, tryPutMVar
, wait , wait
) )
import UnliftIO ( tryPutMVar )
import UnliftIO.Concurrent ( forkIO ) import UnliftIO.Concurrent ( forkIO )
import UnliftIO.Directory ( doesDirectoryExist import UnliftIO.Directory ( doesDirectoryExist
, doesPathExist , doesPathExist
@@ -124,6 +127,7 @@ import Yesod.Core.Content ( typeGif
, typeSvg , typeSvg
) )
import Yesod.Core.Types ( ContentType ) import Yesod.Core.Types ( ContentType )
data ManifestParseException = ManifestParseException FilePath data ManifestParseException = ManifestParseException FilePath
deriving Show deriving Show
instance Exception ManifestParseException instance Exception ManifestParseException
@@ -152,8 +156,10 @@ getViableVersions pkg spec = filter (`satisfies` spec) <$> getVersionsFor pkg
getBestVersion :: (MonadIO m, MonadReader r m, Has PkgRepo r, MonadLogger m) getBestVersion :: (MonadIO m, MonadReader r m, Has PkgRepo r, MonadLogger m)
=> PkgId => PkgId
-> VersionRange -> VersionRange
-> Bool
-> m (Maybe Version) -> m (Maybe Version)
getBestVersion pkg spec = headMay . sortOn Down <$> getViableVersions pkg spec getBestVersion pkg spec preferMin = headMay . sortBy comparator <$> getViableVersions pkg spec
where comparator = if preferMin then compare else compare `on` Down
loadPkgDependencies :: MonadUnliftIO m => ConnectionPool -> PackageManifest -> m () loadPkgDependencies :: MonadUnliftIO m => ConnectionPool -> PackageManifest -> m ()
loadPkgDependencies appConnPool manifest = do loadPkgDependencies appConnPool manifest = do
@@ -234,7 +240,6 @@ watchPkgRepoRoot pool = do
onlyAdded (Added path _ isDir) = not isDir && takeExtension path == ".s9pk" onlyAdded (Added path _ isDir) = not isDir && takeExtension path == ".s9pk"
onlyAdded (Modified path _ isDir) = not isDir && takeExtension path == ".s9pk" onlyAdded (Modified path _ isDir) = not isDir && takeExtension path == ".s9pk"
onlyAdded _ = False onlyAdded _ = False
-- Added path _ isDir -> not isDir && takeExtension path == ".s9pk"
getManifest :: (MonadResource m, MonadReader r m, Has PkgRepo r) getManifest :: (MonadResource m, MonadReader r m, Has PkgRepo r)
=> PkgId => PkgId

View File

@@ -1,6 +1,6 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Util.Shared where module Util.Shared where
@@ -54,6 +54,15 @@ getVersionSpecFromQuery = do
Nothing -> sendResponseStatus status400 ("Invalid App Version Specification" :: Text) Nothing -> sendResponseStatus status400 ("Invalid App Version Specification" :: Text)
Just t -> pure t Just t -> pure t
versionPriorityFromQueryIsMin :: Handler Bool
versionPriorityFromQueryIsMin = do
priorityString <- lookupGetParam "version-priority"
case priorityString of
Nothing -> pure False
(Just "max") -> pure False
(Just "min") -> pure True
(Just t ) -> sendResponseStatus status400 ("Invalid Version Priority Specification: " <> t)
addPackageHeader :: (MonadUnliftIO m, MonadHandler m, MonadReader r m, Has PkgRepo r) => PkgId -> Version -> m () addPackageHeader :: (MonadUnliftIO m, MonadHandler m, MonadReader r m, Has PkgRepo r) => PkgId -> Version -> m ()
addPackageHeader pkg version = do addPackageHeader pkg version = do
packageHash <- getHash pkg version packageHash <- getHash pkg version
@@ -64,7 +73,6 @@ orThrow action other = action >>= \case
Nothing -> other Nothing -> other
Just x -> pure x Just x -> pure x
filterPkgOsCompatible :: Monad m => (Version -> Bool) -> ConduitT PackageMetadata PackageMetadata m () filterPkgOsCompatible :: Monad m => (Version -> Bool) -> ConduitT PackageMetadata PackageMetadata m ()
filterPkgOsCompatible p = filterPkgOsCompatible p =
awaitForever awaitForever
@@ -109,7 +117,7 @@ filterLatestVersionFromSpec versionMap = awaitForever $ \(a, vs, cats) -> do
filterDependencyBestVersion :: MonadLogger m => PackageDependencyMetadata -> m (Maybe (Key PkgRecord, Text, Version)) filterDependencyBestVersion :: MonadLogger m => PackageDependencyMetadata -> m (Maybe (Key PkgRecord, Text, Version))
filterDependencyBestVersion PackageDependencyMetadata { packageDependencyMetadataPkgDependencyRecord = pkgDepRecord, packageDependencyMetadataDepPkgRecord = depRecord, packageDependencyMetadataDepVersions = depVersions } filterDependencyBestVersion PackageDependencyMetadata { packageDependencyMetadataPkgDependencyRecord = pkgDepRecord, packageDependencyMetadataDepPkgRecord = depRecord, packageDependencyMetadataDepVersions = depVersions }
= do = do
-- get best version from VersionRange of dependency -- get best version from VersionRange of dependency
let pkgId = pkgDependencyPkgId $ entityVal pkgDepRecord let pkgId = pkgDependencyPkgId $ entityVal pkgDepRecord
let depId = pkgDependencyDepId $ entityVal pkgDepRecord let depId = pkgDependencyDepId $ entityVal pkgDepRecord
let depTitle = pkgRecordTitle $ entityVal depRecord let depTitle = pkgRecordTitle $ entityVal depRecord
@@ -119,6 +127,6 @@ filterDependencyBestVersion PackageDependencyMetadata { packageDependencyMetadat
-- QUESTION is this an acceptable transformation here? These are the only values that we care about after this filter. -- QUESTION is this an acceptable transformation here? These are the only values that we care about after this filter.
Just bestVersion -> pure $ Just (depId, depTitle, bestVersion) Just bestVersion -> pure $ Just (depId, depTitle, bestVersion)
Nothing -> do Nothing -> do
$logInfo [i|No satisfactory version of #{depId} for dependent package #{pkgId}|]
-- TODO it would be better if we could return the requirements for display -- TODO it would be better if we could return the requirements for display
$logInfo [i|No satisfactory version of #{depId} for dependent package #{pkgId}|]
pure Nothing pure Nothing