Add run command#36
Conversation
371f846 to
198c014
Compare
198c014 to
849bd8b
Compare
| } | ||
|
|
||
| /// Get the version that matches the `owner/repo` | ||
| public func fetchTarget(reference: String, nestfile: Nestfile) -> Nestfile.Target? { |
There was a problem hiding this comment.
[Naming] fetch sounds that the function get the target from a remote server.
How about this interface?
public func target(matchingTo reference: String, in nestfile: Nestfile) -> Nestfile.Target? There was a problem hiding this comment.
And please write DocC that explains the reference can accept only owner/repo format.
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (297dda5)
| return nestfile.targets | ||
| .first { target in | ||
| guard case let .repository(repository) = target, | ||
| repository.reference == reference || GitURL.parse(string: repository.reference)?.referenceName == reference |
There was a problem hiding this comment.
Is not this enough?
| repository.reference == reference || GitURL.parse(string: repository.reference)?.referenceName == reference | |
| GitURL.parse(string: repository.reference)?.referenceName == reference |
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (5571860)
| /// `owner/repo` format | ||
| public var referenceName: String? { | ||
| guard pathComponents.count >= 3 else { return nil } | ||
| let owner = pathComponents[1] | ||
| let repo = pathComponents[2].replacingOccurrences(of: ".\(pathExtension)", with: "") | ||
| return "\(owner)/\(repo)" | ||
| } |
There was a problem hiding this comment.
[Question] I'm not sure whether the logic always correct or not.
For example, is a URL like https://for.com/bar/{owner}/{repo} impossible?
There was a problem hiding this comment.
is a URL like https://for.com/bar/{owner}/{repo} impossible?
In this case, bar/owner is output as a reference.
I added comments and tests (174375c)
| } | ||
|
|
||
| /// Get NestInfo.Command from `owner/repository` | ||
| public func fetchCommand(reference: String, version: String) -> NestInfo.Command? { |
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (cbbe015)
| let command = $0.value | ||
| .first { | ||
| switch $0.manufacturer { | ||
| case let .artifactBundle(sourceInfo): | ||
| return sourceInfo.repository?.reference.referenceName == reference | ||
| case let .localBuild(repository): | ||
| return repository.reference.referenceName == reference | ||
| } | ||
| } | ||
| return command != nil |
There was a problem hiding this comment.
This may be straightforward.
| let command = $0.value | |
| .first { | |
| switch $0.manufacturer { | |
| case let .artifactBundle(sourceInfo): | |
| return sourceInfo.repository?.reference.referenceName == reference | |
| case let .localBuild(repository): | |
| return repository.reference.referenceName == reference | |
| } | |
| } | |
| return command != nil | |
| $0.value | |
| .contains { | |
| switch $0.manufacturer { | |
| case let .artifactBundle(sourceInfo): | |
| return sourceInfo.repository?.reference.referenceName == reference | |
| case let .localBuild(repository): | |
| return repository.reference.referenceName == reference | |
| } | |
| } |
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (3b4f465)
| @Flag(help: "Will not perform installation.") | ||
| var noInstall: Bool = false | ||
|
|
||
| @Option(help: "A nestfile written in yaml.") |
There was a problem hiding this comment.
That nestfile is written in yaml is obvious.
| @Option(help: "A nestfile written in yaml.") | |
| @Option(help: "A path to nestfile") |
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (6f71256)
| import NestCLI | ||
| import Logging | ||
|
|
||
| struct RunCommand: AsyncParsableCommand { |
There was a problem hiding this comment.
nest module should be thin as much as possible.
So could you try to move the logic to other modules and reduce the logic in this module?
| guard !isSkip else { | ||
| self = .skip | ||
| return | ||
| } | ||
| guard let expectedChecksum else { | ||
| self = .printActual { checksum in | ||
| logger.info("ℹ️ The checksum is \(checksum). Please add it to the nestfile to verify the downloaded file.") | ||
| } | ||
| return | ||
| } | ||
| self = .needsCheck(expected: expectedChecksum) |
There was a problem hiding this comment.
I think guard statement is for error case.
guard foo else {
// error case
}
// happy pathIn this function, skip and printActual cases are not error cases.
So, could you use if statements instead?
There was a problem hiding this comment.
Thanks!
I've made the corrections here. (bf4e6e2)
| artifactBundleManager: ArtifactBundleManager, | ||
| logger: Logger | ||
| ) async throws -> String? { | ||
| guard let binaryRelativePath = nestInfoController.fetchCommand(reference: reference, version: version)?.binaryPath |
There was a problem hiding this comment.
Use if statement instead of guard statement.
There was a problem hiding this comment.
Thanks!
I fixed it together here. (bf4e6e2)
|
Thanks for your review! |
ref. mtj0928#36 (comment) Co-authored-by: matsuji <mtj0928@users.noreply.github.com>
ref. mtj0928#36 (comment) Co-authored-by: matsuji <mtj0928@users.noreply.github.com>
mtj0928#36 (comment) Co-authored-by: matsuji <mtj0928@users.noreply.github.com>
4bddde4 to
d800cf2
Compare
d800cf2 to
bf4e6e2
Compare
| /// Returns a relative path. If not, it will attempt to install. | ||
| public func resolveBinaryRelativePath( | ||
| noInstall: Bool, | ||
| reference: String, | ||
| version: String, | ||
| target: Nestfile.Target, | ||
| gitURL: GitURL, | ||
| gitVersion: GitVersion, | ||
| nestInfoController: NestInfoController, | ||
| executableBinaryPreparer: ExecutableBinaryPreparer, | ||
| artifactBundleManager: ArtifactBundleManager, | ||
| logger: Logger | ||
| ) async throws -> String? { |
There was a problem hiding this comment.
Ideally, I would write tests, but there are no tests for the dependent component (ExecutableBinaryPreparer), so I decided not to write tests for the resolveBinaryRelativePath method.
(If it is required, I will write tests together with ExecutableBinaryPreparer!)
| public var assetName: String? { | ||
| switch self { | ||
| case .repository(let repository): repository.assetName | ||
| case .zip, .deprecatedZIP: nil | ||
| } | ||
| } | ||
|
|
||
| public var checksum: String? { | ||
| switch self { | ||
| case .repository(let repository): repository.checksum | ||
| case .zip(let zipURL): zipURL.checksum | ||
| case .deprecatedZIP: nil | ||
| } | ||
| } |
There was a problem hiding this comment.
I moved properties used by bootstrap and run commands.
mtj0928
left a comment
There was a problem hiding this comment.
LGTM, except for the bug mentioned in a comment.
And, could you update README.md to explain the added command?
| _ = try await NestProcessExecutor(logger: logger, logLevel: .info) | ||
| .execute( | ||
| command: "\(nestDirectory.rootDirectory.relativePath)\(binaryRelativePath)", | ||
| executor.subcommands | ||
| ) |
There was a problem hiding this comment.
I noticed a bug that a user cannot input any texts to the command even if the command requires inputs because NestProcessExecutor does't support it.
It's OK to merge this PR without fixing the issue and fix it in another PR.
Of course, it's also welcome to fix it in this PR!
There was a problem hiding this comment.
I would appreciate it if you could merge this PR as the differences are getting bigger.
As for the bugs, I will fix it and submit a PR. (If you need to create an Issue, I will create it.)
There was a problem hiding this comment.
@mtj0928
I tried writing a sample CLI tool to receive standard input, but could not reproduce it. (https://github.com/coffmark/InputText)
v0.0.1 -> only use readline method. (source code)
v0.0.2 -> use readline method with swift-argument-parser (source code)
Would it be possible for you to share the name of the CLI tool (if it is publicly available) or the steps to reproduce it?
Screenshot.2025-05-30.8.01.20.mov
There was a problem hiding this comment.
Oh, sorry.
I might misunderstood something.
Thank you for the investigation!
For now, it's fine to keep the current code.
Thanks for your review! |
mtj0928
left a comment
There was a problem hiding this comment.
Basically, LGTM!
Let me modify the code a bit after merging this PR, for very personal preferences.
|
Thank you for merging! |
Motivation
When
nestfile.yamlwas updated, version mismatches occurred when directly executing local binaries.Therefore, I was using Git Hooks to run
$ nest bootstrapto install the correct version ofnestfile.yaml.As an alternative to directly executing binaries, we can now use
$ nest run owner/repositoryto execute binaries.Describe changes
I newly implemented
RunCommand.swift.Run command accepts the following arguments and options.
$ nest help runI used NestInfoController for manipulating NestInfo and NestfileController for manipulating Nestfile.
Operation check
I used
realm/SwiftLintas an example.realm/SwiftLintspecified innestfile.yamlis installed.realm/SwiftLintspecified innestfile.yamlis not installedrealm/SwiftLintspecified innestfile.yamlis not installed and--no-installoption is enabled$ nest run --no-install realm/SwiftLint lint Sources/NestKitIssue ticket number and link
runcommand #32Checklist before requesting a review