cabal-install-solver-3.12.1.0: The command-line interface for Cabal and Hackage.

Safe Haskell | None
Language | Haskell2010

Distribution.Solver.Types.ProjectConfigPath

Contents

- Project Config Path Manipulation
- Messages
- Checks and Normalization

Synopsis

- newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)
- projectConfigPathRoot :: ProjectConfigPath -> FilePath
- nullProjectConfigPath :: ProjectConfigPath
- consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
- docProjectConfigPath :: ProjectConfigPath -> Doc
- docProjectConfigPaths :: [ProjectConfigPath] -> Doc
- cyclicalImportMsg :: ProjectConfigPath -> Doc
- docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc
- isCyclicConfigPath :: 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

Instances details

Structured ProjectConfigPath Source # |
Instance details Defined in Distribution.Solver.Types.ProjectConfigPath Methods structure :: Proxy ProjectConfigPath -> Structure Source # structureHash' :: Tagged ProjectConfigPath MD5
Binary ProjectConfigPath Source # |
Instance details Defined in Distribution.Solver.Types.ProjectConfigPath Methods put :: ProjectConfigPath -> Put Source # get :: Get ProjectConfigPath Source # putList :: [ProjectConfigPath] -> Put Source #
Generic ProjectConfigPath Source # |

Instance details

Defined in Distribution.Solver.Types.ProjectConfigPath

Associated Types

type Rep ProjectConfigPath |

Instance details

Defined in Distribution.Solver.Types.ProjectConfigPath

type Rep ProjectConfigPath = D1 ('MetaData "ProjectConfigPath" "Distribution.Solver.Types.ProjectConfigPath" "cabal-install-solver-3.12.1.0-5dSETZK2idVHohhzkfJS3u" 'True) (C1 ('MetaCons "ProjectConfigPath" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (NonEmpty FilePath))))

Methods

from :: ProjectConfigPath -> Rep ProjectConfigPath x Source #

to :: Rep ProjectConfigPath x -> ProjectConfigPath Source #

Show ProjectConfigPath Source # |
Instance details Defined in Distribution.Solver.Types.ProjectConfigPath Methods showsPrec :: Int -> ProjectConfigPath -> ShowS Source # show :: ProjectConfigPath -> String Source # showList :: [ProjectConfigPath] -> ShowS Source #
Eq ProjectConfigPath Source # |
Instance details Defined in Distribution.Solver.Types.ProjectConfigPath Methods (==) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source # (/=) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source #
Ord ProjectConfigPath Source # |

Instance details

Defined in Distribution.Solver.Types.ProjectConfigPath

Methods

compare :: ProjectConfigPath -> ProjectConfigPath -> Ordering Source #

(<) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source #

(<=) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source #

(>) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source #

(>=) :: ProjectConfigPath -> ProjectConfigPath -> Bool Source #

max :: ProjectConfigPath -> ProjectConfigPath -> ProjectConfigPath Source #

min :: ProjectConfigPath -> ProjectConfigPath -> ProjectConfigPath Source #

type Rep ProjectConfigPath Source # |

Instance details

Defined in Distribution.Solver.Types.ProjectConfigPath

type Rep ProjectConfigPath = D1 ('MetaData "ProjectConfigPath" "Distribution.Solver.Types.ProjectConfigPath" "cabal-install-solver-3.12.1.0-5dSETZK2idVHohhzkfJS3u" 'True) (C1 ('MetaCons "ProjectConfigPath" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (NonEmpty FilePath))))

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.

# 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.confign imported by: C.confign imported by: B.confign imported by: A.project"

docProjectConfigPaths :: [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-cabalpkgsbenchmarks.config - project-cabalpkgsbuildinfo.config - project-cabalpkgscabal.config - project-cabalpkgsinstall.config - project-cabalpkgsintegration-tests.config - project-cabalpkgstests.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 $ docProjectConfigPaths 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, assuming the head of the path is the duplicate.

docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc Source #

# 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.

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