Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

brew deps: add --include-requirements, plus some fixes #2996

Merged
merged 1 commit into from
Aug 15, 2017
Merged

brew deps: add --include-requirements, plus some fixes #2996

merged 1 commit into from
Aug 15, 2017

Conversation

apjanke
Copy link
Contributor

@apjanke apjanke commented Aug 3, 2017

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew tests with your changes locally?

Adds a --include-requirements option to brew deps, to display all requirements, including ones without a default formula. Ones with a default formula are displayed as a requirement, with the default formula noted in parentheses. Per a suggestion by @ilovezfs.

Mostly useful in conjunction with --tree. This helps hunt down where a deeply-nested requirement is coming from. For example, octave has an indirect dependency on :x11, but it has so many dependencies it's hard to tell where they're coming from. Or it lets you determine where the MinimumMacOS requirement for mytop is coming from.

Also fixes a bug in --tree where the dependencies of a Requirement's default formula were not recursed into.

Also fixes a bug where the --tree mode ignored the --include-optional, --include-build, and --skip-recommended filters, instead always displaying build and recommended dependencies, and never optionals.

Also adds an --annotate option to the --tree mode, marking up optional, recommended, and build dependencies as such in the display.

Also adds an undocumented --for-each switch to help debug the --all/--installed display mode, which couldn't previously be gotten to for a list of specified formulae.

Before:

$ brew deps --tree xpdf
xpdf (required dependencies)
├── openmotif
│   ├── automake
│   │   └── autoconf
│   ├── autoconf
...

$ brew deps --tree mytop
mytop (required dependencies)
├── :mysql
└── openssl
    └── makedepend
        └── pkg-config

After:

$ brew deps --tree --include-requirements xpdf
xpdf
├── :x11
├── openmotif
│   ├── :x11
│   ├── fontconfig
│   │   └── freetype
...

$ brew deps --tree mytop
mytop
├── mysql
│   └── openssl
└── openssl

$ brew deps --tree mytop --include-requirements
mytop
├── :mysql (mysql)
│   ├── :macOS >= 10.7
│   └── openssl
└── openssl

$ brew deps --tree mytop --include-requirements --include-build
mytop
├── :mysql (mysql)
│   ├── :macOS >= 10.7
│   ├── cmake
│   │   └── sphinx-doc
│   └── openssl
│       └── makedepend
│           └── pkg-config
└── openssl
    └── makedepend
        └── pkg-config

Removing the colon before the default formula when not doing --include-requirements makes the --tree output more consistent with the non-tree output.

Note that if you include all of --tree --include-optional --include-build --include-requirements on large formulae (like brew deps octave --tree --include-optional --include-build --include-requirements), you can get a stack overflow error. I suspect this is because there's a circular dependency in the formula definitions somewhere. This could be worked around by using a stack to detect circular dependencies inside the code here, but I haven't put it in yet.

Test failure

I'm getting this failure when I run brew tests locally, but it's also happening for me on master. Don't think it's introduced by this PR.

Failures:

  1) OS::Mac::language can be parsed by Locale::parse
     Failure/Error: expect { Locale.parse(subject.language) }.not_to raise_error

       expected no Exception, got #<Locale::ParserError: '' cannot be parsed to a Locale> with backtrace:
         # ./locale.rb:15:in `parse'
         # ./test/os/mac_spec.rb:19:in `block (4 levels) in <top (required)>'
         # ./test/os/mac_spec.rb:19:in `block (3 levels) in <top (required)>'
         # ./test/spec_helper.rb:96:in `block (2 levels) in <top (required)>'
         # ./vendor/bundle/ruby/2.0.0/gems/rspec-wait-0.0.9/lib/rspec/wait.rb:46:in `block (2 levels) in <top (required)>'
     # ./test/os/mac_spec.rb:19:in `block (3 levels) in <top (required)>'
     # ./test/spec_helper.rb:96:in `block (2 levels) in <top (required)>'
     # ./vendor/bundle/ruby/2.0.0/gems/rspec-wait-0.0.9/lib/rspec/wait.rb:46:in `block (2 levels) in <top (required)>'

Finished in 56.57 seconds (files took 1.49 seconds to load)
446 examples, 1 failure

Failed examples:

rspec ./test/os/mac_spec.rb:18 # OS::Mac::language can be parsed by Locale::parse

@apjanke apjanke changed the title brew deps --tree: add --include-requirements brew deps: add --include-requirements Aug 3, 2017
@apjanke apjanke changed the title brew deps: add --include-requirements brew deps: add --include-requirements, plus some fixes Aug 3, 2017
@ilovezfs
Copy link
Contributor

ilovezfs commented Aug 4, 2017

Thanks for this PR @apjanke! It seems to work as expected in my testing.

you can get a stack overflow error.

It would be good if this were fixed before this goes in. brew deps --tree -include-optional ffmpeg caused my terminal to lose its mind. :)

(Also, it would be neat if --tree respected --1.)

@apjanke
Copy link
Contributor Author

apjanke commented Aug 4, 2017

Added --1 support to --tree. I don't see how that would be useful in practice, but it's nice in that it unifies the behavior of the different display modes; I like it.

I see how to implement cycle detection to avoid the stack overflow. I'll add it. The brew deps --tree -include-optional ffmpeg blow-up reproduces for me too, and that's not an obscure case.

@apjanke
Copy link
Contributor Author

apjanke commented Aug 4, 2017

Added circular-dependency detection. This fixes the stack overflow error.

Now brew deps --tree --include-optional ffmpeg works:

$ brew deps --tree --include-optional ffmpeg
ffmpeg
├── lame
├── x264
│   └── l-smash
├── xvid
...
│       │   ├── jpeg
│       │   ├── libpng
│       │   └── libtiff
│       │       ├── jpeg
│       │       └── xz
│       └── ffmpeg (CIRCULAR DEPENDENCY)

and brew deps octave --tree ... is merely insane, not broken:

$ brew deps octave --tree --include-optional --include-build --include-requirements | wc -l
   25843

@ilovezfs
Copy link
Contributor

ilovezfs commented Aug 4, 2017

and brew deps octave --tree ... is merely insane, not broken:

$ brew deps octave --tree --include-optional --include-build --include-requirements | wc -l
  25843

A generic --depth option would probably help to tame that particular crazy.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Some style pedantry (some of which isn't your fault) but: nice work!

@with_optional = ARGV.include?("--include-optional")
@with_build = ARGV.include?("--include-build")
@skip_recommended = ARGV.include?("--skip-recommended")
@annotate = ARGV.include?("--annotate")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels weird to use class variables for some of ARGV and not others. I'd lean on the side of never using them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I tried writing this to use function parameters for everything, and it got pretty hard to ready. Maybe it should fall back to using ARGV.include? everywhere? Or a single class instance variable for all the options? My impression is we're trying to move away from scattering global ARGV references everywhere.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it should fall back to using ARGV.include? everywhere?

Yeh, I agree.

My impression is we're trying to move away from scattering global ARGV references everywhere.

I think broadly but at this point it's probably reliant on having a decent Command DSL first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it to use direct ARGV references everywhere, and removed the class instance variables.

if @with_reqs
deps
else
deps.map do |d|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deps.map do |dep|

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

end.compact
end
end

def dep_display_name(d)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def dep_display_name(dep)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

prefix_ext = (i == max) ? " " : "│ "
puts prefix + "#{chr} #{dep_display_name(dep)}"
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_ext)
display_s = "#{chr} #{dep_display_name(dep)}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we figure out a better name than chr here? line, maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about tree_lines, to distinguish the graphical lines of the tree structure from a "line" of text?

display_s = "#{chr} #{dep_display_name(dep)}"
is_circular = @dep_stack.include?(dep.name)
display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
puts prefix + display_s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

puts "#{prefix}#{display_s}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
puts prefix + display_s
if recursive && !is_circular
prefix_ext = (i == max) ? " " : "│ "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefix_extension = if i == max

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@apjanke
Copy link
Contributor Author

apjanke commented Aug 7, 2017

Addressed most of the style pedantry, except for the use of class instance variables. Not sure what the right fix to do there is; using function parameters makes the code look pretty gross IMHO. I think class instance variables should be okay in the case of commands, since the modules are only loaded one per process, used once, and then the process ends. Deferring to the judgment of other maintainers here though.

@apjanke
Copy link
Contributor Author

apjanke commented Aug 7, 2017

And, thanks!

@apjanke
Copy link
Contributor Author

apjanke commented Aug 7, 2017

Updated the zsh completions to reflect the new brew deps --tree behavior in this PR.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once brew style passes 👍

@apjanke
Copy link
Contributor Author

apjanke commented Aug 11, 2017

Arg! brew style-ing now...

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good :shipit:

@apjanke apjanke merged commit 60d8218 into Homebrew:master Aug 15, 2017
@apjanke
Copy link
Contributor Author

apjanke commented Aug 15, 2017

Merged. Thanks for the feedback!

@apjanke apjanke deleted the non-formula-reqs-in-brew-deps-tree branch August 15, 2017 00:19
@chdiza
Copy link
Contributor

chdiza commented Aug 15, 2017

For example, octave has an indirect dependency on :x11, but it has so many dependencies it's hard to tell where they're coming from.

I just tried brew deps octave --tree --include-requirements, and no such :x11 appears in the output. Am I doing it wrong?

@ilovezfs
Copy link
Contributor

@Homebrew Homebrew locked and limited conversation to collaborators May 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants