Skip to content

Commit

Permalink
Fix --help option (#665)
Browse files Browse the repository at this point in the history
Restores the behavior where `--help` would always skip the command to be invoked, while still allowing to pass the `--help` to external subcommands:

The following commands print the help message and exit:

- `shards --help`
- `shards --local --help`
- `shards update --help`

While the following tries to call `shards-unknown --help` then falls back to print the help message and exit:

- `shards unknown --help` 

Relies on a fixed list of the builtin command names to avoid having each `when` case starting with `display_help_and_exit(opts) if display_help`.
  • Loading branch information
ysbaddaden authored Jan 21, 2025
1 parent 74fb685 commit b72eacf
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 47 deletions.
29 changes: 29 additions & 0 deletions spec/integration/help_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "./spec_helper"

describe "--help" do
it "prints help and doesn't invoke the command" do
metadata = {
version: "1.0.0",
dependencies: {
mock: {git: git_path("mock")},
},
}

[
"shards --help",
"shards --local --help",
"shards update --help",
].each do |command|
with_shard(metadata) do
output = run command

# it printed the help message
output.should contain("Commands:")
output.should contain("General options:")

# it didn't run the command (or default command)
output.should_not contain("Resolving dependencies")
end
end
end
end
110 changes: 63 additions & 47 deletions src/cli.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ require "option_parser"
require "./commands/*"

module Shards
BUILTIN_COMMANDS = %w[
build
run
check
init
install
list
lock
outdated
prune
update
version
]

def self.display_help_and_exit(opts)
puts <<-HELP
shards [<options>...] [<command>]
Expand Down Expand Up @@ -58,61 +72,63 @@ module Shards
opts.on("-h", "--help", "Print usage synopsis.") { display_help = true }

opts.unknown_args do |args, options|
case args[0]? || DEFAULT_COMMAND
when "build"
targets, build_options = parse_args(args[1..-1])
check_and_install_dependencies(path)

Commands::Build.run(path, targets, build_options)
when "run"
targets, run_options = parse_args(args[1..-1])
check_and_install_dependencies(path)

Commands::Run.run(path, targets, run_options, options)
when "check"
Commands::Check.run(path)
when "init"
Commands::Init.run(path)
when "install"
Commands::Install.run(
path
)
when "list"
Commands::List.run(path, tree: args.includes?("--tree"))
when "lock"
Commands::Lock.run(
path,
args[1..-1].reject(&.starts_with?("--")),
print: args.includes?("--print"),
update: args.includes?("--update")
)
when "outdated"
Commands::Outdated.run(
path,
prereleases: args.includes?("--pre")
)
when "prune"
Commands::Prune.run(path)
when "update"
Commands::Update.run(
path,
args[1..-1].reject(&.starts_with?("--"))
)
when "version"
Commands::Version.run(args[1]? || path)
command = args[0]? || DEFAULT_COMMAND

if BUILTIN_COMMANDS.includes?(command)
if display_help
display_help_and_exit(opts)
end

case command
when "build"
targets, build_options = parse_args(args[1..-1])
check_and_install_dependencies(path)
Commands::Build.run(path, targets, build_options)
when "run"
targets, run_options = parse_args(args[1..-1])
check_and_install_dependencies(path)
Commands::Run.run(path, targets, run_options, options)
when "check"
Commands::Check.run(path)
when "init"
Commands::Init.run(path)
when "install"
Commands::Install.run(path)
when "list"
Commands::List.run(path, tree: args.includes?("--tree"))
when "lock"
Commands::Lock.run(
path,
args[1..-1].reject(&.starts_with?("--")),
print: args.includes?("--print"),
update: args.includes?("--update")
)
when "outdated"
Commands::Outdated.run(
path,
prereleases: args.includes?("--pre")
)
when "prune"
Commands::Prune.run(path)
when "update"
Commands::Update.run(
path,
args[1..-1].reject(&.starts_with?("--"))
)
when "version"
Commands::Version.run(args[1]? || path)
else
raise "BUG: unknown command #{command}"
end
else
program_name = "shards-#{args[0]}"
program_name = "shards-#{command}"
if program_path = Process.find_executable(program_name)
run_shards_subcommand(program_path, cli_options)
else
display_help_and_exit(opts)
end
end

if display_help
display_help_and_exit(opts)
end

exit
end
end
Expand Down

0 comments on commit b72eacf

Please sign in to comment.