{-# 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) 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 lookup license knownLicenses of Just l -> CanSPDX l (Cabal.licenseToSPDX l) Nothing -> case spdxLicense of Just l -> MustSPDX l Nothing -> DontTouch license where knownLicenses :: [(String, Cabal.License)] knownLicenses = map (prettyShow &&& id) (Cabal.BSD4 : Cabal.knownLicenses) spdxLicense :: Maybe SPDX.License spdxLicense = either (const Nothing) Just (eitherParsec license) probabilities :: Text -> [(LicenseId, Double)] probabilities license = map (fmap probability) licenses where probability = realToFrac . levenshteinNorm license 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)