refactor update command to use git diff instead of parsing pull output

This fixes reporting of which formulae changed in git versions where `pull`
output is not compatible.

Signed-off-by: Adam Vandenberg <flangy@gmail.com>
This commit is contained in:
Mislav Marohnić 2011-06-12 17:07:59 +02:00 committed by Adam Vandenberg
parent 5fdb145e76
commit 8c521ca3d0
3 changed files with 138 additions and 123 deletions

View File

@ -16,69 +16,71 @@ class RefreshBrew
INIT_COMMAND = "git init"
CHECKOUT_COMMAND = "git checkout -q master"
UPDATE_COMMAND = "git pull #{REPOSITORY_URL} master"
REVISION_COMMAND = "git log -l -1 --pretty=format:%H 2> /dev/null"
GIT_UP_TO_DATE = "Already up-to-date."
REVISION_COMMAND = "git rev-parse HEAD"
DIFF_COMMAND = "git diff-tree -r --name-status -z %s %s"
formula_regexp = 'Library/Formula/(.+?)\.rb'
ADDED_FORMULA = %r{^\s+create mode \d+ #{formula_regexp}$}
UPDATED_FORMULA = %r{^\s+#{formula_regexp}\s}
DELETED_FORMULA = %r{^\s+delete mode \d+ #{formula_regexp}$}
example_regexp = 'Library/Contributions/examples/([^.\s]+).*'
ADDED_EXAMPLE = %r{^\s+create mode \d+ #{example_regexp}$}
UPDATED_EXAMPLE = %r{^\s+#{example_regexp}}
DELETED_EXAMPLE = %r{^\s+delete mode \d+ #{example_regexp}$}
FORMULA_DIR = 'Library/Formula/'
EXAMPLE_DIR = 'Library/Contributions/examples/'
attr_reader :added_formulae, :updated_formulae, :deleted_formulae, :installed_formulae
attr_reader :added_examples, :updated_examples, :deleted_examples
attr_reader :initial_revision
attr_reader :initial_revision, :current_revision
def initialize
@added_formulae, @updated_formulae, @deleted_formulae, @installed_formulae = [], [], [], []
@added_examples, @updated_examples, @deleted_examples = [], [], []
@initial_revision = self.current_revision
@initial_revision, @current_revision = nil
end
# Performs an update of the homebrew source. Returns +true+ if a newer
# version was available, +false+ if already up-to-date.
def update_from_masterbrew!
output = ''
HOMEBREW_REPOSITORY.cd do
if File.directory? '.git'
if git_repo?
safe_system CHECKOUT_COMMAND
@initial_revision = read_revision
else
safe_system INIT_COMMAND
end
output = execute(UPDATE_COMMAND)
execute(UPDATE_COMMAND)
@current_revision = read_revision
end
output.split("\n").reverse.each do |line|
case line
when ADDED_FORMULA
@added_formulae << $1
when DELETED_FORMULA
@deleted_formulae << $1
when UPDATED_FORMULA
@updated_formulae << $1 unless @added_formulae.include?($1) or @deleted_formulae.include?($1)
when ADDED_EXAMPLE
@added_examples << $1
when DELETED_EXAMPLE
@deleted_examples << $1
when UPDATED_EXAMPLE
@updated_examples << $1 unless @added_examples.include?($1) or @deleted_examples.include?($1)
if initial_revision && initial_revision != current_revision
# hash with status characters for keys:
# Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
@changes_map = Hash.new {|h,k| h[k] = [] }
changes = HOMEBREW_REPOSITORY.cd do
execute(DIFF_COMMAND % [initial_revision, current_revision]).split("\0")
end
while status = changes.shift
file = changes.shift
@changes_map[status] << file
end
if @changes_map.any?
@added_formulae = changed_items('A', FORMULA_DIR)
@deleted_formulae = changed_items('D', FORMULA_DIR)
@updated_formulae = changed_items('M', FORMULA_DIR)
@added_examples = changed_items('A', EXAMPLE_DIR)
@deleted_examples = changed_items('D', EXAMPLE_DIR)
@updated_examples = changed_items('M', EXAMPLE_DIR)
@installed_formulae = HOMEBREW_CELLAR.children.
select{ |pn| pn.directory? }.
map{ |pn| pn.basename.to_s }.sort
return true
end
end
@added_formulae.sort!
@updated_formulae.sort!
@deleted_formulae.sort!
@added_examples.sort!
@updated_examples.sort!
@deleted_examples.sort!
@installed_formulae = HOMEBREW_CELLAR.children.
select{ |pn| pn.directory? }.
map{ |pn| pn.basename.to_s }.sort
# assume nothing was updated
return false
end
output.strip != GIT_UP_TO_DATE
def git_repo?
File.directory? '.git'
end
def pending_formulae_changes?
@ -105,12 +107,6 @@ class RefreshBrew
!@deleted_examples.empty?
end
def current_revision
HOMEBREW_REPOSITORY.cd { execute(REVISION_COMMAND).strip }
rescue
'TAIL'
end
def report
puts "Updated Homebrew from #{initial_revision[0,8]} to #{current_revision[0,8]}."
## New Formulae
@ -151,10 +147,27 @@ class RefreshBrew
private
def read_revision
execute(REVISION_COMMAND).chomp
end
def filter_by_directory(files, dir)
files.select { |f| f.index(dir) == 0 }
end
def basenames(files)
files.map { |f| File.basename(f, '.rb') }
end
# extracts items by status from @changes_map
def changed_items(status, dir)
basenames(filter_by_directory(@changes_map[status], dir)).sort
end
def execute(cmd)
out = `#{cmd}`
if $? && !$?.success?
puts out
$stderr.puts out
raise "Failed while executing #{cmd}"
end
ohai(cmd, out) if ARGV.verbose?

View File

@ -1,53 +1,26 @@
update_git_pull_output_without_formulae_changes: |
remote: counting objects: 58, done.
remote: Compressing objects: 100% (35/35), done.
remote: Total 39 (delta 20), reused 0 (delta 0)
Unpacking objects: 100% (39/39), done.
From git://github.com/mxcl/homebrew
* branch master -> FETCH_HEAD
Updating 14ef7f9..f414bc8
Fast forward
Library/Homebrew/ARGV+yeast.rb | 35 ++--
Library/Homebrew/beer_events.rb | 181 +++++++++++++
Library/Homebrew/hardware.rb | 71 ++++++
Library/Homebrew/hw.model.c | 17 --
README | 337 +++++++++++++------------
bin/brew | 137 ++++++++---
40 files changed, 1107 insertions(+), 426 deletions(-)
create mode 100644 Library/Homebrew/beer_events.rb
create mode 100644 Library/Homebrew/hardware.rb
delete mode 100644 Library/Homebrew/hw.model.c
delete mode 100644 Library/Homebrew/hw.model.rb
update_git_pull_output_with_formulae_changes: |
remote: counting objects: 58, done.
remote: Compressing objects: 100% (35/35), done.
remote: Total 39 (delta 20), reused 0 (delta 0)
Unpacking objects: 100% (39/39), done.
From git://github.com/mxcl/homebrew
* branch master -> FETCH_HEAD
Updating 14ef7f9..f414bc8
Fast forward
Library/Contributions/brew_bash_completion.sh | 6 +-
Library/Formula/antiword.rb | 13 +
Library/Formula/bash-completion.rb | 25 ++
Library/Formula/xar.rb | 19 ++
Library/Formula/yajl.rb | 2 +-
Library/Homebrew/ARGV+yeast.rb | 35 ++--
Library/Homebrew/beer_events.rb | 181 +++++++++++++
Library/Homebrew/hardware.rb | 71 ++++++
Library/Homebrew/hw.model.c | 17 --
Library/Homebrew/pathname+yeast.rb | 28 ++-
Library/Homebrew/unittest.rb | 106 ++++++++-
Library/Homebrew/utils.rb | 36 ++-
README | 337 +++++++++++++------------
bin/brew | 137 ++++++++---
40 files changed, 1107 insertions(+), 426 deletions(-)
create mode 100644 Library/Formula/antiword.rb
create mode 100644 Library/Formula/bash-completion.rb
create mode 100644 Library/Formula/ddrescue.rb
create mode 100644 Library/Formula/dict.rb
create mode 100644 Library/Formula/lua.rb
create mode 100644 Library/Homebrew/beer_events.rb
create mode 100644 Library/Homebrew/hardware.rb
delete mode 100644 Library/Homebrew/hw.model.c
delete mode 100644 Library/Homebrew/hw.model.rb
update_git_diff_output_without_formulae_changes: |
M Library/Homebrew/ARGV+yeast.rb
A Library/Homebrew/beer_events.rb
A Library/Homebrew/hardware.rb
D Library/Homebrew/hw.model.c
M README
M bin/brew
update_git_diff_output_with_formulae_changes: |
M Library/Contributions/brew_bash_completion.sh
A Library/Formula/antiword.rb
A Library/Formula/bash-completion.rb
M Library/Formula/xar.rb
M Library/Formula/yajl.rb
M Library/Homebrew/ARGV+yeast.rb
M Library/Homebrew/pathname+yeast.rb
M Library/Homebrew/unittest.rb
M Library/Homebrew/utils.rb
M README
M bin/brew
A Library/Formula/ddrescue.rb
A Library/Formula/dict.rb
A Library/Formula/lua.rb
A Library/Homebrew/beer_events.rb
A Library/Homebrew/hardware.rb
D Library/Homebrew/hw.model.c
D Library/Homebrew/hw.model.rb

View File

@ -11,15 +11,23 @@ require 'utils'
require 'cmd/update'
class RefreshBrewMock < RefreshBrew
def in_prefix_expect(expect, returns = '')
@expect ||= {}
@expect[expect] = returns
def git_repo?
@git_repo
end
attr_writer :git_repo
def in_prefix_expect(cmd, output = '')
@outputs ||= Hash.new { |h,k| h[k] = [] }
@expected ||= []
@expected << cmd
@outputs[cmd] << output
end
def `(cmd)
if Dir.pwd == HOMEBREW_PREFIX.to_s and @expect.has_key?(cmd)
(@called ||= []) << cmd
@expect[cmd]
if Dir.pwd == HOMEBREW_PREFIX.to_s and @expected.include?(cmd) and !@outputs[cmd].empty?
@called ||= []
@called << cmd
@outputs[cmd].shift
else
raise "#{inspect} Unexpectedly called backticks in pwd `#{HOMEBREW_PREFIX}' and command `#{cmd}'"
end
@ -28,7 +36,7 @@ class RefreshBrewMock < RefreshBrew
alias safe_system `
def expectations_met?
@expect.keys.sort == @called.sort
@expected == @called
end
def inspect
@ -54,11 +62,30 @@ class UpdaterTests < Test::Unit::TestCase
@fixture_data
end
def test_init_homebrew
outside_prefix do
updater = RefreshBrewMock.new
updater.git_repo = false
updater.in_prefix_expect("git init")
updater.in_prefix_expect("git pull #{RefreshBrewMock::REPOSITORY_URL} master")
updater.in_prefix_expect("git rev-parse HEAD", "1234abcd")
assert_equal false, updater.update_from_masterbrew!
assert updater.expectations_met?
assert updater.updated_formulae.empty?
assert updater.added_formulae.empty?
end
end
def test_update_homebrew_without_any_changes
outside_prefix do
updater = RefreshBrewMock.new
updater.in_prefix_expect(RefreshBrew::INIT_COMMAND)
updater.in_prefix_expect(RefreshBrew::UPDATE_COMMAND, "Already up-to-date.\n")
updater.git_repo = true
updater.in_prefix_expect("git checkout -q master")
updater.in_prefix_expect("git rev-parse HEAD", "1234abcd")
updater.in_prefix_expect("git pull #{RefreshBrewMock::REPOSITORY_URL} master")
updater.in_prefix_expect("git rev-parse HEAD", "3456cdef")
updater.in_prefix_expect("git diff-tree -r --name-status -z 1234abcd 3456cdef", "")
assert_equal false, updater.update_from_masterbrew!
assert updater.expectations_met?
@ -70,9 +97,14 @@ class UpdaterTests < Test::Unit::TestCase
def test_update_homebrew_without_formulae_changes
outside_prefix do
updater = RefreshBrewMock.new
updater.in_prefix_expect(RefreshBrew::INIT_COMMAND)
output = fixture('update_git_pull_output_without_formulae_changes')
updater.in_prefix_expect(RefreshBrew::UPDATE_COMMAND, output)
updater.git_repo = true
diff_output = fixture('update_git_diff_output_without_formulae_changes')
updater.in_prefix_expect("git checkout -q master")
updater.in_prefix_expect("git rev-parse HEAD", "1234abcd")
updater.in_prefix_expect("git pull #{RefreshBrewMock::REPOSITORY_URL} master")
updater.in_prefix_expect("git rev-parse HEAD", "3456cdef")
updater.in_prefix_expect("git diff-tree -r --name-status -z 1234abcd 3456cdef", diff_output.gsub(/\s+/, "\0"))
assert_equal true, updater.update_from_masterbrew!
assert !updater.pending_formulae_changes?
@ -84,9 +116,14 @@ class UpdaterTests < Test::Unit::TestCase
def test_update_homebrew_with_formulae_changes
outside_prefix do
updater = RefreshBrewMock.new
updater.in_prefix_expect(RefreshBrew::INIT_COMMAND)
output = fixture('update_git_pull_output_with_formulae_changes')
updater.in_prefix_expect(RefreshBrew::UPDATE_COMMAND, output)
updater.git_repo = true
diff_output = fixture('update_git_diff_output_with_formulae_changes')
updater.in_prefix_expect("git checkout -q master")
updater.in_prefix_expect("git rev-parse HEAD", "1234abcd")
updater.in_prefix_expect("git pull #{RefreshBrewMock::REPOSITORY_URL} master")
updater.in_prefix_expect("git rev-parse HEAD", "3456cdef")
updater.in_prefix_expect("git diff-tree -r --name-status -z 1234abcd 3456cdef", diff_output.gsub(/\s+/, "\0"))
assert_equal true, updater.update_from_masterbrew!
assert updater.pending_formulae_changes?
@ -94,12 +131,4 @@ class UpdaterTests < Test::Unit::TestCase
assert_equal %w{ antiword bash-completion ddrescue dict lua }, updater.added_formulae
end
end
def test_updater_returns_current_revision
outside_prefix do
updater = RefreshBrewMock.new
updater.in_prefix_expect(RefreshBrew::REVISION_COMMAND, 'the-revision-hash')
assert_equal 'the-revision-hash', updater.current_revision
end
end
end