Brew: Add an option to install only if not already installed

Created on 14 Apr 2017  路  14Comments  路  Source: Homebrew/brew

Hi,

We recently added set -e in our CI script. We had something like:

#!/usr/bin/env bash

set -e

PACKAGES="cmake pkg-config fftw libogg libvorbis libsndfile libsamplerate jack sdl stk portaudio node fltk"

brew install $PACKAGES

With set -e, it failed because brew returned a non-zero exit code for already installed packages. So we had to do:

#!/usr/bin/env bash

set -e

PACKAGES="cmake pkg-config fftw libogg libvorbis libsndfile libsamplerate jack sdl stk portaudio node fltk"

# removing already installed packages from the list
for p in $(brew list); do
    PACKAGES=${PACKAGES//$p/}
done;

brew install $PACKAGES

But it's ugly and buggy. E.g. we used to have pkgconfig, so the string replacement didn't work. It now works cause we replaced it by pkg-config as it is in brew list output.

So, I'd like an option like: brew install --if-not-installed $PACKAGES which won't return a non-zero exit code if $PACKAGES contains already installed packages.

What do you think about it ? I wish i could implement it myself, but I don't know ruby and I'm not even a brew user so probably not the best option. I'm sure someone knowing ruby and brew could do this really quickly as it doesn't seem hard.

Most helpful comment

+1. There are valid use cases to the proposed --if-not-installed flag. Creating a brewfile shouldn't have to be the only solution.

All 14 comments

The reason that you are getting a non-zero exit status from your original brew install $PACKAGES, is probably due to one or more of the formula already having a different version installed and linked.

A likely way to resolve this would be to add something like the following to your CI script:

brew update || brew update
brew upgrade
brew install $PACKAGES

in the place of the single line.

Another approach would be to look at homebrew/bundle.

I did a quick test. Indeed, now it doesn't return a non-zero exit code but just display a warning.

Unfortunately, it also make the whole process really much longer, without upgrade 3 min. 47, but 8 min. with it.

So, I'd still like to see this option added to avoid getting warnings and also to be able not to upgrade packages when it's not needed.

If you are using Travis, try removing/skipping the ones from here, or upgrading their version if they are outdated, instead of upgrading everything: https://docs.travis-ci.com/user/osx-ci-environment/#Compilers-and-Build-toolchain

We would like to keep the complete list of packages so the script will be usable for the CI and for users too. So we can't just remove them.

Upgrading only the already installed packages will just lead to the same result we have now: an ugly and buggy script to filter already installed packages.

Have you seen Homebrew Bundle?

So, since the primary issue you are running into is a result of set -e, could you set it after the brew install line? Failing that, in my mind, this seems to at least be a somewhat neater solution:

#!/usr/bin/env bash

set -e

PACKAGES="cmake pkg-config fftw libogg libvorbis libsndfile libsamplerate jack sdl stk portaudio node fltk"

brew install $PACKAGES && true

You could also use brew install $PACKAGES 2>/dev/null && true if you wanted to suppress stderr.

Have you seen Homebrew Bundle?

I had a look at it. I'd rather not adding another tool in the CI just for this, plus, users would have to install it too to build from sources...

Moreover:

If a dependency is already installed and there is an update available it will be upgraded.

We don't want to upgrade.

could you set it after the brew install line?

I guess we could, but that doesn't seem a clean solution to me. We should be able to tell brew: install only if not already here, don't upgrade if already here.

brew install $PACKAGES && true

You mean || true ? But still, the above point is the same here.

So, if you don't want to write this feature, would you accept a PR ? If someone is pointing me to the relevant piece of code, I could try to write this feature.

I had a look at it. I'd rather not adding another tool in the CI just for this, plus, users would have to install it too to build from sources...

It's not another tool, it's part of Homebrew. Just run brew bundle. That's our supported way of handling cases like this.

+1. There are valid use cases to the proposed --if-not-installed flag. Creating a brewfile shouldn't have to be the only solution.

I'm not interested in using brew bundle either @MikeMcQuaid.

It's not really helpful to state that you're not willing to create a Brewfile or use brew bundle without elaborating on why that is the case.

I am supplying a script to users in my group that installs a couple of dependencies. I want to be able to send them just the script via a curl command, not an additional BrewFile. I don't think a BrewFile should be required for these sorts of simple cases.

FWIW you can do this in a script without an additional file:

brew bundle --file=- <<-EOS
brew "formula1"
brew "formula2"
brew "formula3"
EOS

Yep, you can embed them into your script like @bfontaine points out.

I don't think a BrewFile should be required for these sorts of simple cases.

To be clear: it's not, you can accomplish all this without brew bundle but you will need to write more or the logic yourself which seems to be what the complaints are in this issue. If you're asking for a feature so you can essentially mirror brew bundles functionality without using it: sorry, we're not going to implement that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DomT4 picture DomT4  路  3Comments

rtobrien picture rtobrien  路  3Comments

cdekok picture cdekok  路  4Comments

vitahlin picture vitahlin  路  4Comments

javian picture javian  路  4Comments