Skip to content

Commit 2040d21

Browse files
authored
Merge pull request #10646 from cabalism/fix/path-sep-duplicates
Deduplicate path separator duplicates
2 parents e98bc7f + 32b820b commit 2040d21

File tree

24 files changed

+766
-185
lines changed

24 files changed

+766
-185
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,12 @@ description: {
395395
}
396396
```
397397

398-
Changelogs may also be written in "markdown-frontmatter" format. This is useful if your
399-
description contains braces, which must be escaped with backslashes in `.cabal` file
400-
format. The front matter is in YAML syntax, not `.cabal` file syntax, and the file
398+
Changelogs may also be written in "markdown-frontmatter" format. This is useful
399+
if your description contains braces, which must be escaped with backslashes in
400+
`.cabal` file format. Another benefit of using an `.md` extension with your
401+
changelog is that it will be checked for typos.
402+
403+
The front matter is in YAML syntax, not `.cabal` file syntax, and the file
401404
_must_ begin with a line containing only hyphens.
402405

403406
```markdown

cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,17 @@ import Data.Coerce (coerce)
3232
import Data.List.NonEmpty ((<|))
3333
import Network.URI (parseURI, parseAbsoluteURI)
3434
import System.Directory
35-
import System.FilePath
35+
import System.FilePath hiding (splitPath)
36+
import qualified System.FilePath as FP (splitPath)
37+
import qualified System.FilePath.Posix as Posix
38+
import qualified System.FilePath.Windows as Windows
3639
import qualified Data.List.NonEmpty as NE
3740
import Distribution.Solver.Modular.Version (VR)
3841
import Distribution.Pretty (prettyShow)
3942
import Distribution.Utils.String (trim)
4043
import Text.PrettyPrint
4144
import Distribution.Simple.Utils (ordNub)
45+
import Distribution.System (OS(Windows), buildOS)
4246

4347
-- | Path to a configuration file, either a singleton project root, or a longer
4448
-- list representing a path to an import. The path is a non-empty list that we
@@ -61,6 +65,14 @@ newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)
6165
-- The project itself, a single element root path, compared to any of the
6266
-- configuration paths it imports, should always sort first. Comparing one
6367
-- project root path against another is done lexically.
68+
--
69+
-- For comparison purposes, path separators are normalized to the @buildOS@
70+
-- platform's path separator.
71+
--
72+
-- >>> let abFwd = ProjectConfigPath $ "a/b.config" :| []
73+
-- >>> let abBwd = ProjectConfigPath $ "a\\b.config" :| []
74+
-- >>> compare abFwd abBwd
75+
-- EQ
6476
instance Ord ProjectConfigPath where
6577
compare pa@(ProjectConfigPath (NE.toList -> as)) pb@(ProjectConfigPath (NE.toList -> bs)) =
6678
case (as, bs) of
@@ -69,7 +81,7 @@ instance Ord ProjectConfigPath where
6981
-- this though, do a comparison anyway when both sides have length
7082
-- 1. The root path, the project itself, should always be the first
7183
-- path in a sorted listing.
72-
([a], [b]) -> compare a b
84+
([a], [b]) -> compare (splitPath a) (splitPath b)
7385
([_], _) -> LT
7486
(_, [_]) -> GT
7587

@@ -83,6 +95,16 @@ instance Ord ProjectConfigPath where
8395
P.<> compare (length aPaths) (length bPaths)
8496
P.<> compare aPaths bPaths
8597
where
98+
splitPath = FP.splitPath . normSep where
99+
normSep p =
100+
if buildOS == Windows
101+
then
102+
Windows.joinPath $ Windows.splitDirectories
103+
[if Posix.isPathSeparator c then Windows.pathSeparator else c| c <- p]
104+
else
105+
Posix.joinPath $ Posix.splitDirectories
106+
[if Windows.isPathSeparator c then Posix.pathSeparator else c| c <- p]
107+
86108
aPaths = splitPath <$> as
87109
bPaths = splitPath <$> bs
88110
aImporters = snd $ unconsProjectConfigPath pa

cabal-testsuite/PackageTests/BuildDeps/InternalLibrary2/setup.test.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ main = setupAndCabalTest . withPackageDb $ do
66
assertEqual
77
("executable should have linked with the internal library")
88
("foo foo myLibFunc internal")
9-
(concatOutput (resultOutput r))
9+
(lineBreaksToSpaces $ resultOutput r)

cabal-testsuite/PackageTests/BuildDeps/InternalLibrary3/setup.test.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ main = setupAndCabalTest . withPackageDb $ do
88
assertEqual
99
("executable should have linked with the internal library")
1010
("foo foo myLibFunc internal")
11-
(concatOutput (resultOutput r))
11+
(lineBreaksToSpaces $ resultOutput r)

cabal-testsuite/PackageTests/CheckSetup/setup.test.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ main = cabalTest $ do
1313
"The dependency 'setup-depends: 'base' does not specify "
1414
++ "an upper bound on the version number"
1515

16+
-- Replace line breaks with spaces in the haystack so that we can search
17+
-- for a string that wraps lines.
18+
let lineBreakBlind = needleHaystack{txHaystack = txContainsId{txFwd = lineBreaksToSpaces}}
19+
1620
-- Asserts for the desired check messages after configure.
17-
assertOutputContains libError1 checkResult
18-
assertOutputContains libError2 checkResult
21+
assertOn lineBreakBlind libError1 checkResult
22+
assertOn lineBreakBlind libError2 checkResult
1923

2024
return ()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
When using configuration from:
2+
- cabal-missing-package.project
3+
- missing/pkgs.config
4+
- missing/pkgs/default.config
5+
The following errors occurred:
6+
- The package location 'pkg-doesnt-exist' does not exist.

cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs

Lines changed: 11 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Test.Cabal.Prelude
2-
3-
normalizeWindowsOutput :: String -> String
4-
normalizeWindowsOutput = if isWindows then map (\x -> case x of '/' -> '\\'; _ -> x) else id
2+
import Test.Cabal.OutputNormalizer
3+
import Data.Function ((&))
4+
import Data.Functor ((<&>))
55

66
main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
77
let log = recordHeader . pure
@@ -79,7 +79,7 @@ main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
7979
-- +-- etc
8080
log "checking that cyclical check catches a same file name that imports itself"
8181
cyclical4a <- fails $ cabal' "v2-build" [ "--project-file=cyclical-same-filename-out-out-self.project" ]
82-
assertOutputContains (normalizeWindowsOutput "cyclical import of same-filename/cyclical-same-filename-out-out-self.config") cyclical4a
82+
assertOutputContains (normalizePathSeparators "cyclical import of same-filename/cyclical-same-filename-out-out-self.config") cyclical4a
8383

8484
-- +-- cyclical-same-filename-out-out-backback.project
8585
-- +-- cyclical-same-filename-out-out-backback.config
@@ -111,89 +111,9 @@ main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
111111
-- +-- hops/hops-9.config (no further imports so not cyclical)
112112
log "checking that imports work skipping into a subfolder and then back out again and again"
113113
hopping <- cabal' "v2-build" [ "--project-file=hops-0.project" ]
114-
assertOutputContains "Configuration is affected by the following files" hopping
115-
assertOutputContains "- hops-0.project" hopping
116-
117-
assertOutputContains
118-
(normalizeWindowsOutput "- hops-2.config \
119-
\ imported by: hops/hops-1.config \
120-
\ imported by: hops-0.project")
121-
hopping
122-
123-
assertOutputContains
124-
(normalizeWindowsOutput "- hops-4.config \
125-
\ imported by: hops/hops-3.config \
126-
\ imported by: hops-2.config \
127-
\ imported by: hops/hops-1.config \
128-
\ imported by: hops-0.project")
129-
hopping
130-
131-
assertOutputContains
132-
(normalizeWindowsOutput "- hops-6.config \
133-
\ imported by: hops/hops-5.config \
134-
\ imported by: hops-4.config \
135-
\ imported by: hops/hops-3.config \
136-
\ imported by: hops-2.config \
137-
\ imported by: hops/hops-1.config \
138-
\ imported by: hops-0.project")
139-
hopping
140-
141-
assertOutputContains
142-
(normalizeWindowsOutput "- hops-8.config \
143-
\ imported by: hops/hops-7.config \
144-
\ imported by: hops-6.config \
145-
\ imported by: hops/hops-5.config \
146-
\ imported by: hops-4.config \
147-
\ imported by: hops/hops-3.config \
148-
\ imported by: hops-2.config \
149-
\ imported by: hops/hops-1.config \
150-
\ imported by: hops-0.project")
151-
hopping
152114

153-
assertOutputContains
154-
(normalizeWindowsOutput "- hops/hops-1.config \
155-
\ imported by: hops-0.project")
156-
hopping
157-
158-
assertOutputContains
159-
(normalizeWindowsOutput "- hops/hops-3.config \
160-
\ imported by: hops-2.config \
161-
\ imported by: hops/hops-1.config \
162-
\ imported by: hops-0.project")
163-
hopping
164-
165-
assertOutputContains
166-
(normalizeWindowsOutput "- hops/hops-5.config \
167-
\ imported by: hops-4.config \
168-
\ imported by: hops/hops-3.config \
169-
\ imported by: hops-2.config \
170-
\ imported by: hops/hops-1.config \
171-
\ imported by: hops-0.project")
172-
hopping
173-
174-
assertOutputContains
175-
(normalizeWindowsOutput "- hops/hops-7.config \
176-
\ imported by: hops-6.config \
177-
\ imported by: hops/hops-5.config \
178-
\ imported by: hops-4.config \
179-
\ imported by: hops/hops-3.config \
180-
\ imported by: hops-2.config \
181-
\ imported by: hops/hops-1.config \
182-
\ imported by: hops-0.project")
183-
hopping
184-
185-
assertOutputContains
186-
(normalizeWindowsOutput "- hops/hops-9.config \
187-
\ imported by: hops-8.config \
188-
\ imported by: hops/hops-7.config \
189-
\ imported by: hops-6.config \
190-
\ imported by: hops/hops-5.config \
191-
\ imported by: hops-4.config \
192-
\ imported by: hops/hops-3.config \
193-
\ imported by: hops-2.config \
194-
\ imported by: hops/hops-1.config \
195-
\ imported by: hops-0.project")
196-
hopping
115+
readFileVerbatim "hops.expect.txt" >>=
116+
flip (assertOn multilineNeedleHaystack) hopping . normalizePathSeparators
197117

198118
-- The project is named oops as it is like hops but has conflicting constraints.
199119
-- +-- oops-0.project
@@ -208,22 +128,9 @@ main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
208128
-- +-- oops/oops-9.config (has conflicting constraints)
209129
log "checking conflicting constraints skipping into a subfolder and then back out again and again"
210130
oopsing <- fails $ cabal' "v2-build" [ "all", "--project-file=oops-0.project" ]
211-
assertOutputContains "rejecting: hashable-1.4.2.0" oopsing
212-
assertOutputContains "rejecting: hashable-1.4.3.0" oopsing
213-
assertOutputContains "(constraint from oops-0.project requires ==1.4.3.0)" oopsing
214131

215-
assertOutputContains
216-
(normalizeWindowsOutput " (constraint from oops/oops-9.config requires ==1.4.2.0) \
217-
\ imported by: oops-8.config \
218-
\ imported by: oops/oops-7.config \
219-
\ imported by: oops-6.config \
220-
\ imported by: oops/oops-5.config \
221-
\ imported by: oops-4.config \
222-
\ imported by: oops/oops-3.config \
223-
\ imported by: oops-2.config \
224-
\ imported by: oops/oops-1.config \
225-
\ imported by: oops-0.project")
226-
oopsing
132+
readFileVerbatim "oops.expect.txt"
133+
>>= flip (assertOn multilineNeedleHaystack) oopsing . normalizePathSeparators
227134

228135
-- The project is named yops as it is like hops but with y's for forks.
229136
-- +-- yops-0.project
@@ -264,13 +171,8 @@ main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
264171

265172
log "checking that missing package message lists configuration provenance"
266173
missing <- fails $ cabal' "v2-build" [ "--project-file=cabal-missing-package.project" ]
267-
assertOutputContains
268-
(normalizeWindowsOutput "When using configuration from: \
269-
\ - cabal-missing-package.project \
270-
\ - missing/pkgs.config \
271-
\ - missing/pkgs/default.config \
272-
\The following errors occurred: \
273-
\ - The package location 'pkg-doesnt-exist' does not exist.")
274-
missing
174+
175+
readFileVerbatim "cabal-missing-package.expect.txt"
176+
>>= flip (assertOn multilineNeedleHaystack) missing . normalizePathSeparators
275177

276178
return ()
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
Configuration is affected by the following files:
2+
- hops-0.project
3+
- hops-2.config
4+
imported by: hops/hops-1.config
5+
imported by: hops-0.project
6+
- hops-4.config
7+
imported by: hops/hops-3.config
8+
imported by: hops-2.config
9+
imported by: hops/hops-1.config
10+
imported by: hops-0.project
11+
- hops-6.config
12+
imported by: hops/hops-5.config
13+
imported by: hops-4.config
14+
imported by: hops/hops-3.config
15+
imported by: hops-2.config
16+
imported by: hops/hops-1.config
17+
imported by: hops-0.project
18+
- hops-8.config
19+
imported by: hops/hops-7.config
20+
imported by: hops-6.config
21+
imported by: hops/hops-5.config
22+
imported by: hops-4.config
23+
imported by: hops/hops-3.config
24+
imported by: hops-2.config
25+
imported by: hops/hops-1.config
26+
imported by: hops-0.project
27+
- hops/hops-1.config
28+
imported by: hops-0.project
29+
- hops/hops-3.config
30+
imported by: hops-2.config
31+
imported by: hops/hops-1.config
32+
imported by: hops-0.project
33+
- hops/hops-5.config
34+
imported by: hops-4.config
35+
imported by: hops/hops-3.config
36+
imported by: hops-2.config
37+
imported by: hops/hops-1.config
38+
imported by: hops-0.project
39+
- hops/hops-7.config
40+
imported by: hops-6.config
41+
imported by: hops/hops-5.config
42+
imported by: hops-4.config
43+
imported by: hops/hops-3.config
44+
imported by: hops-2.config
45+
imported by: hops/hops-1.config
46+
imported by: hops-0.project
47+
- hops/hops-9.config
48+
imported by: hops-8.config
49+
imported by: hops/hops-7.config
50+
imported by: hops-6.config
51+
imported by: hops/hops-5.config
52+
imported by: hops-4.config
53+
imported by: hops/hops-3.config
54+
imported by: hops-2.config
55+
imported by: hops/hops-1.config
56+
imported by: hops-0.project
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Could not resolve dependencies:
2+
[__0] trying: oops-0.1 (user goal)
3+
[__1] next goal: hashable (dependency of oops)
4+
[__1] rejecting: hashable-1.4.3.0
5+
(constraint from oops/oops-9.config requires ==1.4.2.0)
6+
imported by: oops-8.config
7+
imported by: oops/oops-7.config
8+
imported by: oops-6.config
9+
imported by: oops/oops-5.config
10+
imported by: oops-4.config
11+
imported by: oops/oops-3.config
12+
imported by: oops-2.config
13+
imported by: oops/oops-1.config
14+
imported by: oops-0.project
15+
[__1] rejecting: hashable-1.4.2.0
16+
(constraint from oops-0.project requires ==1.4.3.0)
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Test.Cabal.Prelude
2+
import Data.Function ((&))
23

34
-- This test is similar to the simplified example in issue #4288. The package's
45
-- setup script only depends on base and setup-helper. setup-helper exposes a
@@ -10,8 +11,7 @@ main = cabalTest $ do
1011
skipUnless "no v2-build compatible boot-Cabal" =<< hasNewBuildCompatBootCabal
1112
r <- recordMode DoNotRecord $ cabal' "v2-build" ["T4288"]
1213
assertOutputContains "This is setup-helper-1.0." r
13-
assertOutputContains
14-
("In order, the following will be built: "
15-
++ " - setup-helper-1.0 (lib:setup-helper) (first run) "
16-
++ " - T4288-1.0 (lib:T4288) (first run)")
17-
r
14+
"In order, the following will be built:\n\
15+
\ - setup-helper-1.0 (lib:setup-helper) (first run)\n\
16+
\ - T4288-1.0 (lib:T4288) (first run)"
17+
& flip (assertOn multilineNeedleHaystack) r

0 commit comments

Comments
 (0)