Source code for meta_package_manager.managers.homebrew

# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Kevin Deldycke <kevin@deldycke.com>
#                    and contributors.
# All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

from __future__ import (
    absolute_import,
    division,
    print_function,
    unicode_literals
)

import json

from boltons.cacheutils import cachedproperty
from packaging.version import parse as parse_version

from ..base import PackageManager
from ..platform import MACOS


[docs]class Homebrew(PackageManager): cli_path = '/usr/local/bin/brew' platforms = frozenset([MACOS]) requirement = '>= 1.0.*' @cachedproperty def id(self): return "brew"
[docs] def get_version(self): return self.run( [self.cli_path] + self.cli_args + ['--version']).split()[1]
[docs] def sync(self): """ Fetch latest Homebrew formulas. Sample of brew output: $ brew outdated --json=v1 [ { "name": "cassandra", "installed_versions": [ "3.5" ], "current_version": "3.7" }, { "name": "vim", "installed_versions": [ "7.4.1967" ], "current_version": "7.4.1993" }, { "name": "youtube-dl", "installed_versions": [ "2016.07.06" ], "current_version": "2016.07.09.1" } ] """ super(Homebrew, self).sync() self.run([self.cli_path] + self.cli_args + ['update']) # List available updates. output = self.run( [self.cli_path] + self.cli_args + ['outdated', '--json=v1']) if not output: return for pkg_info in json.loads(output): # Parse versions to avoid lexicographic sorting gotchas. version = None versions = set(pkg_info['installed_versions']) if versions: _, version = max([(parse_version(v), v) for v in versions]) package_id = pkg_info['name'] self.outdated[package_id] = { 'id': package_id, 'name': package_id, 'installed_version': version, 'latest_version': pkg_info['current_version']}
[docs] def upgrade_cli(self, package_id=None): cmd = [self.cli_path] + self.cli_args + ['upgrade', '--cleanup'] if package_id: cmd.append(package_id) return cmd
[docs] def upgrade_all_cli(self): return self.upgrade_cli()
[docs]class HomebrewCask(Homebrew): """ Cask is now part of Homebrew's core and extend it. """ cli_args = ['cask'] # 'cask install' doesn't upgrade to the latest package version, we need to # call 'cask reinstall' instead since 1.1.0. requirement = '>= 1.1.*' @cachedproperty def id(self): return "cask" @cachedproperty def name(self): return "Homebrew Cask"
[docs] def sync(self): """ Fetch latest formulas and their metadata. Sample of brew cask output: $ brew cask list --versions aerial 1.2beta5 android-file-transfer latest audacity 2.1.2-1453294898 2.1.2 bitbar 1.9.2 firefox 49.0.1 flux 37.7 gimp 2.8.18-x86_64 java 1.8.0_112-b16 tunnelblick 3.6.8_build_4625 3.6.9_build_4685 virtualbox 5.1.8-111374 5.1.10-112026 $ brew cask info aerial aerial: 1.2beta5 https://github.com/JohnCoates/Aerial /usr/local/Caskroom/aerial/1.2beta5 (18 files, 6.6M) From: https://github.com/(...)/blob/master/Casks/aerial.rb ==> Name Aerial Screensaver ==> Artifacts Aerial.saver (screen_saver) $ brew cask info firefox firefox: 50.0.1 https://www.mozilla.org/firefox/ /usr/local/Caskroom/firefox/49.0.1 (107 files, 185.3M) From: https://github.com/(...)/blob/master/Casks/firefox.rb ==> Name Mozilla Firefox ==> Artifacts Firefox.app (app) $ brew cask info virtualbox virtualbox: 5.1.10-112026 https://www.virtualbox.org /usr/local/Caskroom/virtualbox/5.1.8-111374 (3 files, 88.8M) /usr/local/Caskroom/virtualbox/5.1.10-112026 (3 files, 89.3M) From: https://github.com/(...)/blob/master/Casks/virtualbox.rb ==> Name Oracle VirtualBox ==> Artifacts VirtualBox.pkg (pkg) $ brew cask info prey prey: 1.6.3 https://preyproject.com/ Not installed From: https://github.com/(...)/blob/master/Casks/prey.rb ==> Name Prey ==> Artifacts prey-mac-1.6.3-x86.pkg (pkg) ==> Caveats Prey requires your API key, found in the bottom-left corner of the Prey web account Settings page, to complete installation. The API key may be set as an environment variable as follows: API_KEY="abcdef123456" brew cask install prey $ brew cask info ubersicht ubersicht: 1.0.44 http://tracesof.net/uebersicht/ Not installed From: https://github.com/(...)/blob/master/Casks/ubersicht.rb ==> Name Übersicht ==> Artifacts Übersicht.app (app) """ super(Homebrew, self).sync() # `brew cask update` is just an alias to `brew update`. self.run([self.cli_path] + self.cli_args + ['update']) # List installed packages. output = self.run( [self.cli_path] + self.cli_args + ['list', '--versions']) # Inspect package one by one as `brew cask list` is not reliable. See: # https://github.com/caskroom/homebrew-cask/blob/master/doc # /reporting_bugs/brew_cask_list_shows_wrong_information.md for installed_pkg in output.split('\n'): if not installed_pkg: continue infos = installed_pkg.split() package_id = infos[0] # Guess latest installed version. versions = set(infos[1:]) # Discard generic 'latest' symbolic version if others are # available. if len(versions) > 1: versions.discard('latest') # Parse versions to avoid lexicographic sorting gotchas. version = None if versions: _, version = max([(parse_version(v), v) for v in versions]) # TODO: Support packages removed from repository (reported with a # `(!)` flag). See: https://github.com/caskroom/homebrew-cask/blob # /master/doc/reporting_bugs # /uninstall_wrongly_reports_cask_as_not_installed.md # Inspect the package closer to evaluate its state. output = self.run([ self.cli_path] + self.cli_args + ['info', package_id]) latest_version = output.split('\n')[0].split(' ')[1] package_name = output.split('==> Name\n')[1].split('\n')[0] # Skip already installed packages. if version == latest_version: continue self.outdated[package_id] = { 'id': package_id, 'name': package_name, 'installed_version': version, 'latest_version': latest_version}
[docs] def upgrade_cli(self, package_id): """ Install a package. TODO: wait for https://github.com/caskroom/homebrew-cask/issues/22647 so we can force a cleanup in one go, as we do above with vanilla Homebrew. """ return [self.cli_path] + self.cli_args + ['reinstall', package_id]
[docs] def upgrade_all_cli(self): """ Cask has no way to upgrade all outdated packages. See: https://github.com/caskroom/homebrew-cask/issues/4678 """ raise NotImplementedError