Skip to content

Commit 14ff208

Browse files
authored
[5.5] Do not crash on relative file URLs in a dependency (#3604)
* Do not crash on relative file URLs in a dependency Currently, SwiftPM crashes when someone specifies the URL of a package dependency as a relative file URL. We should instead be able to just make it absolute based on the location of the package itself. (cherry picked from commit d771063) * Error on relative file URLs It turns out that relative file URLs actually do not exist, see [here](#3604 (comment)) for more discussion. Instead we will now error and guide users to using a local package reference. rdar://80751251 (cherry picked from commit e6a7323)
1 parent 6e191c9 commit 14ff208

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import TSCUtility
1515
import Foundation
1616
public typealias FileSystem = TSCBasic.FileSystem
1717

18-
public enum ManifestParseError: Swift.Error {
18+
public enum ManifestParseError: Swift.Error, Equatable {
1919
/// The manifest contains invalid format.
2020
case invalidManifestFormat(String, diagnosticFile: AbsolutePath?)
2121

Sources/PackageLoading/PackageDescription4Loader.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,11 @@ extension PackageDependencyDescription {
345345
} else if dependencyLocation.hasPrefix(filePrefix) {
346346
// FIXME: SwiftPM can't handle file locations with file:// scheme so we need to
347347
// strip that. We need to design a Location data structure for SwiftPM.
348-
return AbsolutePath(String(dependencyLocation.dropFirst(filePrefix.count))).pathString
348+
let location = String(dependencyLocation.dropFirst(filePrefix.count))
349+
if location.first != "/" {
350+
throw ManifestParseError.invalidManifestFormat("file:// URLs cannot be relative, did you mean to use `.package(path:)`?", diagnosticFile: nil)
351+
}
352+
return AbsolutePath(location).pathString
349353
} else if URL.scheme(dependencyLocation) == nil {
350354
// If the dependency URL is not remote, try to "fix" it.
351355
// If the URL has no scheme, we treat it as a path (either absolute or relative to the base URL).

Tests/PackageLoadingTests/PD4_2LoadingTests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,26 @@ class PackageDescription4_2LoadingTests: PackageDescriptionLoadingTests {
499499
}
500500
}
501501

502+
func testURLContainsNotAbsolutePath() throws {
503+
let stream = BufferedOutputByteStream()
504+
stream <<< """
505+
import PackageDescription
506+
let package = Package(
507+
name: "Trivial",
508+
dependencies: [
509+
.package(url: "file://../best", from: "1.0.0"),
510+
],
511+
targets: [
512+
.target(
513+
name: "foo",
514+
dependencies: []),
515+
]
516+
)
517+
"""
518+
519+
XCTAssertManifestLoadThrows(ManifestParseError.invalidManifestFormat("file:// URLs cannot be relative, did you mean to use `.package(path:)`?", diagnosticFile: nil), stream.bytes)
520+
}
521+
502522
func testCacheInvalidationOnEnv() throws {
503523
try testWithTemporaryDirectory { path in
504524
let fs = localFileSystem

0 commit comments

Comments
 (0)