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

Add uses from macos #6162

Merged
merged 17 commits into from
Jun 5, 2019
Merged

Add uses from macos #6162

merged 17 commits into from
Jun 5, 2019

Conversation

gkpacker
Copy link
Contributor

@gkpacker gkpacker commented May 22, 2019

Fixes #6150

Add uses_from_macos method:

On Linux:

  • Acts like depends_on, ignoring OS version specifications

On MacOS:

  • Delegate to depends_on only if system meets dependency os requirements

Usage

Add specified dependency based on MacOS version

class MyFormula < ::Formula
  url "foo.bar"

  depends_on "foo"
  uses_from_macos "bar", after: :el_capitan
  uses_from_macos "baz", before: :mojave
end
  • 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 style with your changes locally?
  • Have you successfully run brew tests with your changes locally?

Copy link
Contributor

@sjackman sjackman left a comment

Choose a reason for hiding this comment

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

Nicely done, Gabriel! And thanks for the comprehensive tests!

@MikeMcQuaid
Copy link
Member

I'm away on a work trip right now but will review this when I get the chance. Thanks!

@xu-cheng
Copy link
Contributor

FYI, you may want to implement this feature in SoftwareSpec instead of Formula in order to support different specs. For example:

head do
  uses_from_mac "python"
end

@sjackman
Copy link
Contributor

@xu-cheng wrote… #6150 (comment)

Just my two cents, you may want to support :build, :test arguments for this new DSL. For example,

uses_from_macos "m4", tag: :build
uses_from_macos "gpatch", tag: [:build, :test]

@sjackman
Copy link
Contributor

These are both good suggestions.

Gabriel, would you be up for moving the definition of uses_from_macos from Formula to SoftwareSpec? Formula would keep a definition of uses_from_macos that forwards to each of the formula's SoftwareSpec, similar to depends_on.

@sjackman
Copy link
Contributor

sjackman commented May 23, 2019

uses_from_macos "m4", tag: :build
uses_from_macos "gpatch", tag: [:build, :test]

I suggest keeping the same syntax as depends_on:

uses_from_macos "m4" => :build
uses_from_macos "gpatch" => [:build, :test], :before => :mojave

@MikeMcQuaid
Copy link
Member

I suggest keeping the same syntax as depends_on:

Agreed 👍

@gkpacker
Copy link
Contributor Author

Gabriel, would you be up for moving the definition of uses_from_macos from Formula to SoftwareSpec?

Yeah, sure.

@gkpacker
Copy link
Contributor Author

@sjackman Actually, i was wondering if it is really necessary, because uses_from_macos is only a depends_on 'mask', so whatever dependency it adds, it will pass to depends_on, right?

@gkpacker
Copy link
Contributor Author

Ah, head isn't a formula

@sjackman
Copy link
Contributor

Thank you, Gabriel! Sorry that I hadn't given you the right info in the first place.

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.

Great start on this @gkpacker, thanks!

class Formula
class << self
def uses_from_macos(dep, **args)
depends_on(dep) if add_mac_dependency?(args)
Copy link
Member

Choose a reason for hiding this comment

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

Agreed with @xu-cheng this should should tags like :test and :build and pass them through accordingly and it should be on SoftwareSpec.

Copy link
Contributor

Choose a reason for hiding this comment

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

If dep is a hash, I think that does happen with the current code (untested).

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 think it already works with tags, i'll add some specs for it

require "formula"

describe Formula do
describe "#uses_from_macos" do
Copy link
Member

Choose a reason for hiding this comment

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

Nice work on the tests 👏

Copy link
Contributor

@sjackman sjackman left a comment

Choose a reason for hiding this comment

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

Excellent first contribution, Gabriel! I hope there are more to come. 🌟


class SoftwareSpec
def uses_from_macos(deps, **args)
depends_on(deps) if add_mac_dependency?(args)
Copy link
Contributor

Choose a reason for hiding this comment

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

Current code will fail to handle uses_from_macos "foo" => :build, :before => :el_capitan. As in this case,
deps is { "foo" => :build, :before => : el_capitan }, while args is {}

I suggest something like the following. Though you may consider to choose better variable names.

Suggested change
depends_on(deps) if add_mac_dependency?(args)
if deps.is_a?(Hash)
dep, dep_tags = deps.first
deps.delete(dep)
depends_on(dep => dep_tags) if add_mac_dependency?(deps)
else
depends_on(deps) if add_mac_dependency?(args)
end

Further, I suggest you should test all four cases in the test cases.

  • uses_from_macos "foo"
  • uses_from_macos "foo" , :before => :el_capitan
  • uses_from_macos "foo" => :build
  • uses_from_macos "foo" => :build, :before => :el_capitan

Copy link
Contributor

@sjackman sjackman May 25, 2019

Choose a reason for hiding this comment

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

Good catch, @xu-cheng! I suggest…

def uses_from_macos(dep, **args)
  if dep.is_a?(Hash)
    args = dep
    dep = Hash[*args.shift]
  end
  depends_on(dep) if add_mac_dependency?(args)
end

Further, I suggest you should test all four cases in the test cases.

Good suggestion!

return false if args[:before] && OS::Mac.version >= args[:before]

true
end
Copy link
Contributor

Choose a reason for hiding this comment

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

From my understanding, uses_from_macos "foo" (i.e. without version args) should not add foo as dependency on macOS. However, the current logic does the opposite.


class SoftwareSpec
def uses_from_macos(deps, **args)
depends_on(deps) if add_mac_dependency?(args)
Copy link
Contributor

@sjackman sjackman May 25, 2019

Choose a reason for hiding this comment

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

Good catch, @xu-cheng! I suggest…

def uses_from_macos(dep, **args)
  if dep.is_a?(Hash)
    args = dep
    dep = Hash[*args.shift]
  end
  depends_on(dep) if add_mac_dependency?(args)
end

Further, I suggest you should test all four cases in the test cases.

Good suggestion!


return false if args[:before] && OS::Mac.version >= args[:before]

true
Copy link
Contributor

Choose a reason for hiding this comment

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

From my understanding, uses_from_macos "foo" (i.e. without version args) should not add foo as dependency on macOS. However, the current logic does the opposite.

Suggested change
true
!args.empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, actually i think it makes sense to have this behaviour only on Linux, since it uses from macos. Without any version specification it seems that the method uses from macos unconditionally, so:

On MacOS

uses_from_macos "foo"                    # always add foo as dep in macos
uses_from_macos "foo", after: :sierra    # add foo as dep only after macos sierra

On Linux

uses_from_macos "foo" # Does nothing, since we're adding a macos dependency

What do you think? @sjackman @xu-cheng

Copy link
Contributor

Choose a reason for hiding this comment

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

In fact it's the exact opposite of that. uses_from_macos "foo", after: :sierra means that on macOS Sierra and later we use foo provided by macOS operating system, and so we do not need to to use the brewed dependency. Before macOS Sierra we need to install the brewed dependency. On Linux we always install the dependency.

On macOS

uses_from_macos "foo"                    # Never add foo as dep in macos
uses_from_macos "foo", after: :sierra    # add foo as dep only before macos sierra

On Linux

uses_from_macos "foo" # Always add foo as dep on Linux

@@ -1,6 +1,8 @@
# frozen_string_literal: true

class SoftwareSpec
undef uses_from_macos
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about this, i was troubleshooting a misterious spec that was failling because it requires linux and it wasn't mocking with OS.linux?. Saw this on other files and added here...

expect(spec.deps.last.tags).to include(:head)
end
end
end
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe it shouldn't be on os/linux/ anyway, since it's the default behaviour

Copy link
Contributor

Choose a reason for hiding this comment

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

If these tests fail on macOS, then they do need to be in os/linux/. If they pass on macOS, then yeah, they could be moved.

Copy link
Member

Choose a reason for hiding this comment

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

You can use the :needs_linux tag instead for (the only) Linux specific tests. The test file folder locations should match the source file definitions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mocking OS.linux shouldn't be enough for this case? It was running the extended uses_from_macos version even returning true on OS.linux?

Copy link
Member

Choose a reason for hiding this comment

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

It would be sufficient but it's not how we've been doing things with other tests. Would appreciate consistency for now and could change elsewhere in a follow-up PR?

@@ -170,6 +170,12 @@ def depends_on(spec)
add_dep_option(dep) if dep
end

def uses_from_macos(deps, **_args)
deps.is_a?(Hash) && deps = Hash[*deps.shift]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
deps.is_a?(Hash) && deps = Hash[*deps.shift]
deps = Hash[*deps.shift] if deps.is_a?(Hash)

Copy link
Contributor

Choose a reason for hiding this comment

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

Minor style nit, otherwise this PR looks good to me!

expect(spec.deps.last.tags).to include(:head)
end
end
end
Copy link
Contributor

Choose a reason for hiding this comment

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

If these tests fail on macOS, then they do need to be in os/linux/. If they pass on macOS, then yeah, they could be moved.

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.

A few comments from @xu-cheng and @sjackman still need addressed but looking good so far!

@sjackman
Copy link
Contributor

Three CI failures on Linux to check out:

Failed examples:

rspec ./test/software_spec_spec.rb:136 # SoftwareSpec#uses_from_macos allows specifying dependencies
rspec ./test/software_spec_spec.rb:149 # SoftwareSpec#uses_from_macos ignores OS version specifications
rspec ./test/software_spec_spec.rb:142 # SoftwareSpec#uses_from_macos works with tags

https://dev.azure.com/Homebrew/Homebrew/_build/results?buildId=10713&view=logs

@gkpacker
Copy link
Contributor Author

@sjackman How can i fix if can't run them locally?

@gkpacker
Copy link
Contributor Author

Oh, sorry, dind't checked the logs

@sjackman
Copy link
Contributor

I use Docker for macOS to run brew tests on Linux. It works great!

@gkpacker
Copy link
Contributor Author

gkpacker commented Jun 3, 2019

@sjackman Another few questions:

  • How can i run the CI on the last commit?
  • Do i have to commit another file?
  • What are the next steps?

@sjackman
Copy link
Contributor

sjackman commented Jun 3, 2019

The CI seems stalled. To rerun it, rebase the PR onto origin/master and git push --force gkpacker add_uses_from_macos.

@gkpacker gkpacker force-pushed the add_uses_from_macos branch from 57d20a1 to 9fa8dc5 Compare June 3, 2019 18:53
@gkpacker
Copy link
Contributor Author

gkpacker commented Jun 4, 2019

@sjackman Done!

Copy link
Contributor

@sjackman sjackman left a comment

Choose a reason for hiding this comment

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

Thank you for this work, Gabriel!

@sjackman sjackman merged commit 7c5f71e into Homebrew:master Jun 5, 2019
@sjackman
Copy link
Contributor

sjackman commented Jun 5, 2019

Merged! Thank you for your first contribution to Homebrew, Gabriel! 🥇

@MikeMcQuaid
Copy link
Member

Great work here @gkpacker 🎉

A suggested next PR would be to expose this information in brew info --json! The relevant code is here:

def to_hash
dependencies = deps
hsh = {
"name" => name,
"full_name" => full_name,
"oldname" => oldname,
"aliases" => aliases.sort,
"versioned_formulae" => versioned_formulae.map(&:name),
"desc" => desc,
"homepage" => homepage,
"versions" => {
"stable" => stable&.version&.to_s,
"devel" => devel&.version&.to_s,
"head" => head&.version&.to_s,
"bottle" => !bottle_specification.checksums.empty?,
},
"revision" => revision,
"version_scheme" => version_scheme,
"bottle" => {},
"keg_only" => keg_only?,
"bottle_disabled" => bottle_disabled?,
"options" => [],
"build_dependencies" => dependencies.select(&:build?)
.map(&:name)
.uniq,
"dependencies" => dependencies.reject(&:optional?)
.reject(&:recommended?)
.reject(&:build?)
.map(&:name)
.uniq,
"recommended_dependencies" => dependencies.select(&:recommended?)
.map(&:name)
.uniq,
"optional_dependencies" => dependencies.select(&:optional?)
.map(&:name)
.uniq,
"requirements" => [],
"conflicts_with" => conflicts.map(&:name),
"caveats" => caveats&.gsub(HOMEBREW_PREFIX, "$(brew --prefix)"),
"installed" => [],
"linked_keg" => linked_version&.to_s,
"pinned" => pinned?,
"outdated" => outdated?,
}
%w[stable devel].each do |spec_sym|
next unless spec = send(spec_sym)
next unless spec.bottle_defined?
bottle_spec = spec.bottle_specification
bottle_info = {
"rebuild" => bottle_spec.rebuild,
"cellar" => (cellar = bottle_spec.cellar).is_a?(Symbol) ? cellar.inspect : cellar,
"prefix" => bottle_spec.prefix,
"root_url" => bottle_spec.root_url,
}
bottle_info["files"] = {}
bottle_spec.collector.keys.each do |os|
bottle_url = "#{bottle_spec.root_url}/#{Bottle::Filename.create(self, os, bottle_spec.rebuild).bintray}"
checksum = bottle_spec.collector[os]
bottle_info["files"][os] = {
"url" => bottle_url,
checksum.hash_type.to_s => checksum.hexdigest,
}
end
hsh["bottle"][spec_sym] = bottle_info
end

@sjackman
Copy link
Contributor

sjackman commented Jun 5, 2019

Another suggested next PR would be to revive this PR to add depends_on :macos => :help_wanted from @jonchang to the archived Linuxbrew/brew and submit it to Homebrew/brew.
Linuxbrew/brew#831 (comment)

@sjackman
Copy link
Contributor

Homebrew/brew 2.1.5 is released, which includes this PR and the DSL command uses_from_macos. We can start replacing depends_on "foo" unless OS.mac? in Homebrew/linuxbrew-core with uses_from_macos "foo" in Homebrew/homebrew-core.

@lock lock bot added the outdated PR was locked due to age label Jan 1, 2020
@lock lock bot locked as resolved and limited conversation to collaborators Jan 1, 2020
@gkpacker gkpacker deleted the add_uses_from_macos branch July 15, 2020 21:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated PR was locked due to age
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add uses_from_macos "python" DSL
4 participants