Brew: Cleanup ARGV usage

Created on 13 Feb 2019  路  16Comments  路  Source: Homebrew/brew

Now we have a proper argument parser (thanks @GauthamGoli!) we should replace all uses of ARGV in the Homebrew/brew codebase with calls to Homebrew.args instead.

extend/ARGV.rb should be moved into https://github.com/Homebrew/brew/blob/master/Library/Homebrew/cli/args.rb where needed or removed where not. This may warrant changes to formulae and odeprecated.

Note formula_installer.rb and build.rb should be handled last as they read from and modify ARGV: https://github.com/Homebrew/brew/blob/b4f73e61649fcfc5aaa779c311e2514619ce01e7/Library/Homebrew/formula_installer.rb#L678-L751

No need to say "I'm planning on working on this" or similar in this issue but feel free to open a PR that doesn't work (yet!) and ask for help.

good first issue help wanted in progress outdated

Most helpful comment

Note to @goibon and @GauthamGoli: all Homebrew organisation tap commands are now using Homebrew::CLI::Parser.

All 16 comments

This seems like something I'd be happy to help out with, though it seems like an incremental approach to this is best (rather than getting rid of it all in one PR)

Would this be a reasonable way to do that?

  1. Add a nested Homebrew::CLI::Parser::ArgvExtension module
  2. Add ARGV.extend(Homebrew::CLI::Parser::ArgvExtension) to global.rb (but do not remove the other ARGV.extend call)
  3. From this point, extract logic to the new ArgvExtension module when needed, and replace ARGV.* methods with Homebrew.args.* when possible
  4. Remove HomebrewArgvExtension entirely

And then after repeating step 3 on all the various ARGV calls, it would eventually be possible to remove the old HomebrewArgvExtension

One other clarification: Is the goal to add more info into the Homebrew.args struct, or just to add the ARGV logic into the cli_parser file?

For example, we could pre-compute the named arguments and add it as a field to Homebrew.args, and then delete ARGV.named. But doing this for _every_ ARGV method would make the Homebrew.args struct somewhat bloated (which might still be worth it!)

@BenMusch Sounds great!

For example, we could pre-compute the named arguments and add it as a field to Homebrew.args, and then delete ARGV.named. But doing this for _every_ ARGV method would make the Homebrew.args struct somewhat bloated (which might still be worth it!)

I think we can avoid precomputing but we could cache it intelligently.

Part of the motivation for this is that I don't think we will need to do it for every ARGV method; some of them will be able to be removed or replaced with better APIs. Any that aren't used in Homebrew/brew or Homebrew/homebrew-core can be considered internal APIs and removed. Even among those it may be they can be refactored so they aren't needed.

The easy ones to start with should be those like ARGV.build_bottle?. That should be able to be replaced with according args.build_bottle? and the method deleted without any code needing to be added.

I've updated the original issue a bit now https://github.com/Homebrew/brew/pull/6021 is merged which should simplify things a bit.

Could I start to work on this?

@jeduardo824 Yes, please!

Hi! I'd like to work on this issue, but I'm having trouble running the tests. What is the command to run them? I tried ruby collector_spec.rb and a couple other file names/folder structure paths, but I'm getting require errors. Thanks!

Tests can be run using brew tests command

Hi @TedTran2019! I am working on this in my free time, but you can work on this too, #6433 is part of the on-going effort. You can take a look at the other PRs referenced here to get an idea.

In a tap of mine (homebrew-upup) I use the flags? method that ARGV used to be extended with to test for flags. Since #6857 this method has been made private and no longer accessible as ARGV.flags?.
I can see that you are moving away from use of ARGV and to use Homebrew.args instead and I was wondering what the proper way of parsing args is now 馃
Will it be possible for me to use Homebrew.args and if so how?
Or will I have to parse args myself?

@goibon You can just replace flag? with include?. Should work the same way.

@goibon Sorry for the inconvenience but that was essentially a private API 馃槶. I hope in the near future to be able to provide an example in e.g. Homebrew/bundle of using Homebrew::CLI::Parser in a tap.

@issyl0 already made first steps, to provide an example how to use it in a tap: https://github.com/Homebrew/homebrew-linux-dev/pull/137.

Note to @goibon and @GauthamGoli: all Homebrew organisation tap commands are now using Homebrew::CLI::Parser.

@MikeMcQuaid @GauthamGoli Thanks for the pointers, I switched to using Homebrew::CLI::Parser now and it seems to work 馃憦
However I'm not sure how to get the usage banner to show 馃
When I invoke my command like brew upup --help or brew upup -h I see the usage banner for brew itself. Oddly though if I invoke my command like brew upup -help with _one_ dash, it actually shows my usage banner. When using -help I don't get an error message at the bottom like when using unknown options 馃し鈥嶁檪
Can you see anything wrong with the way I'm implementing it?

require "cli/parser"

def announce_args
  Homebrew::CLI::Parser.new do
    usage_banner <<~EOS
    `upup` [`--cleanup`][`--quiet`]
    EOS
    switch "--cleanup",
      description: "Calls brew cleanup after the last step"
    switch "--quiet",
      description: "Runs quietly with no output unless something goes wrong"
  end
end
announce_args.parse

@goibon Check the other PRs. TL;DR you need to:

  • rename e.g. brew-services.rb to services.rb
  • move everything into the Homebrew module
  • use services_args and services methods; the latter will be called to run and the prior to generate help text etc.
  • ensure services calls services_args.parse
Was this page helpful?
0 / 5 - 0 ratings

Related issues

javian picture javian  路  4Comments

rtobrien picture rtobrien  路  3Comments

JustinTArthur picture JustinTArthur  路  3Comments

cdekok picture cdekok  路  4Comments

paanvaannd picture paanvaannd  路  4Comments