packages feed

pantry 0.5.2.3 → 0.5.3

raw patch · 6 files changed

+145/−32 lines, 6 filesdep ~aesonPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: aeson

API changes (from Hackage documentation)

+ Pantry: SimpleRepo :: !Text -> !Text -> !RepoType -> SimpleRepo
+ Pantry: [sRepoCommit] :: SimpleRepo -> !Text
+ Pantry: [sRepoType] :: SimpleRepo -> !RepoType
+ Pantry: [sRepoUrl] :: SimpleRepo -> !Text
+ Pantry: data SimpleRepo
+ Pantry: fetchRepos :: (HasPantryConfig env, HasLogFunc env, HasProcessContext env) => [(Repo, PackageMetadata)] -> RIO env ()
+ Pantry: fetchReposRaw :: (HasPantryConfig env, HasLogFunc env, HasProcessContext env) => [(Repo, RawPackageMetadata)] -> RIO env ()
- Pantry: FailedToCloneRepo :: !Repo -> PantryException
+ Pantry: FailedToCloneRepo :: !SimpleRepo -> PantryException
- Pantry: withRepo :: forall env a. (HasLogFunc env, HasProcessContext env) => Repo -> RIO env a -> RIO env a
+ Pantry: withRepo :: forall env a. (HasLogFunc env, HasProcessContext env) => SimpleRepo -> RIO env a -> RIO env a

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for pantry +## v0.5.3++* improve and expose `fetchRepos`/`fetchReposRaw`+ ## v0.5.2.3  * Support for GHC 9 [#39](https://github.com/commercialhaskell/pantry/pull/39)
pantry.cabal view
@@ -7,7 +7,7 @@ -- hash: 290314cf42f0f169e5cb395c4b35e867438c4e2652df972ec59c548dc39f1b6d  name:           pantry-version:        0.5.2.3+version:        0.5.3 synopsis:       Content addressable Haskell package management description:    Please see the README on Github at <https://github.com/commercialhaskell/pantry#readme> category:       Development
src/Pantry.hs view
@@ -67,7 +67,10 @@     -- ** Repos   , Repo (..)   , RepoType (..)+  , SimpleRepo (..)   , withRepo+  , fetchRepos+  , fetchReposRaw      -- ** Package location   , RawPackageLocation (..)@@ -193,7 +196,7 @@ import Casa.Client (thParserCasaRepo, CasaRepoPrefix) import Pantry.Repo import qualified Pantry.SHA256 as SHA256-import Pantry.Storage hiding (TreeEntry, PackageName, Version)+import Pantry.Storage hiding (TreeEntry, PackageName, Version, findOrGenerateCabalFile) import Pantry.Tree import Pantry.Types as P import Pantry.Hackage
src/Pantry/Repo.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE LambdaCase #-} module Pantry.Repo   ( fetchReposRaw   , fetchRepos@@ -11,6 +14,7 @@   , withRepo   ) where + import Pantry.Types import Pantry.Archive import Pantry.Storage@@ -35,12 +39,21 @@   let bs = toStrict stdoutBS   pure $ if "GNU" `isInfixOf` bs then Gnu else Bsd +-- | Like 'fetchRepos', except with 'RawPackageMetadata' instead of 'PackageMetadata'.+--+-- @since 0.5.3 fetchReposRaw   :: (HasPantryConfig env, HasLogFunc env, HasProcessContext env)   => [(Repo, RawPackageMetadata)]   -> RIO env ()-fetchReposRaw pairs = for_ pairs $ uncurry getRepo+fetchReposRaw pairs = do+  let repos = toAggregateRepos pairs+  logDebug (displayShow repos)+  for_ repos getRepos +-- | Fetch the given repositories at once and populate the pantry database.+--+-- @since 0.5.3 fetchRepos   :: (HasPantryConfig env, HasLogFunc env, HasProcessContext env)   => [(Repo, PackageMetadata)]@@ -61,7 +74,7 @@   => Repo   -> RawPackageMetadata   -> RIO env Package-getRepo repo pm =+getRepo repo pm = do   withCache $ getRepo' repo pm   where     withCache@@ -85,8 +98,8 @@   => Repo   -> RawPackageMetadata   -> RIO env Package-getRepo' repo rpm = do-  withRepoArchive repo $ \tarball -> do+getRepo' repo@Repo{..} rpm = do+  withRepoArchive (rToSimpleRepo repo) $ \tarball -> do     abs' <- resolveFile' tarball     getArchivePackage       (RPLIRepo repo rpm)@@ -97,21 +110,69 @@             }         , raHash = Nothing         , raSize = Nothing-        , raSubdir = repoSubdir repo+        , raSubdir = repoSubdir         }       rpm +getRepos+  :: forall env. (HasPantryConfig env, HasLogFunc env, HasProcessContext env)+  => AggregateRepo+  -> RIO env [Package]+getRepos repo@(AggregateRepo (SimpleRepo{..}) repoSubdirs) =+  withCache getRepos'+  where+    withCache inner = do+      pkgs <- forM repoSubdirs $ \(subdir, rpm) -> withStorage $ do+        loadRepoCache (Repo sRepoUrl sRepoCommit sRepoType subdir) subdir >>= \case+          Just tid -> fmap Right $ (, subdir) <$> loadPackageById (RPLIRepo (Repo sRepoUrl sRepoCommit sRepoType subdir) rpm) tid+          Nothing  -> pure $ Left (subdir, rpm)+      let (missingPkgs, cachedPkgs) = partitionEithers pkgs+      newPkgs <-+        if null missingPkgs+        then pure []+        else do+          packages <- inner repo { aRepoSubdirs = missingPkgs }+          forM packages $ \(package, subdir) -> do+            withStorage $ do+              ment <- getTreeForKey $ packageTreeKey package+              case ment of+                Nothing -> error $ "invariant violated, Tree not found: " ++ show (packageTreeKey package)+                Just (Entity tid _) -> storeRepoCache (Repo sRepoUrl sRepoCommit sRepoType subdir) subdir tid+            pure package+      pure (nubOrd ((fst <$> cachedPkgs) ++ newPkgs))++getRepos'+  :: forall env. (HasPantryConfig env, HasLogFunc env, HasProcessContext env)+  => AggregateRepo+  -> RIO env [(Package, Text)] -- ^ [(package, subdir)]+getRepos' ar@(AggregateRepo (SimpleRepo{..}) repoSubdirs) = do+  withRepoArchive (arToSimpleRepo ar) $ \tarball -> do+    abs' <- resolveFile' tarball+    forM repoSubdirs $ \(subdir, rpm) -> do+      (,subdir) <$> getArchivePackage+        (RPLIRepo (Repo sRepoUrl sRepoCommit sRepoType subdir) rpm)+        RawArchive+          { raLocation = ALFilePath $ ResolvedPath+              { resolvedRelative = RelFilePath $ T.pack tarball+              , resolvedAbsolute = abs'+              }+          , raHash = Nothing+          , raSize = Nothing+          , raSubdir = subdir+          }+        rpm+ -- | Fetch a repository and create a (temporary) tar archive from it. Pass the -- path of the generated tarball to the given action. withRepoArchive   :: forall env a. (HasLogFunc env, HasProcessContext env)-  => Repo+  => SimpleRepo   -> (FilePath -> RIO env a)   -> RIO env a-withRepoArchive repo action =-  withSystemTempDirectory "with-repo-archive" $ \tmpdir -> do-    let tarball = tmpdir </> "foo.tar"-    createRepoArchive repo tarball+withRepoArchive sr action =+  withSystemTempDirectory "with-repo-archive" $ \tmpdirArchive -> do+    let tarball = tmpdirArchive </> "foo.tar"+    createRepoArchive sr tarball     action tarball  -- | Run a git command, setting appropriate environment variable settings. See@@ -174,12 +235,12 @@ -- | Create a tarball containing files from a repository createRepoArchive ::      forall env. (HasLogFunc env, HasProcessContext env)-  => Repo+  => SimpleRepo   -> FilePath -- ^ Output tar archive filename   -> RIO env ()-createRepoArchive repo tarball = do-  withRepo repo $-    case repoType repo of+createRepoArchive sr tarball = do+  withRepo sr $+    case sRepoType sr of       RepoGit -> do         runGitCommand           ["-c", "core.autocrlf=false", "archive", "-o", tarball, "HEAD"]@@ -193,10 +254,10 @@ -- @since 0.1.0.0 withRepo   :: forall env a. (HasLogFunc env, HasProcessContext env)-  => Repo+  => SimpleRepo   -> RIO env a   -> RIO env a-withRepo repo@(Repo url commit repoType' _subdir) action =+withRepo sr@SimpleRepo{..} action =   withSystemTempDirectory "with-repo" $ \tmpDir -> do     -- Note we do not immediately change directories into the new temporary directory,     -- but instead wait until we have finished cloning the repo. This is because the@@ -204,15 +265,15 @@     -- it as relative to the current directory, not the temporary directory.     let dir = tmpDir </> "cloned"         (runCommand, resetArgs, submoduleArgs) =-          case repoType' of+          case sRepoType of             RepoGit ->               ( runGitCommand-              , ["reset", "--hard", T.unpack commit]+              , ["reset", "--hard", T.unpack sRepoCommit]               , Just ["submodule", "update", "--init", "--recursive"]               )             RepoHg ->               ( runHgCommand-              , ["update", "-C", T.unpack commit]+              , ["update", "-C", T.unpack sRepoCommit]               , Nothing               )         fixANSIForWindows =@@ -222,11 +283,11 @@           -- folowing hack re-enables the lost ANSI-capability.           when osIsWindows $ void $ liftIO $ hSupportsANSIWithoutEmulation stdout -    logInfo $ "Cloning " <> display commit <> " from " <> display url-    runCommand ["clone", T.unpack url, dir]+    logInfo $ "Cloning " <> display sRepoCommit <> " from " <> display sRepoUrl+    runCommand ["clone", T.unpack sRepoUrl, dir]     fixANSIForWindows     created <- doesDirectoryExist dir-    unless created $ throwIO $ FailedToCloneRepo repo+    unless created $ throwIO $ FailedToCloneRepo sr      withWorkingDir dir $ do       runCommand resetArgs
src/Pantry/Storage.hs view
@@ -68,6 +68,7 @@   , getSnapshotCacheId   , storeSnapshotModuleCache   , loadExposedModulePackages+  , findOrGenerateCabalFile   , PackageNameId   , PackageName   , VersionId
src/Pantry/Types.hs view
@@ -12,6 +12,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE NamedFieldPuns #-} module Pantry.Types   ( PantryConfig (..)   , HackageSecurityConfig (..)@@ -61,6 +62,11 @@   , Archive (..)   , toRawArchive   , Repo (..)+  , AggregateRepo (..)+  , SimpleRepo (..)+  , toAggregateRepos+  , rToSimpleRepo+  , arToSimpleRepo   , RepoType (..)   , parsePackageIdentifier   , parsePackageName@@ -120,7 +126,7 @@ import qualified RIO.Text as T import qualified RIO.ByteString as B import qualified RIO.ByteString.Lazy as BL-import RIO.List (intersperse)+import RIO.List (intersperse, groupBy) import RIO.Time (toGregorian, Day, UTCTime) import qualified RIO.Map as Map import qualified RIO.HashMap as HM@@ -181,18 +187,18 @@   --   -- @since 0.1.0.0   }-  deriving (Show, Eq)+  deriving (Show, Eq, Ord)  data PHpack = PHpack     {       phOriginal :: !TreeEntry, -- ^ Original hpack file       phGenerated :: !TreeEntry, -- ^ Generated Cabal file       phVersion :: !Version -- ^ Version of Hpack used-    } deriving (Show, Eq)+    } deriving (Show, Eq, Ord)  data PackageCabal = PCCabalFile !TreeEntry -- ^ TreeEntry of Cabal file                   | PCHpack !PHpack-                  deriving (Show, Eq)+                  deriving (Show, Eq, Ord)  cabalFileName :: PackageName -> SafeFilePath cabalFileName name =@@ -530,7 +536,45 @@       then mempty       else " in subdirectory " <> display subdir) +rToSimpleRepo :: Repo -> SimpleRepo+rToSimpleRepo Repo {..} = SimpleRepo { sRepoUrl = repoUrl, sRepoCommit = repoCommit, sRepoType = repoType } +data AggregateRepo = AggregateRepo+  { aRepo :: !SimpleRepo+  , aRepoSubdirs :: [(Text, RawPackageMetadata)]+  }+    deriving (Show, Generic, Eq, Ord, Typeable)+++-- | Group input repositories by non-subdir values.+toAggregateRepos :: [(Repo, RawPackageMetadata)] -> [AggregateRepo]+toAggregateRepos =+  fmap (\xs@((repo, _):_) -> AggregateRepo (rToSimpleRepo repo) (fmap (first repoSubdir) xs))+  . groupBy (\(Repo url1 commit1 type1 _, _) (Repo url2 commit2 type2 _, _) -> (url1, commit1 ,type1) == (url2, commit2, type2))++arToSimpleRepo :: AggregateRepo -> SimpleRepo+arToSimpleRepo AggregateRepo {..} = aRepo++-- | Repository without subdirectory information.+--+-- @since 0.5.3+data SimpleRepo = SimpleRepo+  { sRepoUrl :: !Text+  , sRepoCommit :: !Text+  , sRepoType :: !RepoType+  }+    deriving (Show, Generic, Eq, Ord, Typeable)++instance Display SimpleRepo where+  display (SimpleRepo url commit typ) =+    (case typ of+       RepoGit -> "Git"+       RepoHg -> "Mercurial") <>+    " repo at " <>+    display url <>+    ", commit " <>+    display commit+ -- An unexported newtype wrapper to hang a 'FromJSON' instance off of. Contains -- a GitHub user and repo name separated by a forward slash, e.g. "foo/bar". newtype GitHubRepo = GitHubRepo Text@@ -844,7 +888,7 @@   | InvalidTarFileType !ArchiveLocation !FilePath !Tar.FileType   | UnsupportedTarball !ArchiveLocation !Text   | NoHackageCryptographicHash !PackageIdentifier-  | FailedToCloneRepo !Repo+  | FailedToCloneRepo !SimpleRepo   | TreeReferencesMissingBlob !RawPackageLocationImmutable !SafeFilePath !BlobKey   | CompletePackageMetadataMismatch !RawPackageLocationImmutable !PackageMetadata   | CRC32Mismatch !ArchiveLocation !FilePath !(Mismatch Word32)@@ -1101,7 +1145,7 @@   deriving (Show, Eq)  data FileType = FTNormal | FTExecutable-  deriving (Show, Eq, Enum, Bounded)+  deriving (Show, Eq, Enum, Bounded, Ord) instance PersistField FileType where   toPersistValue FTNormal = PersistInt64 1   toPersistValue FTExecutable = PersistInt64 2@@ -1119,7 +1163,7 @@   { teBlob :: !BlobKey   , teType :: !FileType   }-  deriving (Show, Eq)+  deriving (Show, Eq, Ord)  newtype SafeFilePath = SafeFilePath Text   deriving (Show, Eq, Ord, Display)@@ -1177,7 +1221,7 @@   -- In the future, consider allowing more lax parsing   -- See: https://www.fpcomplete.com/blog/2018/07/pantry-part-2-trees-keys   -- TreeTarball !PackageTarball-  deriving (Show, Eq)+  deriving (Show, Eq, Ord)  renderTree :: Tree -> ByteString renderTree = BL.toStrict . toLazyByteString . go