davetron5000 / gli

Make awesome command-line applications the easy way
http://davetron5000.github.io/gli
Apache License 2.0
1.26k stars 102 forks source link

Subcommand multiple actions #227

Closed manther closed 8 years ago

manther commented 8 years ago

Can we have multiple actions? In the below example only 'add' gets printed. If not, how can you have a remote command that you can sometimes execute alone, and sometimes execute with the subcommand add, so that both can specify flags etc unique to their individual commands?

desc 'manage remote repos'
command :remote do |c|
  c.desc 'add a remote repo'
  c.command :add do |add|
    add.action do |_, _, _|
      puts 'add'
    end
  end

  c.default_desc 'show a list of existing remotes'
  c.action do |_, _, _|
    puts 'remote'
  end
end
manther commented 8 years ago

Also how can you have a required flag in a subcommand, that doesn't raise "error: is required" if the subcommand is omitted?

davetron5000 commented 8 years ago
manther commented 8 years ago

What I'm trying to accomplish is a command (compile) that you can optionally call load-plugins, but If you call load plugins there is a required argument or flag for calling load plugins. If you don't call load plugins, then the flag isn't required.

command :compile do |c|
  c.flag :f,
         :type     => String,
         :desc     => 'Source folder',
         :required => true
  c.flag :n,
         :type     => String,
         :desc     => 'Root name of source to compile',
         :required => true
  c.flag :t,
         :type     => String,
         :desc     => 'Root type of source to compile',
         :required => true
  c.default_desc 'Compile source code.'
  c.command 'load-plugins' do |load|
    load.flag [:g],
              :type     => Array,
              :desc     => 'Names of the plugin gems to load',
              :required => true
    load.action do |_, options, _|
      puts 'plugins loaded' #need to know the args/flag
    end
  end
  c.action do |_, options, _|
      puts 'compiled' #need to know the args/flag
  end
end

so if you call compile by itself it would go like this: compile -f somefolder -n somename -t sometype and it would execute properly, and not complain about the -g flag missing because you didn't call the load-plugins command

But if you wanted to optionally use the subcommand load plugins it would look like this: compile -f somefolder -n somename -t sometype load-plugins -g gem1,gem2 and it would execute, but passing in args or filling out a flag for load-plugins is required.

manther commented 8 years ago

So I have the problem with flags that are required when I want them to be, and maybe the answer is to use args instead for load-plugins, but I don't think it yells at you if you omit a command arg does it?

And the second problem is only one action will actually be executed. (Which may not be a problem I just need to understand the typical way to get this behavior using your framework).

davetron5000 commented 8 years ago

can you post your entire file? There is a configuration option that makes multi-level commands like this not work the way you expect. It should not be set by default, but older versions of GLI did set it. It's called subcommand_option_handling and it must be set explicitly to :normal or the way in which nested commands is handled is the old, legacy way, which may cause the behavior you are seeing.

manther commented 8 years ago

Sorry I got some NDA stuff in there, but I do have these two lines.

subcommand_option_handling :normal arguments :strict

I just started using your framework with the latest and greatest and let your bootstrapper get me started.

manther commented 8 years ago

Here it is paired down a bit

#!/usr/bin/env ruby
require 'gli'

include GLI::App

program_desc 'Describe your application here'

subcommand_option_handling :normal
arguments :strict

desc 'Describe some switch here'
switch [:s, :switch]

desc 'Describe some flag here'
default_value 'the default'
arg_name 'The name of the argument'
flag [:f, :flagname]

desc 'Describe compile here'
# arg_name 'Describe arguments to compile here'
command :compile do |c|
  c.flag :f,
         :type     => String,
         :desc     => 'Source folder',
         :required => true
  c.flag :n,
         :type     => String,
         :desc     => 'Name of source to compile',
         :required => true
  c.flag :t,
         :type     => String,
         :desc     => 'Type of source to compile',
         :required => true
  c.default_desc 'Compile source code.'
  c.command 'load-plugins' do |load|
    load.flag [:g],
              :type     => Array,
              :desc     => 'Names of the plugin gems to load',
              :required => true
    load.action do |_, options, _|
      puts 'plugins loaded'
    end
  end
  c.action do |_, options, _|
    puts 'compiled'
  end
end

pre do |global, command, options, args|
  # Pre logic here
  # Return true to proceed; false to abort and not call the
  # chosen command
  # Use skips_pre before a command to skip this block
  # on that command only
  true
end

post do |global, command, options, args|
  # Post logic here
  # Use skips_post before a command to skip this
  # block on that command only
end

on_error do |exception|
  # Error logic here
  # return false to skip default error handling
  true
end

exit run(ARGV)
davetron5000 commented 8 years ago

OK, this makes more sense, and I see what you are trying to do.

I think GLI is acting as designed, though this is just one of the weird things about the subcommand feature. So, I think this is more emergent behavior. The idea is that flags are required always or not.

So, you could get around this in a few ways

manther commented 8 years ago

Thanks for this, was helpful. I think best would be to just make load-plugins an option. Probably a global flag, because several commands are going to want to have use of this flag.