packages feed

hpack 0.29.0 → 0.29.1

raw patch · 8 files changed

+294/−82 lines, 8 filesdep +text-metricsPVP ok

version bump matches the API change (PVP)

Dependencies added: text-metrics

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,3 +1,6 @@+## Changes in 0.29.1+  - Infer `license` from `license-file`+ ## Changes in 0.29.0   - Put the `cabal-version` at the beginning of the generated file. This Is     required with `cabal-version: 2.1` and higher. (see #292)
hpack.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: cfd597be64fbc0242e6c338653cce17e853d1ce5843d07785f81ce0f208ee198+-- hash: 708562cac33767420b742070fb9e5bb031688eb4b55688a47c9803455468d2ee  name:           hpack-version:        0.29.0+version:        0.29.1 synopsis:       An alternative format for Haskell packages description:    See README at <https://github.com/sol/hpack#readme> category:       Development@@ -46,6 +46,7 @@     , pretty     , scientific     , text+    , text-metrics     , transformers     , unordered-containers     , vector@@ -67,6 +68,7 @@       Hpack.Options       Hpack.Render.Dsl       Hpack.Render.Hints+      Hpack.SpdxLicenses       Hpack.Syntax.Defaults       Hpack.Syntax.Dependency       Hpack.Syntax.Git@@ -99,6 +101,7 @@     , pretty     , scientific     , text+    , text-metrics     , transformers     , unordered-containers     , vector@@ -140,6 +143,7 @@     , template-haskell     , temporary     , text+    , text-metrics     , transformers     , unordered-containers     , vector@@ -179,6 +183,7 @@       Hpack.Render       Hpack.Render.Dsl       Hpack.Render.Hints+      Hpack.SpdxLicenses       Hpack.Syntax.Defaults       Hpack.Syntax.Dependency       Hpack.Syntax.Git
src/Hpack/Config.hs view
@@ -72,7 +72,7 @@ ) where  import           Control.Applicative-import           Control.Arrow ((>>>), (&&&))+import           Control.Arrow ((>>>)) import           Control.Monad import           Data.Bifunctor import           Data.Bitraversable@@ -504,7 +504,7 @@ , packageConfigMaintainer :: Maybe (List String) , packageConfigCopyright :: Maybe (List String) , packageConfigBuildType :: Maybe BuildType-, packageConfigLicense :: Maybe String+, packageConfigLicense :: Maybe (Maybe String) , packageConfigLicenseFile :: Maybe (List String) , packageConfigTestedWith :: Maybe String , packageConfigFlags :: Maybe (Map String FlagSection)@@ -580,8 +580,8 @@   userDataDir <- liftIO $ maybe (getAppUserDataDirectory "hpack") return mUserDataDir   toPackage userDataDir dir config   where-    addCabalFile :: (Package, [String]) -> DecodeResult-    addCabalFile (pkg, warnings) = uncurry DecodeResult (cabalVersion pkg) (takeDirectory_ file </> (packageName pkg ++ ".cabal")) warnings+    addCabalFile :: ((Package, String), [String]) -> DecodeResult+    addCabalFile ((pkg, cabalVersion), warnings) = DecodeResult pkg cabalVersion (takeDirectory_ file </> (packageName pkg ++ ".cabal")) warnings      takeDirectory_ :: FilePath -> FilePath     takeDirectory_ p@@ -600,29 +600,31 @@   VerbatimBool b -> show b   VerbatimNull -> "" -cabalVersion :: Package -> (Package, String)-cabalVersion pkg@Package{..} = (+determineCabalVersion :: Maybe (License String) -> Package -> (Package, String)+determineCabalVersion inferredLicense pkg@Package{..} = (     pkg {         packageVerbatim = deleteVerbatimField "cabal-version" packageVerbatim-      , packageLicense = formatLicense <$> parsedLicense+      , packageLicense = formatLicense <$> license       }   , "cabal-version: " ++ fromMaybe inferredCabalVersion verbatimCabalVersion ++ "\n\n"   )   where-    parsedLicense = (fmap prettyShow . parseLicense &&& id) <$> packageLicense+    license = parsedLicense <|> inferredLicense +    parsedLicense = fmap prettyShow . parseLicense <$> packageLicense+     formatLicense = \ case-      (MustSPDX spdx, _) -> spdx-      (CanSPDX spdx, _) | version >= makeVersion [2,2] -> spdx-      (CanSPDX _, original) -> original-      (DontTouch, original) -> original+      MustSPDX spdx -> spdx+      CanSPDX _ spdx | version >= makeVersion [2,2] -> spdx+      CanSPDX cabal _ -> prettyShow cabal+      DontTouch original -> original      mustSPDX :: Bool-    mustSPDX = maybe False (f . fst) parsedLicense+    mustSPDX = maybe False f license       where         f = \case-          DontTouch -> False-          CanSPDX _ -> False+          DontTouch _ -> False+          CanSPDX _ _ -> False           MustSPDX _ -> True      verbatimCabalVersion :: Maybe String@@ -827,7 +829,7 @@ type CommonOptionsWithDefaults a = Product DefaultsConfig (CommonOptions ParseCSources ParseCxxSources ParseJsSources a) type WithCommonOptionsWithDefaults a = Product DefaultsConfig (WithCommonOptions ParseCSources ParseCxxSources ParseJsSources a) -toPackage :: FilePath -> FilePath -> ConfigWithDefaults -> Warnings (Errors IO) Package+toPackage :: FilePath -> FilePath -> ConfigWithDefaults -> Warnings (Errors IO) (Package, String) toPackage userDataDir dir =       expandDefaultsInConfig userDataDir dir   >=> traverseConfig (expandForeignSources dir)@@ -916,7 +918,7 @@  type GlobalOptions = CommonOptions CSources CxxSources JsSources Empty -toPackage_ :: MonadIO m => FilePath -> Product GlobalOptions (PackageConfig CSources CxxSources JsSources) -> Warnings m Package+toPackage_ :: MonadIO m => FilePath -> Product GlobalOptions (PackageConfig CSources CxxSources JsSources) -> Warnings m (Package, String) toPackage_ dir (Product g PackageConfig{..}) = do   let     globalVerbatim = commonOptionsVerbatim g@@ -949,14 +951,25 @@    dataFiles <- expandGlobs "data-files" dataBaseDir (fromMaybeList packageConfigDataFiles) +  let+    licenseFiles :: [String]+    licenseFiles = fromMaybeList $ packageConfigLicenseFile <|> do+      guard licenseFileExists+      Just (List ["LICENSE"])++  inferredLicense <- case (packageConfigLicense, licenseFiles) of+    (Nothing, [file]) -> do+      input <- liftIO (tryReadFile (dir </> file))+      case input >>= inferLicense of+        Nothing -> do+          tell ["Inferring license from file " ++ file ++ " failed!"]+          return Nothing+        license -> return license+    _ -> return Nothing+   let defaultBuildType :: BuildType       defaultBuildType = maybe Simple (const Custom) mCustomSetup -      configLicenseFiles :: Maybe (List String)-      configLicenseFiles = packageConfigLicenseFile <|> do-        guard licenseFileExists-        Just (List ["LICENSE"])-       pkg = Package {         packageName = packageName_       , packageVersion = maybe "0.0.0" unPackageVersion packageConfigVersion@@ -970,8 +983,8 @@       , packageMaintainer = fromMaybeList packageConfigMaintainer       , packageCopyright = fromMaybeList packageConfigCopyright       , packageBuildType = fromMaybe defaultBuildType packageConfigBuildType-      , packageLicense = packageConfigLicense-      , packageLicenseFile = fromMaybeList configLicenseFiles+      , packageLicense = join packageConfigLicense+      , packageLicenseFile = licenseFiles       , packageTestedWith = packageConfigTestedWith       , packageFlags = flags       , packageExtraSourceFiles = extraSourceFiles@@ -990,7 +1003,7 @@    tell nameWarnings   tell (formatMissingSourceDirs missingSourceDirs)-  return pkg+  return (determineCabalVersion inferredLicense pkg)   where     nameWarnings :: [String]     packageName_ :: String
src/Hpack/License.hs view
@@ -1,48 +1,53 @@ {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE ViewPatterns #-} module Hpack.License where +import           Control.Arrow ((&&&))+import           Data.List+import           Data.Ord (comparing)+import           Data.Text (Text)+import qualified Data.Text as T+import           Data.Text.Metrics++import           Distribution.Pretty (prettyShow) import qualified Distribution.License as Cabal import qualified Distribution.SPDX.License as SPDX+import           Distribution.SPDX.LicenseId import           Distribution.Parsec.Class (eitherParsec) -data License a = DontTouch | CanSPDX a | MustSPDX a+import           Hpack.SpdxLicenses (licenses)++data License a = DontTouch String | CanSPDX Cabal.License a | MustSPDX a   deriving (Eq, Show, Functor)  parseLicense :: String -> License SPDX.License-parseLicense license = case spdxLicense of-  Right l | isUnknown -> MustSPDX l-  Left  _ | isUnknown -> DontTouch-  Right l -> CanSPDX l-  Left  _ -> case cabalLicense of-    Right l -> CanSPDX (Cabal.licenseToSPDX l)-    Left _ -> DontTouch+parseLicense license = case lookup license knownLicenses of+  Just l -> CanSPDX l (Cabal.licenseToSPDX l)+  Nothing -> case spdxLicense of+    Just l -> MustSPDX l+    Nothing -> DontTouch license   where-    spdxLicense :: Either String SPDX.License-    spdxLicense  = eitherParsec license+    knownLicenses :: [(String, Cabal.License)]+    knownLicenses = map (prettyShow &&& id) (Cabal.BSD4 : Cabal.knownLicenses) -    cabalLicense :: Either String Cabal.License-    cabalLicense = eitherParsec license+    spdxLicense :: Maybe SPDX.License+    spdxLicense  = either (const Nothing) Just (eitherParsec license) -    isUnknown = license `notElem` knownLicenses+probabilities :: Text -> [(LicenseId, Double)]+probabilities license = map (fmap probability) licenses+  where+    probability = realToFrac . levenshteinNorm license -    knownLicenses = [-        "GPL"-      , "GPL-2"-      , "GPL-3"-      , "LGPL"-      , "LGPL-2.1"-      , "LGPL-3"-      , "AGPL"-      , "AGPL-3"-      , "BSD2"-      , "BSD3"-      , "BSD4"-      , "MIT"-      , "ISC"-      , "MPL-2.0"-      , "Apache"-      , "Apache-2.0"-      , "PublicDomain"-      , "AllRightsReserved"-      , "OtherLicense"-      ]+inferLicense :: String -> Maybe (License String)+inferLicense (T.pack -> xs) = case maximumBy (comparing snd) (probabilities xs) of+  (license, n) | n > 0.85 -> Just (toLicense license)+  _ -> Nothing+  where+    toLicense :: LicenseId -> License String+    toLicense license = (case license of+      MIT -> CanSPDX Cabal.MIT+      BSD_2_Clause -> CanSPDX Cabal.BSD2+      BSD_3_Clause -> CanSPDX Cabal.BSD3+      BSD_4_Clause -> CanSPDX Cabal.BSD4+      _ -> MustSPDX+      ) (licenseId license)
src/Hpack/Render.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE CPP #-}
+ src/Hpack/SpdxLicenses.hs view
@@ -0,0 +1,118 @@+-- DO NOT MODIFY MANUALLY+--+-- This file has been generated with ./generate-spdx-licenses-module.sh.++{-# LANGUAGE OverloadedStrings #-}+module Hpack.SpdxLicenses where+import Data.Text (Text)+import Distribution.SPDX.LicenseId+licenses :: [(LicenseId, Text)]+licenses = [+    (BSD_2_Clause, "\+\Copyright (c) <year> <owner> . All rights reserved.\n\+\\n\+\Redistribution and use in source and binary forms, with or without modification,\n\+\are permitted provided that the following conditions are met:\n\+\\n\+\1. Redistributions of source code must retain the above copyright notice,\n\+\this list of conditions and the following disclaimer.\n\+\\n\+\2. Redistributions in binary form must reproduce the above copyright notice,\n\+\this list of conditions and the following disclaimer in the documentation\n\+\and/or other materials provided with the distribution.\n\+\\n\+\THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n\+\AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\+\IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\+\ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n\+\LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\+\DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n\+\SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n\+\CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n\+\OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\n\+\USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\+\")+  , (BSD_3_Clause, "\+\Copyright (c) <year> <owner> . All rights reserved.\n\+\\n\+\Redistribution and use in source and binary forms, with or without modification,\n\+\are permitted provided that the following conditions are met:\n\+\\n\+\1. Redistributions of source code must retain the above copyright notice,\n\+\this list of conditions and the following disclaimer.\n\+\\n\+\2. Redistributions in binary form must reproduce the above copyright notice,\n\+\this list of conditions and the following disclaimer in the documentation\n\+\and/or other materials provided with the distribution.\n\+\\n\+\3. Neither the name of the copyright holder nor the names of its contributors\n\+\may be used to endorse or promote products derived from this software without\n\+\specific prior written permission.\n\+\\n\+\THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n\+\AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\+\IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\+\ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n\+\LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\+\DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n\+\SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n\+\CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n\+\OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\n\+\USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\+\")+  , (BSD_4_Clause, "\+\Copyright (c) <year> <owner> . All rights reserved.\n\+\\n\+\Redistribution and use in source and binary forms, with or without modification,\n\+\are permitted provided that the following conditions are met:\n\+\\n\+\1. Redistributions of source code must retain the above copyright notice,\n\+\this list of conditions and the following disclaimer.\n\+\\n\+\2. Redistributions in binary form must reproduce the above copyright notice,\n\+\this list of conditions and the following disclaimer in the documentation\n\+\and/or other materials provided with the distribution.\n\+\\n\+\3. All advertising materials mentioning features or use of this software must\n\+\display the following acknowledgement:\n\+\\n\+\   This product includes software developed by the organization .\n\+\\n\+\4. Neither the name of the copyright holder nor the names of its contributors\n\+\may be used to endorse or promote products derived from this software without\n\+\specific prior written permission.\n\+\\n\+\THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER \"AS IS\" AND ANY EXPRESS OR IMPLIED\n\+\WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n\+\AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT\n\+\HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n\+\OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n\+\GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n\+\HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n\+\LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n\+\OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n\+\DAMAGE.\n\+\")+  , (MIT, "\+\MIT License\n\+\\n\+\Copyright (c) <year> <copyright holders>\n\+\\n\+\Permission is hereby granted, free of charge, to any person obtaining a copy\n\+\of this software and associated documentation files (the \"Software\"), to deal\n\+\in the Software without restriction, including without limitation the rights\n\+\to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n\+\copies of the Software, and to permit persons to whom the Software is furnished\n\+\to do so, subject to the following conditions:\n\+\\n\+\The above copyright notice and this permission notice shall be included in\n\+\all copies or substantial portions of the Software.\n\+\\n\+\THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\+\IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n\+\FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n\+\OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n\+\WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\n\+\OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\+\")+  ]
test/EndToEndSpec.hs view
@@ -351,6 +351,30 @@             default-language: Haskell2010           |]) {packageCabalVersion = "2.2"} +      context "with a LICENSE file" $ do+        before_ (writeFile "LICENSE" license) $ do+          it "infers license" $ do+            [i|+            |] `shouldRenderTo` (package [i|+            license-file: LICENSE+            license: MIT+            |])++          context "when license can not be inferred" $ do+            it "warns" $ do+              writeFile "LICENSE" "some-licenese"+              [i|+              name: foo+              |] `shouldWarn` ["Inferring license from file LICENSE failed!"]++          context "when license is null" $ do+            it "does not infer license" $ do+              [i|+              license: null+              |] `shouldRenderTo` (package [i|+              license-file: LICENSE+              |])+     describe "build-type" $ do       it "accept Simple" $ do         [i|@@ -1411,3 +1435,26 @@  indentBy :: Int -> String -> String indentBy n = unlines . map (replicate n ' ' ++) . lines++license :: String+license = [i|+Copyright (c) 2014-2018 Simon Hengel <sol@typeful.net>++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.+|]
test/Hpack/LicenseSpec.hs view
@@ -2,41 +2,47 @@ module Hpack.LicenseSpec (spec) where  import           Helper+import           Data.Maybe import           Data.String.Interpolate  import           Distribution.Pretty (prettyShow)+import           Distribution.Parsec.Class (simpleParsec)+import qualified Distribution.License as Cabal  import           Hpack.License +cabal :: String -> Cabal.License+cabal = fromJust . simpleParsec+ cabalLicenses :: [(String, License String)] cabalLicenses = [-    ("GPL",               CanSPDX "LicenseRef-GPL")-  , ("GPL-2",             CanSPDX "GPL-2.0-only")-  , ("GPL-3",             CanSPDX "GPL-3.0-only")+    ("GPL",               CanSPDX (cabal "GPL") "LicenseRef-GPL")+  , ("GPL-2",             CanSPDX (cabal "GPL-2") "GPL-2.0-only")+  , ("GPL-3",             CanSPDX (cabal "GPL-3") "GPL-3.0-only") -  , ("LGPL",              CanSPDX "LicenseRef-LGPL")-  , ("LGPL-2.1",          CanSPDX "LGPL-2.1-only")-  , ("LGPL-3",            CanSPDX "LGPL-3.0-only")+  , ("LGPL",              CanSPDX (cabal "LGPL") "LicenseRef-LGPL")+  , ("LGPL-2.1",          CanSPDX (cabal "LGPL-2.1") "LGPL-2.1-only")+  , ("LGPL-3",            CanSPDX (cabal "LGPL-3") "LGPL-3.0-only") -  , ("AGPL",              CanSPDX "LicenseRef-AGPL")-  , ("AGPL-3",            CanSPDX "AGPL-3.0-only")+  , ("AGPL",              CanSPDX (cabal "AGPL") "LicenseRef-AGPL")+  , ("AGPL-3",            CanSPDX (cabal "AGPL-3") "AGPL-3.0-only")  -  , ("BSD2",              CanSPDX "BSD-2-Clause")-  , ("BSD3",              CanSPDX "BSD-3-Clause")-  , ("BSD4",              CanSPDX "BSD-4-Clause")+  , ("BSD2",              CanSPDX (cabal "BSD2") "BSD-2-Clause")+  , ("BSD3",              CanSPDX (cabal "BSD3") "BSD-3-Clause")+  , ("BSD4",              CanSPDX (cabal "BSD4") "BSD-4-Clause") -  , ("MIT",               CanSPDX "MIT")-  , ("ISC",               CanSPDX "ISC")+  , ("MIT",               CanSPDX (cabal "MIT") "MIT")+  , ("ISC",               CanSPDX (cabal "ISC") "ISC") -  , ("MPL-2.0",           CanSPDX "MPL-2.0")+  , ("MPL-2.0",           CanSPDX (cabal "MPL-2.0") "MPL-2.0") -  , ("Apache",            CanSPDX "LicenseRef-Apache")-  , ("Apache-2.0",        CanSPDX "Apache-2.0")+  , ("Apache",            CanSPDX (cabal "Apache") "LicenseRef-Apache")+  , ("Apache-2.0",        CanSPDX (cabal "Apache-2.0") "Apache-2.0") -  , ("PublicDomain",      CanSPDX "LicenseRef-PublicDomain")-  , ("OtherLicense",      CanSPDX "LicenseRef-OtherLicense")-  , ("AllRightsReserved", CanSPDX "NONE")+  , ("PublicDomain",      CanSPDX (cabal "PublicDomain") "LicenseRef-PublicDomain")+  , ("OtherLicense",      CanSPDX (cabal "OtherLicense") "LicenseRef-OtherLicense")+  , ("AllRightsReserved", CanSPDX (cabal "AllRightsReserved") "NONE")   ]  spdxLicenses :: [(String, License String)]@@ -46,7 +52,7 @@  unknownLicenses :: [(String, License String)] unknownLicenses = [-    ("some-license",      DontTouch)+    ("some-license",      DontTouch "some-license")   ]  spec :: Spec@@ -55,3 +61,19 @@     forM_ (cabalLicenses ++ spdxLicenses ++ unknownLicenses) $ \ (license, expected) -> do       it [i|parses #{license}|] $ do         prettyShow <$> parseLicense license `shouldBe` expected++  describe "inferLicense" $ do+    it "infers MIT" $ do+      inferLicense <$> readFile "test/resources/mit" `shouldReturn` Just (CanSPDX Cabal.MIT "MIT")++    it "infers BSD-2-Clause" $ do+      inferLicense <$> readFile "test/resources/bsd2" `shouldReturn` Just (CanSPDX Cabal.BSD2 "BSD-2-Clause")++    it "infers BSD-3-Clause" $ do+      inferLicense <$> readFile "test/resources/bsd3" `shouldReturn` Just (CanSPDX Cabal.BSD3 "BSD-3-Clause")++    it "infers BSD-4-Clause" $ do+      inferLicense <$> readFile "test/resources/bsd4" `shouldReturn` Just (CanSPDX Cabal.BSD4 "BSD-4-Clause")++    it "rejects unknown licenses" $ do+      inferLicense "unknown" `shouldBe` Nothing