pantry 0.9.3.2 → 0.10.0
raw patch · 7 files changed
+734/−484 lines, 7 filesdep ~Cabaldep ~static-bytesPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: Cabal, static-bytes
API changes (from Hackage documentation)
+ Pantry: Force :: Force
+ Pantry: GHLFilePath :: !ResolvedPath File -> GlobalHintsLocation
+ Pantry: GHLUrl :: !Text -> GlobalHintsLocation
+ Pantry: InvalidFilePathGlobalHints :: !Text -> PantryException
+ Pantry: InvalidGlobalHintsLocation :: !Path Abs Dir -> !Text -> PantryException
+ Pantry: NoForce :: Force
+ Pantry: data () => Force
+ Pantry: data () => GlobalHintsLocation
+ Pantry: defaultGlobalHintsLocation :: WantedCompiler -> GlobalHintsLocation
+ Pantry: hpackForceL :: Lens' PantryConfig Force
+ Pantry.Internal.Stackage: [pcGlobalHintsLocation] :: PantryConfig -> WantedCompiler -> GlobalHintsLocation
+ Pantry.Internal.Stackage: [pcHpackForce] :: PantryConfig -> !Force
- Pantry: withPantryConfig :: HasLogFunc env => Path Abs Dir -> PackageIndexConfig -> HpackExecutable -> Int -> CasaRepoPrefix -> Int -> (SnapName -> RawSnapshotLocation) -> (PantryConfig -> RIO env a) -> RIO env a
+ Pantry: withPantryConfig :: HasLogFunc env => Path Abs Dir -> PackageIndexConfig -> HpackExecutable -> Int -> CasaRepoPrefix -> Int -> (SnapName -> RawSnapshotLocation) -> (WantedCompiler -> GlobalHintsLocation) -> (PantryConfig -> RIO env a) -> RIO env a
- Pantry: withPantryConfig' :: HasLogFunc env => Path Abs Dir -> PackageIndexConfig -> HpackExecutable -> Int -> Maybe (CasaRepoPrefix, Int) -> (SnapName -> RawSnapshotLocation) -> (PantryConfig -> RIO env a) -> RIO env a
+ Pantry: withPantryConfig' :: HasLogFunc env => Path Abs Dir -> PackageIndexConfig -> HpackExecutable -> Force -> Int -> Maybe (CasaRepoPrefix, Int) -> (SnapName -> RawSnapshotLocation) -> (WantedCompiler -> GlobalHintsLocation) -> (PantryConfig -> RIO env a) -> RIO env a
- Pantry.Internal.Stackage: PantryConfig :: !PackageIndexConfig -> !HpackExecutable -> !Path Abs Dir -> !Storage -> !MVar Bool -> !IORef (Map RawPackageLocationImmutable GenericPackageDescription) -> !IORef (Map (Path Abs Dir) (PrintWarnings -> IO GenericPackageDescription, PackageName, Path Abs File)) -> !Int -> !Maybe (CasaRepoPrefix, Int) -> (SnapName -> RawSnapshotLocation) -> PantryConfig
+ Pantry.Internal.Stackage: PantryConfig :: !PackageIndexConfig -> !HpackExecutable -> !Force -> !Path Abs Dir -> !Storage -> !MVar Bool -> !IORef (Map RawPackageLocationImmutable GenericPackageDescription) -> !IORef (Map (Path Abs Dir) (PrintWarnings -> IO GenericPackageDescription, PackageName, Path Abs File)) -> !Int -> !Maybe (CasaRepoPrefix, Int) -> (SnapName -> RawSnapshotLocation) -> (WantedCompiler -> GlobalHintsLocation) -> PantryConfig
Files
- ChangeLog.md +12/−0
- app/test-pretty-exceptions/Main.hs +2/−0
- int/Pantry/HPack.hs +9/−4
- int/Pantry/Types.hs +159/−14
- pantry.cabal +354/−354
- src/Pantry.hs +191/−111
- src/Pantry/Hackage.hs +7/−1
ChangeLog.md view
@@ -1,5 +1,17 @@ # Changelog for pantry +## v0.10.0 + +* Name of tar file of local cache of package index is not hard coded. +* `withPantryConfig` and `withPantryConfig'` require the location of global + hints to be specified. +* `GlobalHintsLocation`, `defaultGlobalHintsLocation`, `globalHintsLocation` and + `parseGlobalHintsLocation` added. +* `withPantryConfig'` now requires the specification of whether or not Hpack's + `--force` flag is to be applied. +* Expose `hpackForceL`, a lens to view or modify the `Force` (Hpack) of a + `PantryConfig`. + ## v0.9.3.2 * Support `ansi-terminal-1.0.2`.
app/test-pretty-exceptions/Main.hs view
@@ -145,6 +145,8 @@ , [ InvalidSnapshot rawSnapshotLocation someExceptionExample | rawSnapshotLocation <- rawSnapshotLocationExamples ] + , [ InvalidGlobalHintsLocation pathAbsDirExample rawPathExample ] + , [ InvalidFilePathGlobalHints rawPathExample ] , [ MismatchedPackageMetadata rawPackageLocationImmutable rawPackageMetadata treeKey packageIdentifierExample | rawPackageLocationImmutable <- rawPackageLocationImmutableExamples , rawPackageMetadata <- rawPackageMetadataExamples
int/Pantry/HPack.hs view
@@ -51,10 +51,13 @@ whenM (doesFileExist hpackFile) $ do logDebug $ "Running hpack on " <> fromString (toFilePath hpackFile) he <- view $ pantryConfigL.to pcHpackExecutable + hpackForce <- view $ pantryConfigL.to pcHpackForce case he of HpackBundled -> do r <- liftIO $ Hpack.hpackResult $ Hpack.setProgramName "stack" $ - Hpack.setTarget (toFilePath hpackFile) Hpack.defaultOptions + Hpack.setTarget + (toFilePath hpackFile) + Hpack.defaultOptions { Hpack.optionsForce = hpackForce } forM_ (Hpack.resultWarnings r) (logWarn . fromString) let cabalFile = fromString . Hpack.resultCabalFile $ r case Hpack.resultStatus r of @@ -82,6 +85,8 @@ <> fromString (toFilePath (filename hpackFile)) <> " file instead of the Cabal file,\n" <> "then please delete the Cabal file." - HpackCommand command -> - withWorkingDir (toFilePath pkgDir) $ - proc command [] runProcess_ + HpackCommand command -> do + let hpackArgs = case hpackForce of + Hpack.Force -> ["--force"] + Hpack.NoForce -> [] + withWorkingDir (toFilePath pkgDir) $ proc command hpackArgs runProcess_
int/Pantry/Types.hs view
@@ -98,6 +98,8 @@ --, resolveSnapshotLocation , snapshotLocation , defaultSnapshotLocation + , globalHintsLocation + , defaultGlobalHintsLocation , SnapName (..) , parseSnapName , RawSnapshotLocation (..) @@ -112,6 +114,8 @@ , Snapshot (..) , RawSnapshotPackage (..) , SnapshotPackage (..) + , GlobalHintsLocation (..) + , parseGlobalHintsLocation , parseWantedCompiler , RawPackageMetadata (..) , PackageMetadata (..) @@ -171,6 +175,7 @@ ( PackageName, mkPackageName, unPackageName ) import Distribution.Types.Version ( Version, mkVersion, nullVersion ) import Distribution.Types.VersionRange ( VersionRange ) +import qualified Hpack import qualified Hpack.Config as Hpack import Network.HTTP.Client ( parseRequest ) import Network.HTTP.Types ( Status, statusCode ) @@ -285,6 +290,7 @@ data PantryConfig = PantryConfig { pcPackageIndex :: !PackageIndexConfig , pcHpackExecutable :: !HpackExecutable + , pcHpackForce :: !Hpack.Force , pcRootDir :: !(Path Abs Dir) , pcStorage :: !Storage , pcUpdateRef :: !(MVar Bool) @@ -317,6 +323,8 @@ -- the maximum number of Casa keys to pull per request. , pcSnapshotLocation :: SnapName -> RawSnapshotLocation -- ^ The location of snapshot synonyms + , pcGlobalHintsLocation :: WantedCompiler -> GlobalHintsLocation + -- ^ The location of global hints } -- | Get the location of a snapshot synonym from the 'PantryConfig'. @@ -330,6 +338,17 @@ loc <- view $ pantryConfigL.to pcSnapshotLocation pure $ loc name +-- | Get the location of global hints from the 'PantryConfig'. +-- +-- @since 0.9.4 +globalHintsLocation :: + HasPantryConfig env + => WantedCompiler + -> RIO env GlobalHintsLocation +globalHintsLocation wc = do + loc <- view $ pantryConfigL.to pcGlobalHintsLocation + pure $ loc wc + -- | Should we print warnings when loading a cabal file? -- -- @since 0.1.0.0 @@ -1066,6 +1085,8 @@ | InvalidOverrideCompiler !WantedCompiler !WantedCompiler | InvalidFilePathSnapshot !Text | InvalidSnapshot !RawSnapshotLocation !SomeException + | InvalidGlobalHintsLocation !(Path Abs Dir) !Text + | InvalidFilePathGlobalHints !Text | MismatchedPackageMetadata !RawPackageLocationImmutable !RawPackageMetadata @@ -1241,6 +1262,17 @@ <> display loc <> ":\n" <> displayShow err + display (InvalidGlobalHintsLocation dir t) = + "Error: [S-926]\n" + <> "Invalid global hints location " + <> displayShow t + <> " relative to directory " + <> displayShow (toFilePath dir) + display (InvalidFilePathGlobalHints t) = + "Error: [S-832]\n" + <> "Specified global hints as file path with " + <> displayShow t + <> ", but not reading from a local file" display (MismatchedPackageMetadata loc pm mtreeKey foundIdent) = "Error: [S-427]\n" <> "Mismatched package metadata for " @@ -1627,6 +1659,23 @@ ] <> blankLine <> string (displayException err) + pretty (InvalidGlobalHintsLocation dir t) = + "[S-926]" + <> line + <> fillSep + [ flow "Invalid global hints location" + , style Current (fromString $ T.unpack t) + , flow "relative to directory" + , pretty dir <> "." + ] + pretty (InvalidFilePathGlobalHints t) = + "[S-832]" + <> line + <> fillSep + [ flow "Specified global hints as file path with" + , style File (fromString $ T.unpack t) <> "," + , flow "but not reading from a local file." + ] pretty (MismatchedPackageMetadata loc pm mtreeKey foundIdent) = "[S-427]" <> line @@ -2895,32 +2944,76 @@ parseUrl = parseRequest (T.unpack t0) $> pure (RSLUrl t0 Nothing) -parseRawSnapshotLocationPath :: Text -> Unresolved RawSnapshotLocation -parseRawSnapshotLocationPath t = +parseLocationPath :: + (Text -> PantryException) + -> (Path Abs Dir -> Text -> PantryException) + -> (ResolvedPath File -> a) + -> Text + -> Unresolved a +parseLocationPath invalidPath invalidLocation resolver t = Unresolved $ \case - Nothing -> throwIO $ InvalidFilePathSnapshot t + Nothing -> throwIO $ invalidPath t Just dir -> do - abs' <- resolveFile dir (T.unpack t) `catchAny` \_ -> throwIO (InvalidSnapshotLocation dir t) - pure $ RSLFilePath $ ResolvedPath (RelFilePath t) abs' + abs' <- resolveFile dir (T.unpack t) `catchAny` + \_ -> throwIO (invalidLocation dir t) + pure $ resolver $ ResolvedPath (RelFilePath t) abs' +parseRawSnapshotLocationPath :: Text -> Unresolved RawSnapshotLocation +parseRawSnapshotLocationPath = parseLocationPath + InvalidFilePathSnapshot + InvalidSnapshotLocation + RSLFilePath + +githubLocation :: Text -> Text -> Text -> Text +githubLocation user repo path =T.concat + [ "https://raw.githubusercontent.com/" + , user + , "/" + , repo + , "/master/" + , path + ] + githubSnapshotLocation :: Text -> Text -> Text -> RawSnapshotLocation githubSnapshotLocation user repo path = - let url = T.concat - [ "https://raw.githubusercontent.com/" - , user - , "/" - , repo - , "/master/" - , path - ] - in RSLUrl url Nothing + RSLUrl (githubLocation user repo path) Nothing +-- | Parse a 'Text' into an 'Unresolved' 'GlobalHintsLocation'. +-- +-- @since 0.9.4 +parseGlobalHintsLocation :: Text -> Unresolved GlobalHintsLocation +parseGlobalHintsLocation t0 = fromMaybe (parseGlobalHintsLocationPath t0) $ + parseGitHub <|> parseUrl + where + parseGitHub = do + t1 <- T.stripPrefix "github:" t0 + let (user, t2) = T.break (== '/') t1 + t3 <- T.stripPrefix "/" t2 + let (repo, t4) = T.break (== ':') t3 + path <- T.stripPrefix ":" t4 + Just $ pure $ githubGlobalHintsLocation user repo path + + parseUrl = parseRequest (T.unpack t0) $> pure (GHLUrl t0) + +parseGlobalHintsLocationPath :: Text -> Unresolved GlobalHintsLocation +parseGlobalHintsLocationPath = parseLocationPath + InvalidFilePathGlobalHints + InvalidGlobalHintsLocation + GHLFilePath + +githubGlobalHintsLocation :: Text -> Text -> Text -> GlobalHintsLocation +githubGlobalHintsLocation user repo path = + GHLUrl (githubLocation user repo path) + defUser :: Text defUser = "commercialhaskell" defRepo :: Text defRepo = "stackage-snapshots" +defGlobalHintsRepo :: Text +defGlobalHintsRepo = "stackage-content" + -- | Default location of snapshot synonyms, i.e. commercialhaskell's GitHub -- repository. -- @@ -2945,6 +3038,17 @@ where (year, month, day) = toGregorian date +-- | Default location of global hints, i.e. commercialhaskell's GitHub +-- repository. +-- +-- @since 0.9.4 +defaultGlobalHintsLocation :: + WantedCompiler + -> GlobalHintsLocation +defaultGlobalHintsLocation _ = + githubGlobalHintsLocation defUser defGlobalHintsRepo $ + utf8BuilderToText "stack/global-hints.yaml" + -- | A snapshot synonym. It is expanded according to the field -- 'snapshotLocation' of a 'PantryConfig'. -- @@ -3361,3 +3465,44 @@ <> "This usage is deprecated; please see " <> "https://github.com/commercialhaskell/stack/issues/5210.\n" <> "Support for this workflow will be removed in the future.\n" + +-- | Where to load global hints from. +-- +-- @since 0.9.4 +data GlobalHintsLocation + = GHLUrl !Text + -- ^ Download the global hints from the given URL. + | GHLFilePath !(ResolvedPath File) + -- ^ Global hints at a local file path. + deriving (Show, Eq, Ord, Generic) + +instance NFData GlobalHintsLocation + +instance Display GlobalHintsLocation where + display (GHLUrl url) = display url + display (GHLFilePath resolved) = display (resolvedRelative resolved) + +instance Pretty GlobalHintsLocation where + pretty (GHLUrl url) = style Url (fromString $ T.unpack url) + pretty (GHLFilePath resolved) = + style File (fromString . T.unpack $ textDisplay (resolvedRelative resolved)) + +instance ToJSON GlobalHintsLocation where + toJSON (GHLUrl url) = object ["url" .= url] + toJSON (GHLFilePath resolved) = + object ["filepath" .= resolvedRelative resolved] + +instance FromJSON (WithJSONWarnings (Unresolved GlobalHintsLocation)) where + parseJSON v = file v <|> url v + where + file = withObjectWarnings "GHLFilepath" $ \o -> do + ufp <- o ..: "filepath" + pure $ Unresolved $ \case + Nothing -> throwIO $ InvalidFilePathGlobalHints ufp + Just dir -> do + absolute <- resolveFile dir (T.unpack ufp) + let fp = ResolvedPath (RelFilePath ufp) absolute + pure $ GHLFilePath fp + url = withObjectWarnings "GHLUrl" $ \o -> do + url' <- o ..: "url" + pure $ Unresolved $ \_ -> pure $ GHLUrl url'
pantry.cabal view
@@ -1,355 +1,355 @@ cabal-version: 2.0 ---- This file has been generated from package.yaml by hpack version 0.36.0.------ see: https://github.com/sol/hpack--name: pantry-version: 0.9.3.2-synopsis: Content addressable Haskell package management-description: Please see the README on GitHub at <https://github.com/commercialhaskell/pantry#readme>-category: Development-homepage: https://github.com/commercialhaskell/pantry#readme-bug-reports: https://github.com/commercialhaskell/pantry/issues-author: Michael Snoyman-maintainer: michael@snoyman.com-copyright: 2018-2022 FP Complete-license: BSD3-license-file: LICENSE-build-type: Simple-extra-source-files:- CONTRIBUTING.md- README.md- ChangeLog.md- attic/hpack-0.1.2.3.tar.gz- attic/package-0.1.2.3.tar.gz- attic/symlink-to-dir.tar.gz--source-repository head- type: git- location: https://github.com/commercialhaskell/pantry--flag test-pretty-exceptions- description: Build an executable to test pretty exceptions- manual: False- default: False--library- exposed-modules:- Pantry- Pantry.SQLite- Pantry.Internal.Stackage- other-modules:- Hackage.Security.Client.Repository.HttpLib.HttpClient- Pantry.Archive- Pantry.HTTP- Pantry.Hackage- Pantry.Repo- Pantry.Storage- Pantry.Casa- Pantry.Tree- reexported-modules:- Pantry.SHA256- hs-source-dirs:- src/- ghc-options: -fwrite-ide-info -hiedir=.hie -Wall- build-depends:- Cabal >=3 && <3.11- , aeson- , aeson-warning-parser >=0.1.1- , ansi-terminal- , base >=4.13 && <5- , bytestring- , casa-client >=0.0.2- , casa-types- , companion- , conduit- , conduit-extra- , containers- , crypton- , crypton-conduit- , digest- , filelock- , generic-deriving- , hackage-security- , hpack >=0.35.3- , http-client- , http-client-tls >=0.3.6.2- , http-conduit- , http-download >=0.2.1.0- , http-types- , internal- , memory- , mtl- , network-uri- , path- , path-io- , persistent- , persistent-sqlite >=2.9.3- , persistent-template- , primitive- , resourcet- , rio- , rio-orphans- , rio-prettyprint >=0.1.7.0- , static-bytes- , tar-conduit >=0.4.1- , text- , text-metrics- , time- , transformers- , unix-compat- , unliftio- , unordered-containers- , vector- , yaml- , zip-archive- default-language: Haskell2010- if impl(ghc >= 9.4.5) && os(windows)- build-depends:- network >=3.1.2.9- if os(windows)- other-modules:- System.IsWindows- hs-source-dirs:- src/windows/- else- other-modules:- System.IsWindows- hs-source-dirs:- src/unix/--library internal- exposed-modules:- Pantry.HPack- Pantry.Internal- Pantry.SHA256- Pantry.Types- other-modules:- Paths_pantry- autogen-modules:- Paths_pantry- hs-source-dirs:- int/- ghc-options: -fwrite-ide-info -hiedir=.hie -Wall- build-depends:- Cabal >=3 && <3.11- , aeson- , aeson-warning-parser >=0.1.1- , ansi-terminal- , base >=4.13 && <5- , bytestring- , casa-client >=0.0.2- , casa-types- , companion- , conduit- , conduit-extra- , containers- , crypton- , crypton-conduit- , digest- , filelock- , generic-deriving- , hackage-security- , hpack >=0.35.3- , http-client- , http-client-tls >=0.3.6.2- , http-conduit- , http-download >=0.2.1.0- , http-types- , memory- , mtl- , network-uri- , path- , path-io- , persistent- , persistent-sqlite >=2.9.3- , persistent-template- , primitive- , resourcet- , rio- , rio-orphans- , rio-prettyprint >=0.1.7.0- , static-bytes- , tar-conduit >=0.4.1- , text- , text-metrics- , time- , transformers- , unix-compat- , unliftio- , unordered-containers- , vector- , yaml- , zip-archive- default-language: Haskell2010- if impl(ghc >= 9.4.5) && os(windows)- build-depends:- network >=3.1.2.9--executable test-pretty-exceptions- main-is: Main.hs- other-modules:- Paths_pantry- autogen-modules:- Paths_pantry- hs-source-dirs:- app/test-pretty-exceptions- ghc-options: -fwrite-ide-info -hiedir=.hie -Wall- build-depends:- Cabal >=3 && <3.11- , aeson- , aeson-warning-parser >=0.1.1- , ansi-terminal- , base >=4.13 && <5- , bytestring- , casa-client >=0.0.2- , casa-types- , companion- , conduit- , conduit-extra- , containers- , crypton- , crypton-conduit- , digest- , filelock- , generic-deriving- , hackage-security- , hpack >=0.35.3- , http-client- , http-client-tls >=0.3.6.2- , http-conduit- , http-download >=0.2.1.0- , http-types- , memory- , mtl- , network-uri- , optparse-applicative- , pantry- , path- , path-io- , persistent- , persistent-sqlite >=2.9.3- , persistent-template- , primitive- , resourcet- , rio- , rio-orphans- , rio-prettyprint >=0.1.7.0- , static-bytes- , tar-conduit >=0.4.1- , text- , text-metrics- , time- , transformers- , unix-compat- , unliftio- , unordered-containers- , vector- , yaml- , zip-archive- default-language: Haskell2010- if impl(ghc >= 9.4.5) && os(windows)- build-depends:- network >=3.1.2.9- if !flag(test-pretty-exceptions)- buildable: False- if os(windows)- other-modules:- PathAbsExamples- System.Terminal- hs-source-dirs:- app/test-pretty-exceptions/windows/- build-depends:- Win32- , process- else- other-modules:- PathAbsExamples- System.Terminal- hs-source-dirs:- app/test-pretty-exceptions/unix/--test-suite spec- type: exitcode-stdio-1.0- main-is: Spec.hs- other-modules:- Pantry.ArchiveSpec- Pantry.BuildPlanSpec- Pantry.CabalSpec- Pantry.CasaSpec- Pantry.FileSpec- Pantry.GlobalHintsSpec- Pantry.HackageSpec- Pantry.InternalSpec- Pantry.TreeSpec- Pantry.TypesSpec- Paths_pantry- autogen-modules:- Paths_pantry- hs-source-dirs:- test- ghc-options: -fwrite-ide-info -hiedir=.hie -Wall- build-tool-depends:- hspec-discover:hspec-discover- build-depends:- Cabal >=3 && <3.11- , QuickCheck- , aeson- , aeson-warning-parser >=0.1.1- , ansi-terminal- , base >=4.13 && <5- , bytestring- , casa-client >=0.0.2- , casa-types- , companion- , conduit- , conduit-extra- , containers- , crypton- , crypton-conduit- , digest- , exceptions- , filelock- , generic-deriving- , hackage-security- , hedgehog- , hpack >=0.35.3- , hspec- , http-client- , http-client-tls >=0.3.6.2- , http-conduit- , http-download >=0.2.1.0- , http-types- , internal- , memory- , mtl- , network-uri- , pantry- , path- , path-io- , persistent- , persistent-sqlite >=2.9.3- , persistent-template- , primitive- , raw-strings-qq- , resourcet- , rio- , rio-orphans- , rio-prettyprint >=0.1.7.0- , static-bytes- , tar-conduit >=0.4.1- , text- , text-metrics- , time- , transformers- , unix-compat- , unliftio- , unordered-containers- , vector- , yaml- , zip-archive- default-language: Haskell2010- if impl(ghc >= 9.4.5) && os(windows)- build-depends:- network >=3.1.2.9+ +-- This file has been generated from package.yaml by hpack version 0.36.0. +-- +-- see: https://github.com/sol/hpack + +name: pantry +version: 0.10.0 +synopsis: Content addressable Haskell package management +description: Please see the README on GitHub at <https://github.com/commercialhaskell/pantry#readme> +category: Development +homepage: https://github.com/commercialhaskell/pantry#readme +bug-reports: https://github.com/commercialhaskell/pantry/issues +author: Michael Snoyman +maintainer: michael@snoyman.com +copyright: 2018-2022 FP Complete +license: BSD3 +license-file: LICENSE +build-type: Simple +extra-source-files: + CONTRIBUTING.md + README.md + ChangeLog.md + attic/hpack-0.1.2.3.tar.gz + attic/package-0.1.2.3.tar.gz + attic/symlink-to-dir.tar.gz + +source-repository head + type: git + location: https://github.com/commercialhaskell/pantry + +flag test-pretty-exceptions + description: Build an executable to test pretty exceptions + manual: False + default: False + +library + exposed-modules: + Pantry + Pantry.SQLite + Pantry.Internal.Stackage + other-modules: + Hackage.Security.Client.Repository.HttpLib.HttpClient + Pantry.Archive + Pantry.HTTP + Pantry.Hackage + Pantry.Repo + Pantry.Storage + Pantry.Casa + Pantry.Tree + reexported-modules: + Pantry.SHA256 + hs-source-dirs: + src/ + ghc-options: -fwrite-ide-info -hiedir=.hie -Wall + build-depends: + Cabal >=3 && <3.11 + , aeson + , aeson-warning-parser >=0.1.1 + , ansi-terminal + , base >=4.13 && <5 + , bytestring + , casa-client >=0.0.2 + , casa-types + , companion + , conduit + , conduit-extra + , containers + , crypton + , crypton-conduit + , digest + , filelock + , generic-deriving + , hackage-security + , hpack >=0.35.3 + , http-client + , http-client-tls >=0.3.6.2 + , http-conduit + , http-download >=0.2.1.0 + , http-types + , internal + , memory + , mtl + , network-uri + , path + , path-io + , persistent + , persistent-sqlite >=2.9.3 + , persistent-template + , primitive + , resourcet + , rio + , rio-orphans + , rio-prettyprint >=0.1.7.0 + , static-bytes + , tar-conduit >=0.4.1 + , text + , text-metrics + , time + , transformers + , unix-compat + , unliftio + , unordered-containers + , vector + , yaml + , zip-archive + default-language: Haskell2010 + if impl(ghc >= 9.4.5) && os(windows) + build-depends: + network >=3.1.2.9 + if os(windows) + other-modules: + System.IsWindows + hs-source-dirs: + src/windows/ + else + other-modules: + System.IsWindows + hs-source-dirs: + src/unix/ + +library internal + exposed-modules: + Pantry.HPack + Pantry.Internal + Pantry.SHA256 + Pantry.Types + other-modules: + Paths_pantry + autogen-modules: + Paths_pantry + hs-source-dirs: + int/ + ghc-options: -fwrite-ide-info -hiedir=.hie -Wall + build-depends: + Cabal >=3 && <3.11 + , aeson + , aeson-warning-parser >=0.1.1 + , ansi-terminal + , base >=4.13 && <5 + , bytestring + , casa-client >=0.0.2 + , casa-types + , companion + , conduit + , conduit-extra + , containers + , crypton + , crypton-conduit + , digest + , filelock + , generic-deriving + , hackage-security + , hpack >=0.35.3 + , http-client + , http-client-tls >=0.3.6.2 + , http-conduit + , http-download >=0.2.1.0 + , http-types + , memory + , mtl + , network-uri + , path + , path-io + , persistent + , persistent-sqlite >=2.9.3 + , persistent-template + , primitive + , resourcet + , rio + , rio-orphans + , rio-prettyprint >=0.1.7.0 + , static-bytes + , tar-conduit >=0.4.1 + , text + , text-metrics + , time + , transformers + , unix-compat + , unliftio + , unordered-containers + , vector + , yaml + , zip-archive + default-language: Haskell2010 + if impl(ghc >= 9.4.5) && os(windows) + build-depends: + network >=3.1.2.9 + +executable test-pretty-exceptions + main-is: Main.hs + other-modules: + Paths_pantry + autogen-modules: + Paths_pantry + hs-source-dirs: + app/test-pretty-exceptions + ghc-options: -fwrite-ide-info -hiedir=.hie -Wall + build-depends: + Cabal >=3 && <3.11 + , aeson + , aeson-warning-parser >=0.1.1 + , ansi-terminal + , base >=4.13 && <5 + , bytestring + , casa-client >=0.0.2 + , casa-types + , companion + , conduit + , conduit-extra + , containers + , crypton + , crypton-conduit + , digest + , filelock + , generic-deriving + , hackage-security + , hpack >=0.35.3 + , http-client + , http-client-tls >=0.3.6.2 + , http-conduit + , http-download >=0.2.1.0 + , http-types + , memory + , mtl + , network-uri + , optparse-applicative + , pantry + , path + , path-io + , persistent + , persistent-sqlite >=2.9.3 + , persistent-template + , primitive + , resourcet + , rio + , rio-orphans + , rio-prettyprint >=0.1.7.0 + , static-bytes + , tar-conduit >=0.4.1 + , text + , text-metrics + , time + , transformers + , unix-compat + , unliftio + , unordered-containers + , vector + , yaml + , zip-archive + default-language: Haskell2010 + if impl(ghc >= 9.4.5) && os(windows) + build-depends: + network >=3.1.2.9 + if !flag(test-pretty-exceptions) + buildable: False + if os(windows) + other-modules: + PathAbsExamples + System.Terminal + hs-source-dirs: + app/test-pretty-exceptions/windows/ + build-depends: + Win32 + , process + else + other-modules: + PathAbsExamples + System.Terminal + hs-source-dirs: + app/test-pretty-exceptions/unix/ + +test-suite spec + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + Pantry.ArchiveSpec + Pantry.BuildPlanSpec + Pantry.CabalSpec + Pantry.CasaSpec + Pantry.FileSpec + Pantry.GlobalHintsSpec + Pantry.HackageSpec + Pantry.InternalSpec + Pantry.TreeSpec + Pantry.TypesSpec + Paths_pantry + autogen-modules: + Paths_pantry + hs-source-dirs: + test + ghc-options: -fwrite-ide-info -hiedir=.hie -Wall + build-tool-depends: + hspec-discover:hspec-discover + build-depends: + Cabal >=3 && <3.11 + , QuickCheck + , aeson + , aeson-warning-parser >=0.1.1 + , ansi-terminal + , base >=4.13 && <5 + , bytestring + , casa-client >=0.0.2 + , casa-types + , companion + , conduit + , conduit-extra + , containers + , crypton + , crypton-conduit + , digest + , exceptions + , filelock + , generic-deriving + , hackage-security + , hedgehog + , hpack >=0.35.3 + , hspec + , http-client + , http-client-tls >=0.3.6.2 + , http-conduit + , http-download >=0.2.1.0 + , http-types + , internal + , memory + , mtl + , network-uri + , pantry + , path + , path-io + , persistent + , persistent-sqlite >=2.9.3 + , persistent-template + , primitive + , raw-strings-qq + , resourcet + , rio + , rio-orphans + , rio-prettyprint >=0.1.7.0 + , static-bytes + , tar-conduit >=0.4.1 + , text + , text-metrics + , time + , transformers + , unix-compat + , unliftio + , unordered-containers + , vector + , yaml + , zip-archive + default-language: Haskell2010 + if impl(ghc >= 9.4.5) && os(windows) + build-depends: + network >=3.1.2.9
src/Pantry.hs view
@@ -22,6 +22,7 @@ , defaultCasaRepoPrefix , defaultCasaMaxPerRequest , defaultSnapshotLocation + , defaultGlobalHintsLocation , HasPantryConfig (..) , withPantryConfig , withPantryConfig' @@ -33,6 +34,7 @@ , runPantryAppClean , runPantryAppWith , hpackExecutableL + , hpackForceL -- * Types @@ -47,6 +49,9 @@ , FlagName , PackageIdentifier (..) + -- ** Hpack types + , Hpack.Force (..) + -- ** Files , FileSize (..) , RelFilePath (..) @@ -106,6 +111,9 @@ , SnapName (..) , snapshotLocation + -- ** Global hints + , GlobalHintsLocation (..) + -- * Loading values , resolvePaths , loadPackageRaw @@ -252,49 +260,54 @@ import Pantry.Types as P ( Archive (..), ArchiveLocation (..), BlobKey (..) , CabalFileInfo (..), CabalString (..), FileSize (..) - , FuzzyResults (..), HackageSecurityConfig (..) - , HasPantryConfig (..), HpackExecutable (..), Mismatch (..) - , ModuleName, Package (..), PackageCabal (..) - , PackageIdentifier (..), PackageIdentifierRevision (..) - , PackageIndexConfig (..), PackageLocation (..) - , PackageLocationImmutable (..), PackageMetadata (..) - , PackageName, PantryConfig (..), PantryException (..) - , PHpack (..), PrintWarnings (..), RawArchive (..) - , RawPackageLocation (..), RawPackageLocationImmutable (..) - , RawPackageMetadata (..), RawSnapshot (..) - , RawSnapshotLayer (..), RawSnapshotLocation (..) - , RawSnapshotPackage (..), RelFilePath (..), Repo (..) - , RepoType (..), ResolvedPath (..), Revision (..) - , SafeFilePath, SHA256, SimpleRepo (..), SnapName (..) - , Snapshot (..), SnapshotCacheHash (..), SnapshotLayer (..) + , FuzzyResults (..), GlobalHintsLocation (..) + , HackageSecurityConfig (..), HasPantryConfig (..) + , HpackExecutable (..), Mismatch (..), ModuleName + , Package (..), PackageCabal (..), PackageIdentifier (..) + , PackageIdentifierRevision (..), PackageIndexConfig (..) + , PackageLocation (..), PackageLocationImmutable (..) + , PackageMetadata (..), PackageName, PantryConfig (..) + , PantryException (..), PHpack (..), PrintWarnings (..) + , RawArchive (..), RawPackageLocation (..) + , RawPackageLocationImmutable (..), RawPackageMetadata (..) + , RawSnapshot (..), RawSnapshotLayer (..) + , RawSnapshotLocation (..), RawSnapshotPackage (..) + , RelFilePath (..), Repo (..), RepoType (..) + , ResolvedPath (..), Revision (..), SafeFilePath, SHA256 + , SimpleRepo (..), SnapName (..), Snapshot (..) + , SnapshotCacheHash (..), SnapshotLayer (..) , SnapshotLocation (..), SnapshotPackage (..), Tree (..) , TreeEntry (..), TreeKey (..), Unresolved, Version , WantedCompiler (..), bsToBlobKey, cabalFileName - , defaultHackageSecurityConfig, defaultSnapshotLocation - , flagNameString, getGlobalHintsFile, mkSafeFilePath - , moduleNameString, packageIdentifierString - , packageNameString, parseFlagName, parseHackageText - , parsePackageIdentifier, parsePackageIdentifierRevision - , parsePackageName, parsePackageNameThrowing - , parseRawSnapshotLocation, parseSnapName, parseTreeM - , parseVersion, parseVersionThrowing, parseWantedCompiler - , pirForHash, resolvePaths, snapshotLocation - , toCabalStringMap, toRawPL, toRawPLI, toRawPM, toRawSL - , toRawSnapshotLayer, unCabalStringMap, unSafeFilePath - , versionString, warnMissingCabalFile + , defaultGlobalHintsLocation, defaultHackageSecurityConfig + , defaultSnapshotLocation, flagNameString, getGlobalHintsFile + , globalHintsLocation, mkSafeFilePath, moduleNameString + , packageIdentifierString, packageNameString, parseFlagName + , parseHackageText, parsePackageIdentifier + , parsePackageIdentifierRevision, parsePackageName + , parsePackageNameThrowing, parseRawSnapshotLocation + , parseSnapName, parseTreeM, parseVersion + , parseVersionThrowing, parseWantedCompiler, pirForHash + , resolvePaths, snapshotLocation, toCabalStringMap, toRawPL + , toRawPLI, toRawPM, toRawSL, toRawSnapshotLayer + , unCabalStringMap, unSafeFilePath, versionString + , warnMissingCabalFile ) import Path ( Abs, Dir, File, Path, (</>), filename, parent, parseAbsDir , parseRelFile, toFilePath ) -import Path.IO ( doesFileExist, listDir, resolveDir' ) +import Path.IO ( copyFile, doesFileExist, listDir, resolveDir' ) import RIO import qualified RIO.ByteString as B import RIO.Directory ( getAppUserDataDirectory ) import qualified RIO.FilePath as FilePath import qualified RIO.List as List import qualified RIO.Map as Map -import RIO.PrettyPrint ( HasTerm (..) ) +import RIO.PrettyPrint + ( HasTerm (..), blankLine, flow, line, pretty, prettyDebugL + , prettyError, prettyInfoL, string + ) import RIO.PrettyPrint.StylesUpdate ( HasStylesUpdate (..), StylesUpdate ) import RIO.Process @@ -324,7 +337,8 @@ <> displayException e -- | Create a new 'PantryConfig' with the given settings. For a version where --- the use of Casa (content-addressable storage archive) is optional, see +-- Hpack's approach to overwriting Cabal files is configurable and the use of +-- Casa (content-addressable storage archive) is optional, see -- 'withPantryConfig''. -- -- For something easier to use in simple cases, see 'runPantryApp'. @@ -349,11 +363,13 @@ -- ^ Max casa keys to pull per request. -> (SnapName -> RawSnapshotLocation) -- ^ The location of snapshot synonyms + -> (WantedCompiler -> GlobalHintsLocation) + -- ^ The location of global hints -> (PantryConfig -> RIO env a) -- ^ What to do with the config -> RIO env a withPantryConfig root pic he count pullURL maxPerRequest = - withPantryConfig' root pic he count (Just (pullURL, maxPerRequest)) + withPantryConfig' root pic he Hpack.NoForce count (Just (pullURL, maxPerRequest)) -- | Create a new 'PantryConfig' with the given settings. -- @@ -363,44 +379,63 @@ withPantryConfig' :: HasLogFunc env => Path Abs Dir - -- ^ pantry root directory, where the SQLite database and Hackage - -- downloads are kept. + -- ^ pantry root directory, where the SQLite database and Hackage + -- downloads are kept. -> PackageIndexConfig - -- ^ Package index configuration. You probably want - -- 'defaultPackageIndexConfig'. + -- ^ Package index configuration. You probably want + -- 'defaultPackageIndexConfig'. -> HpackExecutable - -- ^ When converting an hpack @package.yaml@ file to a cabal file, - -- what version of hpack should we use? + -- ^ When converting an hpack @package.yaml@ file to a cabal file, + -- what version of hpack should we use? + -> Hpack.Force + -- ^ Should Hpack force the overwriting of a Cabal file that has been + -- modified manually? + -- + -- @since 0.10.0 -> Int - -- ^ Maximum connection count + -- ^ Maximum connection count -> Maybe (CasaRepoPrefix, Int) - -- ^ Optionally, the Casa pull URL e.g. @https://casa.fpcomplete.com@ and the - -- maximum number of Casa keys to pull per request. + -- ^ Optionally, the Casa pull URL e.g. @https://casa.fpcomplete.com@ and + -- the maximum number of Casa keys to pull per request. -> (SnapName -> RawSnapshotLocation) - -- ^ The location of snapshot synonyms + -- ^ The location of snapshot synonyms + -> (WantedCompiler -> GlobalHintsLocation) + -- ^ The location of global hints -> (PantryConfig -> RIO env a) - -- ^ What to do with the config + -- ^ What to do with the config -> RIO env a -withPantryConfig' root pic he count mCasaConfig snapLoc inner = do - env <- ask - pantryRelFile <- parseRelFile "pantry.sqlite3" - -- Silence persistent's logging output, which is really noisy - runRIO (mempty :: LogFunc) $ initStorage (root </> pantryRelFile) $ \storage -> runRIO env $ do - ur <- newMVar True - ref1 <- newIORef mempty - ref2 <- newIORef mempty - inner PantryConfig - { pcPackageIndex = pic - , pcHpackExecutable = he - , pcRootDir = root - , pcStorage = storage - , pcUpdateRef = ur - , pcConnectionCount = count - , pcParsedCabalFilesRawImmutable = ref1 - , pcParsedCabalFilesMutable = ref2 - , pcCasaConfig = mCasaConfig - , pcSnapshotLocation = snapLoc - } +withPantryConfig' + root + pic + he + hpackForce + count + mCasaConfig + snapLoc + globalHintsLoc + inner + = do + env <- ask + pantryRelFile <- parseRelFile "pantry.sqlite3" + -- Silence persistent's logging output, which is really noisy + runRIO (mempty :: LogFunc) $ initStorage (root </> pantryRelFile) $ \storage -> runRIO env $ do + ur <- newMVar True + ref1 <- newIORef mempty + ref2 <- newIORef mempty + inner PantryConfig + { pcPackageIndex = pic + , pcHpackExecutable = he + , pcHpackForce = hpackForce + , pcRootDir = root + , pcStorage = storage + , pcUpdateRef = ur + , pcConnectionCount = count + , pcParsedCabalFilesRawImmutable = ref1 + , pcParsedCabalFilesMutable = ref2 + , pcCasaConfig = mCasaConfig + , pcSnapshotLocation = snapLoc + , pcGlobalHintsLocation = globalHintsLoc + } -- | Default pull URL for Casa. -- @@ -870,17 +905,19 @@ when exists $ do logDebug $ "Running Hpack on " <> fromString (toFilePath hpackFile) he <- view $ pantryConfigL.to pcHpackExecutable + hpackForce <- view $ pantryConfigL.to pcHpackForce case he of HpackBundled -> - liftIO - ( Hpack.hpackResultWithError - $ mHpackProgName - $ Hpack.setDecode decodeYaml - $ Hpack.setFormatYamlParseError formatYamlParseError - $ Hpack.setTarget - (toFilePath hpackFile) Hpack.defaultOptions - ) - >>= \ case + liftIO + ( Hpack.hpackResultWithError + $ mHpackProgName + $ Hpack.setDecode decodeYaml + $ Hpack.setFormatYamlParseError formatYamlParseError + $ Hpack.setTarget + (toFilePath hpackFile) + Hpack.defaultOptions { Hpack.optionsForce = hpackForce } + ) + >>= \ case Left err -> throwIO (HpackLibraryException hpackFile $ formatHpackError (fromMaybe "hpack" progName) err) Right r -> do forM_ (Hpack.resultWarnings r) (logWarn . fromString) @@ -909,11 +946,15 @@ <> fromString (toFilePath (filename hpackFile)) <> " file instead of the Cabal file,\n" <> "then please delete the Cabal file." - HpackCommand command -> catchAny - ( withWorkingDir (toFilePath pkgDir) $ - proc command [] runProcess_ - ) - ( throwIO . HpackExeException command pkgDir) + HpackCommand command -> do + let hpackArgs = case hpackForce of + Hpack.Force -> ["--force"] + Hpack.NoForce -> [] + catchAny + ( withWorkingDir (toFilePath pkgDir) $ + proc command hpackArgs runProcess_ + ) + ( throwIO . HpackExeException command pkgDir) -- | Get the 'PackageIdentifier' from a 'GenericPackageDescription'. -- @@ -1871,13 +1912,22 @@ simpleAppL :: Lens' PantryApp SimpleApp simpleAppL = lens paSimpleApp (\x y -> x { paSimpleApp = y }) --- | Lens to view or modify the 'HpackExecutable' of a 'PantryConfig' +-- | Lens to view or modify the 'HpackExecutable' of a 'PantryConfig'. -- -- @since 0.1.0.0 hpackExecutableL :: Lens' PantryConfig HpackExecutable hpackExecutableL k pconfig = fmap (\hpExe -> pconfig { pcHpackExecutable = hpExe }) (k (pcHpackExecutable pconfig)) +-- | Lens to view or modify the 'Hpack.Force' of a 'PantryConfig'. +-- +-- @since 0.10.0 +hpackForceL :: Lens' PantryConfig Hpack.Force +hpackForceL k pconfig = + fmap + (\hpackForce -> pconfig { pcHpackForce = hpackForce }) + (k (pcHpackForce pconfig)) + instance HasLogFunc PantryApp where logFuncL = simpleAppL.logFuncL @@ -1922,9 +1972,11 @@ root defaultPackageIndexConfig HpackBundled + Hpack.NoForce maxConnCount (Just (casaRepoPrefix, casaMaxPerRequest)) defaultSnapshotLocation + defaultGlobalHintsLocation $ \pc -> runRIO PantryApp @@ -1949,9 +2001,11 @@ root defaultPackageIndexConfig HpackBundled + Hpack.NoForce 8 (Just (defaultCasaRepoPrefix, defaultCasaMaxPerRequest)) defaultSnapshotLocation + defaultGlobalHintsLocation $ \pc -> runRIO PantryApp @@ -1963,46 +2017,72 @@ } f --- | Load the global hints from GitHub. +-- | Load the global hints. -- --- @since 0.1.0.0 +-- @since 9.4.0 loadGlobalHints :: (HasTerm env, HasPantryConfig env) => WantedCompiler -> RIO env (Maybe (Map PackageName Version)) -loadGlobalHints wc = - inner False +loadGlobalHints wc = do + dest <- getGlobalHintsFile + loc <- globalHintsLocation wc + inner dest loc False where - inner alreadyDownloaded = do - dest <- getGlobalHintsFile - req <- parseRequest "https://raw.githubusercontent.com/commercialhaskell/stackage-content/master/stack/global-hints.yaml" - downloaded <- download req dest - eres <- tryAny (inner2 dest) - mres <- - case eres of - Left e -> Nothing <$ logError - ( "Error: [S-912]\n" - <> "Error when parsing global hints: " - <> displayShow e - ) - Right x -> pure x - case mres of - Nothing | not alreadyDownloaded && not downloaded -> do - logInfo $ - "Could not find local global hints for " <> - RIO.display wc <> - ", forcing a redownload" - x <- redownload req dest - if x - then inner True - else do - logInfo "Redownload didn't happen" - pure Nothing - _ -> pure mres - - inner2 dest = liftIO $ - Map.lookup wc . fmap (fmap unCabalString . unCabalStringMap) - <$> Yaml.decodeFileThrow (toFilePath dest) + inner dest loc alreadyDownloaded = case loc of + GHLUrl url -> do + req <- parseRequest $ T.unpack url + downloaded <- download req dest + mres <- tryParseYaml dest + case mres of + Nothing | not alreadyDownloaded && not downloaded -> do + prettyInfoL + [ flow "Could not find local global hints for" + , string (T.unpack $ RIO.textDisplay wc) <> "," + , flow "forcing a redownload." + ] + redownloaded <- redownload req dest + if redownloaded + then inner dest loc True + else do + logInfo "Redownload didn't happen" + pure Nothing + _ -> pure mres + GHLFilePath fp -> do + let source = resolvedAbsolute fp + mres <- tryParseYaml source + case mres of + Nothing -> do + prettyInfoL + [ flow "Could not find local global hints for" + , string (T.unpack $ RIO.textDisplay wc) + , "in" + , pretty source <> "." + ] + pure Nothing + _ -> do + liftIO $ copyFile source dest + prettyDebugL + [ flow "Installed global hints from" + , pretty source + ] + pure mres + inner2 fp = liftIO $ do + allGlobalHints <- Yaml.decodeFileThrow (toFilePath fp) + let globalHints = Map.lookup wc allGlobalHints + pure $ fmap (fmap unCabalString . unCabalStringMap) globalHints + tryParseYaml fp = do + eres <- tryAny (inner2 fp) + case eres of + Left e -> do + prettyError $ + "[S-912]" + <> line + <> flow "Error when parsing global hints:" + <> blankLine + <> string (displayException e) + pure Nothing + Right x -> pure x -- | Partition a map of global packages with its versions into a Set of replaced -- packages and its dependencies and a map of remaining (untouched) packages.
src/Pantry/Hackage.hs view
@@ -98,8 +98,14 @@ hackageDirL :: HasPantryConfig env => SimpleGetter env (Path Abs Dir) hackageDirL = pantryConfigL.to ((</> hackageRelDir) . pcRootDir) +-- | The name of the tar file that is part of the local cache of the package +-- index is determined by this package's use of 'HS.cabalCacheLayout' as the +-- layout of the local cache. indexRelFile :: Path Rel File -indexRelFile = either impureThrow id $ parseRelFile "00-index.tar" +indexRelFile = either impureThrow id $ parseRelFile indexTar + where + indexTar' = HS.cacheLayoutIndexTar HS.cabalCacheLayout + indexTar = HS.toUnrootedFilePath $ HS.unrootPath indexTar' -- | Where does pantry download its 01-index.tar file from Hackage? --