aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew
diff options
context:
space:
mode:
authorSimon Sigurdhsson2013-03-11 16:41:08 +0100
committerMike McQuaid2013-03-30 19:50:47 +0000
commitf8a88b5f28070b15eb31285f8ae6ffdd37e0859b (patch)
tree73a2cf37557a5939357fb637843558a2a5ed47a3 /Library/Homebrew
parent4a52bf1c3186b75551cb37cbf721da185291c384 (diff)
downloadbrew-f8a88b5f28070b15eb31285f8ae6ffdd37e0859b.tar.bz2
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 <mike@mikemcquaid.com>
Diffstat (limited to 'Library/Homebrew')
-rw-r--r--Library/Homebrew/cmd/list.rb17
-rw-r--r--Library/Homebrew/cmd/pin.rb16
-rw-r--r--Library/Homebrew/cmd/uninstall.rb2
-rw-r--r--Library/Homebrew/cmd/unpin.rb16
-rw-r--r--Library/Homebrew/cmd/upgrade.rb20
-rw-r--r--Library/Homebrew/formula.rb19
-rw-r--r--Library/Homebrew/formula_pin.rb36
7 files changed, 124 insertions, 2 deletions
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.
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 80e2e478c..1d9c1034c 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -2,6 +2,7 @@ require 'download_strategy'
require 'dependency_collector'
require 'formula_support'
require 'formula_lock'
+require 'formula_pin'
require 'hardware'
require 'bottles'
require 'patches'
@@ -68,6 +69,8 @@ class Formula
# make sure to strip "--" from the start of options
self.class.build.add opt[/--(.+)$/, 1], desc
end
+
+ @pin = FormulaPin.new(self)
end
def url; @active_spec.url; end
@@ -80,6 +83,22 @@ class Formula
installed_prefix.children.length > 0 rescue false
end
+ def pinable?
+ @pin.pinable?
+ end
+
+ def pinned?
+ @pin.pinned?
+ end
+
+ def pin
+ @pin.pin
+ end
+
+ def unpin
+ @pin.unpin
+ end
+
def linked_keg
HOMEBREW_REPOSITORY/'Library/LinkedKegs'/@name
end
diff --git a/Library/Homebrew/formula_pin.rb b/Library/Homebrew/formula_pin.rb
new file mode 100644
index 000000000..cdffd7fc0
--- /dev/null
+++ b/Library/Homebrew/formula_pin.rb
@@ -0,0 +1,36 @@
+require 'formula'
+require 'fileutils'
+
+class FormulaPin
+ HOMEBREW_PINNED = HOMEBREW_LIBRARY/'PinnedKegs'
+
+ def initialize(formula)
+ @formula = formula
+ @name = formula.name
+ HOMEBREW_PINNED.mkdir unless HOMEBREW_PINNED.exist?
+ @path = HOMEBREW_PINNED/@name
+ end
+
+ def pin_at(version)
+ version_path = @formula.installed_prefix.parent.join(version)
+ FileUtils.ln_s version_path, @path unless pinned? or not version_path.exist?
+ end
+
+ def pin
+ versions = @formula.installed_prefix.parent.children.map { |item| item.basename.to_s }
+ version = versions.map { |item| Version.new(item) }.sort[0].to_s
+ pin_at(version)
+ end
+
+ def unpin
+ FileUtils.rm @path if pinned?
+ end
+
+ def pinned?
+ @path.exist?
+ end
+
+ def pinable?
+ @formula.installed_prefix.parent.children.length > 0
+ end
+end