|
2 | 2 | {-# LANGUAGE DeriveGeneric #-}
|
3 | 3 | {-# LANGUAGE RecordWildCards #-}
|
4 | 4 | {-# LANGUAGE BangPatterns #-}
|
| 5 | +{-# LANGUAGE OverloadedStrings #-} |
5 | 6 | {-# LANGUAGE GADTs #-}
|
6 | 7 |
|
7 | 8 | -----------------------------------------------------------------------------
|
@@ -53,15 +54,16 @@ import Distribution.Package
|
53 | 54 | import Distribution.Types.Dependency
|
54 | 55 | import Distribution.Simple.PackageIndex (InstalledPackageIndex)
|
55 | 56 | import Distribution.PackageDescription
|
56 |
| - ( GenericPackageDescription ) |
| 57 | + ( GenericPackageDescription(..) |
| 58 | + , PackageDescription(..), emptyPackageDescription ) |
57 | 59 | import Distribution.Simple.Compiler
|
58 | 60 | ( Compiler, PackageDBStack )
|
59 | 61 | import Distribution.Simple.Program
|
60 | 62 | ( ProgramDb )
|
61 | 63 | import qualified Distribution.Simple.Configure as Configure
|
62 | 64 | ( getInstalledPackages, getInstalledPackagesMonitorFiles )
|
63 | 65 | import Distribution.Version
|
64 |
| - ( mkVersion, intersectVersionRanges ) |
| 66 | + ( Version, mkVersion, intersectVersionRanges, versionNumbers ) |
65 | 67 | import Distribution.Text
|
66 | 68 | ( display, simpleParse )
|
67 | 69 | import Distribution.Simple.Utils
|
@@ -94,6 +96,7 @@ import Control.Exception
|
94 | 96 | import qualified Data.ByteString.Lazy as BS
|
95 | 97 | import qualified Data.ByteString.Lazy.Char8 as BS.Char8
|
96 | 98 | import qualified Data.ByteString.Char8 as BSS
|
| 99 | +import qualified Data.ByteString as BSW8 |
97 | 100 | import Data.ByteString.Lazy (ByteString)
|
98 | 101 | import Distribution.Client.GZipUtils (maybeDecompress)
|
99 | 102 | import Distribution.Client.Utils ( byteStringToFilePath
|
@@ -678,7 +681,7 @@ packageListFromCache verbosity mkPkg hnd Cache{..} mode = accum mempty [] mempty
|
678 | 681 | -- Most of the time we only need the package id.
|
679 | 682 | ~(pkg, pkgtxt) <- unsafeInterleaveIO $ do
|
680 | 683 | pkgtxt <- getEntryContent blockno
|
681 |
| - pkg <- readPackageDescription pkgtxt |
| 684 | + pkg <- readPackageDescription pkgid pkgtxt |
682 | 685 | return (pkg, pkgtxt)
|
683 | 686 | case mode of
|
684 | 687 | ReadPackageIndexLazyIO -> pure ()
|
@@ -710,22 +713,102 @@ packageListFromCache verbosity mkPkg hnd Cache{..} mode = accum mempty [] mempty
|
710 | 713 | -> return content
|
711 | 714 | _ -> interror "unexpected tar entry type"
|
712 | 715 |
|
713 |
| - readPackageDescription :: ByteString -> IO GenericPackageDescription |
714 |
| - readPackageDescription content = |
| 716 | + interror :: String -> IO a |
| 717 | + interror msg = die' verbosity $ "internal error when reading package index: " ++ msg |
| 718 | + ++ "The package index or index cache is probably " |
| 719 | + ++ "corrupt. Running cabal update might fix it." |
| 720 | + |
| 721 | + readPackageDescription pkgid content = do |
| 722 | + case parseGenericPackageDescription' content of |
| 723 | + ParseGPDOk gpd -> return gpd |
| 724 | + ParseError (Just specVer) | specVer >= mkVersion [2,0] |
| 725 | + -> return (dummyPackageDescription specVer) |
| 726 | + ParseError _ -> interror "failed to parse .cabal file" |
| 727 | + where |
| 728 | + dummyPackageDescription :: Version -> GenericPackageDescription |
| 729 | + dummyPackageDescription specVer = GenericPackageDescription |
| 730 | + { packageDescription = emptyPackageDescription |
| 731 | + { specVersionRaw = Left specVer |
| 732 | + , package = pkgid |
| 733 | + , synopsis = dummySynopsis |
| 734 | + } |
| 735 | + , genPackageFlags = [] |
| 736 | + , condLibrary = Nothing |
| 737 | + , condSubLibraries = [] |
| 738 | + , condForeignLibs = [] |
| 739 | + , condExecutables = [] |
| 740 | + , condTestSuites = [] |
| 741 | + , condBenchmarks = [] |
| 742 | + } |
| 743 | + |
| 744 | + dummySynopsis = "<could not be parsed due to unsupported CABAL spec-version>" |
| 745 | + |
| 746 | +-- | Result of 'parseGenericPackageDescription'' |
| 747 | +data ParseGPDResult = ParseGPDOk GenericPackageDescription |
| 748 | + -- ^ parsing succeeded (may still have unsupported spec-version) |
| 749 | + | ParseError !(Maybe Version) |
| 750 | + -- ^ parsing failed, but we were able to recover |
| 751 | + -- a new-style spec-version declaration |
| 752 | + |
| 753 | +-- | Variant of 'parseGenericPackageDescription' which is able to |
| 754 | +-- extract new-style spec-version in case of parser errors |
| 755 | +parseGenericPackageDescription' :: ByteString -> ParseGPDResult |
| 756 | +parseGenericPackageDescription' content = |
| 757 | + case parseGPDMaybe of |
| 758 | + Just gpd -> ParseGPDOk gpd |
| 759 | + Nothing -> ParseError (scanSpecVersion content) |
| 760 | + where |
| 761 | + parseGPDMaybe = |
715 | 762 | #ifdef CABAL_PARSEC
|
716 |
| - case parseGenericPackageDescriptionMaybe (BS.toStrict content) of |
717 |
| - Just gpd -> return gpd |
718 |
| - Nothing -> interror "failed to parse .cabal file" |
| 763 | + parseGenericPackageDescriptionMaybe (BS.toStrict content) |
719 | 764 | #else
|
720 | 765 | case parseGenericPackageDescription . ignoreBOM . fromUTF8 . BS.Char8.unpack $ content of
|
721 |
| - ParseOk _ d -> return d |
722 |
| - _ -> interror "failed to parse .cabal file" |
| 766 | + ParseOk _ d -> Just d |
| 767 | + _ -> Nothing |
723 | 768 | #endif
|
724 | 769 |
|
725 |
| - interror :: String -> IO a |
726 |
| - interror msg = die' verbosity $ "internal error when reading package index: " ++ msg |
727 |
| - ++ "The package index or index cache is probably " |
728 |
| - ++ "corrupt. Running cabal update might fix it." |
| 770 | +-- | Quickly scan new-style spec-version |
| 771 | +-- |
| 772 | +-- A new-style spec-version declaration begins the .cabal file and |
| 773 | +-- follow the following case-insensitive grammar (expressed in |
| 774 | +-- RFC5234 ABNF): |
| 775 | +-- |
| 776 | +-- newstyle-spec-version-decl = "cabal-version" *WS ":" *WS newstyle-pec-version *WS |
| 777 | +-- |
| 778 | +-- spec-version = NUM "." NUM [ "." NUM ] |
| 779 | +-- |
| 780 | +-- NUM = DIGIT0 / DIGITP 1*DIGIT0 |
| 781 | +-- DIGIT0 = %x30-39 |
| 782 | +-- DIGITP = %x31-39 |
| 783 | +-- WS = %20 |
| 784 | +-- |
| 785 | +-- TODO: move into lib:Cabal |
| 786 | +scanSpecVersion :: ByteString -> Maybe Version |
| 787 | +scanSpecVersion bs = do |
| 788 | + fstline':_ <- pure (BS.Char8.lines bs) |
| 789 | + |
| 790 | + -- parse <newstyle-spec-version-decl> |
| 791 | + -- normalise: remove all whitespace, convert to lower-case |
| 792 | + let fstline = BSW8.map toLowerW8 $ BSW8.filter (/= 0x20) $ BS.toStrict fstline' |
| 793 | + ["cabal-version",vers] <- pure (BSS.split ':' fstline) |
| 794 | + |
| 795 | + -- parse <spec-version> |
| 796 | + -- |
| 797 | + -- This is currently more tolerant regarding leading 0 digits. |
| 798 | + -- |
| 799 | + ver <- simpleParse (BSS.unpack vers) |
| 800 | + guard $ case versionNumbers ver of |
| 801 | + [_,_] -> True |
| 802 | + [_,_,_] -> True |
| 803 | + _ -> False |
| 804 | + |
| 805 | + pure ver |
| 806 | + where |
| 807 | + -- | Translate ['A'..'Z'] to ['a'..'z'] |
| 808 | + toLowerW8 :: Word8 -> Word8 |
| 809 | + toLowerW8 w | 0x40 < w && w < 0x5b = w+0x20 |
| 810 | + | otherwise = w |
| 811 | + |
729 | 812 |
|
730 | 813 | ------------------------------------------------------------------------
|
731 | 814 | -- Index cache data structure
|
|
0 commit comments