Code Monkey home page Code Monkey logo

admiral.cr's People

Contributors

bew avatar djmaze avatar hak8or avatar jjlorenzo avatar jwaldrip avatar lodestone avatar silasb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

admiral.cr's Issues

Flags don't work with spaces.

class Converter < Admiral::Command
  define_flag input : String,
              description: "Whatever",
              default: "/dev/stdin",
              long: input,
              short: i,
              required: true
  def run
    puts "Input is #{flags.input}"
  end
end

Works

-i=foo
--input=foo

Doesn't work

-i foo
--input foo
-ifoo

Exit status for unknown command/subcommand

When command or subcommand is unknown the default behavior is to print help and exit 0 :

Usage:
  /home/nonroot/.asdf/installs/squarectl/1.4.0/bin/squarectl compose [flags...] [arg...]
Run Docker Compose commands
Flags:
  --config, -c (default: "squarectl.yml")  # Path to config file
  --help                                   # Displays help for the current command.
Subcommands:
  build                                    # Run docker-compose build
  clean                                    # Run docker-compose clean
  config                                   # Run docker-compose config
  down                                     # Run docker-compose down
  exec                                     # Run docker-compose exec
  ps                                       # Run docker-compose ps
  setup                                    # Run docker-compose setup
  start                                    # Run docker-compose start
  stop                                     # Run docker-compose stop
  top                                      # Run docker-compose top
  up                                       # Run docker-compose up
* Done!
Job succeeded

It would be nice to notify user about the missing command, something like Unknow "squarectl compose push" command and to exit 1,

Thank you!

Note: this issue has been found while working on https://github.com/jbox-web/squarectl

Required arguments not working

Required arguments don't raise an error when no argument is passed.

Add the following line at the bottom of examples/complex.cr to reproduce this bug.

Complex.run ""

There is no error even though the argument required, which is required, is not passed. The argument is defined below.

  define_argument required : Int32, required: true

This is my shards.yaml.

name: kato
version: 0.1.0

authors:
  - Ravern Koh <[email protected]>

description: |
  Toy virtual machine written in Crystal

targets:
  kato:
    main: src/kato/cli.cr

dependencies:
  admiral:
    github: jwaldrip/admiral.cr

development_dependencies:
  cake:
    git: https://github.com/ravernkoh/cake.git
    branch: master

license: GPL-3.0

Edit: Made a mistake in the example to reproduce, was originally Complex.run —required woah”.

Ability to remove parsed parts

Hey,

If one defines some flags and arguments, like:
define_flag a
define_flag b
define_argument c

Then upon calling:
cmd subcmd -a one -b two three four

It would be great if there was a way to automatically remove parsed parts out of ARGV or original array, so that only "four" remains in it.

Currently, it appears as if original contents are never modified.

No variable named long_reg

I just tried to create a flag with a long version that didn't match the regex checked here, and the error message references a variable that isn't defined:

  define_flag skip_install : Bool,
  ^~~~~~~~~~~

in lib/admiral/src/admiral/command/flag.cr:285: undefined macro variable 'long_reg'

        raise "The long flag #{@type}(#{long}) must match the regex: #{long_reg}"
                                                                       ^~~~~~~~

I was still able to figure out what needed to be fixed in my code, but thought you would want to know.

Parent flags/arguments in subcommands help

Hi,

currently, the help of the subcommands doesn't show the global flags/arguments of the parent.
Taking the following example:

equire "admiral"

class ParentCmd < Admiral::Command
  class ChildCmd < Admiral::Command
    define_help description: "Execute a subcommand."

    define_argument childarg : String, description: "Arg for child", required: true

    def run
      puts "in ChildCmd with #{arguments.childarg}"
    end
  end

  register_sub_command child : ChildCmd, "Child Command"

  define_flag parentflag : Bool, description: "Parent flag", default: false, short: p
  define_help description: "Test subcommands help with global flag"

  def run
    puts help
  end
end

ParentCmd.run

I would expect the parentflag to show up in the ChildCmd help page:

$ ./testsub --help
Usage:
  ./testsub [flags...] [arg...]

Test subcommands help with global flag

Flags:
  --help            # Displays help for the current command.
  --parentflag, -p  # Parent flag

Subcommands:
  child             # Execute a subcommand.

$ /testsub child --help 
Usage:
  ./testsub child [flags...] <childarg> [arg...]

Execute a subcommand.

Flags:
  --help               # Displays help for the current command.

Arguments:
  childarg (required)  # Arg for child

Displaying application version in examples

I wrote a small application and used the define_version to display a literal string of the version. Since I built the app with crystal init app, there is already a module in version.cr that contains the version number. I tried this and it actually worked:

define_version "app #{App::VERSION}"

also:

define_version <<-VERSION
app #{App::VERSION}
Copyright ...
License ...
VERSION

Is this something you would consider including in the README? For me this means having only one place to bump versions.

Great shard. Thanks

Empty arg error handling

It would be great to have a simple way to handle if no argument is provided.
Ex:

define_argument name : String,
  description: "The name of the new project",
  required: false,
  empty: "Please provide the name"

Help does not work when required arguments are missing

When a command has required arguments and help defined, it is not possible to get help without also specifying the required arguments at the command line. This is not an expected behaviour in my opinion.

# test.cr
require "admiral"

class TestCommand < Admiral::Command
  define_help description: "does foobar"
  define_argument foo : String, required: true
  define_argument bar : String, required: true

  def run
  end
end

TestCommand.run
$ ./crystal build test.cr
$ ./test --help
Missing required attribute: <foo>
$ ./test one --help  
Missing required attribute: <bar>
$ ./test one two --help
Usage:
  ./test [flags...] <foo> <bar> [arg...]

does foobar

Flags:
  --help          # Displays help for the current command.

Arguments:
  foo (required)
  bar (required)

Flag arrays with required false are still required

require "admiral"

class Main < Admiral::Command
  define_flag bloop : Array(String),
    default: [] of String,
    required: false

  def run
    puts flags.bloop
  end
end

Main.run
> bin/cli_test 
Flag required: --bloop

Am I doing something wrong?

Actually this seems a bit odd. The default must be nil or not a boolean?
https://github.com/jwaldrip/admiral.cr/blob/master/src/admiral/command/flag.cr#L288

edit:
There also seems to be a related issue here where the type specification is change to type | nil unless the type is set to required:
https://github.com/jwaldrip/admiral.cr/blob/master/src/admiral/command/flag.cr#L321

So even when the first issue is fixed, the type of bloop is Array(String) | Nil instead of the requested Array(String)

A way to say "this or this"

So, I want one of two flags to be required, not both, not none, but this or the other

flag1
flag2

raise unless flag1 || flag2

This is what I use now, but it lacks "promise" that one will be required.

Nested subcommands?

Couldn't get this to work, what am I missing?

# hello.cr
require "admiral"

class Hello < Admiral::Command
  class Planetary < Admiral::Command
    def run
      puts "Hello World"
    end
  end

  class Municipality < Admiral::Command
    define_help description: "City"

    class Zip < Admiral::Command
      def run
        puts "Hello City, Zip!"
      end
    end

    def run
      puts help
    end

    register_sub_command zip : Zip, description: "Nested subcommand"
  end

  register_sub_command planet : Planetary, description: ""
  register_sub_command city : Municipality, description: ""

  define_help description: "Testing subcommands"

  def run
    puts help
  end
end

Hello.run

In words, the expectation was to see:

./hello city zip
# Hello City, Zip!

But it never hits the Zip class.

Can't call --help when there is any required flags

define_help description: "Generate SQL files to load content data to DB"
define_flag account_id : Int32, required: true, description: "Account ID to process"

Calling with --help gives:

Flag: --account-id is required (Admiral::Error)
0x10fdec935: *CallStack::unwind:Array(Pointer(Void)) at ??
0x10fdec8d1: *CallStack#initialize:Array(Pointer(Void)) at ??
0x10fdec8a8: *CallStack::new:CallStack at ??
0x10fde93d1: *raise<Admiral::Error>:NoReturn at ??

Setting required: false solves the issue, but requires extra manual check on command run.

Negative numbers not accepted as argument

This is probably related to #15 .
Example code below:

require "admiral"

class NegativeNumber < Admiral::Command
  define_flag typed_int : Int32, required: true
  define_argument typed_arg : Int32, required: true

  def run
    puts flags.typed_int
    puts arguments.typed_arg
  end
end

puts "Negative flag:"
NegativeNumber.run "2 --typed-int -1"  # negative number works for flags
puts "Negative argument:"
NegativeNumber.run "-2 --typed-int 1"  # negative number produces a traceback for arguments

The typed_arg argument is defined as Int32, which can be positive or negative. But if I try to input a negative argument to it, a traceback is shown.
The output of the above code:

Negative flag:
-1
2
Negative argument:
1
Unhandled exception: Nil assertion failed (NilAssertionError)
  from /usr/lib/crystal/nil.cr:106:5 in 'not_nil!'
  from src/negative.cr:5:3 in 'typed_arg'
  from src/negative.cr:9:5 in 'run'
  from src/negative.cr:3:1 in 'parse_and_run'
  from src/negative.cr:3:1 in 'run'
  from src/negative.cr:16:1 in '__crystal_main'
  from /usr/lib/crystal/crystal/main.cr:97:5 in 'main_user_code'
  from /usr/lib/crystal/crystal/main.cr:86:7 in 'main'
  from /usr/lib/crystal/crystal/main.cr:106:3 in 'main'
  from __libc_start_main
  from _start
  from ???

Flags inheritance with subcommands

Hello,

I'm unhappy about how to keep active some "global" flags when using subcommands

This is an example where a --verbose flag is setup on top of every subcommands:

require "admiral"

module Log
  class_property verbose = false
end

class HelloWorld < Admiral::Command
  def run
    Log.verbose = self.flags.verbose

    puts "Hello World"
  end

  class SubCommand < Admiral::Command
    def run
      Log.verbose = self.parent.as(HelloWorld).flags.verbose

      puts "SubCommand"
    end
  end

  define_flag verbose : Bool, default: false, short: v

  register_sub_command sub_command, type: SubCommand
end

HelloWorld.run

My main problem is I need to repeat the code Log.verbose = self.parent.as(HelloWorld).flags.verbose on every run for each subcommands or the flag will be ignored.

Would it be great if we can put a block on define_flag like this:

define_flag(verbose : Bool, default: false, short: v){ |flag| Log.verbose = flag }

This code would be triggered even if run of the command is not called due to subcommand

IO might be Bool

in macro 'define_version' admiral/src/admiral/command/version.cr:19, line 5:

   1.     
   2.       define_flag __version__ : Bool, long: version, short: nil
   3.       protected def __run__ : Nil
   4.         if flags.__version__
>  5.           puts version
   6.           exit
   7.         else
   8.           previous_def
   9.         end
  10.       end
  11.     
  12. 
  13.     def version
  14.       "0.0.1"
  15.     end
  16.   

instantiating 'puts(String)'
in lib/admiral/src/admiral/command.cr:79: undefined method 'puts' for Bool (compile-time type is (Bool | IO::FileDescriptor))

      io.puts(*args)
         ^~~~

================================================================================

Bool trace:

  lib/admiral/src/admiral/command.cr:77

        case (io = @output_io)
              ^~

  lib/admiral/src/admiral/command.cr:77

        case (io = @output_io)
                   ^~~~~~~~~~

  lib/admiral/src/admiral/command.cr:8

      @output_io : IO::FileDescriptor | Bool = STDOUT
      ^~~~~~~~~~

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.