-
Notifications
You must be signed in to change notification settings - Fork 1.4k
improve error message when using invalid path for local binary artifacts #4129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,7 +76,7 @@ public protocol ManifestLoaderProtocol { | |
} | ||
|
||
public extension ManifestLoaderProtocol { | ||
var supportedArchiveExtension: String { "zip" } | ||
var supportedArchiveExtensions: [String] { ["zip"] } | ||
} | ||
|
||
public protocol ManifestLoaderDelegate { | ||
|
@@ -408,30 +408,69 @@ public final class ManifestLoader: ManifestLoaderProtocol { | |
private func validateBinaryTargets(_ manifest: Manifest, observabilityScope: ObservabilityScope) throws { | ||
// Check that binary targets point to the right file type. | ||
for target in manifest.targets where target.type == .binary { | ||
guard let location = URL(string: target.url ?? target.path ?? "") else { | ||
if target.isLocal { | ||
guard let path = target.path else { | ||
observabilityScope.emit(.invalidBinaryLocation(targetName: target.name)) | ||
continue | ||
} | ||
|
||
guard let path = path.spm_chuzzle(), !path.isEmpty else { | ||
observabilityScope.emit(.invalidLocalBinaryPath(path: path, targetName: target.name)) | ||
continue | ||
} | ||
|
||
guard let relativePath = try? RelativePath(validating: path) else { | ||
observabilityScope.emit(.invalidLocalBinaryPath(path: path, targetName: target.name)) | ||
continue | ||
} | ||
|
||
let validExtensions = self.supportedArchiveExtensions + BinaryTarget.Kind.allCases.filter{ $0 != .unknown }.map { $0.fileExtension } | ||
guard let fileExtension = relativePath.extension, validExtensions.contains(fileExtension) else { | ||
observabilityScope.emit(.unsupportedBinaryLocationExtension( | ||
targetName: target.name, | ||
validExtensions: validExtensions | ||
)) | ||
continue | ||
} | ||
} else if target.isRemote { | ||
guard let url = target.url else { | ||
observabilityScope.emit(.invalidBinaryLocation(targetName: target.name)) | ||
continue | ||
} | ||
|
||
guard let url = url.spm_chuzzle(), !url.isEmpty else { | ||
observabilityScope.emit(.invalidBinaryURL(url: url, targetName: target.name)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think each error case should have some distinction, e.g. this should say that the URL is empty. Just makes it easier when someone unexpectedly hits one of these, we won't have to guess which case they are encountering. Similar for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks @neonichu we could add a special case for empty vs. invalid, tho we do print the bad URL/Path to make it obvious. wdyt? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah sorry, I missed that we are printing the URL now, that should be sufficient here. |
||
continue | ||
} | ||
|
||
guard let url = URL(string: url) else { | ||
observabilityScope.emit(.invalidBinaryURL(url: url, targetName: target.name)) | ||
continue | ||
} | ||
|
||
let validSchemes = ["https"] | ||
guard url.scheme.map({ validSchemes.contains($0) }) ?? false else { | ||
observabilityScope.emit(.invalidBinaryURLScheme( | ||
targetName: target.name, | ||
validSchemes: validSchemes | ||
)) | ||
continue | ||
} | ||
|
||
guard self.supportedArchiveExtensions.contains(url.pathExtension) else { | ||
observabilityScope.emit(.unsupportedBinaryLocationExtension( | ||
targetName: target.name, | ||
validExtensions: self.supportedArchiveExtensions | ||
)) | ||
continue | ||
} | ||
|
||
} else { | ||
observabilityScope.emit(.invalidBinaryLocation(targetName: target.name)) | ||
continue | ||
} | ||
|
||
let validSchemes = ["https"] | ||
if target.isRemote && (location.scheme.map({ !validSchemes.contains($0) }) ?? true) { | ||
observabilityScope.emit(.invalidBinaryURLScheme( | ||
targetName: target.name, | ||
validSchemes: validSchemes | ||
)) | ||
} | ||
|
||
var validExtensions = [self.supportedArchiveExtension] | ||
if target.isLocal { | ||
validExtensions += BinaryTarget.Kind.allCases.filter{ $0 != .unknown }.map { $0.fileExtension } | ||
} | ||
|
||
if !validExtensions.contains(location.pathExtension) { | ||
observabilityScope.emit(.unsupportedBinaryLocationExtension( | ||
targetName: target.name, | ||
validExtensions: validExtensions | ||
)) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1070,6 +1109,14 @@ extension Basics.Diagnostic { | |
.error("invalid location for binary target '\(targetName)'") | ||
} | ||
|
||
static func invalidBinaryURL(url: String, targetName: String) -> Self { | ||
.error("invalid URL '\(url)' for binary target '\(targetName)'") | ||
} | ||
|
||
static func invalidLocalBinaryPath(path: String, targetName: String) -> Self { | ||
.error("invalid local path '\(path)' for binary target '\(targetName)', path expected to be relative to package root.") | ||
} | ||
|
||
static func invalidBinaryURLScheme(targetName: String, validSchemes: [String]) -> Self { | ||
.error("invalid URL scheme for binary target '\(targetName)'; valid schemes are: '\(validSchemes.joined(separator: "', '"))'") | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make this a do-catch and include the underlying error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is intentional - the underlying error in this case would be a generic "the path is an invalid relative path" which we fine-tune to invalidLocalBinaryPath which explains that this must be relative to the project root
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, the question is what happens if the underlying error ever changes and includes useful info. I guess that's not super likely in this particular case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, that was my thinking here as it basically validates that the value is valid relative path