From f8a88b5f28070b15eb31285f8ae6ffdd37e0859b Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 11 Mar 2013 16:41:08 +0100 Subject: brew-pin: prevent selected formulae from upgrade. * Added `pin` et. al. to manpage. * Added `brew pin` to `brew.1` * Added `brew unpin` to `brew.1` * Added `brew list --pinned` to `brew.1` * Added information about frozen formulae to `brew upgrade` in `brew.1` * Added `pin` et.al. to completion scripts. * Unpin formulae when uninstalling them * Unpin and re-pin formulae when upgrading (avoids stale symlink) References Homebrew/homebrew#18386. Closes Homebrew/homebrew#18515. Signed-off-by: Mike McQuaid --- Library/Homebrew/cmd/list.rb | 17 ++++++++++++++++- Library/Homebrew/cmd/pin.rb | 16 ++++++++++++++++ Library/Homebrew/cmd/uninstall.rb | 2 ++ Library/Homebrew/cmd/unpin.rb | 16 ++++++++++++++++ Library/Homebrew/cmd/upgrade.rb | 20 +++++++++++++++++++- 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 Library/Homebrew/cmd/pin.rb create mode 100644 Library/Homebrew/cmd/unpin.rb (limited to 'Library/Homebrew/cmd') diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb index 4b0aa4a13..3ce3b18e3 100644 --- a/Library/Homebrew/cmd/list.rb +++ b/Library/Homebrew/cmd/list.rb @@ -8,7 +8,10 @@ module Homebrew extend self # Things below use the CELLAR, which doesn't until the first formula is installed. return unless HOMEBREW_CELLAR.exist? - if ARGV.include? '--versions' + if ARGV.include? '--pinned' + require 'formula' + list_pinned + elsif ARGV.include? '--versions' list_versions elsif ARGV.named.empty? ENV['CLICOLOR'] = nil @@ -48,6 +51,18 @@ private puts "#{d.basename} #{versions*' '}" end end + + def list_pinned + if ARGV.named.empty? + HOMEBREW_CELLAR.children.select{ |pn| pn.directory? } + else + ARGV.named.map{ |n| HOMEBREW_CELLAR+n }.select{ |pn| pn.exist? } + end.select do |d| + Formula.factory(d.basename.to_s).pinned? + end.each do |d| + puts "#{d.basename}" + end + end end class PrettyListing diff --git a/Library/Homebrew/cmd/pin.rb b/Library/Homebrew/cmd/pin.rb new file mode 100644 index 000000000..26b487a0d --- /dev/null +++ b/Library/Homebrew/cmd/pin.rb @@ -0,0 +1,16 @@ +require 'formula' + +module Homebrew extend self + def pin + if Process.uid.zero? and not File.stat(HOMEBREW_BREW_FILE).uid.zero? + abort "Cowardly refusing to `sudo pin'" + end + raise FormulaUnspecifiedError if ARGV.named.empty? + ARGV.formulae.each do |fmla| + f = Formula.factory(fmla.to_s) + onoe "Cannot pin uninstalled formula #{f.name}!" unless f.pinable? + opoo "Formula #{f.name} already pinned!" if f.pinable? and f.pinned? + f.pin if f.pinable? and not f.pinned? + end + end +end diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb index 19ad6eeb5..5a7479f9c 100644 --- a/Library/Homebrew/cmd/uninstall.rb +++ b/Library/Homebrew/cmd/uninstall.rb @@ -10,6 +10,7 @@ module Homebrew extend self keg.lock do puts "Uninstalling #{keg}..." keg.unlink + Formula.factory(keg.fname).unpin keg.uninstall rm_opt_link keg.fname end @@ -28,6 +29,7 @@ module Homebrew extend self if keg.directory? keg = Keg.new(keg) keg.unlink + Formula.factory(keg.fname).unpin keg.rmtree end end diff --git a/Library/Homebrew/cmd/unpin.rb b/Library/Homebrew/cmd/unpin.rb new file mode 100644 index 000000000..6855db4bf --- /dev/null +++ b/Library/Homebrew/cmd/unpin.rb @@ -0,0 +1,16 @@ +require 'formula' + +module Homebrew extend self + def unpin + if Process.uid.zero? and not File.stat(HOMEBREW_BREW_FILE).uid.zero? + abort "Cowardly refusing to `sudo unpin'" + end + raise FormulaUnspecifiedError if ARGV.named.empty? + ARGV.formulae.each do |fmla| + f = Formula.factory(fmla.to_s) + onoe "Cannot unpin uninstalled formula #{f.name}!" unless f.pinable? + opoo "Formula #{f.name} already unpinned!" if f.pinable? and not f.pinned? + f.unpin if f.pinable? and f.pinned? + end + end +end diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index b5effee50..af2e4a0e1 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -18,8 +18,10 @@ module Homebrew extend self if ARGV.named.empty? require 'cmd/outdated' + upgrade_pinned = false outdated = Homebrew.outdated_brews else + upgrade_pinned = true outdated = ARGV.formulae.select do |f| if f.installed? onoe "#{f}-#{f.installed_version} already installed" @@ -32,10 +34,19 @@ module Homebrew extend self exit 1 if outdated.empty? end - if outdated.length > 1 + unless upgrade_pinned + pinned = outdated.select { |f| f.pinned? } + outdated -= pinned + end + + if outdated.length > 0 oh1 "Upgrading #{outdated.length} outdated package#{outdated.length.plural_s}, with result:" puts outdated.map{ |f| "#{f.name} #{f.version}" } * ", " end + if not upgrade_pinned and pinned.length > 0 + oh1 "Not upgrading #{pinned.length} pinned package#{outdated.length.plural_s}:" + puts pinned.map{ |f| "#{f.name} #{f.version}" } * ", " + end outdated.each do |f| upgrade_formula f @@ -60,6 +71,13 @@ module Homebrew extend self installer.install installer.caveats installer.finish + + # If the formula was pinned, and we were force-upgrading it, unpin and + # pin it again to get a symlink pointing to the correct keg. + if f.pinned? + f.unpin + f.pin + end rescue FormulaInstallationAlreadyAttemptedError # We already attempted to upgrade f as part of the dependency tree of # another formula. In that case, don't generate an error, just move on. -- cgit v1.2.3