swift-argument-parser
swift-argument-parser copied to clipboard
@Flag properties that begin with "v" do not work.
I had a "verbose" flag for log output, but it was getting completely ignored and failed silently.
ArgumentParser version: 1.0.2
Swift version:
swift-driver version: 1.26.9 Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6)
Target: arm64-apple-macosx12.0
Checklist
- [ ] If possible, I've reproduced the issue using the
main
branch of this package - [x] I've searched for existing GitHub issues
Steps to Reproduce
Create your own ParsableCommand
with a flag such as:
struct MyCommand: ParsableCommand {
// other boilerplate here.
@Flag(name: .shortAndLong, help: "Whether to enable verbose logging.")
var verbose = false
mutating func run() throws {
print("Verbose Logging Enabled: \(self.verbose)") // is ALWAYS false.
// the rest of what you do here.
}
}
If you include this flag in your command line arguments, it is not parsed as expected.
Expected behavior
The Flag should be set to true when you swift run MyCommand --verbose
Stretch goal: The compiler should fail or complain or warn about your variable name.
Actual behavior
The argument --verbose is ignored and "fails silently"
Workaround
make a custom flag name that doesn't begin with "v". In this case "fatlog" did the trick.
I can't reproduce this, either with a preexisting project or a brand new one. 🤔
I can't reproduce this either, and we have a variety of v
-prefixed flags in the tests. Could you include some more information about how this command is configured? Are you using the @main
attribute or e.g. calling parseAsRoot()
?
I set up my command line tool as a Swift package. Could it have to do with that?
import PackageDescription
let package = Package(
name: "Locobit",
platforms: [.macOS(.v11)],
products: [
.executable(name: "locobit", targets: ["LocobitTool"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "LocobitTool",
dependencies: ["LocobitCore"]),
.target(
name: "LocobitCore",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser")
]),
.testTarget(
name: "LocobitCoreTests",
dependencies: ["LocobitCore"],
resources: [
.copy("Fixtures/Localization.zip"),
.copy("Fixtures/Source.zip"),
.copy("Fixtures/TestLocalizable.strings"),
.copy("Fixtures/TestSourceFile.sweeft"), // yes, it's called .sweeft. Look at the comments in that file for the reason for that.
]
),
],
swiftLanguageVersions: [.v5]
)
Then the tool executable looks like this:
// main.swift
import LocobitCore
CommandLineTool.main()
// CommandLineTool.swift
import Foundation
public final class CommandLineTool {
public static func main(_ arguments: [String]? = nil) {
LocobitCommand.main(arguments)
}
}
Then the part of the ParsableCommand
that's likely relevant:
import ArgumentParser
import Foundation
struct LocobitCommand: ParsableCommand {
// other boilerplate, configuration, other options and flags here.
@Flag(name: .customLong("fatlog", withSingleDash: true), help: "Whether to enable verbose logging.")
var verboseLogging = false
mutating func run() throws {
logger.info("Locobit v\(Locobit.version)\n")
logger.isVerbose = self.verboseLogging
let configuration = try createConfiguration()
try runLocobit(with: configuration)
throw ExitCode.success
}
}
You can see that when I make it a custom long flag, it will work. Otherwise it won't. At least not when you run the executable (i.e. from the command line). It took a while to track down as tests weren't finding it as it wasn't testing via the executable, but testing the LocobitCore target.
The issue is most likely because swift run
is eating the --verbose
flag
➜ repro swift run repro
[3/3] Build complete!
Verbose Logging Enabled: false
➜ repro swift run repro --verbose
/usr/bin/xcrun --sdk macosx --show-sdk-platform-path
/usr/bin/xcrun --sdk macosx --find xctest
/usr/bin/xcrun --sdk macosx --show-sdk-platform-path
/usr/bin/xcrun --sdk macosx --show-sdk-platform-path
/usr/bin/xcrun --sdk iphoneos --show-sdk-platform-path
/usr/bin/xcrun --sdk appletvos --show-sdk-platform-path
/usr/bin/xcrun --sdk watchos --show-sdk-platform-path
[0/0] Build complete!
Verbose Logging Enabled: false
➜ repro .build/debug/repro --verbose
Verbose Logging Enabled: true
If that's the case, does inserting a --
work? E.g.,
swift run -- MyCommand --verbose
@soconnor-florio Recent releases have fixed the behavior that @rauhul described above — are you able to reproduce this behavior with a Swift 5.6 toolchain?
When I update my toolchain I can investigate