@@ -34,6 +34,7 @@ import System.FilePath
34
34
import qualified Data.List.NonEmpty as NE
35
35
import Distribution.Solver.Modular.Version (VR )
36
36
import Distribution.Pretty (prettyShow )
37
+ import Distribution.Utils.String (trim )
37
38
import Text.PrettyPrint
38
39
import Distribution.Simple.Utils (ordNub )
39
40
@@ -98,9 +99,13 @@ instance Structured ProjectConfigPath
98
99
-- >>> render . docProjectConfigPath $ ProjectConfigPath $ "D.config" :| ["C.config", "B.config", "A.project"]
99
100
-- "D.config\n imported by: C.config\n imported by: B.config\n imported by: A.project"
100
101
docProjectConfigPath :: ProjectConfigPath -> Doc
101
- docProjectConfigPath (ProjectConfigPath (p :| [] )) = text p
102
- docProjectConfigPath (ProjectConfigPath (p :| ps)) = vcat $
103
- text p : [ text " " <+> text " imported by:" <+> text l | l <- ps ]
102
+ docProjectConfigPath (ProjectConfigPath (p :| [] )) = quoteUntrimmed p
103
+ docProjectConfigPath (ProjectConfigPath (p :| ps)) = vcat $ quoteUntrimmed p :
104
+ [ text " " <+> text " imported by:" <+> quoteUntrimmed l | l <- ps ]
105
+
106
+ -- | If the path has leading or trailing spaces then show it quoted.
107
+ quoteUntrimmed :: FilePath -> Doc
108
+ quoteUntrimmed s = if trim s /= s then quotes (text s) else text s
104
109
105
110
-- | Renders the paths as a list without showing which path imports another,
106
111
-- like this;
@@ -196,7 +201,7 @@ unconsProjectConfigPath ps = fmap ProjectConfigPath <$> NE.uncons (coerce ps)
196
201
makeRelativeConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
197
202
makeRelativeConfigPath dir (ProjectConfigPath p) =
198
203
ProjectConfigPath
199
- $ (\ segment -> (if isURI segment then segment else makeRelative dir segment))
204
+ $ (\ segment@ (trim -> trimSegment) -> (if isURI trimSegment then trimSegment else makeRelative dir segment))
200
205
<$> p
201
206
202
207
-- | Normalizes and canonicalizes a path removing '.' and '..' indirections.
@@ -273,11 +278,25 @@ makeRelativeConfigPath dir (ProjectConfigPath p) =
273
278
-- return $ expected == render (docProjectConfigPath p) ++ "\n"
274
279
-- :}
275
280
-- True
281
+ --
282
+ -- "A string is a valid URL potentially surrounded by spaces if, after stripping leading and trailing whitespace from it, it is a valid URL."
283
+ -- [W3C/HTML5/URLs](https://www.w3.org/TR/2010/WD-html5-20100624/urls.html)
284
+ --
285
+ -- Trailing spaces for @ProjectConfigPath@ URLs are trimmed.
286
+ --
287
+ -- >>> p <- canonicalizeConfigPath "" (ProjectConfigPath $ ("https://www.stackage.org/nightly-2024-12-05/cabal.config ") :| [])
288
+ -- >>> render $ docProjectConfigPath p
289
+ -- "https://www.stackage.org/nightly-2024-12-05/cabal.config"
290
+ --
291
+ -- >>> let d = testDir
292
+ -- >>> p <- canonicalizeConfigPath d (ProjectConfigPath $ ("https://www.stackage.org/nightly-2024-12-05/cabal.config ") :| [d </> "cabal.project"])
293
+ -- >>> render $ docProjectConfigPath p
294
+ -- "https://www.stackage.org/nightly-2024-12-05/cabal.config\n imported by: cabal.project"
276
295
canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath
277
296
canonicalizeConfigPath d (ProjectConfigPath p) = do
278
- xs <- sequence $ NE. scanr (\ importee -> (>>= \ importer ->
279
- if isURI importee
280
- then pure importee
297
+ xs <- sequence $ NE. scanr (\ importee@ (trim -> trimImportee) -> (>>= \ importer@ (trim -> trimImporter) ->
298
+ if isURI trimImportee || isURI trimImporter
299
+ then pure trimImportee
281
300
else canonicalizePath $ d </> takeDirectory importer </> importee))
282
301
(pure " ." ) p
283
302
return . makeRelativeConfigPath d . ProjectConfigPath . NE. fromList $ NE. init xs
0 commit comments