HORIZON HASKELLDocslts/ghc-9.14.x3e2d5682026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · 3e2d568 · 2026-10-11

Modulecabal-install-solver-3.16.0.0Haskell2010

Distribution.Solver.Types.ProjectConfigPath

  • 1 type
  • 14 values

Project Config Path Manipulation

5 declarations
newtypenewtype ProjectConfigPath
#

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.

Instances8Eq, Ord, Show, Generic, Binary, Pretty, …
  • Eq ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • Ord ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath

    Sorts URIs after local file paths and longer file paths after shorter ones as measured by the number of path segments. If still equal, then sorting is lexical.

    The project itself, a single element root path, compared to any of the configuration paths it imports, should always sort first. Comparing one project root path against another is done lexically.

    For comparison purposes, path separators are normalized to the buildOS platform's path separator.

    Example3 expressions
    let abFwd = ProjectConfigPath $ "a/b.config" :| []let abBwd = ProjectConfigPath $ "a\\b.config" :| []compare abFwd abBwdEQ
  • Show ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • Generic ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • Binary ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • Pretty ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • Structured ProjectConfigPathDefined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath
  • type Rep ProjectConfigPath = D1 ('MetaData "ProjectConfigPath" "Distribution.Solver.Types.ProjectConfigPath" "cabal-install-solver-3.16.0.0-1EUIXvFUry24MkMMJQfegz" 'True) (C1 ('MetaCons "ProjectConfigPath" 'PrefixI 'False) (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (NonEmpty FilePath))))Defined in cabal-install-solver-3.16.0.0 · Distribution.Solver.Types.ProjectConfigPath

Messages

6 declarations

Renders the path like this;

D.config
  imported by: C.config
  imported by: B.config
  imported by: A.project
Example1 expression
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"

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
Example1 expression
:{  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"

Checks and Normalization

4 declarations

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.

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.

Example2 expressions
let d = testDirmakeRelative d <$> canonicalizePath (d </> "hops/../hops/../hops/../hops/../hops-8.config")"hops-8.config"
Example3 expressions
let d = testDirp <- canonicalizeConfigPath d (ProjectConfigPath $ (d </> "hops/../hops/../hops/../hops/../hops-8.config") :| [])render $ docProjectConfigPath p"hops-8.config"
Example1 expression
:{  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.

Example2 expressions
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"
Example3 expressions
let d = testDirp <- 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"