update-report: use tap inside Reporter

* Avoid tons of unnecessary file path manipulation. Use abstraction
offered by Tap class if possible.
* Handle formula rename/tap migration inside reporter in per tap basis.
* Avoid duplicated computation.
* Remove redundant/dead code.
This commit is contained in:
Xu Cheng 2016-02-25 15:34:11 +08:00
parent 87ecd621eb
commit 849e62c736

View File

@ -115,119 +115,143 @@ module Homebrew
end end
class Reporter class Reporter
attr_reader :initial_revision, :current_revision, :repository class ReporterRevisionUnsetError < RuntimeError
def initialize(var_name)
super "#{var_name} is unset!"
end
end
def self.repository_variable(repository) attr_reader :tap, :initial_revision, :current_revision
if repository == HOMEBREW_REPOSITORY
def initialize(tap)
@tap = tap
initial_revision_var = "HOMEBREW_UPDATE_BEFORE#{repo_var}"
@initial_revision = ENV[initial_revision_var].to_s
raise ReporterRevisionUnsetError, initial_revision_var if @initial_revision.empty?
current_revision_var = "HOMEBREW_UPDATE_AFTER#{repo_var}"
@current_revision = ENV[current_revision_var].to_s
raise ReporterRevisionUnsetError, current_revision_var if @current_revision.empty?
end
def report
return @report if @report
@report = Hash.new { |h, k| h[k] = [] }
return @report unless updated?
diff.each_line do |line|
status, *paths = line.split
src = Pathname.new paths.first
dst = Pathname.new paths.last
next unless dst.extname == ".rb"
next unless paths.any? { |p| tap.formula_file?(p) }
case status
when "A", "D"
@report[status.to_sym] << tap.formula_file_to_name(src)
when "M"
begin
formula = Formulary.factory(tap.path/src)
new_version = formula.pkg_version
old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version)
next if new_version == old_version
rescue Exception => e
onoe e if ARGV.homebrew_developer?
end
@report[:M] << tap.formula_file_to_name(src)
when /^R\d{0,3}/
@report[:D] << tap.formula_file_to_name(src) if tap.formula_file?(src)
@report[:A] << tap.formula_file_to_name(dst) if tap.formula_file?(dst)
end
end
renamed_formulae = []
@report[:D].each do |old_full_name|
old_name = old_full_name.split("/").last
new_name = tap.formula_renames[old_name]
next unless new_name
if tap.core_formula_repository?
new_full_name = new_name
else
new_full_name = "#{tap}/#{new_full_name}"
end
renamed_formulae << [old_full_name, new_full_name] if @report[:A].include? new_full_name
end
unless renamed_formulae.empty?
@report[:A] -= renamed_formulae.map(&:last)
@report[:D] -= renamed_formulae.map(&:first)
@report[:R] = renamed_formulae
end
@report
end
def updated?
initial_revision != current_revision
end
def migrate_tap_migration
report[:D].each do |full_name|
name = full_name.split("/").last
next unless (dir = HOMEBREW_CELLAR/name).exist? # skip if formula is not installed.
next unless new_tap_name = tap.tap_migrations[name] # skip if formula is not in tap_migrations list.
tabs = dir.subdirs.map { |d| Tab.for_keg(Keg.new(d)) }
next unless tabs.first.tap == tap # skip if installed formula is not from this tap.
new_tap = Tap.fetch(new_tap_name)
new_tap.install unless new_tap.installed?
# update tap for each Tab
tabs.each { |tab| tab.tap = new_tap }
tabs.each(&:write)
end
end
def migrate_formula_rename
report[:R].each do |old_full_name, new_full_name|
old_name = old_full_name.split("/").last
next unless (dir = HOMEBREW_CELLAR/old_name).directory? && !dir.subdirs.empty?
begin
f = Formulary.factory(new_full_name)
rescue Exception => e
onoe e if ARGV.homebrew_developer?
next
end
begin
migrator = Migrator.new(f)
migrator.migrate
rescue Migrator::MigratorDifferentTapsError
rescue Exception => e
onoe e
end
end
end
private
def repo_var
@repo_var ||= if tap.path == HOMEBREW_REPOSITORY
"" ""
else else
repository.to_s. tap.path.to_s.
strip_prefix(Tap::TAP_DIRECTORY.to_s). strip_prefix(Tap::TAP_DIRECTORY.to_s).
tr("^A-Za-z0-9", "_"). tr("^A-Za-z0-9", "_").
upcase upcase
end end
end end
def initialize(repository)
@repository = repository
repo_var = Reporter.repository_variable(@repository)
initial_revision_var = "HOMEBREW_UPDATE_BEFORE#{repo_var}"
@initial_revision = ENV[initial_revision_var].to_s
if @initial_revision.empty?
raise "#{initial_revision_var} is unset!" if ARGV.homebrew_developer?
raise "update-report should not be called directly!"
end
current_revision_var = "HOMEBREW_UPDATE_AFTER#{repo_var}"
@current_revision = ENV[current_revision_var].to_s
if @current_revision.empty?
raise "#{current_revision_var} is unset!" if ARGV.homebrew_developer?
raise "update-report should not be called directly!"
end
end
def report
map = Hash.new { |h, k| h[k] = [] }
if initial_revision && initial_revision != current_revision
wc_revision = read_current_revision
diff.each_line do |line|
status, *paths = line.split
src = paths.first
dst = paths.last
next unless File.extname(dst) == ".rb"
next unless paths.any? { |p| File.dirname(p) == formula_directory }
case status
when "A", "D"
map[status.to_sym] << repository.join(src)
when "M"
file = repository.join(src)
begin
formula = Formulary.factory(file)
new_version = if wc_revision == current_revision
formula.pkg_version
else
FormulaVersions.new(formula).formula_at_revision(@current_revision, &:pkg_version)
end
old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version)
next if new_version == old_version
# short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616
rescue Exception => e
onoe e if ARGV.homebrew_developer?
end
map[:M] << file
when /^R\d{0,3}/
map[:D] << repository.join(src) if File.dirname(src) == formula_directory
map[:A] << repository.join(dst) if File.dirname(dst) == formula_directory
end
end
end
map
end
def updated?
initial_revision && initial_revision != current_revision
end
private
def formula_directory
if repository == HOMEBREW_REPOSITORY
"Library/Formula"
elsif repository.join("Formula").directory?
"Formula"
elsif repository.join("HomebrewFormula").directory?
"HomebrewFormula"
else
"."
end
end
def read_current_revision
`git rev-parse -q --verify HEAD`.chomp
end
def diff def diff
Utils.popen_read( Utils.popen_read(
"git", "diff-tree", "-r", "--name-status", "--diff-filter=AMDR", "git", "-C", tap.path, "diff-tree", "-r", "--name-status", "--diff-filter=AMDR",
"-M85%", initial_revision, current_revision "-M85%", initial_revision, current_revision
) )
end end
def `(cmd)
out = super
unless $?.success?
$stderr.puts(out) unless out.empty?
raise ErrorDuringExecution.new(cmd)
end
ohai(cmd, out) if ARGV.verbose?
out
end
end end
class Report class Report