arch-hs 0.12.2 → 0.12.3
raw patch · 8 files changed
+140/−29 lines, 8 filesdep ~Cabaldep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: Cabal, template-haskell
API changes (from Hackage documentation)
Files
- CHANGELOG.md +10/−0
- README.md +23/−1
- arch-hs.cabal +4/−4
- data/NAME_PRESET.json +4/−3
- rdepcheck/Args.hs +5/−3
- rdepcheck/Check.hs +38/−6
- rdepcheck/Main.hs +14/−1
- src/Distribution/ArchHs/Hackage.hs +42/−11
CHANGELOG.md view
@@ -3,6 +3,16 @@ `arch-hs` uses [PVP Versioning][1]. The changelog is available [on GitHub][2]. +## 0.12.3++- Teach `arch-hs-rdepcheck` to validate a candidate version against reverse dependency ranges++- Use the newest cached Hackage index when multiple mirrors are available++- Update supported GHC/Cabal dependency bounds++- Update name preset+ ## 0.12.2 - Fail `arch-hs-sync submit` when Hackage returns an unsuccessful upload status
README.md view
@@ -511,7 +511,29 @@ ✔ Success! ``` -`arch-hs-diff` does not require hackage db, it downloads cabal files from hackage server instead. +`arch-hs-diff` does not require hackage db, it downloads cabal files from hackage server instead.++## Reverse dependency checks++`arch-hs-rdepcheck` lists Haskell reverse dependencies in [extra] and the Cabal version ranges they require:++```+$ arch-hs-rdepcheck aeson+Reverse dependency: agda+ Depends: >=1.1.2.0 && <2.3+...+```++Pass an optional version to check whether that version satisfies every listed range. Out-of-range entries are printed as errors, and the command exits with a non-zero status if any range fails:++```+$ arch-hs-rdepcheck aeson 3.0+Reverse dependency: agda+ Depends: >=1.1.2.0 && <2.3+ Error: 3.0 is outside Depends range (>=1.1.2.0 && <2.3)+...+68 reverse dependency range check(s) failed.+``` ## Sync
arch-hs.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: arch-hs-version: 0.12.2+version: 0.12.3 synopsis: Distribute hackage packages to archlinux description: @arch-hs@ is a command-line program, which simplifies the process of producing@@ -23,7 +23,7 @@ CHANGELOG.md README.md -tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.3+tested-with: GHC ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 source-repository head type: git@@ -41,7 +41,7 @@ , arch-web ^>=0.3.2 , base >=4.12 && <5 , bytestring- , Cabal >=3.2 && <3.11+ , Cabal >=3.8 && <3.11 , conduit ^>=1.3.2 , conduit-extra ^>=1.3.5 , containers@@ -64,7 +64,7 @@ , servant-client >=0.18.2 && <0.21 , split ^>=0.2.3 , tar-conduit ^>=0.3.2 || ^>=0.4.0- , template-haskell ^>=2.16.0 || ^>=2.17.0 || ^>=2.18.0 || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0+ , template-haskell ^>=2.18.0 || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0 , text ghc-options:
data/NAME_PRESET.json view
@@ -8,6 +8,7 @@ "c2hs": "c2hs", "haskell-cabal": "Cabal", "cabal-install": "cabal-install",+ "cabal-fmt": "cabal-fmt", "cabal-plan": "cabal-plan", "haskell-cabal-syntax": "Cabal-syntax", "cbor-tool": "cbor-tool",@@ -15,6 +16,7 @@ "clash-ghc": "clash-ghc", "cryptol": "cryptol", "darcs": "darcs",+ "dice": "dice", "dhall": "dhall", "dhall-bash": "dhall-bash", "dhall-docs": "dhall-docs",@@ -26,16 +28,15 @@ "gitit": "gitit", "glirc": "glirc", "happy": "happy",+ "haskell-bindings-dsl": "bindings-DSL", "haskell-boolean": "Boolean", "haskell-boundedchan": "BoundedChan", "haskell-chasingbottoms": "ChasingBottoms", "haskell-ci": "haskell-ci",- "haskell-configfile": "ConfigFile", "haskell-cracknum": "crackNum", "haskell-dav": "DAV", "haskell-decimal": "Decimal", "haskell-diff": "Diff",- "haskell-drbg": "DRBG", "haskell-edisonapi": "EdisonAPI", "haskell-edisoncore": "EdisonCore", "haskell-findbin": "FindBin",@@ -113,11 +114,11 @@ "stylish-haskell": "stylish-haskell", "taffybar": "taffybar", "tamarin-prover": "tamarin-prover",- "tidalcycles": "tidal", "unlambda": "unlambda", "uusi": "uusi", "xmobar": "xmobar", "xmonad": "xmonad",+ "xmonad-dbus": "xmonad-dbus", "xmonad-contrib": "xmonad-contrib", "xmonad-extras": "xmonad-extras", "xmonad-utils": "xmonad-utils"
rdepcheck/Args.hs view
@@ -14,7 +14,8 @@ { optFlags :: FlagAssignments, optExtraDB :: ExtraDBOptions, optHackage :: HackageDBOptions,- optPackageName :: PackageName+ optPackageName :: PackageName,+ optCheckVersion :: Maybe Version } cmdOptions :: Parser Options@@ -24,14 +25,15 @@ <*> extraDBOptionsParser <*> hackageDBOptionsParser <*> argument optPackageNameReader (metavar "TARGET")+ <*> optional (argument optVersionReader (metavar "VERSION")) runArgsParser :: IO Options runArgsParser = do (x, ()) <- simpleOptions archHsVersion- "arch-hs-rdepcheck - check the version of a dependent Haskell package"- "arch-hs-rdepcheck is a CLI tool that shows all reverse dependencies of a Haskell package in [extra], giving the version range how it is depended on"+ "arch-hs-rdepcheck - inspect reverse dependency version ranges"+ "arch-hs-rdepcheck shows all reverse dependencies of a Haskell package in [extra] and the version ranges they require. If VERSION is provided, it reports ranges that do not accept VERSION and exits with failure." cmdOptions empty pure x
rdepcheck/Check.hs view
@@ -6,7 +6,7 @@ module Check (check) where -import Control.Monad (forM_, unless)+import Control.Monad (forM, unless) import Data.List (find) import qualified Data.Map.Strict as Map import Data.Maybe (catMaybes)@@ -41,9 +41,10 @@ Embed IO ] r =>+ Maybe Version -> PackageName ->- Sem r ()-check target = do+ Sem r Int+check mVersion target = do let aTarget = toArchLinuxName target exists <- isInExtra aTarget unless exists $ throw $ PkgNotFound target@@ -65,7 +66,7 @@ ) . Map.toList <$> ask @ExtraDB- forM_ reverseDeps $ \(PkgDesc {..}, src) -> do+ failures <- forM reverseDeps $ \(PkgDesc {..}, src) -> do eCabal <- try @MyException $ getCabal (toHackageName _name) =<< case simpleParsec _version of@@ -74,15 +75,46 @@ case eCabal of Right cabal -> do result <- getDepVersion cabal target src+ let failedRanges = versionFailures mVersion result embed . putDoc $ vsep ( annMagneta "Reverse dependency" <> colon <+> pretty (unArchLinuxName _name)- : [indent 2 $ pretty s <> colon <+> viaPretty r | (s, r) <- result]+ : (rangeDocs result <> versionErrors mVersion failedRanges) ) <> line- Left e ->+ pure $ length failedRanges+ Left e -> do printWarn $ "Skip" <+> pretty (unArchLinuxName _name) <> colon <+> viaShow e+ pure 0+ pure $ sum failures++rangeDocs :: [(DepSrc, VersionRange)] -> [Doc AnsiStyle]+rangeDocs result =+ [ indent 2 $ pretty s <> colon <+> viaPretty r+ | (s, r) <- result+ ]++versionFailures :: Maybe Version -> [(DepSrc, VersionRange)] -> [(DepSrc, VersionRange)]+versionFailures Nothing _ = []+versionFailures (Just version) result =+ [ (src, range)+ | (src, range) <- result,+ not $ withinRange version range+ ]++versionErrors :: Maybe Version -> [(DepSrc, VersionRange)] -> [Doc AnsiStyle]+versionErrors Nothing _ = []+versionErrors (Just version) result =+ [ indent 2 $+ annRed "Error:"+ <+> viaPretty version+ <+> "is outside"+ <+> pretty src+ <+> "range"+ <+> parens (viaPretty range)+ | (src, range) <- result+ ] getDepVersion :: Members
rdepcheck/Main.hs view
@@ -16,6 +16,7 @@ import Distribution.ArchHs.Types import GHC.IO.Encoding (setLocaleEncoding) import GHC.IO.Encoding.UTF8 (utf8)+import System.Exit (exitFailure) main :: IO () main = printHandledIOException $@@ -32,7 +33,19 @@ extra <- loadExtraDBFromOptions optExtraDB printInfo "Start running..."- runCheck hackage extra optFlags (subsumeGHCVersion $ check optPackageName) & printAppResult+ runCheck hackage extra optFlags (subsumeGHCVersion $ check optCheckVersion optPackageName) & printRdepcheckResult++printRdepcheckResult :: IO (Either MyException Int) -> IO ()+printRdepcheckResult io = do+ result <- io+ case result of+ Left x -> do+ printError $ "Runtime Exception" <> colon <+> viaShow x+ exitFailure+ Right 0 -> printSuccess "Success!"+ Right n -> do+ printError $ pretty n <+> "reverse dependency range check(s) failed."+ exitFailure runCheck :: HackageDB ->
src/Distribution/ArchHs/Hackage.hs view
@@ -20,29 +20,60 @@ ) where +import Control.Monad (filterM) import qualified Data.ByteString as BS+import Data.List (maximumBy) import qualified Data.Map as Map-import Data.Maybe (fromJust)+import Data.Maybe (catMaybes, fromJust)+import Data.Ord (comparing) import Distribution.ArchHs.Exception import Distribution.ArchHs.Internal.Prelude import Distribution.ArchHs.Types import Distribution.ArchHs.Utils (getPkgName, getPkgVersion) import Distribution.Hackage.DB (HackageDB, VersionData (VersionData, cabalFile), readTarball, tarballHashes)+import Distribution.Hackage.DB.Path (cabalStateDir) import Distribution.PackageDescription.Parsec (parseGenericPackageDescriptionMaybe)-import System.Directory (findFile, getHomeDirectory, listDirectory)+import System.Directory (doesDirectoryExist, doesFileExist, getModificationTime, listDirectory) --- | Look up hackage tarball path from @~/.cabal@.--- Arbitrary hackage mirror is potential to be selected.--- Preferred to @01-index.tar@, whereas fallback to @00-index.tar@.+-- | Look up hackage tarball path from Cabal's package index cache.+-- Preferred to the newest @01-index.tar@, whereas fallback to the newest @00-index.tar@. lookupHackagePath :: IO FilePath lookupHackagePath = do- home <- (\d -> d </> ".cabal" </> "packages") <$> getHomeDirectory- subs <- fmap (home </>) <$> listDirectory home- legacy <- findFile subs "00-index.tar"- new <- findFile subs "01-index.tar"- case new <|> legacy of+ root <- (</> "packages") <$> cabalStateDir+ candidates <- hackageIndexCandidates root+ case newestIndex "01-index.tar" candidates <|> newestIndex "00-index.tar" candidates of Just x -> return x- Nothing -> fail $ "Unable to find hackage index tarball from " <> show subs+ Nothing -> fail $ "Unable to find hackage index tarball from " <> root+ where+ hackageIndexCandidates root = do+ exists <- doesDirectoryExist root+ if exists+ then do+ rootIndexes <- indexesIn root+ dirs <- fmap (root </>) <$> listDirectory root+ repoDirs <- filterM doesDirectoryExist dirs+ repoIndexes <- concat <$> traverse indexesIn repoDirs+ pure $ rootIndexes <> repoIndexes+ else pure []++ indexesIn dir =+ catMaybes+ <$> traverse+ ( \name -> do+ let path = dir </> name+ exists <- doesFileExist path+ if exists+ then do+ time <- getModificationTime path+ pure $ Just (name, path, time)+ else pure Nothing+ )+ ["01-index.tar", "00-index.tar"]++ newestIndex name candidates =+ case filter (\(candidateName, _, _) -> candidateName == name) candidates of+ [] -> Nothing+ xs -> Just $ (\(_, path, _) -> path) (maximumBy (comparing (\(_, _, time) -> time)) xs) -- | Read and parse hackage index tarball. loadHackageDB :: FilePath -> IO HackageDB