Safe Haskell | None |
---|---|
Language | Haskell2010 |
Distribution.Solver.Types.ProjectConfigPath
Synopsis
- newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)
- projectConfigPathRoot :: ProjectConfigPath -> FilePath
- nullProjectConfigPath :: ProjectConfigPath
- consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
- unconsProjectConfigPath :: ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath)
- docProjectConfigPath :: ProjectConfigPath -> Doc
- docProjectConfigFiles :: [ProjectConfigPath] -> Doc
- cyclicalImportMsg :: ProjectConfigPath -> Doc
- untrimmedUriImportMsg :: Doc -> ProjectConfigPath -> Doc
- docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc
- quoteUntrimmed :: FilePath -> Doc
- isCyclicConfigPath :: ProjectConfigPath -> Bool
- isTopLevelConfigPath :: ProjectConfigPath -> Bool
- isUntrimmedUriConfigPath :: ProjectConfigPath -> Bool
- canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath
Project Config Path Manipulation
newtype ProjectConfigPath Source #
Path to a configuration file, either a singleton project root, or a longer
list representing a path to an import. The path is a non-empty list that we
build up by prepending relative imports with consProjectConfigPath
.
An import can be a URI, such as a stackage cabal.config, but we do not support URIs in the middle of the path, URIs that import other URIs, or URIs that import local files.
List elements are relative to each other but once canonicalized, elements are relative to the directory of the project root.
Constructors
ProjectConfigPath (NonEmpty FilePath) |
Instances
projectConfigPathRoot :: ProjectConfigPath -> FilePath Source #
The root of the path, the project itself.
nullProjectConfigPath :: ProjectConfigPath Source #
Used by some tests as a dummy "unused" project root.
consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath Source #
Prepends the path of the importee to the importer path.
unconsProjectConfigPath :: ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath) Source #
Split the path into the importee and the importer path.
Messages
docProjectConfigPath :: ProjectConfigPath -> Doc Source #
Renders the path like this;
D.config imported by: C.config imported by: B.config imported by: A.project
>>>
render . docProjectConfigPath $ ProjectConfigPath $ "D.config" :| ["C.config", "B.config", "A.project"]
"D.config\n imported by: C.config\n imported by: B.config\n imported by: A.project"
docProjectConfigFiles :: [ProjectConfigPath] -> Doc Source #
Renders the paths as a list without showing which path imports another, like this;
- cabal.project - project-cabal/constraints.config - project-cabal/ghc-latest.config - project-cabal/ghc-options.config - project-cabal/pkgs.config - project-cabal/pkgs/benchmarks.config - project-cabal/pkgs/buildinfo.config - project-cabal/pkgs/cabal.config - project-cabal/pkgs/install.config - project-cabal/pkgs/integration-tests.config - project-cabal/pkgs/tests.config
>>>
:{
do let ps = [ ProjectConfigPath ("cabal.project" :| []) , ProjectConfigPath ("project-cabal/constraints.config" :| ["cabal.project"]) , ProjectConfigPath ("project-cabal/ghc-latest.config" :| ["cabal.project"]) , ProjectConfigPath ("project-cabal/ghc-options.config" :| ["cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs.config" :| ["cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/benchmarks.config" :| ["project-cabal/pkgs.config","cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/buildinfo.config" :| ["project-cabal/pkgs.config","cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/cabal.config" :| ["project-cabal/pkgs.config","cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/install.config" :| ["project-cabal/pkgs.config","cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/integration-tests.config" :| ["project-cabal/pkgs.config","cabal.project"]) , ProjectConfigPath ("project-cabal/pkgs/tests.config" :| ["project-cabal/pkgs.config","cabal.project"]) ] return . render $ docProjectConfigFiles ps :} "- cabal.project\n- project-cabal/constraints.config\n- project-cabal/ghc-latest.config\n- project-cabal/ghc-options.config\n- project-cabal/pkgs.config\n- project-cabal/pkgs/benchmarks.config\n- project-cabal/pkgs/buildinfo.config\n- project-cabal/pkgs/cabal.config\n- project-cabal/pkgs/install.config\n- project-cabal/pkgs/integration-tests.config\n- project-cabal/pkgs/tests.config"
cyclicalImportMsg :: ProjectConfigPath -> Doc Source #
A message for a cyclical import, a "cyclical import of".
untrimmedUriImportMsg :: Doc -> ProjectConfigPath -> Doc Source #
A message for an import that has leading or trailing spaces.
quoteUntrimmed :: FilePath -> Doc Source #
If the path has leading or trailing spaces then show it quoted.
Checks and Normalization
isCyclicConfigPath :: ProjectConfigPath -> Bool Source #
Check if the path has duplicates. A cycle of imports is not allowed. This
check should only be done after the path has been canonicalized with
canonicalizeConfigPath
. This is because the import path may contain paths
that are the same in relation to their importers but different in relation to
the project root directory.
isTopLevelConfigPath :: ProjectConfigPath -> Bool Source #
Check if the project config path is top-level, meaning it was not included by some other project config.
isUntrimmedUriConfigPath :: ProjectConfigPath -> Bool Source #
Check if the last segment of the path (root or importee) is a URI that has leading or trailing spaces.
canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath Source #
Normalizes and canonicalizes a path removing .
and '..' indirections.
Makes the path relative to the given directory (typically the project root)
instead of relative to the file it was imported from.
It converts paths like this:
hops-0.project └─ hops/hops-1.config └─ ../hops-2.config └─ hops/hops-3.config └─ ../hops-4.config └─ hops/hops-5.config └─ ../hops-6.config └─ hops/hops-7.config └─ ../hops-8.config └─ hops/hops-9.config
Into paths like this:
hops-0.project └─ hops/hops-1.config └─ hops-2.config └─ hops/hops-3.config └─ hops-4.config └─ hops/hops-5.config └─ hops-6.config └─ hops/hops-7.config └─ hops-8.config └─ hops/hops-9.config
That way we have hops-8.config
instead of
.hops..hops..hops..hops../hops-8.config
.
Let's see how canonicalizePath
works that is used in the implementation
then we'll see how canonicalizeConfigPath
works.
>>>
let d = testDir
>>>
makeRelative d <$> canonicalizePath (d </> "hops/../hops/../hops/../hops/../hops-8.config")
"hops-8.config"
>>>
let d = testDir
>>>
p <- canonicalizeConfigPath d (ProjectConfigPath $ (d </> "hops/../hops/../hops/../hops/../hops-8.config") :| [])
>>>
render $ docProjectConfigPath p
"hops-8.config"
>>>
:{
do let expected = unlines [ "hops/hops-9.config" , " imported by: hops-8.config" , " imported by: hops/hops-7.config" , " imported by: hops-6.config" , " imported by: hops/hops-5.config" , " imported by: hops-4.config" , " imported by: hops/hops-3.config" , " imported by: hops-2.config" , " imported by: hops/hops-1.config" , " imported by: hops-0.project" ] let d = testDir let configPath = ProjectConfigPath ("hops/hops-9.config" :| [ "../hops-8.config" , "hops/hops-7.config" , "../hops-6.config" , "hops/hops-5.config" , "../hops-4.config" , "hops/hops-3.config" , "../hops-2.config" , "hops/hops-1.config" , d </> "hops-0.project"]) p <- canonicalizeConfigPath d configPath return $ expected == render (docProjectConfigPath p) ++ "\n" :} True
"A string is a valid URL potentially surrounded by spaces if, after stripping leading and trailing whitespace from it, it is a valid URL." W3CHTML5URLs
Trailing spaces for ProjectConfigPath
URLs are trimmed.
>>>
p <- canonicalizeConfigPath "" (ProjectConfigPath $ ("https://www.stackage.org/nightly-2024-12-05/cabal.config ") :| [])
>>>
render $ docProjectConfigPath p
"https://www.stackage.org/nightly-2024-12-05/cabal.config"
>>>
let d = testDir
>>>
p <- canonicalizeConfigPath d (ProjectConfigPath $ ("https://www.stackage.org/nightly-2024-12-05/cabal.config ") :| [d </> "cabal.project"])
>>>
render $ docProjectConfigPath p
"https://www.stackage.org/nightly-2024-12-05/cabal.config\n imported by: cabal.project"