Skip to content

Duplicate project import as a warning only#10933

Merged
mergify[bot] merged 1 commit into
haskell:masterfrom
cabalism:fix/y-fork-project-import-warning-only
May 25, 2026
Merged

Duplicate project import as a warning only#10933
mergify[bot] merged 1 commit into
haskell:masterfrom
cabalism:fix/y-fork-project-import-warning-only

Conversation

@philderbeast
Copy link
Copy Markdown
Collaborator

@philderbeast philderbeast commented Apr 21, 2025

Depends-on #11773.

I'll squash commits before applying the merge label if this pull request is approved.

Pretty much the same as #9933 but gives a warning instead of an error when duplicate imports that are not cyclical are detected. I did this work in Oct 2024 but didn't raise a pull request for it then. I was reporting the warning during parsing but needed an IORef for that. After Matthew Pickering suggesting it, I'm now doing the reporting after parsing.

  • Add a new module cabal-install/src/Distribution/Client/ProjectConfig/Import.hs and move some stuff there from cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs that was only ever used in cabal-install.
  • Shorten the haddock sections in Distribution.Client.ProjectConfig.Legacy so that they don't wrap when rendered.

For messages, I added some doctests and ended up with two ways of comparing ProjectConfigPath.

-- | A comparison that puts projects first, URLs last and sorts the other paths
-- lexically.
compareLexically :: ProjectConfigPath -> ProjectConfigPath -> Ordering

-- | A comparison that puts projects first, URLs last and sorts the other paths
-- by putting longer paths after shorter ones as measured by the number of path
-- segments. If still equal, then sorting is lexical.
compareSegmentally:: ProjectConfigPath -> ProjectConfigPath -> Ordering

I changed the project skeleton, retaining the info we have already (because we have to read the file), that the item is a local file or a URI.

- type ProjectConfigSkeleton = CondTree ConfVar ([ProjectConfigPath], ProjectConfig)
+ type ProjectConfigSkeleton = CondTree ConfVar ([(Maybe URI, ProjectConfigPath)], ProjectConfig)

With that information, I'm able to avoid monitoring remote files:

- monitorFiles $ map monitorFileHashed (projectConfigPathRoot <$> projectSkeletonImports pcs)
+ monitorFiles
+  [ monitorFileHashed (projectConfigPathRoot path)
+  | (Nothing, path) <- projectSkeletonImports pcs
+  ]

I added another type to help classify between, root, file import and URI import. I used this to help detect and report duplicates:

-- | Isomorphic with 'ProjectConfigPath' but with separate constructors for the
-- root, imported file and imported URI.
data ProjectNode a where
  ProjectRoot :: FilePath -> ProjectNode ProjectFilePath
  ProjectFileImport :: FilePath -> ProjectConfigPath -> ProjectNode FilePath
  ProjectUriImport :: URI -> ProjectConfigPath -> ProjectNode URI

I developed this with ghc-9.14.1 and required some extra type annotations for prior GHC versions to compile, those in seenImport and instance Ord (ProjectNode a).

I moved the following types and functions to the Import module too. These were either in the Legacy parser or in both parsers.

type ProjectConfigSkeleton = CondTree ConfVar ([(Maybe URI, ProjectConfigPath)], ProjectConfig)

projectSkeletonImports :: ProjectConfigSkeleton -> [(Maybe URI, ProjectConfigPath)]
projectSkeletonImports = fst . view traverseCondTreeA

fetchImportConfig
  :: FilePath
  -> HttpTransport
  -> Verbosity
  -> FilePath
  -> ProjectConfigPath
  -> IO (Maybe URI, BS.ByteString)

@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from 16a11bd to 95ec86a Compare April 21, 2025 15:41
Copy link
Copy Markdown
Collaborator

@ulysses4ever ulysses4ever left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment thread cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs Outdated
Comment thread cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs Outdated
Comment thread cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs Outdated
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 3 times, most recently from c230d20 to b61e031 Compare April 27, 2025 00:52
@sebright sebright added the re: project-file Concerning cabal.project files label May 8, 2025
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from a926d99 to ec9ea13 Compare July 6, 2025 19:58
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from ec9ea13 to 7ab2b20 Compare July 15, 2025 14:19
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 2 times, most recently from d5552f3 to 0c99ae5 Compare July 25, 2025 12:25
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 3 times, most recently from 7fe8c13 to 61d8a74 Compare August 11, 2025 15:10
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 2 times, most recently from fd40a31 to 814b84c Compare August 11, 2025 19:29
@philderbeast
Copy link
Copy Markdown
Collaborator Author

I've updated the tests and moved them to cabal-testsuite/PackageTests/ProjectImport/UniquePathDuplicates/cabal.test.hs, fixing them for Windows and for the changes in the project parser.

@philderbeast
Copy link
Copy Markdown
Collaborator Author

This pull request is complete for the --project-file-parser=legacy. I'd prefer to add this feature to the parsec parser on a separate pull request.

@mpickering
Copy link
Copy Markdown
Collaborator

Is there an issue which describe the problem or feature this PR is adding?

@mpickering
Copy link
Copy Markdown
Collaborator

mpickering commented Aug 12, 2025

This pull request is complete for the --project-file-parser=legacy. I'd prefer to add this feature to the parsec parser on a separate pull request.

In the next + 1 release the legacy parser will be removed, so I would advise implementing the feature firstly for the parsec parser.

@philderbeast
Copy link
Copy Markdown
Collaborator Author

Is there an issue which describe the problem or feature this PR is adding?

From the description in this pull request:

Pretty much the same as #9933

From the description of #9933:

A follow on from #9578.

From the description of #9578:

Fixes #9562.

Before I started working on this stuff, there were some tests for cyclical imports but none for duplicates without cycles. This pull request adds these tests and reporting those duplicates as a warning when we'd punted on including this reporting as an error in an earlier pull request in the chain.

Comment thread cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs Outdated
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 2 times, most recently from 3021e83 to bd7c594 Compare August 14, 2025 13:28
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 2 times, most recently from 557c9b3 to f62f929 Compare August 27, 2025 13:09
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from f62f929 to 90cafdb Compare March 12, 2026 12:59
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 8 times, most recently from a6476d4 to c8e778f Compare May 19, 2026 19:49
@ulysses4ever
Copy link
Copy Markdown
Collaborator

- type ProjectConfigSkeleton = CondTree ConfVar ([ProjectConfigPath], ProjectConfig)
+ type ProjectConfigSkeleton = CondTree ConfVar ([(Maybe URI, ProjectConfigPath)], ProjectConfig)

the level of nestedness is a little much here. Would it be possible to have a type synonym (at least) for (Maybe URI, ProjectConfigPath)? Something like ProjectConfigPathWithProvenance or some such.

@philderbeast
Copy link
Copy Markdown
Collaborator Author

philderbeast commented May 21, 2026

- (Maybe URI, ProjectConfigPath)
+ ProjectConfigPathWithProvenance

The suggested type synonym is longer than the tuple and I'm not able to see what it is at a glance. Once we get rid of the legacy parser, there'll be only one type signature using this 2-tuple outside of the Distribution.Client.ProjectConfig.Import module:

sanityWalkBranch :: CondBranch ConfVar ([ProjectConfigPath], ProjectConfig) -> ParseResult ProjectFileSource ()

@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch 2 times, most recently from 9a3b1d2 to 743a236 Compare May 22, 2026 15:51
@philderbeast
Copy link
Copy Markdown
Collaborator Author

philderbeast commented May 22, 2026

@geekosaur and @ulysses4ever thanks for your approvals. I've resolved all open review comments and will add the merge me label when it has passed the check run, unless you have any further objections?

@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from 743a236 to 976109a Compare May 22, 2026 15:58
@philderbeast philderbeast added merge me Tell Mergify Bot to merge and removed attention: needs-review labels May 22, 2026
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from 976109a to dbb260b Compare May 22, 2026 20:01
@mergify mergify Bot added the ready and waiting Mergify is waiting out the cooldown period label May 22, 2026
- Add Y-forking import test
- A test for detecting when the same config is imported via many different paths
- Error on duplicate imports
- Do the filtering in duplicateImportMsg
- Use duplicateImportMsg for cycles too
- Add haddocks to IORef parameter
- Add changelog entry
- Use ordNub instead of nub
- Use NubList
- Share implement of duplicate and cyclical messages
- Update expectation for non-cyclical duplicate import
- Only show a warning
- Add woops project with a time cost
- Use noticeDoc instead of warn
- Render duplicate imports
- Add Ord instance for Dupes, sort on dupesNormLocPath
- Fixups after rebase
- Satisfy hlint
- Remove -XMultiWayIf
- Remove mention of yops from the changelog
- Satisfy fix-whitespace
- Test with a time cost of duplicate imports
- Fewer imports from PrettyPrint qualified as Disp
- Add data ProjectImport replacing tuples
- Combine fields as ProjectImport
- Rename field to dupesImports
- Add haddocks to Dupes fields
- Mark test as flaky
- Any test accessing stackage seems susceptible
- Move unique duplicates to own test
- Use legacy parser for path duplicates test
- Add foo.cabal package so that packages exist
- Satisfy fix-whitespace
- Use local version of lts-21.25
- Remove repo
- Use </> for expected paths
- Note that this change gives a warning.
- Exclude lts-21.25.config from typos
- Detect duplicate imports after parsing
- Merge upstream
- Update duplicate import counts
- Satisfy fourmolu
- Move duplicate detection to calling module
- Add parsing module haddock section header
- Export only reportDuplicateImports
- Test all project parser options
- Add script tests
- Add haddocks to reportDuplicateImportsh
- Use Data.Function ((&)) pipelining
- Inline do blockh
- Satisfy fix-whitespace
- Redo Ord Dupes
- Try to enforce sorting
- Add docs to ProjectImport
- Add instances & doctests for sorting ProjectImport
- Fix sorting of ProjectConfigPath
- Update test expectation with correct sorting
- Compare versions of compare
- Update cabal.out for dedup tests
- Rename to compareForDisplay
- Add more detail to docProjectConfigFiles docs
- Add haddocks and rename comparisons
- Don't repeat the root comment
- Pattern match on NonEmpty not List
- Sort expectation by import chain length
- Use GADTs for ProjectImport
- Satisfy hlint, remove unused LANGUAGE pragmas
- Bubble up Maybe URI
- Add ProjectRoot constructorh
- Rename ProjectImport to ProjectNode
- Add Maybe URI to project skeleton
- Use ProjectFilePath
- Satisfy hlint
- Add projectNodes
- Redo detectDupes
- Move duplicate imports to Import module
- Move fetchImportConfig to Import module
- Don't export parseProjectSkeleton
- Don't re-export ProjectConfigSkeleton
- Remove unnecessary primes
- Add splitImports
- Remove ProjectNodes and projectNodes
- Move stuff to Client.ProjectConfig.Import
- Fixup after rebase
- Satisfy fourmolu
- Don't monitor (Nothing :: Maybe URI)
- Add type annotation for older ghc versions
- Setup for doctests
- Need -XConstraintKinds with older ghcsh
- Update .out files for UniquePathDuplicates
- Don't repeat recordMode
- Remove +legacy-comparison
- Note significance in changelog and movements
- Less indent
- Remove redundant comparison
- Hide newtype ProjectFilePath
- Don't export duplicateImportMsg or ProjectNode
- Gut lts-21.25.config but leave notes
@philderbeast philderbeast force-pushed the fix/y-fork-project-import-warning-only branch from dbb260b to 246537a Compare May 24, 2026 00:18
@philderbeast
Copy link
Copy Markdown
Collaborator Author

@mergify refresh

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 25, 2026

refresh

✅ Pull request refreshed

@philderbeast
Copy link
Copy Markdown
Collaborator Author

@mergify queue

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 25, 2026

Merge Queue Status

This pull request spent 1 hour 47 minutes 48 seconds in the queue, including 1 hour 36 minutes 52 seconds running CI.

Waiting for any of
  • check-neutral = Validate post job
  • check-skipped = Validate post job
  • check-success = Validate post job
All conditions
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Validate post job
    • check-skipped = Validate post job
    • check-success = Validate post job
  • #approved-reviews-by >= 2 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Doctest Cabal
    • check-neutral = Doctest Cabal
    • check-skipped = Doctest Cabal
  • any of [🛡 GitHub branch protection]:
    • check-success = Meta checks
    • check-neutral = Meta checks
    • check-skipped = Meta checks
  • any of [🛡 GitHub branch protection]:
    • check-success = docs/readthedocs.org:cabal
    • check-neutral = docs/readthedocs.org:cabal
    • check-skipped = docs/readthedocs.org:cabal
  • any of [🛡 GitHub branch protection]:
    • check-success = fourmolu
    • check-neutral = fourmolu
    • check-skipped = fourmolu
  • any of [🛡 GitHub branch protection]:
    • check-success = hlint
    • check-neutral = hlint
    • check-skipped = hlint
  • any of [🛡 GitHub branch protection]:
    • check-success = Bootstrap post job
    • check-neutral = Bootstrap post job
    • check-skipped = Bootstrap post job
  • any of [🛡 GitHub branch protection]:
    • check-success = whitespace
    • check-neutral = whitespace
    • check-skipped = whitespace
  • any of [🛡 GitHub branch protection]:
    • check-success = Check sdist post job
    • check-neutral = Check sdist post job
    • check-skipped = Check sdist post job
  • any of [🛡 GitHub branch protection]:
    • check-success = Changelogs
    • check-neutral = Changelogs
    • check-skipped = Changelogs

Reason

The merge conditions cannot be satisfied due to failing checks

Failing checks:

Hint

You may have to fix your CI before adding the pull request to the queue again.
If you update this pull request, to fix the CI, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

@philderbeast
Copy link
Copy Markdown
Collaborator Author

This pull request was dequeued because of a failing run. I reran that failing run and it succeeded. @Mikolaj, @ulysses4ever, @geekosaur is this something that mergify could do itself, try the failing job once more before dequeuing?

The job that failed and caused the dequeue as reported earlier in this thread:

https://github.com/haskell/cabal/actions/runs/26403491730/job/77734323407

The run that passed when I reran its failed jobs:

https://github.com/haskell/cabal/actions/runs/26403491730

@philderbeast
Copy link
Copy Markdown
Collaborator Author

@mergify queue

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 25, 2026

Merge Queue Status

This pull request spent 2 hours 3 seconds in the queue, including 1 hour 48 minutes 2 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 2 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Doctest Cabal
    • check-neutral = Doctest Cabal
    • check-skipped = Doctest Cabal
  • any of [🛡 GitHub branch protection]:
    • check-success = Meta checks
    • check-neutral = Meta checks
    • check-skipped = Meta checks
  • any of [🛡 GitHub branch protection]:
    • check-success = docs/readthedocs.org:cabal
    • check-neutral = docs/readthedocs.org:cabal
    • check-skipped = docs/readthedocs.org:cabal
  • any of [🛡 GitHub branch protection]:
    • check-success = Validate post job
    • check-neutral = Validate post job
    • check-skipped = Validate post job
  • any of [🛡 GitHub branch protection]:
    • check-success = fourmolu
    • check-neutral = fourmolu
    • check-skipped = fourmolu
  • any of [🛡 GitHub branch protection]:
    • check-success = hlint
    • check-neutral = hlint
    • check-skipped = hlint
  • any of [🛡 GitHub branch protection]:
    • check-success = Bootstrap post job
    • check-neutral = Bootstrap post job
    • check-skipped = Bootstrap post job
  • any of [🛡 GitHub branch protection]:
    • check-success = whitespace
    • check-neutral = whitespace
    • check-skipped = whitespace
  • any of [🛡 GitHub branch protection]:
    • check-success = Check sdist post job
    • check-neutral = Check sdist post job
    • check-skipped = Check sdist post job
  • any of [🛡 GitHub branch protection]:
    • check-success = Changelogs
    • check-neutral = Changelogs
    • check-skipped = Changelogs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge me Tell Mergify Bot to merge re: project-file Concerning cabal.project files ready and waiting Mergify is waiting out the cooldown period

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants