aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Library/Contributions/brew_bash_completion.sh8
-rw-r--r--Library/Contributions/brew_fish_completion.fish3
-rw-r--r--Library/Contributions/brew_zsh_completion.zsh5
-rw-r--r--Library/Contributions/manpages/brew.1.md19
-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
-rw-r--r--share/man/man1/brew.117
13 files changed, 168 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 022c5e137..c5d39ab2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,5 +9,6 @@
!/share/man/man1/brew.1
.DS_Store
/Library/LinkedKegs
+/Library/PinnedKegs
/Library/Taps
/Library/Formula/.gitignore
diff --git a/Library/Contributions/brew_bash_completion.sh b/Library/Contributions/brew_bash_completion.sh
index 069567423..98c140d23 100644
--- a/Library/Contributions/brew_bash_completion.sh
+++ b/Library/Contributions/brew_bash_completion.sh
@@ -238,10 +238,12 @@ _brew_list ()
return
elif __brewcomp_words_include "--verbose"; then
return
+ elif __brewcomp_words_include "--pinned"; then
+ return
elif __brewcomp_words_include "--versions"; then
return
else
- __brewcomp "--unbrewed --verbose --versions"
+ __brewcomp "--unbrewed --verbose --pinned --versions"
return
fi
;;
@@ -400,11 +402,13 @@ _brew ()
options
outdated
prune
+ pin
search
tap
test
uninstall remove rm
unlink
+ unpin
untap
update
upgrade
@@ -435,9 +439,11 @@ _brew ()
missing) __brew_complete_formulae ;;
options) _brew_options ;;
outdated) _brew_outdated ;;
+ pin) _brew_complete_formulae ;;
search|-S) _brew_search ;;
tap) __brew_complete_taps ;;
uninstall|remove|rm) _brew_uninstall ;;
+ unpin) __brew_complete_formulae ;;
untap) __brew_complete_tapped ;;
update) _brew_update ;;
uses) _brew_uses ;;
diff --git a/Library/Contributions/brew_fish_completion.fish b/Library/Contributions/brew_fish_completion.fish
index e037ae480..df13a6f05 100644
--- a/Library/Contributions/brew_fish_completion.fish
+++ b/Library/Contributions/brew_fish_completion.fish
@@ -32,7 +32,7 @@ function __fish_complete_brew_argument
return 0
end
- if contains -- $cmd cleanup link ln missing rm remove test unlink uninstall upgrade
+ if contains -- $cmd cleanup link ln missing rm remove test unlink uninstall upgrade pin unpin
ls (brew --prefix)/Cellar
return 0
end
@@ -148,6 +148,7 @@ complete -c brew -s f -l force -n '__fish_complete_brew_command link ln' -d "Ove
complete -c brew -s n -l dry-run -n '__fish_complete_brew_command link ln' -d "Show which files would be deleted"
complete -c brew -l unbrewed -n '__fish_complete_brew_command list ls' -d "List files in Homebrew prefix not installed by Homebrew"
+complete -c brew -l pinned -n '__fish_complete_brew_command list ls' -d "Show the version number for (specified) pinned formulae"
complete -c brew -l versions -n '__fish_complete_brew_command list ls' -d "Show the version number for specified formulae"
complete -c brew -n '__fish_complete_brew_command log' -u
diff --git a/Library/Contributions/brew_zsh_completion.zsh b/Library/Contributions/brew_zsh_completion.zsh
index cabd73420..57c1f4ed5 100644
--- a/Library/Contributions/brew_zsh_completion.zsh
+++ b/Library/Contributions/brew_zsh_completion.zsh
@@ -34,11 +34,13 @@ _1st_arguments=(
'log:git commit log for a formula'
'missing:check all installed formuale for missing dependencies.'
'outdated:list formulae for which a newer version is available'
+ 'pin:pin specified formulae'
'prune:remove dead links'
'remove:remove a formula'
'search:search for a formula (/regex/ or string)'
'server:start a local web app that lets you browse formulae (requires Sinatra)'
'unlink:unlink a formula'
+ 'unpin:unpin specified formulae'
'update:freshen up links'
'upgrade:upgrade outdated formulae'
'uses:show formulae which depend on a formula'
@@ -71,6 +73,7 @@ case "$words[1]" in
list|ls)
_arguments \
'(--unbrewed)--unbrewed[files in brew --prefix not controlled by brew]' \
+ '(--pinned)--pinned[list all versions of pinned formulae]' \
'(--versions)--versions[list all installed versions of a formula]' \
'1: :->forms' && return 0
@@ -81,7 +84,7 @@ case "$words[1]" in
install|home|homepage|log|info|abv|uses|cat|deps|edit|options)
_brew_all_formulae
_wanted formulae expl 'all formulae' compadd -a formulae ;;
- remove|rm|uninstall|unlink|cleanup|link|ln)
+ remove|rm|uninstall|unlink|cleanup|link|ln|pin|unpin)
_brew_installed_formulae
_wanted installed_formulae expl 'installed formulae' compadd -a installed_formulae ;;
upgrade)
diff --git a/Library/Contributions/manpages/brew.1.md b/Library/Contributions/manpages/brew.1.md
index 93df07341..eb86ba32f 100644
--- a/Library/Contributions/manpages/brew.1.md
+++ b/Library/Contributions/manpages/brew.1.md
@@ -195,7 +195,7 @@ Note that these flags should only appear after a command.
be linked or which would be deleted by `brew link --overwrite`, but will not
actually link or delete any files.
- * `ls, list [--unbrewed] [--versions]` [<formulae>]:
+ * `ls, list [--unbrewed] [--versions] [--pinned]` [<formulae>]:
Without any arguments, list all installed formulae.
If <formulae> are given, list the installed files for <formulae>.
@@ -208,6 +208,10 @@ Note that these flags should only appear after a command.
If `--versions` is passed, show the version number for installed formulae,
or only the specified formulae if <formulae> are given.
+ If `--pinned` is passed, show the versions of pinned formulae, or only the
+ specified (pinned) formulae if <formulae> are given.
+ See also [`pin`][], [`unpin`][].
+
* `log [git-log-options]` <formula> ...:
Show the git log for the given formulae. Options that `git-log`(1)
recognizes can be passed before the formula list.
@@ -233,6 +237,10 @@ Note that these flags should only appear after a command.
If `--quiet` is passed, list only the names of outdated brews. Otherwise,
the versions are printed as well.
+ * `pin` <formulae>:
+ Pin the specified <formulae>, preventing them from being upgraded when
+ issuing the `brew upgrade` command without arguments. See also [`unpin`][].
+
* `prune`:
Remove dead symlinks from the Homebrew prefix. This is generally not
needed, but can be useful when doing DIY installations.
@@ -273,6 +281,10 @@ Note that these flags should only appear after a command.
Unsymlink <formula> from the Homebrew prefix. This can be useful for
temporarily disabling a formula: `brew unlink foo && commands && brew link foo`.
+ * `unpin` <formulae>:
+ Unpin <formulae>, allowing them to be upgraded by `brew upgrade`. See also
+ [`pin`][].
+
* `untap` <tap>:
Remove a tapped repository.
@@ -283,9 +295,10 @@ Note that these flags should only appear after a command.
If `--rebase` is specified then `git pull --rebase` is used.
* `upgrade` [<formulae>]:
- Upgrade outdated brews.
+ Upgrade outdated, non-pinned brews.
- If <formulae> are given, upgrade only the specified brews.
+ If <formulae> are given, upgrade only the specified brews (but do so even
+ if they are pinned; see [`pin`][], [`unpin`][]).
* `uses [--installed] [--recursive]` <formula>:
Show the formulae that specify <formula> as a dependency.
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
diff --git a/share/man/man1/brew.1 b/share/man/man1/brew.1
index 952e87876..96886e6b7 100644
--- a/share/man/man1/brew.1
+++ b/share/man/man1/brew.1
@@ -215,7 +215,7 @@ If \fB\-\-overwrite\fR is passed, Homebrew will delete files which already exist
If \fB\-\-dry\-run\fR or \fB\-n\fR is passed, Homebrew will list all files which would be linked or which would be deleted by \fBbrew link \-\-overwrite\fR, but will not actually link or delete any files\.
.
.TP
-\fBls, list [\-\-unbrewed] [\-\-versions]\fR [\fIformulae\fR]
+\fBls, list [\-\-unbrewed] [\-\-versions] [\-\-pinned]\fR [\fIformulae\fR]
Without any arguments, list all installed formulae\.
.
.IP
@@ -227,6 +227,9 @@ If \fB\-\-unbrewed\fR is passed, list all files in the Homebrew prefix not insta
.IP
If \fB\-\-versions\fR is passed, show the version number for installed formulae, or only the specified formulae if \fIformulae\fR are given\.
.
+.IP
+If \fB\-\-pinned\fR is passed, show the versions of pinned formulae, or only the specified (pinned) formulae if \fIformulae\fR are given\. See also [\fBpin\fR][], [\fBunpin\fR][]\.
+.
.TP
\fBlog [git\-log\-options]\fR \fIformula\fR \.\.\.
Show the git log for the given formulae\. Options that \fBgit\-log\fR(1) recognizes can be passed before the formula list\.
@@ -259,6 +262,10 @@ Show formulae that have an updated version available\.
If \fB\-\-quiet\fR is passed, list only the names of outdated brews\. Otherwise, the versions are printed as well\.
.
.TP
+\fBpin\fR \fIformulae\fR
+Pin the specified \fIformulae\fR, preventing them from being upgraded when issuing the \fBbrew upgrade\fR command without arguments\. See also [\fBunpin\fR][]\.
+.
+.TP
\fBprune\fR
Remove dead symlinks from the Homebrew prefix\. This is generally not needed, but can be useful when doing DIY installations\.
.
@@ -302,6 +309,10 @@ Example: \fBbrew install jruby && brew test jruby\fR
Unsymlink \fIformula\fR from the Homebrew prefix\. This can be useful for temporarily disabling a formula: \fBbrew unlink foo && commands && brew link foo\fR\.
.
.TP
+\fBunpin\fR \fIformulae\fR
+Unpin \fIformulae\fR, allowing them to be upgraded by \fBbrew upgrade\fR\. See also [\fBpin\fR][]\.
+.
+.TP
\fBuntap\fR \fItap\fR
Remove a tapped repository\.
.
@@ -314,10 +325,10 @@ If \fB\-\-rebase\fR is specified then \fBgit pull \-\-rebase\fR is used\.
.
.TP
\fBupgrade\fR [\fIformulae\fR]
-Upgrade outdated brews\.
+Upgrade outdated, non\-pinned brews\.
.
.IP
-If \fIformulae\fR are given, upgrade only the specified brews\.
+If \fIformulae\fR are given, upgrade only the specified brews (but do so even if they are pinned; see [\fBpin\fR][], [\fBunpin\fR][])\.
.
.TP
\fBuses [\-\-installed] [\-\-recursive]\fR \fIformula\fR