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

Homebrew module incorrectly fails executing task when package is already installed #864

Closed
mpereira opened this issue Sep 4, 2020 · 36 comments · Fixed by #7870
Closed
Assignees
Labels
bug This issue/PR relates to a bug has_pr module module os packaging plugins plugin (any type)

Comments

@mpereira
Copy link

mpereira commented Sep 4, 2020

SUMMARY
- name: Install wkhtmltopdf
  homebrew:
    name: homebrew/cask/wkhtmltopdf 
    state: present

results in

PLAY [localhost] ***************************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Install wkhtmltopdf] *****************************************************
fatal: [localhost]: FAILED! => changed=false 
  msg: |-
    Updating Homebrew...
    Warning: Cask 'wkhtmltopdf' is already installed.
  
    To re-install wkhtmltopdf, run:
      brew cask reinstall wkhtmltopdf

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
ISSUE TYPE
  • Bug Report
COMPONENT NAME

Homebrew module

ANSIBLE VERSION
$ ansible --version
ansible 2.9.13
  config file = /Users/mpereira/git/macbook-playbook/ansible.cfg
  configured module search path = ['/Users/mpereira/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/mpereira/Library/Python/3.8/lib/python/site-packages/ansible
  executable location = /Users/mpereira/Library/Python/3.8/bin/ansible
  python version = 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27) [Clang 6.0 (clang-600.0.57)]
CONFIGURATION
$ ansible-config dump --only-changed
DEFAULT_STDOUT_CALLBACK(/Users/mpereira/git/macbook-playbook/ansible.cfg) = yaml
OS / ENVIRONMENT
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.5
BuildVersion:	19F101
STEPS TO REPRODUCE

Refer to summary.

EXPECTED RESULTS

I expect the task to complete successfully when a package is already installed and a homebrew task is executed with either state: present or state: latest.

ACTUAL RESULTS

The task fails, as shown in the summary.

@ansibullbot
Copy link
Collaborator

Files identified in the description:

If these files are inaccurate, please update the component name section of the description or use the !component bot command.

click here for bot help

@ansibullbot
Copy link
Collaborator

@ansibullbot ansibullbot added affects_2.10 bug This issue/PR relates to a bug module module needs_triage os packaging plugins plugin (any type) labels Sep 4, 2020
@mpereira
Copy link
Author

mpereira commented Sep 4, 2020

The issue seems to only happen with casks. e.g., the following works:

- name: Install Hugo
  homebrew:
    name: hugo
PLAY [localhost] ***************************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [hugo : Install Hugo] *****************************************************
ok: [localhost] => changed=false 
  msg: 'Package already installed: hugo'

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

@MichaelWasher
Copy link
Contributor

/assign

@MichaelWasher
Copy link
Contributor

It depends on the expected usage. For installing casks homebrew_cask should be used.
Testing with homebrew_cask as below works fine:

    - name: Install Packages through Homebrew
      homebrew_cask:
        name: visual-studio-code
        state: present
ok: [localhost] => {
    "changed": false,
    "invocation": {
        "module_args": {
            "accept_external_apps": false,
            "greedy": false,
            "install_options": [],
            "name": [
                "visual-studio-code"
            ],
            "path": "/usr/local/bin",
            "state": "present",
            "sudo_password": null,
            "update_homebrew": false,
            "upgrade_all": false
        }
    },
    "msg": "Cask already installed: visual-studio-code"
}

However when using the homebrew package to install casks fails for me in general.

    - name: Remove visual-studio-code
      homebrew_cask:
        name: visual-studio-code
        state: absent
    - name: Install Packages through Homebrew
      homebrew:
        name: visual-studio-code
        state: present
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "install_options": [],
            "name": [
                "visual-studio-code"
            ],
            "path": "/usr/local/bin",
            "state": "present",
            "update_homebrew": false,
            "upgrade_all": false,
            "upgrade_options": []
        }
    },
    "msg": ""
}

Seems like we should deal with the output message better but not sure if the homebrew module should manage cask installs

@MichaelWasher
Copy link
Contributor

@felixfontein Do you want the homebrew module to be more friendly with failing on cask issues;
Error something like "This Homebrew package is a cask and requires using the homebrew_cask module" or do you think this case should just be closed?

@felixfontein
Copy link
Collaborator

@MichaelWasher I don't use or maintain the module, so I'm not the right person to ask. In general, having better error messages is always a good thing though :)

@dansholds
Copy link

I think this would be preferred behaviour, seems unnecessary to have to split package installs between two separate modules when it could/should stay in homebrew / community.general.homebrew.

TASK [Ensure apps are installed] *********************************************************************************************************************************************************************************************
failed: [localhost] (item=cheatsheet) => {"ansible_loop_var": "item", "changed": false, "item": "cheatsheet", "msg": "Warning: Cask 'cheatsheet' is already installed.\n\nTo re-install cheatsheet, run:\n  brew reinstall cheatsheet"}
ok: [localhost] => (item=docker)
failed: [localhost] (item=firefox) => {"ansible_loop_var": "item", "changed": false, "item": "firefox", "msg": "Error: It seems there is already an App at '/Applications/Firefox.app'."}
failed: [localhost] (item=gimp) => {"ansible_loop_var": "item", "changed": false, "item": "gimp", "msg": "Warning: Cask 'gimp' is already installed.\n\nTo re-install gimp, run:\n  brew reinstall gimp"}
ok: [localhost] => (item=gnupg)
failed: [localhost] (item=google-chrome) => {"ansible_loop_var": "item", "changed": false, "item": "google-chrome", "msg": "Error: It seems there is already an App at '/Applications/Google Chrome.app'."}
failed: [localhost] (item=gpg-suite) => {"ansible_loop_var": "item", "changed": false, "item": "gpg-suite", "msg": "Warning: Cask 'gpg-suite' is already installed.\n\nTo re-install gpg-suite, run:\n  brew reinstall gpg-suite"}
failed: [localhost] (item=inkscape) => {"ansible_loop_var": "item", "changed": false, "item": "inkscape", "msg": "Warning: Cask 'inkscape' is already installed.\n\nTo re-install inkscape, run:\n  brew reinstall inkscape"}
failed: [localhost] (item=iterm2) => {"ansible_loop_var": "item", "changed": false, "item": "iterm2", "msg": "Warning: Cask 'iterm2' is already installed.\n\nTo re-install iterm2, run:\n  brew reinstall iterm2"}
ok: [localhost] => (item=jq)
ok: [localhost] => (item=maven)
ok: [localhost] => (item=md5sha1sum)
ok: [localhost] => (item=openjdk)
ok: [localhost] => (item=pass)
failed: [localhost] (item=pgadmin3) => {"ansible_loop_var": "item", "changed": false, "item": "pgadmin3", "msg": "Warning: Cask 'pgadmin3' is already installed.\n\nTo re-install pgadmin3, run:\n  brew reinstall pgadmin3"}
failed: [localhost] (item=pgp2) => {"ansible_loop_var": "item", "changed": false, "item": "pgp2", "msg": "Error: No available formula or cask with the name \"pgp2\".\nError: No previously deleted formula found.\nError: No similarly named formulae found.\n==> Searching taps on GitHub...\nError: No formulae found in taps."}
failed: [localhost] (item=sequel pro) => {"ansible_loop_var": "item", "changed": false, "item": "sequel pro", "msg": "Invalid package: sequel pro."}
ok: [localhost] => (item=terraform)
ok: [localhost] => (item=tree)
failed: [localhost] (item=vagrant) => {"ansible_loop_var": "item", "changed": false, "item": "vagrant", "msg": "Warning: Cask 'vagrant' is already installed.\n\nTo re-install vagrant, run:\n  brew reinstall vagrant"}
failed: [localhost] (item=virtualbox) => {"ansible_loop_var": "item", "changed": false, "item": "virtualbox", "msg": "Warning: Cask 'virtualbox' is already installed.\n\nTo re-install virtualbox, run:\n  brew reinstall virtualbox"}
failed: [localhost] (item=virtualbox-extension-pack) => {"ansible_loop_var": "item", "changed": false, "item": "virtualbox-extension-pack", "msg": "Warning: Cask 'virtualbox-extension-pack' is already installed.\n\nTo re-install virtualbox-extension-pack, run:\n  brew reinstall virtualbox-extension-pack"}
failed: [localhost] (item=visual-studio-code) => {"ansible_loop_var": "item", "changed": false, "item": "visual-studio-code", "msg": "Warning: Cask 'visual-studio-code' is already installed.\n\nTo re-install visual-studio-code, run:\n  brew reinstall visual-studio-code"}
ok: [localhost] => (item=watch)
ok: [localhost] => (item=wireshark)
failed: [localhost] (item=xquartz) => {"ansible_loop_var": "item", "changed": false, "item": "xquartz", "msg": "Warning: Cask 'xquartz' is already installed.\n\nTo re-install xquartz, run:\n  brew reinstall xquartz"}

PLAY RECAP *******************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0 

@MichaelWasher
Copy link
Contributor

It all really depends on what everyone wants.

But the issue for failing on already installed is due to the below lines, and could be resolved with the snippet below:
https://github.com/ansible-collections/community.general/blob/main/plugins/modules/packaging/os/homebrew.py#L462-L481

    # NOTE: This command will output both installed packages and casks
        cmd = [
            "{brew_path}".format(brew_path=self.brew_path), "list", "-1"
        ]
        rc, out, err = self.module.run_command(cmd)
        for package in out.split('\n'):
            if package == self.current_package:
                return True

        return False

@MichaelWasher
Copy link
Contributor

Actually looks like HomeBrew doesn't provode the same output depending on TTY and pipes... 👎
https://github.com/Homebrew/brew/blob/master/Library/Homebrew/cmd/list.rb#L90-L96

Something more like this would fix:

        cmd0 = ["{brew_path}".format(brew_path=self.brew_path), "list", "--casks"]
        cmd1 = ["{brew_path}".format(brew_path=self.brew_path), "list", "--formula"]

        rc, out, err = self.module.run_command(cmd0)
        rc1, out1, err1 = self.module.run_command(cmd1)

        out += '\n' + out1
        for package in out.split('\n'):
            if package == self.current_package:
                return True

@dansholds
Copy link

The latest updates to the homebrew & homebrew_cask modules that caught the regex issue for catching dashes is enough for me, it appears that was an underlying issues I hadn't noticed and it was forcing me to try to install some casks using homebrew which then wasn't idempotent.

@martinm82
Copy link
Contributor

I ran into this problem as well and the issue is the following:

At time X I ran brew install python3 and brew itself got updated. At that moment the formula was pointing to Python 3.8 (python@3.8). The output of brew info python3 was:

brew info python3
python@3.8: stable 3.8.5 (bottled)
Interpreted, interactive, object-oriented programming language
https://www.python.org/
/usr/local/Cellar/python@3.8/3.8.5 (4,372 files, 67.6MB) *
  Poured from bottle on 2020-09-22 at 09:17:06
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/python@3.8.rb
License: Python-2.0

[...]

At time X+n I ran again brew install python3 and brew updated itself again fetching a new formula Python pointing to python@3.9. The output of brew info python3 is suddenly this:

brew info python3
python@3.9: stable 3.9.0 (bottled)
Interpreted, interactive, object-oriented programming language
https://www.python.org/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/python@3.9.rb
License: Python-2.0

[...]

As you can see it says that the packge is not installed.

If I use brew info python@3.8 one receives the expected output:

brew info python@3.8
python@3.8: stable 3.8.6 (bottled) [keg-only]
Interpreted, interactive, object-oriented programming language
https://www.python.org/
/usr/local/Cellar/python@3.8/3.8.5 (4,372 files, 67.6MB) *
  Poured from bottle on 2020-09-22 at 09:17:06
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/python@3.8.rb
License: Python-2.0

[...]

@MichaelWasher the fix you provided would not solve my issue in case I would use python3 instead python@3.8.

Of course one could argue whether I should actually use python3 as it is clearly not pinning to a Major.Minor version of a package. I am also thinking to use always update_homebrew: no in each call to avoid updating brew itself.

But still I thing this is an issue on brew side that it returns information about a package that it actually does not have locally.

@Sergong
Copy link

Sergong commented Dec 29, 2020

It would seem the homebrew_cask no longer works and is failing with the following error:
Error: Calling brew cask install is disabled! Use brew install [--cask] instead.
My target host is running macOS 11.1 and Homebrew version2.7.1.

Installing a cask with homebrew fails with the following:
failed: [192.168.122.242] (item=sublime-text) => {"ansible_loop_var": "item", "changed": false, "item": "sublime-text", "msg": ""}
but actually does install the package.

It looks like the module(s) require(s) updating to support Homebrew version 2.7.1 correctly.

@felixfontein
Copy link
Collaborator

@Sergong your problem is a duplicate of #1524.

@deniscostadsc
Copy link

I'm having similar problem.

My task

---
- name: install cask
  when: ansible_distribution == 'MacOSX'
  homebrew_cask:
    name:
      - docker
      - firefox
      - google-chrome
      - password-gorilla
      - slack
      - spotify
      - visual-studio
    state: present

Error I see:

TASK [osx : install cask] ************************************************************************************
task path: /Users/denis.costa/projects/dotfiles/roles/osx/tasks/main.yml:2
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: denis.costa
<127.0.0.1> EXEC /bin/sh -c 'echo ~denis.costa && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/denis.costa/.ansible/tmp `"&& mkdir "` echo /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702 `" && echo ansible-tmp-1624454349.499657-26582-53145583098702="` echo /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702 `" ) && sleep 0'
redirecting (type: modules) ansible.builtin.homebrew_cask to community.general.homebrew_cask
Using module file /Users/denis.costa/.pyenv/versions/3.9.1/lib/python3.9/site-packages/ansible_collections/community/general/plugins/modules/homebrew_cask.py
<127.0.0.1> PUT /Users/denis.costa/.ansible/tmp/ansible-local-24467fsn_s279/tmp0g39rtcq TO /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702/AnsiballZ_homebrew_cask.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702/ /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702/AnsiballZ_homebrew_cask.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702/AnsiballZ_homebrew_cask.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/denis.costa/.ansible/tmp/ansible-tmp-1624454349.499657-26582-53145583098702/ > /dev/null 2>&1 && sleep 0'
fatal: [127.0.0.1]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "accept_external_apps": false,
            "greedy": false,
            "install_options": [],
            "name": [
                "docker",
                "firefox",
                "google-chrome",
                "password-gorilla",
                "slack",
                "spotify",
                "visual-studio"
            ],
            "path": "/usr/local/bin:/opt/homebrew/bin",
            "state": "present",
            "sudo_password": null,
            "update_homebrew": false,
            "upgrade_all": false
        }
    },
    "msg": "Updating Homebrew...\n==> Auto-updated Homebrew!\nUpdated 1 tap (homebrew/core).\n==> Updated Formulae\nUpdated 1 formula.\n\nError: It seems there is already an App at '/Applications/Firefox.app'."
}

Ansible version:

$ ansible --version
ansible 2.10.9
  config file = /Users/denis.costa/projects/dotfiles/ansible.cfg
  configured module search path = ['/Users/denis.costa/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/denis.costa/.pyenv/versions/3.9.1/lib/python3.9/site-packages/ansible
  executable location = /Users/denis.costa/.pyenv/versions/3.9.1/bin/ansible
  python version = 3.9.1 (default, May  6 2021, 10:38:39) [Clang 12.0.0 (clang-1200.0.32.29)]

My OS info:
Screen Shot 2021-06-23 at 10 16 11

@lockejan
Copy link

I would also expect using ansible.builtin.package to invoke the homebrew_cask and not the homebrew module.
Right now this doesn't happen and I have to explicitly use homebrew_cask for my play to work.

ansible [core 2.11.2]
  config file = None
  configured module search path = ['~/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/Cellar/ansible/4.2.0/libexec/lib/python3.9/site-packages/ansible
  ansible collection location = ~/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.9.6 (default, Jun 29 2021, 05:25:02) [Clang 12.0.5 (clang-1205.0.22.9)]
  jinja version = 3.0.1
  libyaml = True

@felixfontein
Copy link
Collaborator

@lockejan not sure how that is related to this bug report? Also we have no influence on what the package module does, that module is part of ansible-core.

@lockejan
Copy link

@felixfontein my bad.
In my case it failed when invoking the wrong variant of the homebrew module, but worked when explicitily calling the "correct" one, which is somewhat different on second sight to what the initial issuer seems to experience.

My initial thought was: why is it not possible to have one homebrew module for both variants (casks and non-casks)?
Such as one is used to when using any linux package manager.
Sorry for the noise. I'll might open a new issue then.

@felixfontein
Copy link
Collaborator

My initial thought was: why is it not possible to have one homebrew module for both variants (casks and non-casks)?

I guess that would be great. I know too little about homebrew and casks to be able to say whether this is possible in a backwards-compatible way for the homebrew module. (I don't use homebrew at all.)

@prajain12
Copy link

Facing the same issue. If an application is already installed without using homebrew, ansible install fails.
Example:
- name: Install slack homebrew_cask: name: slack state: present

Error: fatal: [localhost]: FAILED! => { "changed": false, "invocation": { "module_args": { "accept_external_apps": false, "greedy": false, "install_options": [], "name": [ "slack" ], "path": "/usr/local/bin:/opt/homebrew/bin", "state": "present", "sudo_password": null, "update_homebrew": false, "upgrade_all": false } }, "msg": "Running brew update --preinstall...\n==> Auto-updated Homebrew!\nUpdated 1 tap (homebrew/core).\n==> Updated Formulae\nUpdated 6 formulae.\n\nError: It seems there is already an App at '/Applications/Slack.app'." }

Specs:
Mac OS Monterey
M1 MacBook Pro

@felixfontein
Copy link
Collaborator

@prajain12 this issue is about apps installed by homebrew. If you install an app another way and try to install it with homebrew, that error is expected as far as I can tell. This is not a bug in the module, but expected behavior from homebrew.

@jackfarzan
Copy link

I am facing this issue as well. Since Homebrew removed the cask install option, I have added my cask install to the regular package mgmt module, which causes brew to fail if the package is already installed. Are there any updates to this, or is there a new issue tracking this problem?

@prajain12
Copy link

@jackfarzan You can add logic to check whether the app already exists at the destination or not. If it does not already exist, then you can move ahead with installing using homebrew.
As this is not an ansible problem, this can be addressed in homebrew.

@Akasurde
Copy link
Member

Akasurde commented Feb 9, 2022

Hey folks, sorry for the delay. Could you please check if #4177 works for you and let me know? Thanks in advance.

@Akasurde
Copy link
Member

Akasurde commented Feb 9, 2022

resolved_by_pr #4177

@Akasurde Akasurde self-assigned this Feb 9, 2022
Akasurde added a commit to Akasurde/community.general that referenced this issue Mar 21, 2022
In order to maintain idempotency, detect already installed cask using
``brew ls`` command.

Fixes: ansible-collections#864

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
@FredrikWendt
Copy link

I applied the changes in https://github.com/ansible-collections/community.general/pull/4177/files (homebrew.py) and that fixes the issue with detecting already installed casks.

+1 for not having to separate between homebrew and homebrew_cask from me.

@killua99
Copy link

killua99 commented Aug 9, 2022

I applied the last PR #4177 only the homebrew.py file and I still get that message

Warning: Cask 'alfred' is already installed. To re-install Alfred, run: brew reinstall - - cask alfred

I'm using the task as community.general.homebrew

I don't know if I've to to a force reinstall with ansible first or what.

@BaldFabi
Copy link

I also ran into this issue with several package installations. The only package that works is zoxide because on brew info zoxide Poured from bottle on... is returned.
The condition on line https://github.com/ansible-collections/community.general/blob/main/plugins/modules/packaging/os/homebrew.py#L480 checks if Built from source or Poured from bottle is returned and maybe I'm to naive but couldn't we just check if Not installed is not returned in the info command?
In my short test for packages that are not installed the brew info package command always had the Not installed line in it and all packages that are installed don't have this line in their output.

@ansibullbot
Copy link
Collaborator

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

@sacgov
Copy link

sacgov commented Jan 25, 2023

@prajain12 i solved it with following work around

- name: Check the list of installed apps
  stat: path=/Applications/{{item.path}}
  with_items:
    - { path: "GoLand.app", name: "goland" }
    - { path: "pgAdmin 4.app", name: "pgadmin4" }
    - { path: "Google Chrome.app", name: "google-chrome" }
    - { path: "Postman.app", name: "postman" }
    - { path: "Slack.app", name: "slack" }
    - { path: "Visual Studio Code.app", name: "visual-studio-code" }
  register: apps_install_status

- name: Install Apps not in the applications folder
  homebrew_cask: name={{ item.item.name }} state=present
  with_items: "{{ apps_install_status.results }}"
  when: not item.stat.exists

@joao-victor-silva
Copy link
Contributor

Hello, I've been using this module from the ansible.builtin.package and I've also ran into this issue.

I tried to evaluate whether a package is installed with the command brew info <package> and noticed that when a package isn't installed, regardless of whether it's a cask or formulae, the Not installed line is added to the output.

Could this be a valid solution?

I'm considering to open a pull request to try to solve this.

@felixfontein
Copy link
Collaborator

Could this be a valid solution?

Sounds sensible to me, assuming that it isn't possible that Not installed shows up even when the package is installed, for example if it is part of the package's description as a single line.

(I have no idea how the brew info output looks like, so maybe this is impossible.)

@joao-victor-silva
Copy link
Contributor

Sounds sensible to me, assuming that it isn't possible that Not installed shows up even when the package is installed, for example if it is part of the package's description as a single line.

Well thought, is unlikely but not impossible. I think that by using the JSON output of brew info we can get a more robust solution, I've done some tests of it using jq for formulae and casks, and this is what I found.

Formulae

Check if installed

brew info --json=v2 <formula> | jq '.formulae[0].installed'

Installed output

Not empty JSON array

[
  {
    "version": "3.3a_3",
    "used_options": [],
    "built_as_bottle": true,
    "poured_from_bottle": true,
    "time": 1705034723,
    "runtime_dependencies": [
       ...
    ]
  }
]

Not installed output

Empty JSON array

[]

Casks

Check if installed

brew info --json=v2 <cask> | jq '.casks[0].installed'

Installed output

Not empty JSON string

"121.0.1"

Not installed output

null

null

Seems to me that if we check those fields of the JSON output and any of them are different from null and [] the formula/cask is installed.

@felixfontein
Copy link
Collaborator

Using JSON output is generally the best way forward. Since when has JSON output been available for homebrew? The module doesn't seem to specify which versions of homebrew it supports, so this could be a bit tricky.

@tigattack
Copy link

Since when has JSON output been available for homebrew?

Looks like at least a decade, according to blame on the docs. Brew v1 was released in 2016. Seems like a safe change to me.

@joao-victor-silva
Copy link
Contributor

To clarify, according to docs, only the v2 version of brew info --json supports formulae and casks, this got introduced on October 2020 in the 2.5.7 release of brew. If we choose to use the v1 version, we have to handle casks in a different way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue/PR relates to a bug has_pr module module os packaging plugins plugin (any type)
Projects
None yet