Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended project files (conditionals and imports) #7783

Merged
merged 30 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4dd4975
initial parser pass
gbaz Oct 4, 2021
2ccd991
first compiling pass
gbaz Oct 28, 2021
e807d2d
get more stuff sort of working
gbaz Nov 29, 2021
ca7499a
conditional parsing actually works
gbaz Nov 30, 2021
26a4cb7
Merge branch 'master' into gb/extended-project-files
gbaz Nov 30, 2021
0c6e6e3
error cleanup and downloads
gbaz Jan 3, 2022
912205c
thread through http transport
gbaz Jan 3, 2022
e2a6259
Merge branch 'master' into gb/extended-project-files
gbaz Jan 3, 2022
e0607be
fix merge
gbaz Jan 3, 2022
ec3763f
better errors and use extended project parsing uniformly
gbaz Jan 5, 2022
21ebfc1
elif support, maybe?
gbaz Jan 5, 2022
bd0031e
fix outdated cmd, add tests, docs
gbaz Jan 6, 2022
e8ae8e0
fix docs
gbaz Jan 7, 2022
0b2e15c
Merge branch 'master' into gb/extended-project-files
gbaz Jan 10, 2022
189262c
use legacyReadFields parser
gbaz Jan 11, 2022
ca71ea7
Merge branch 'master' into gb/extended-project-files
gbaz Feb 1, 2022
1233acf
changelog
gbaz Feb 1, 2022
782892f
cyclical import detection
gbaz Feb 2, 2022
0fcc0b5
fix shadowing
gbaz Feb 2, 2022
9867fbc
add missing file
gbaz Feb 2, 2022
111ae08
Merge branch 'master' into gb/extended-project-files
gbaz Feb 21, 2022
4dc4789
Merge branch 'master' into gb/extended-project-files
gbaz Mar 25, 2022
5d59b18
finish merge
gbaz Mar 25, 2022
c12ef88
Merge branch 'master' into gb/extended-project-files
gbaz Mar 26, 2022
f812afb
fix outstanding merge issue
gbaz Mar 26, 2022
f3c8704
use existing config available when checking for compiler for package …
gbaz Mar 28, 2022
e70d6f9
review comments
gbaz Mar 30, 2022
7525a7d
add missing test file
gbaz Mar 31, 2022
2496a7d
Update pr-7783
gbaz Mar 31, 2022
e562334
Merge branch 'master' into gb/extended-project-files
mergify[bot] Mar 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Cabal-syntax/src/Distribution/Fields/ConfVar.hs
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
{-# LANGUAGE OverloadedStrings #-}
module Distribution.Fields.ConfVar (parseConditionConfVar) where
module Distribution.Fields.ConfVar (parseConditionConfVar, parseConditionConfVarFromClause) where

import Distribution.Compat.CharParsing (char, integral)
import Distribution.Compat.Prelude
import Distribution.Fields.Field (SectionArg (..))
import Distribution.Fields.Field (SectionArg (..), Field(..))
import Distribution.Fields.ParseResult
import Distribution.Parsec (Parsec (..), Position (..), runParsecParser)
import Distribution.Parsec.FieldLineStream (fieldLineStreamFromBS)
import Distribution.Types.Condition
import Distribution.Types.ConfVar (ConfVar (..))
import Distribution.Fields.Parser (readFields)
import Distribution.Version
(anyVersion, earlierVersion, intersectVersionRanges, laterVersion, majorBoundVersion,
mkVersion, noVersion, orEarlierVersion, orLaterVersion, thisVersion, unionVersionRanges,
withinVersion)
import Prelude ()

import qualified Text.Parsec as P
import qualified Text.Parsec.Pos as P
import qualified Text.Parsec.Error as P
import qualified Data.ByteString.Char8 as B8

parseConditionConfVarFromClause :: B8.ByteString -> Either P.ParseError (Condition ConfVar)
parseConditionConfVarFromClause x = readFields x >>= \r -> case r of
(Section _ xs _ : _ ) -> P.runParser (parser <* P.eof) () "<condition>" xs
_ -> Left $ P.newErrorMessage (P.Message "No fields in clause") (P.initialPos "<condition>")

-- | Parse @'Condition' 'ConfVar'@ from section arguments provided by parsec
-- based outline parser.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module Distribution.PackageDescription.Configuration (
transformAllBuildInfos,
transformAllBuildDepends,
transformAllBuildDependsN,
simplifyWithSysParams
) where

import Distribution.Compat.Prelude
Expand Down
9 changes: 8 additions & 1 deletion Cabal-syntax/src/Distribution/Types/CondTree.hs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ instance (Binary v, Binary c, Binary a) => Binary (CondTree v c a)
instance (Structured v, Structured c, Structured a) => Structured (CondTree v c a)
instance (NFData v, NFData c, NFData a) => NFData (CondTree v c a) where rnf = genericRnf

instance (Semigroup a, Semigroup c) => Semigroup (CondTree v c a) where
(CondNode a c bs) <> (CondNode a' c' bs') = CondNode (a <> a') (c <> c') (bs <> bs')

instance (Semigroup a, Semigroup c, Monoid a, Monoid c) => Monoid (CondTree v c a) where
mappend = (<>)
mempty = CondNode mempty mempty mempty

-- | A 'CondBranch' represents a conditional branch, e.g., @if
-- flag(foo)@ on some syntax @a@. It also has an optional false
-- branch.
Expand Down Expand Up @@ -191,4 +198,4 @@ foldCondTree e u mergeInclusive mergeExclusive = goTree
goTree :: CondTree v c a -> b
goTree (CondNode a c ifs) = u (c, a) `mergeInclusive` foldl goBranch e ifs
goBranch :: b -> CondBranch v c a -> b
goBranch acc (CondBranch _ t mt) = mergeInclusive acc (maybe (goTree t) (mergeExclusive (goTree t) . goTree) mt)
goBranch acc (CondBranch _ t mt) = mergeInclusive acc (maybe (goTree t) (mergeExclusive (goTree t) . goTree) mt)
15 changes: 12 additions & 3 deletions cabal-install/src/Distribution/Client/CmdConfigure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ import Distribution.Verbosity
import Distribution.Simple.Command
( CommandUI(..), usageAlternatives )
import Distribution.Simple.Utils
( wrapText, notice )
( wrapText, notice, die' )

import Distribution.Client.DistDirLayout
( DistDirLayout(..) )
import Distribution.Client.RebuildMonad (runRebuild)
import Distribution.Client.ProjectConfig.Types
import Distribution.Client.HttpUtils
import Distribution.Utils.NubList
( fromNubList )
import Distribution.Types.CondTree
( CondTree (..) )

configureCommand :: CommandUI (NixStyleFlags ())
configureCommand = CommandUI {
Expand Down Expand Up @@ -126,8 +131,12 @@ configureAction' flags@NixStyleFlags {..} _extraArgs globalFlags = do
-- If the flag @configAppend@ is set to true, append and do not overwrite
if exists && appends
then do
conf <- runRebuild (distProjectRootDirectory . distDirLayout $ baseCtx) $
readProjectLocalExtraConfig v (distDirLayout baseCtx)
httpTransport <- configureTransport v
(fromNubList . projectConfigProgPathExtra $ projectConfigShared cliConfig)
(flagToMaybe . projectConfigHttpTransport $ projectConfigBuildOnly cliConfig)
(CondNode conf imps bs) <- runRebuild (distProjectRootDirectory . distDirLayout $ baseCtx) $
readProjectLocalExtraConfig v httpTransport (distDirLayout baseCtx)
when (not (null imps && null bs)) $ die' v "local project file has conditional and/or import logic, unable to perform and automatic in-place update"
return (baseCtx, conf <> cliConfig)
else
return (baseCtx, cliConfig)
Expand Down
32 changes: 19 additions & 13 deletions cabal-install/src/Distribution/Client/CmdOutdated.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ import Distribution.Client.DistDirLayout
( defaultDistDirLayout
, DistDirLayout(distProjectRootDirectory, distProjectFile) )
import Distribution.Client.ProjectConfig
( ProjectConfig(projectConfigShared),
ProjectConfigShared(projectConfigConstraints), findProjectRoot,
readProjectLocalFreezeConfig )
import Distribution.Client.ProjectConfig.Legacy
( instantiateProjectConfigSkeleton )
import Distribution.Client.ProjectFlags
( projectFlagsOptions, ProjectFlags(..), defaultProjectFlags
, removeIgnoreProjectOption )
Expand All @@ -40,8 +39,6 @@ import Distribution.Client.RebuildMonad
import Distribution.Client.Sandbox
( loadConfigOrSandboxConfig )
import Distribution.Client.Setup
( withRepoContext, GlobalFlags, configCompilerAux'
, ConfigExFlags(configExConstraints) )
import Distribution.Client.Targets
( userToPackageConstraint, UserConstraint )
import Distribution.Client.Types.SourcePackageDb as SourcePackageDb
Expand All @@ -65,7 +62,7 @@ import Distribution.Simple.Setup
import Distribution.Simple.Utils
( die', notice, debug, tryFindPackageDesc )
import Distribution.System
( Platform )
( Platform (..) )
import Distribution.Types.ComponentRequestedSpec
( ComponentRequestedSpec(..) )
import Distribution.Types.Dependency
Expand All @@ -86,6 +83,9 @@ import Distribution.Simple.PackageDescription
import qualified Distribution.Compat.CharParsing as P
import Distribution.ReadE
( parsecToReadE )
import Distribution.Client.HttpUtils
import Distribution.Utils.NubList
( fromNubList )

import qualified Data.Set as S
import System.Directory
Expand Down Expand Up @@ -220,18 +220,23 @@ outdatedAction (ProjectFlags{flagProjectFileName}, OutdatedFlags{..}) _targetStr
config <- loadConfigOrSandboxConfig verbosity globalFlags
let globalFlags' = savedGlobalFlags config `mappend` globalFlags
configFlags = savedConfigureFlags config
(comp, platform, _progdb) <- configCompilerAux' configFlags
withRepoContext verbosity globalFlags' $ \repoContext -> do
when (not newFreezeFile && isJust mprojectFile) $
die' verbosity $
"--project-file must only be used with --v2-freeze-file."

sourcePkgDb <- IndexUtils.getSourcePackages verbosity repoContext
(comp, platform, _progdb) <- configCompilerAux' configFlags
deps <- if freezeFile
then depsFromFreezeFile verbosity
else if newFreezeFile
then depsFromNewFreezeFile verbosity mprojectFile
else depsFromPkgDesc verbosity comp platform
then do
httpTransport <- configureTransport verbosity
Mikolaj marked this conversation as resolved.
Show resolved Hide resolved
(fromNubList . globalProgPathExtra $ globalFlags)
(flagToMaybe . globalHttpTransport $ globalFlags)
depsFromNewFreezeFile verbosity httpTransport comp platform mprojectFile
else do
depsFromPkgDesc verbosity comp platform
debug verbosity $ "Dependencies loaded: "
++ intercalate ", " (map prettyShow deps)
let outdatedDeps = listOutdated deps sourcePkgDb
Expand Down Expand Up @@ -293,14 +298,15 @@ depsFromFreezeFile verbosity = do
return deps

-- | Read the list of dependencies from the new-style freeze file.
depsFromNewFreezeFile :: Verbosity -> Maybe FilePath -> IO [PackageVersionConstraint]
depsFromNewFreezeFile verbosity mprojectFile = do
depsFromNewFreezeFile :: Verbosity -> HttpTransport -> Compiler -> Platform -> Maybe FilePath -> IO [PackageVersionConstraint]
depsFromNewFreezeFile verbosity httpTransport compiler (Platform arch os) mprojectFile = do
projectRoot <- either throwIO return =<<
findProjectRoot Nothing mprojectFile
let distDirLayout = defaultDistDirLayout projectRoot
{- TODO: Support dist dir override -} Nothing
projectConfig <- runRebuild (distProjectRootDirectory distDirLayout) $
readProjectLocalFreezeConfig verbosity distDirLayout
projectConfig <- runRebuild (distProjectRootDirectory distDirLayout) $ do
pcs <- readProjectLocalFreezeConfig verbosity httpTransport distDirLayout
pure $ instantiateProjectConfigSkeleton os arch (compilerInfo compiler) mempty pcs
let ucnstrs = map fst . projectConfigConstraints . projectConfigShared
$ projectConfig
deps = userConstraintsToDependencies ucnstrs
Expand Down
1 change: 0 additions & 1 deletion cabal-install/src/Distribution/Client/ParseUtils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,3 @@ parseConfig fieldDescrs sectionDescrs fgSectionDescrs empty str =
--
showConfig :: [FieldDescr a] -> [SectionDescr a] -> [FGSectionDescr FG.PrettyFieldGrammar a] -> a -> Disp.Doc
showConfig = ppFieldsAndSections

76 changes: 27 additions & 49 deletions cabal-install/src/Distribution/Client/ProjectConfig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ module Distribution.Client.ProjectConfig (
readGlobalConfig,
readProjectLocalExtraConfig,
readProjectLocalFreezeConfig,
parseProjectConfig,
reportParseResult,
showProjectConfig,
withProjectOrGlobalConfig,
Expand Down Expand Up @@ -504,31 +503,33 @@ withProjectOrGlobalConfig' verbosity globalConfigFlag with without = do
-- file if any, plus other global config.
--
readProjectConfig :: Verbosity
-> HttpTransport
-> Flag FilePath
-> DistDirLayout
-> Rebuild ProjectConfig
readProjectConfig verbosity configFileFlag distDirLayout = do
global <- readGlobalConfig verbosity configFileFlag
local <- readProjectLocalConfigOrDefault verbosity distDirLayout
freeze <- readProjectLocalFreezeConfig verbosity distDirLayout
extra <- readProjectLocalExtraConfig verbosity distDirLayout
-> Rebuild ProjectConfigSkeleton
readProjectConfig verbosity httpTransport configFileFlag distDirLayout = do
global <- singletonProjectConfigSkeleton <$> readGlobalConfig verbosity configFileFlag
local <- readProjectLocalConfigOrDefault verbosity httpTransport distDirLayout
freeze <- readProjectLocalFreezeConfig verbosity httpTransport distDirLayout
extra <- readProjectLocalExtraConfig verbosity httpTransport distDirLayout
return (global <> local <> freeze <> extra)


-- | Reads an explicit @cabal.project@ file in the given project root dir,
-- or returns the default project config for an implicitly defined project.
--
readProjectLocalConfigOrDefault :: Verbosity
-> HttpTransport
-> DistDirLayout
-> Rebuild ProjectConfig
readProjectLocalConfigOrDefault verbosity distDirLayout = do
-> Rebuild ProjectConfigSkeleton
readProjectLocalConfigOrDefault verbosity httpTransport distDirLayout = do
usesExplicitProjectRoot <- liftIO $ doesFileExist projectFile
if usesExplicitProjectRoot
then do
readProjectFile verbosity distDirLayout "" "project file"
readProjectFileSkeleton verbosity httpTransport distDirLayout "" "project file"
else do
monitorFiles [monitorNonExistentFile projectFile]
return defaultImplicitProjectConfig
return (singletonProjectConfigSkeleton defaultImplicitProjectConfig)

where
projectFile :: FilePath
Expand All @@ -547,66 +548,43 @@ readProjectLocalConfigOrDefault verbosity distDirLayout = do
-- or returns empty. This file gets written by @cabal configure@, or in
-- principle can be edited manually or by other tools.
--
readProjectLocalExtraConfig :: Verbosity -> DistDirLayout
-> Rebuild ProjectConfig
readProjectLocalExtraConfig verbosity distDirLayout =
readProjectFile verbosity distDirLayout "local"
readProjectLocalExtraConfig :: Verbosity -> HttpTransport -> DistDirLayout
-> Rebuild ProjectConfigSkeleton
readProjectLocalExtraConfig verbosity httpTransport distDirLayout =
readProjectFileSkeleton verbosity httpTransport distDirLayout "local"
"project local configuration file"

-- | Reads a @cabal.project.freeze@ file in the given project root dir,
-- or returns empty. This file gets written by @cabal freeze@, or in
-- principle can be edited manually or by other tools.
--
readProjectLocalFreezeConfig :: Verbosity -> DistDirLayout
-> Rebuild ProjectConfig
readProjectLocalFreezeConfig verbosity distDirLayout =
readProjectFile verbosity distDirLayout "freeze"
readProjectLocalFreezeConfig :: Verbosity -> HttpTransport ->DistDirLayout
-> Rebuild ProjectConfigSkeleton
readProjectLocalFreezeConfig verbosity httpTransport distDirLayout =
readProjectFileSkeleton verbosity httpTransport distDirLayout "freeze"
"project freeze file"

-- | Reads a named config file in the given project root dir, or returns empty.
-- | Reads a named extended (with imports and conditionals) config file in the given project root dir, or returns empty.
--
readProjectFile :: Verbosity
-> DistDirLayout
-> String
-> String
-> Rebuild ProjectConfig
readProjectFile verbosity DistDirLayout{distProjectFile}
readProjectFileSkeleton :: Verbosity -> HttpTransport -> DistDirLayout -> String -> String -> Rebuild ProjectConfigSkeleton
readProjectFileSkeleton verbosity httpTransport DistDirLayout{distProjectFile, distDownloadSrcDirectory}
extensionName extensionDescription = do
exists <- liftIO $ doesFileExist extensionFile
if exists
then do monitorFiles [monitorFileHashed extensionFile]
addProjectFileProvenance <$> liftIO readExtensionFile
pcs <- liftIO readExtensionFile
monitorFiles $ map monitorFileHashed (projectSkeletonImports pcs)
pure pcs
else do monitorFiles [monitorNonExistentFile extensionFile]
return mempty
where
extensionFile :: FilePath
extensionFile = distProjectFile extensionName

readExtensionFile :: IO ProjectConfig
readExtensionFile =
reportParseResult verbosity extensionDescription extensionFile
. (parseProjectConfig extensionFile)
=<< parseProjectSkeleton distDownloadSrcDirectory httpTransport verbosity [] extensionFile
=<< BS.readFile extensionFile

addProjectFileProvenance :: ProjectConfig -> ProjectConfig
addProjectFileProvenance config =
config {
projectConfigProvenance =
Set.insert (Explicit extensionFile) (projectConfigProvenance config)
}


-- | Parse the 'ProjectConfig' format.
--
-- For the moment this is implemented in terms of parsers for legacy
-- configuration types, plus a conversion.
--
parseProjectConfig :: FilePath -> BS.ByteString -> OldParser.ParseResult ProjectConfig
parseProjectConfig source content =
convertLegacyProjectConfig <$>
(parseLegacyProjectConfig source content)


-- | Render the 'ProjectConfig' format.
--
-- For the moment this is implemented in terms of a pretty printer for the
Expand Down
Loading