@@ -15,6 +15,8 @@ module Cabal.Project (
1515 -- * Parse project
1616 readProject ,
1717 parseProject ,
18+ readProjectWithConditionals ,
19+ parseProjectWithConditionals ,
1820 -- * Resolve project
1921 resolveProject ,
2022 ResolveError (.. ),
@@ -179,6 +181,13 @@ readProject fp = do
179181 prj1 <- resolveProject fp prj0 >>= either throwIO return
180182 readPackagesOfProject prj1 >>= either throwIO return
181183
184+ readProjectWithConditionals :: FilePath -> IO (C. CondTree C. ConfVar () (Project URI Void (FilePath , C. GenericPackageDescription )))
185+ readProjectWithConditionals fp = do
186+ contents <- BS. readFile fp
187+ prj0 <- either throwIO return (parseProjectWithConditionals fp contents)
188+ prj1 <- traverse (\ p -> resolveProject fp p >>= either throwIO return ) prj0
189+ traverse (\ p -> readPackagesOfProject p >>= either throwIO return ) prj1
190+
182191-- | Parse project file. Extracts only few fields.
183192--
184193-- >>> fmap prjPackages $ parseProject "cabal.project" "packages: foo bar/*.cabal"
@@ -207,6 +216,39 @@ parseProject = parseWith $ \fields0 -> do
207216
208217 parseSec _ = return id
209218
219+ -- | Parse project files with conditionals.
220+ --
221+ -- >>> fmap (fmap prjPackages) $ parseProjectWithConditionals "cabal.project" "packages: foo bar/*.cabal"
222+ -- Right (CondNode {condTreeData = ["foo","bar/*.cabal"], condTreeConstraints = (), condTreeComponents = []})
223+ --
224+ -- TODO:
225+ --
226+ -- >>> fmap (fmap prjPackages) $ parseProjectWithConditionals "cabal.project" "packages: foo bar/*.cabal\nif impl(ghc >=9)\n packages: quu"
227+ -- Right (CondNode {condTreeData = ["foo","bar/*.cabal"], condTreeConstraints = (), condTreeComponents = []})
228+ --
229+ parseProjectWithConditionals :: FilePath -> ByteString -> Either (ParseError NonEmpty ) (C. CondTree C. ConfVar () (Project Void String String ))
230+ parseProjectWithConditionals = parseWith $ \ fields0 -> do
231+ let (fields1, sections) = C. partitionFields fields0
232+ let fields2 = M. filterWithKey (\ k _ -> k `elem` knownFields) fields1
233+ (\ n -> C. CondNode n () [] ) <$> parse fields0 fields2 sections
234+ where
235+ knownFields = C. fieldGrammarKnownFieldList $ grammar []
236+
237+ parse otherFields fields sections = do
238+ let prettyOtherFields = map void $ C. fromParsecFields $ filter otherFieldName otherFields
239+ prj <- C. parseFieldGrammar C. cabalSpecLatest fields $ grammar prettyOtherFields
240+ foldl' (&) prj <$> traverse parseSec (concat sections)
241+
242+ -- Special case for source-repository-package. If you add another such
243+ -- special case, make sure to update otherFieldName appropriately.
244+ parseSec :: C. Section C. Position -> C. ParseResult (Project Void String String -> Project Void String String )
245+ parseSec (C. MkSection (C. Name _pos name) [] fields) | name == sourceRepoSectionName = do
246+ let fields' = fst $ C. partitionFields fields
247+ repos <- C. parseFieldGrammar C. cabalSpecLatest fields' sourceRepositoryPackageGrammar
248+ return $ over prjSourceReposL (++ toList (srpFanOut repos))
249+
250+ parseSec _ = return id
251+
210252-- | Returns 'True' if a field should be a part of 'prjOtherFields'. This
211253-- excludes any field that is a part of 'grammar' as well as
212254-- @source-repository-package@ (see 'parseProject', which has a special case
0 commit comments