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
Implementation for the swift run
command
#1187
Conversation
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
/// Executes and returns execution status. Prints output on standard streams. | ||
private func run(path: AbsolutePath) throws { | ||
let process = Process(arguments: [path.asString] + options.arguments, redirectOutput: false) |
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.
On UNIX, we should exec
the process rather than run it in a subprocess. These will ensure that we don't influence the programs behavior w.r.t. signal handling, buffering, etc.
Sources/Commands/SwiftRunTool.swift
Outdated
/// Builds the "executable" target if enabled in options. | ||
/// | ||
/// - Returns: The path to the executable binary. | ||
private func buildIfNeeded() throws -> AbsolutePath { |
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.
It feels weird that this returns path to the executable. We can just inline this for now.
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.
Agreed. I was just reproducing the structure of swift test
in case that's what you preferred. Will inline it.
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
return buildPath | ||
.appending(RelativePath(options.config.dirname)) | ||
.appending(component: executable.name) |
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.
We should be using buildplan to get the path to executable, can you land the refactor first?
We accepted SE-179 with revisions: |
I have an implementation ready for the accepted (revised) version. Just need to wait for #1215 to be merged first. |
66f7067
to
32e47e2
Compare
swift run
commandswift run
command
Sources/Commands/SwiftRunTool.swift
Outdated
case .executableNotFound(let executable): | ||
return "could not find executable '\(executable)'" | ||
case .multipleExecutables: | ||
return "multiple products defined" |
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.
We should make this more descriptive, maybe something like: "There are multiple executable products in the package. Use 'swift run ' to run one of the executable".
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.
It might be nice to also list the executables, so users don't then have to look up the names.
Sources/Commands/SwiftRunTool.swift
Outdated
private enum RunError: Swift.Error { | ||
case noExecutableFound | ||
case executableNotFound(String) | ||
case multipleExecutables |
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.
doc comments
Sources/Commands/SwiftRunTool.swift
Outdated
} | ||
} | ||
|
||
/// Executes and returns execution status. Prints output on standard streams. |
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.
Stale comment
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
let product = try findExecutable(in: plan) | ||
let path = plan.buildParameters.buildPath.appending(component: product.name) | ||
try run(at: path) |
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 sounds wrong. Maybe findExectuable
can return the path of the exe and then we can do this:
...
let executable = try findExecutable(in: plan)
try run(executable)
...
Sources/Commands/SwiftRunTool.swift
Outdated
} | ||
|
||
return executableProduct | ||
} else { |
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.
Else is not required
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.
What do you mean by that?
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.
That you can just put the else branch after the if, since it early returns.
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.
Ok, got it!
Sources/Commands/SwiftRunTool.swift
Outdated
throw RunError.multipleExecutables | ||
} | ||
|
||
return executableProducts.first! |
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.
nit: return executableProducts[0]
feels nicer for some reason.
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.
Maybe we should have an extension .only
which returns the only item iff array has one element, this is a not uncommon pattern, and that utility works nicely in guard.
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.
Sounds like a nice utility! Separate PR I guess?
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.
Ya, I wouldn't block this one on it, just update it to use it if we decide it is a good idea.
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
/// Executes and returns execution status. Prints output on standard streams. | ||
private func run(at path: AbsolutePath) throws { | ||
if let workingDirectory = options.workingDirectory { |
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.
Where is this set?
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.
I think this became dead code, and the option can be removed.
Sources/Commands/SwiftRunTool.swift
Outdated
try POSIX.chdir(workingDirectory.asString) | ||
} | ||
|
||
let relativePath = path.relative(to: currentWorkingDirectory) |
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.
currentWorkingDirectory
-> originalWorkingDirectory
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.
We should have a test case that fails w/o this fix.
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.
I'm confused. Looking at the code, it seems originalWorkingDirectory
is currently only set once to currentWorkingDirectory
. Not quite sure what its use case is.
Sources/Utility/ArgumentParser.swift
Outdated
@@ -929,6 +929,18 @@ public final class ArgumentBinder<Options> { | |||
} | |||
} | |||
|
|||
/// Bind an array positional argument. | |||
public func bindArray<T>( |
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.
Please add this in a separate commit/PR
|
||
func testVersion() throws { | ||
XCTAssert(try execute(["--version"]).contains("Swift Package Manager")) | ||
} |
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.
We should add a basic functional test. We can extend one of the executable related functional test.
Sources/Commands/SwiftRunTool.swift
Outdated
case .executableNotFound(let executable): | ||
return "could not find executable '\(executable)'" | ||
case .multipleExecutables: | ||
return "multiple products defined" |
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.
It might be nice to also list the executables, so users don't then have to look up the names.
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
/// Executes and returns execution status. Prints output on standard streams. | ||
private func run(at path: AbsolutePath) throws { | ||
if let workingDirectory = options.workingDirectory { |
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.
I think this became dead code, and the option can be removed.
Sources/Commands/SwiftRunTool.swift
Outdated
public convenience init(args: [String]) { | ||
self.init( | ||
toolName: "run", | ||
usage: "[options] [executable <arguments>]", |
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 somewhat unconventional syntax for usage, I would spell it as:
[executable [arguments ...]]
Sources/Commands/SwiftRunTool.swift
Outdated
throw RunError.multipleExecutables | ||
} | ||
|
||
return executableProducts.first! |
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.
Maybe we should have an extension .only
which returns the only item iff array has one element, this is a not uncommon pattern, and that utility works nicely in guard.
Sources/Commands/SwiftRunTool.swift
Outdated
try POSIX.chdir(workingDirectory.asString) | ||
} | ||
|
||
let relativePath = path.relative(to: currentWorkingDirectory) |
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.
We should have a test case that fails w/o this fix.
815cde3
to
ffc6e67
Compare
Sources/Commands/SwiftRunTool.swift
Outdated
} | ||
} | ||
|
||
/// Find executable path based on options. |
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.
nit: The API guidelines recommend wording the doc comments in terms of what the method returns. Something like Returns executable path ...
will be more appropriate.
Sources/Commands/SwiftRunTool.swift
Outdated
product = executableProducts[0] | ||
} | ||
|
||
return plan.buildParameters.buildPath.appending(component: product.name) |
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.
nit: Consider adding some high level comments on whats going on in this method.
Sources/Commands/SwiftRunTool.swift
Outdated
|
||
/// Executes the executable at the specified path. | ||
private func run(_ excutablePath: AbsolutePath) throws { | ||
let relativePath = excutablePath.relative(to: originalWorkingDirectory) |
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.
The name relativePath
is too vague.
Sources/Commands/SwiftRunTool.swift
Outdated
See http://swift.org/CONTRIBUTORS.txt for Swift project authors | ||
*/ | ||
|
||
import class Foundation.ProcessInfo |
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.
Is this needed?
@swift-ci please smoke test |
1 similar comment
@swift-ci please smoke test |
@swift-ci please smoke test |
@swift-ci please smoke test |
1 similar comment
@swift-ci please smoke test |
No description provided.