git.iko.soy/typeable/stackage2nix
on master help sign in
Add support for new syntax in extra-deps
commit334955f196b4256024e003e493465d1152f21bdb authorDmitry Bushev <bushevdv@gmail.com> dateSun 18 Mar 2018, 14:29 (9 years ago) parent7d6dcef
5 files changed+204−58
src/Distribution/Nixpkgs/Haskell/Stack.hs+2−2 src/LtsHaskell.hs+1−1 src/Stack/Config.hs+93−40 src/Stack/Config/Yaml.hs+39−14 test/Stack/Config/YamlSpec.hs+69−1
src/Distribution/Nixpkgs/Haskell/Stack.hs+2−2
@@ -42,8 +42,8 @@ stackLocationToSource
4242 -> Maybe FilePath
4343 -> Source
4444stackLocationToSource pl mCabalDir = case pl of
45− HackagePackage p -> Source
46− { sourceUrl = "cabal://" ++ T.unpack p
45+ StackIndex p -> Source
46+ { sourceUrl = "cabal://" ++ T.unpack (p ^. piNameVersion)
4747 , sourceRevision = mempty
4848 , sourceHash = UnknownHash
4949 , sourceCabalDir = cabalDir }
src/LtsHaskell.hs+1−1
@@ -52,7 +52,7 @@ getPackageFromRepo allCabalHashesPath mSha1Hash pkgId = do
5252getPackageFromDb :: DB.HackageDB -> PackageIdentifier -> IO Package
5353getPackageFromDb hackageDb pkgId =
5454 getStackPackageFromDb hackageDb
55− $ StackPackage (HackagePackage (T.pack $ Text.display pkgId)) True Nothing
55+ $ StackPackage (StackIndex $ PackageIndex (T.pack $ Text.display pkgId) Nothing) True Nothing
5656
5757loadPackage :: DB.HackageDB -> FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package
5858loadPackage hackageDb allCabalHashesPath mSha1Hash pkgId =
src/Stack/Config.hs+93−40
@@ -6,16 +6,15 @@ import Control.Lens
66import Data.Bifunctor
77import Data.ByteString as BS
88import Data.Coerce
9−import Data.Foldable as F
109import Data.List.NonEmpty as NE
1110import Data.Maybe
12−import Data.Semigroup (sconcat)
11+import Data.Semigroup
1312import Data.Text as T
1413import Data.Yaml
1514import Network.URI
1615import Stack.Config.Yaml as Yaml
1716import Stack.Types
18−import System.FilePath
17+import System.FilePath as FilePath
1918
2019
2120newtype StackResolver = StackResolver { fromStackResolver :: Text }
@@ -30,15 +29,29 @@ newtype Vcs = Vcs { fromVcs :: Text }
3029 deriving (Eq, Ord, Show)
3130
3231data Repo = Repo
33− { _rVcs :: !Vcs
34− , _rUri :: !Text
35− , _rCommit :: !Text
32+ { _rVcs :: Vcs
33+ , _rUri :: Text
34+ , _rCommit :: Text
3635 } deriving (Eq, Ord, Show)
3736
3837makeLenses ''Repo
3938
39+data PackageRevision
40+ = PrSha256 Text
41+ | PrRev Text
42+ deriving (Eq, Ord, Show)
43+
44+makePrisms ''PackageRevision
45+
46+data PackageIndex = PackageIndex
47+ { _piNameVersion :: Text
48+ , _piRevision :: Maybe PackageRevision
49+ } deriving (Eq, Ord, Show)
50+
51+makeLenses ''PackageIndex
52+
4053data PackageLocation
41− = HackagePackage Text
54+ = StackIndex PackageIndex
4255 | StackFilePath FilePath
4356 | StackUri URI
4457 | StackRepo Repo
@@ -47,17 +60,17 @@ data PackageLocation
4760makePrisms ''PackageLocation
4861
4962data StackPackage = StackPackage
50− { _spLocation :: !PackageLocation
51− , _spExtraDep :: !Bool
63+ { _spLocation :: PackageLocation
64+ , _spExtraDep :: Bool
5265 -- | Subdirectory containing the cabal file if any specified.
53− , _spDir :: !(Maybe FilePath)
66+ , _spDir :: Maybe FilePath
5467 } deriving (Eq, Ord, Show)
5568
5669makeLenses ''StackPackage
5770
5871data StackConfig = StackConfig
59− { _scResolver :: !StackResolver
60− , _scPackages :: !(NonEmpty StackPackage)
72+ { _scResolver :: StackResolver
73+ , _scPackages :: NonEmpty StackPackage
6174 } deriving (Eq, Ord, Show)
6275
6376makeLenses ''StackConfig
@@ -66,52 +79,92 @@ fromYamlConfig :: Yaml.Config -> StackConfig
6679fromYamlConfig c = StackConfig{..}
6780 where
6881 _scResolver = coerce $ c ^. cResolver
69− _scPackages = F.foldr (NE.<|) neYamlPackages yamlExtraDeps
70− neYamlPackages = fromMaybe (pure defaultPackage)
71− . fmap sconcat $ NE.nonEmpty yamlPackages
72− yamlPackages = fromYamlPackage <$> (fromMaybe mempty (c ^. cPackages))
73− yamlExtraDeps = fromYamlExtraDep <$> fromMaybe mempty (c ^. cExtraDeps)
82+ _scPackages = NE.nub
83+ $ fromMaybe (pure defaultPackage)
84+ $ fmap sconcat
85+ $ NE.nonEmpty (yamlPackages <> yamlExtraDeps)
86+ yamlPackages = fromYamlPackage packagesSimplePath False
87+ <$> fromMaybe mempty (c ^. cPackages)
88+ yamlExtraDeps = fromYamlPackage extraDepsSimplePath True
89+ <$> fromMaybe mempty (c ^. cExtraDeps)
7490 defaultPackage = StackPackage (StackFilePath ".") False Nothing
7591
92+-- | Simple string in a packages section can be an URI or FilePath location
93+packagesSimplePath :: Text -> StackPackage
94+packagesSimplePath t = StackPackage (parseSimplePath t) False Nothing
95+
96+-- | Parse location as URI or a FilePath
97+parseSimplePath :: Text -> PackageLocation
98+parseSimplePath (T.unpack -> p) = maybe (StackFilePath p) StackUri $ parseURI p
7699
100+-- | Simple string in an extra-deps section can be an URI or FilePath or PackageIndex name-version
101+extraDepsSimplePath :: Text -> StackPackage
102+extraDepsSimplePath t = StackPackage loc True Nothing
103+ where
104+ loc = maybe (parsePackageIndex t) StackUri $ parseURI (T.unpack t)
105+
106+-- TODO: support new package index format with hash and revision
107+parsePackageIndex :: Text -> PackageLocation
108+parsePackageIndex t = if isFilePath t
109+ then StackFilePath (T.unpack t)
110+ else StackIndex $ PackageIndex t Nothing
111+
112+-- Determine wether package is file path
113+isFilePath :: Text -> Bool
114+isFilePath = T.any (== FilePath.pathSeparator)
115+
116+-- | A single 'Yaml.Package' can result in multiple actual
117+-- packages if it has multiple subdirs specified.
77118fromYamlPackage
78− :: Yaml.Package
79− -- ^ A single 'Yaml.Package' can result in multiple actual
80− -- packages if it has multiple subdirs specified.
119+ :: (Text -> StackPackage)
120+ -> Bool
121+ -> Yaml.Package
81122 -> NonEmpty StackPackage
82−fromYamlPackage = \case
123+fromYamlPackage fromSimple isExtraDep = \case
83124 Yaml.Simple p ->
84− unroll Nothing $ StackPackage (parseSimplePath p) False
125+ pure (fromSimple p)
85126 Yaml.LocationSimple (Location p extraDep ms) ->
86127 unroll ms $ StackPackage (parseSimplePath p) (fromMaybe False extraDep)
87− Yaml.LocationGit (Location git extraDep ms) ->
88− unroll ms $ StackPackage (StackRepo $ fromYamlGit git) (fromMaybe False extraDep)
89− Yaml.LocationHg (Location hg extraDep ms) ->
90− unroll ms $ StackPackage (StackRepo $ fromYamlHg hg) (fromMaybe False extraDep)
128+ Yaml.LocationGit loc ->
129+ mkStackPackageRepo fromYamlGit loc
130+ Yaml.LocationHg loc ->
131+ mkStackPackageRepo fromYamlHg loc
132+ Yaml.PNewGit ng -> unroll (ng ^. ngSubdirs)
133+ $ StackPackage (StackRepo $ fromYamlNewGit ng) isExtraDep
134+ Yaml.PNewHg nh -> unroll (nh ^. nhSubdirs)
135+ $ StackPackage (StackRepo $ fromYamlNewHg nh) isExtraDep
91136 where
92− parseSimplePath (T.unpack -> p) = maybe (StackFilePath p) StackUri $ parseURI p
137+ mkStackPackageRepo f loc = unroll (loc ^. lSubdirs)
138+ $ StackPackage (StackRepo (loc ^. lLocation . to f)) (fromMaybe isExtraDep $ loc ^. lExtraDep)
93139 -- Each package gets a single directory with cabal file in it. If
94140 -- it's not specified, path is empty.
95141 unroll subs p = case subs of
96142 Just (x : xs) -> NE.map (p . Just) (x :| xs)
97143 _ -> p Nothing :| []
98144
99−fromYamlExtraDep :: Text -> StackPackage
100−fromYamlExtraDep t = StackPackage (HackagePackage t) True Nothing
101−
102145fromYamlGit :: Yaml.Git -> Repo
103−fromYamlGit yg = Repo{..}
104− where
105− _rVcs = Vcs "git"
106− _rUri = yg ^. gGit
107− _rCommit = yg ^. gCommit
146+fromYamlGit yg = Repo
147+ { _rVcs = Vcs "git"
148+ , _rUri = yg ^. gGit
149+ , _rCommit = yg ^. gCommit }
108150
109151fromYamlHg :: Yaml.Hg -> Repo
110−fromYamlHg yh = Repo{..}
111− where
112− _rVcs = Vcs "hg"
113− _rUri = yh ^. hHg
114− _rCommit = yh ^. hCommit
152+fromYamlHg yh = Repo
153+ { _rVcs = Vcs "hg"
154+ , _rUri = yh ^. hHg
155+ , _rCommit = yh ^. hCommit }
156+
157+fromYamlNewGit :: NewGit -> Repo
158+fromYamlNewGit ng = Repo
159+ { _rVcs = Vcs "git"
160+ , _rUri = ng ^. ngGit
161+ , _rCommit = ng ^. ngCommit }
162+
163+fromYamlNewHg :: NewHg -> Repo
164+fromYamlNewHg nh = Repo
165+ { _rVcs = Vcs "hg"
166+ , _rUri = nh ^. nhHg
167+ , _rCommit = nh ^. nhCommit }
115168
116169readStackConfig :: StackYaml -> IO (Either String StackConfig)
117170readStackConfig stackYaml = do
src/Stack/Config/Yaml.hs+39−14
@@ -8,38 +8,57 @@ import Data.Text as T
88import Stack.Config.TH
99
1010data Location a = Location
11− { _lLocation :: !a
12− , _lExtraDep :: !(Maybe Bool)
13− , _lSubdirs :: !(Maybe [FilePath])
11+ { _lLocation :: a
12+ , _lExtraDep :: Maybe Bool
13+ , _lSubdirs :: Maybe [FilePath]
1414 } deriving (Eq, Show)
1515
1616makeLenses ''Location
17−
1817deriveJSON jsonOpts ''Location
1918
2019data Git = Git
21− { _gGit :: !Text
22− , _gCommit :: !Text
20+ { _gGit :: Text
21+ , _gCommit :: Text
2322 } deriving (Eq, Show)
2423
2524makeLenses ''Git
26−
2725deriveJSON jsonOpts ''Git
2826
2927data Hg = Hg
30− { _hHg :: !Text
31− , _hCommit :: !Text
28+ { _hHg :: Text
29+ , _hCommit :: Text
3230 } deriving (Eq, Show)
3331
3432makeLenses ''Hg
35−
3633deriveJSON jsonOpts ''Hg
3734
35+-- New syntax
36+
37+data NewGit = NewGit
38+ { _ngGit :: Text
39+ , _ngCommit :: Text
40+ , _ngSubdirs :: Maybe [FilePath]
41+ } deriving (Eq, Show)
42+
43+makeLenses ''NewGit
44+deriveJSON jsonOpts ''NewGit
45+
46+data NewHg = NewHg
47+ { _nhHg :: Text
48+ , _nhCommit :: Text
49+ , _nhSubdirs :: Maybe [FilePath]
50+ } deriving (Eq, Show)
51+
52+makeLenses ''NewHg
53+deriveJSON jsonOpts ''NewHg
54+
3855data Package
3956 = Simple Text
4057 | LocationSimple (Location Text)
4158 | LocationGit (Location Git)
4259 | LocationHg (Location Hg)
60+ | PNewGit NewGit
61+ | PNewHg NewHg
4362 deriving (Eq, Show)
4463
4564makePrisms ''Package
@@ -49,7 +68,9 @@ instance FromJSON Package where
4968 (Simple <$> parseJSON v) <|>
5069 (LocationSimple <$> parseJSON v) <|>
5170 (LocationGit <$> parseJSON v) <|>
52− (LocationHg <$> parseJSON v)
71+ (LocationHg <$> parseJSON v) <|>
72+ (PNewGit <$> parseJSON v) <|>
73+ (PNewHg <$> parseJSON v)
5374
5475instance ToJSON Package where
5576 toJSON = \case
@@ -57,11 +78,15 @@ instance ToJSON Package where
5778 LocationSimple t -> toJSON t
5879 LocationGit t -> toJSON t
5980 LocationHg t -> toJSON t
81+ PNewGit t -> toJSON t
82+ PNewHg t -> toJSON t
6083
84+-- To support support both old and new syntax, we allow all varieties of package
85+-- definitions in both "packages" and "extra-deps" sections
6186data Config = Config
62− { _cResolver :: !Text
63− , _cPackages :: !(Maybe [Package])
64− , _cExtraDeps :: !(Maybe [Text])
87+ { _cResolver :: Text
88+ , _cPackages :: Maybe [Package]
89+ , _cExtraDeps :: Maybe [Package]
6590 } deriving (Eq, Show)
6691
6792makeLenses ''Config
test/Stack/Config/YamlSpec.hs+69−1
@@ -39,6 +39,39 @@ extra-deps:
3939- acme-missiles-0.3
4040|]
4141
42+-- | New yaml config support all package definitions in "extra-deps" section
43+configNewYaml :: ByteString
44+configNewYaml = T.encodeUtf8 [st|
45+resolver: lts-3.7
46+packages:
47+ - .
48+ - location: dir1/dir2
49+ - location: https://example.com/foo/bar/baz-0.0.2.tar.gz
50+ extra-dep: true
51+ - location:
52+ git: git@github.com:commercialhaskell/stack.git
53+ commit: 6a86ee32e5b869a877151f74064572225e1a0398
54+ - location:
55+ git: git@github.com:example/mega-repo
56+ commit: 6a86ee32e5b869a877151f74064572225e1a0000
57+ subdirs:
58+ - subdir1
59+ - subdir2
60+# Comment
61+extra-deps:
62+ - acme-missiles-0.3
63+ - acme-missiles-hash-0.4@@sha256:2ba66a092a32593880a87fb00f3213762d7bca65a687d45965778deb8694c5d1
64+ - acme-missiles-rev-0.5@@rev:0
65+ - git: git@github.com:commercialhaskell/stack.git
66+ commit: 6a86ee32e5b869a877151f74064572225e1a0398
67+ - git: git@github.com:example/mega-repo
68+ commit: 6a86ee32e5b869a877151f74064572225e1a0000
69+ subdirs:
70+ - subdir1
71+ - subdir2
72+|]
73+
74+
4275configMinimal :: Config
4376configMinimal = Config
4477 { _cResolver = "lts-8.15"
@@ -65,7 +98,40 @@ config = Config
6598 Nothing (Just ["subdir1", "subdir2"]))
6699 ]
67100 , _cExtraDeps = Just
68− ["acme-missiles-0.3"]
101+ [Simple "acme-missiles-0.3"]
102+ }
103+
104+configNew :: Config
105+configNew = Config
106+ { _cResolver = "lts-3.7"
107+ , _cPackages = Just
108+ [ Simple "."
109+ , LocationSimple (Location "dir1/dir2" Nothing Nothing)
110+ , LocationSimple (Location "https://example.com/foo/bar/baz-0.0.2.tar.gz" (Just True) Nothing)
111+ , LocationGit $ Location
112+ (Git
113+ "git@github.com:commercialhaskell/stack.git"
114+ "6a86ee32e5b869a877151f74064572225e1a0398")
115+ Nothing Nothing
116+ , LocationGit (Location
117+ (Git
118+ "git@github.com:example/mega-repo"
119+ "6a86ee32e5b869a877151f74064572225e1a0000")
120+ Nothing (Just ["subdir1", "subdir2"]))
121+ ]
122+ , _cExtraDeps = Just
123+ [ Simple "acme-missiles-0.3"
124+ , Simple "acme-missiles-hash-0.4@@sha256:2ba66a092a32593880a87fb00f3213762d7bca65a687d45965778deb8694c5d1"
125+ , Simple "acme-missiles-rev-0.5@@rev:0"
126+ , PNewGit $ NewGit
127+ "git@github.com:commercialhaskell/stack.git"
128+ "6a86ee32e5b869a877151f74064572225e1a0398"
129+ Nothing
130+ , PNewGit $ NewGit
131+ "git@github.com:example/mega-repo"
132+ "6a86ee32e5b869a877151f74064572225e1a0000"
133+ (Just ["subdir1", "subdir2"])
134+ ]
69135 }
70136
71137spec :: Spec
@@ -74,3 +140,5 @@ spec = describe "Parse" $ do
74140 (Y.decode configYamlMinimal :: Maybe Config) `shouldBe` Just configMinimal
75141 specify "config-full" $
76142 (Y.decode configYaml :: Maybe Config) `shouldBe` Just config
143+ specify "config-new" $
144+ (Y.decode configNewYaml :: Maybe Config) `shouldBe` Just configNew