brew/Library/Homebrew/cmd/update.rb
phinze 9a94a77fa3 Properly define tapped formulae in update
A tapped formula is a ruby file present:

  - in the root of the tap
  - in directory of the tap called Formula
  - in a directory of the tap called HomebrewFormula

And nowhere else. This corrects an overzealous definition of tapped
formula in the updater. (the correct definition has been in Pathname
since e613cbe5783cea2abb8100b56c22126a1ab6b9f2)

Refs Homebrew/homebrew#19743.
Closes Homebrew/homebrew#21087.

Signed-off-by: Jack Nagel <jacknagel@gmail.com>
2013-07-09 20:52:51 -05:00

194 lines
4.8 KiB
Ruby

require 'cmd/tap'
require 'cmd/untap'
module Homebrew extend self
def update
unless ARGV.named.empty?
abort <<-EOS.undent
This command updates brew itself, and does not take formula names.
Use `brew upgrade <formula>`.
EOS
end
abort "Please `brew install git' first." unless which "git"
# ensure GIT_CONFIG is unset as we need to operate on .git/config
ENV.delete('GIT_CONFIG')
cd HOMEBREW_REPOSITORY
git_init_if_necessary
report = Report.new
master_updater = Updater.new
master_updater.pull!
report.merge!(master_updater.report)
Dir["Library/Taps/*"].each do |tapd|
next unless File.directory?(tapd)
cd tapd do
begin
updater = Updater.new
updater.pull!
report.merge!(updater.report) do |key, oldval, newval|
oldval.concat(newval)
end
rescue
tapd =~ %r{^Library/Taps/(\w+)-(\w+)}
onoe "Failed to update tap: #$1/#$2"
end
end
end
# we unlink first in case the formula has moved to another tap
Homebrew.unlink_tap_formula(report.removed_tapped_formula)
Homebrew.link_tap_formula(report.new_tapped_formula)
if report.empty?
puts "Already up-to-date."
else
puts "Updated Homebrew from #{master_updater.initial_revision[0,8]} to #{master_updater.current_revision[0,8]}."
report.dump
end
end
private
def git_init_if_necessary
if Dir['.git/*'].empty?
safe_system "git init"
safe_system "git config core.autocrlf false"
safe_system "git remote add origin https://github.com/mxcl/homebrew.git"
safe_system "git fetch origin"
safe_system "git reset --hard origin/master"
end
rescue Exception
FileUtils.rm_rf ".git"
raise
end
end
class Updater
attr_reader :initial_revision, :current_revision
def pull!
safe_system "git checkout -q master"
@initial_revision = read_current_revision
# ensure we don't munge line endings on checkout
safe_system "git config core.autocrlf false"
args = ["pull"]
args << "--rebase" if ARGV.include? "--rebase"
args << "-q" unless ARGV.verbose?
args << "origin"
# the refspec ensures that 'origin/master' gets updated
args << "refs/heads/master:refs/remotes/origin/master"
safe_system "git", *args
@current_revision = read_current_revision
end
# Matches raw git diff format (see `man git-diff-tree`)
DIFFTREE_RX = /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} [0-9a-fA-F]{40} ([ACDMR])\d{0,3}\t(.+?)(?:\t(.+))?$/
def report
map = Hash.new{ |h,k| h[k] = [] }
if initial_revision && initial_revision != current_revision
`git diff-tree -r --raw -M85% #{initial_revision} #{current_revision}`.each_line do |line|
DIFFTREE_RX.match line
path = case status = $1.to_sym
when :R then $3
else $2
end
path = Pathname.pwd.join(path).relative_path_from(HOMEBREW_REPOSITORY)
map[status] << path.to_s
end
end
map
end
private
def read_current_revision
`git rev-parse -q --verify HEAD`.chomp
end
def `(cmd)
out = Kernel.`(cmd) #`
if $? && !$?.success?
$stderr.puts out
raise ErrorDuringExecution, "Failure while executing: #{cmd}"
end
ohai(cmd, out) if ARGV.verbose?
out
end
end
class Report < Hash
def dump
# Key Legend: Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
dump_formula_report :A, "New Formulae"
dump_formula_report :M, "Updated Formulae"
dump_formula_report :D, "Deleted Formulae"
dump_formula_report :R, "Renamed Formulae"
# dump_new_commands
# dump_deleted_commands
end
def tapped_formula_for key
fetch(key, []).map do |path|
case path when %r{^Library/Taps/(\w+-\w+/.*)}
relative_path = $1
if valid_formula_location?(relative_path)
Pathname.new(relative_path)
end
end
end.compact
end
def valid_formula_location?(relative_path)
ruby_file = /\A.*\.rb\Z/
parts = relative_path.split('/')[1..-1]
[
parts.length == 1 && parts.first =~ ruby_file,
parts.length == 2 && parts.first == 'Formula' && parts.last =~ ruby_file,
parts.length == 2 && parts.first == 'HomebrewFormula' && parts.last =~ ruby_file,
].any?
end
def new_tapped_formula
tapped_formula_for :A
end
def removed_tapped_formula
tapped_formula_for :D
end
def select_formula key
fetch(key, []).map do |path|
case path when %r{^Library/Formula}
File.basename(path, ".rb")
when %r{^Library/Taps/(\w+)-(\w+)/(.*)\.rb}
"#$1/#$2/#{File.basename(path, '.rb')}"
end
end.compact.sort
end
def dump_formula_report key, title
formula = select_formula(key)
unless formula.empty?
ohai title
puts_columns formula.uniq
end
end
end