git.iko.soy/typeable/cabal2nix
on 763562e help sign in
100 lines 3.8 kB history raw
1module Cabal2Nix.Normalize ( normalize, normalizeCabalFlags ) where
3import Cabal2Nix.CorePackages
4import Cabal2Nix.Name
5import Control.Lens
6import Data.Function
7import Data.List
8import Data.Set ( Set )
9import qualified Data.Set as Set
10import Language.Nix.Identifier ( Identifier(..) )
11import Distribution.Nixpkgs.Haskell
12import Distribution.Nixpkgs.Meta
13import Distribution.Nixpkgs.Util.Regex ( regsubmatch )
14import Distribution.Package
15import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )
16import Distribution.Simple.Utils ( lowercase )
18normalize :: Derivation -> Derivation
19normalize drv = drv
20 & over libraryDepends (normalizeBuildInfo (packageName drv))
21 & over executableDepends (normalizeBuildInfo (packageName drv))
22 & over testDepends (normalizeBuildInfo (packageName drv))
23 & over metaSection normalizeMeta
24 & over cabalFlags normalizeCabalFlags
26normalizeBuildInfo :: PackageName -> BuildInfo -> BuildInfo
27normalizeBuildInfo (PackageName pname) bi = bi
28 & haskell . contains (Identifier pname) .~ False
29 & tool %~ normalizeNixBuildTools . Set.filter (\(Identifier n) -> n `notElem` coreBuildTools)
31 {-
32 {
33 , testDepends = normalizeNixNames (Set.delete pname testDepends)
34 , extraLibs = normalizeNixLibs extraLibs
35 , pkgConfDeps = normalizeNixLibs pkgConfDeps
36 , configureFlags = normalizeSet configureFlags
37 }
38-}
40normalizeMeta :: Meta -> Meta
41normalizeMeta = over description normalizeSynopsis
42 . over maintainers normalizeMaintainers
43 . over platforms normalizePlatforms
45normalizeSynopsis :: String -> String
46normalizeSynopsis desc
47 | null desc = []
48 | last desc == '.' && length (filter ('.'==) desc) == 1 = normalizeSynopsis (init desc)
49 | otherwise = quote (unwords (words desc))
51quote :: String -> String
52quote ('\\':c:cs) = '\\' : c : quote cs
53quote ('"':cs) = '\\' : '"' : quote cs
54quote (c:cs) = c : quote cs
55quote [] = []
57normalizeSet :: Set String -> Set String
58normalizeSet = Set.filter (not . null)
60-- normalizeNixNames :: Set String -> Set String
61-- normalizeNixNames = normalizeSet . Set.map toNixName
63-- normalizeNixLibs :: Set String -> Set String
64-- normalizeNixLibs = normalizeSet . Set.fromList . concatMap libNixName . Set.toList
66normalizeNixBuildTools :: Set Identifier -> Set Identifier
67normalizeNixBuildTools = Set.fromList . concatMap buildToolNixName' . Set.toList
68 where
69 buildToolNixName' :: Identifier -> [Identifier]
70 buildToolNixName' (Identifier n) = [ Identifier n' | n' <- buildToolNixName n ]
72-- |Strip any kind of path prefix from maintainer names, filter duplicates, and
73-- sort the resulting list alphabetically.
74--
75-- >>> normalizeMaintainers $ Set.fromList ["self.stdenv.lib.maintainers.foobar", "foobar"]
76-- fromList ["foobar"]
77--
78-- >>> normalizeMaintainers $ Set.fromList ["any.prefix.is.recognized.yo", "abc.def"]
79-- fromList ["def","yo"]
81normalizeMaintainers :: Set String -> Set String
82normalizeMaintainers = normalizeSet . Set.map
83 (\m -> (m `regsubmatch` "^([^.].*\\.)?([^.]+)$") !! 1)
85normalizePlatforms :: Set String -> Set String
86normalizePlatforms = normalizeSet . Set.map
87 (\p -> if '.' `elem` p then p else "stdenv.lib.platforms." ++ p)
90-- |When a flag is specified multiple times, the first occurrence
91-- counts. This is counter-intuitive, IMHO, but it's how cabal does it.
92-- Flag names are spelled in all lowercase.
93--
94-- >>> normalizeCabalFlags [(FlagName "foo", True), (FlagName "FOO", True), (FlagName "Foo", False)]
95-- [(FlagName "foo",True)]
97normalizeCabalFlags :: FlagAssignment -> FlagAssignment
98normalizeCabalFlags flags' = nubBy ((==) `on` fst) (sortBy (compare `on` fst) flags)
99 where
100 flags = [ (FlagName (lowercase n), b) | (FlagName n, b) <- flags' ]