Skip to content
Snippets Groups Projects
Commit 79e8cdd3 authored by Josh Hagins's avatar Josh Hagins Committed by GitHub
Browse files

Merge pull request #1253 from jawshooah/perf/relocate-text-files

keg_relocate: cache files rewritten during brew bottle
parents e6bce5ec fab2cffe
No related branches found
No related tags found
No related merge requests found
...@@ -187,14 +187,11 @@ module Homebrew ...@@ -187,14 +187,11 @@ module Homebrew
keg.lock do keg.lock do
original_tab = nil original_tab = nil
changed_files = nil
begin begin
unless ARGV.include? "--skip-relocation" unless ARGV.include? "--skip-relocation"
keg.relocate_dynamic_linkage prefix, Keg::PREFIX_PLACEHOLDER, changed_files = keg.replace_locations_with_placeholders
cellar, Keg::CELLAR_PLACEHOLDER
keg.relocate_text_files prefix, Keg::PREFIX_PLACEHOLDER,
cellar, Keg::CELLAR_PLACEHOLDER,
repository, Keg::REPOSITORY_PLACEHOLDER
end end
keg.delete_pyc_files! keg.delete_pyc_files!
...@@ -205,6 +202,7 @@ module Homebrew ...@@ -205,6 +202,7 @@ module Homebrew
tab.poured_from_bottle = false tab.poured_from_bottle = false
tab.HEAD = nil tab.HEAD = nil
tab.time = nil tab.time = nil
tab.changed_files = changed_files
tab.write tab.write
keg.find do |file| keg.find do |file|
...@@ -264,11 +262,7 @@ module Homebrew ...@@ -264,11 +262,7 @@ module Homebrew
ignore_interrupts do ignore_interrupts do
original_tab.write if original_tab original_tab.write if original_tab
unless ARGV.include? "--skip-relocation" unless ARGV.include? "--skip-relocation"
keg.relocate_dynamic_linkage Keg::PREFIX_PLACEHOLDER, prefix, keg.replace_placeholders_with_locations changed_files
Keg::CELLAR_PLACEHOLDER, cellar
keg.relocate_text_files Keg::PREFIX_PLACEHOLDER, prefix,
Keg::CELLAR_PLACEHOLDER, cellar,
Keg::REPOSITORY_PLACEHOLDER, repository
end end
end end
end end
......
...@@ -17,19 +17,19 @@ class Keg ...@@ -17,19 +17,19 @@ class Keg
generic_fix_dynamic_linkage generic_fix_dynamic_linkage
end end
def relocate_dynamic_linkage(old_prefix, new_prefix, old_cellar, new_cellar) def relocate_dynamic_linkage(relocation)
mach_o_files.each do |file| mach_o_files.each do |file|
file.ensure_writable do file.ensure_writable do
if file.dylib? if file.dylib?
id = dylib_id_for(file).sub(old_prefix, new_prefix) id = dylib_id_for(file).sub(relocation.old_prefix, relocation.new_prefix)
change_dylib_id(id, file) change_dylib_id(id, file)
end end
each_install_name_for(file) do |old_name| each_install_name_for(file) do |old_name|
if old_name.start_with? old_cellar if old_name.start_with? relocation.old_cellar
new_name = old_name.sub(old_cellar, new_cellar) new_name = old_name.sub(relocation.old_cellar, relocation.new_cellar)
elsif old_name.start_with? old_prefix elsif old_name.start_with? relocation.old_prefix
new_name = old_name.sub(old_prefix, new_prefix) new_name = old_name.sub(relocation.old_prefix, relocation.new_prefix)
end end
change_install_name(old_name, new_name, file) if new_name change_install_name(old_name, new_name, file) if new_name
......
...@@ -762,13 +762,12 @@ class FormulaInstaller ...@@ -762,13 +762,12 @@ class FormulaInstaller
end end
keg = Keg.new(formula.prefix) keg = Keg.new(formula.prefix)
unless formula.bottle_specification.skip_relocation? unless formula.bottle_specification.skip_relocation?
keg.relocate_dynamic_linkage Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s, tab = Tab.for_keg(keg)
Keg::CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s Tab.clear_cache
keg.replace_placeholders_with_locations tab.changed_files
end end
keg.relocate_text_files Keg::PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s,
Keg::CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s,
Keg::REPOSITORY_PLACEHOLDER, HOMEBREW_REPOSITORY.to_s
Pathname.glob("#{formula.bottle_prefix}/{etc,var}/**/*") do |path| Pathname.glob("#{formula.bottle_prefix}/{etc,var}/**/*") do |path|
path.extend(InstallRenamed) path.extend(InstallRenamed)
...@@ -776,7 +775,7 @@ class FormulaInstaller ...@@ -776,7 +775,7 @@ class FormulaInstaller
end end
FileUtils.rm_rf formula.bottle_prefix FileUtils.rm_rf formula.bottle_prefix
tab = Tab.for_keg(formula.prefix) tab = Tab.for_keg(keg)
CxxStdlib.check_compatibility( CxxStdlib.check_compatibility(
formula, formula.recursive_dependencies, formula, formula.recursive_dependencies,
......
...@@ -3,6 +3,14 @@ class Keg ...@@ -3,6 +3,14 @@ class Keg
CELLAR_PLACEHOLDER = "@@HOMEBREW_CELLAR@@".freeze CELLAR_PLACEHOLDER = "@@HOMEBREW_CELLAR@@".freeze
REPOSITORY_PLACEHOLDER = "@@HOMEBREW_REPOSITORY@@".freeze REPOSITORY_PLACEHOLDER = "@@HOMEBREW_REPOSITORY@@".freeze
Relocation = Struct.new(:old_prefix, :old_cellar, :old_repository,
:new_prefix, :new_cellar, :new_repository) do
# Use keyword args instead of positional args for initialization
def initialize(**kwargs)
super(*members.map { |k| kwargs[k] })
end
end
def fix_dynamic_linkage def fix_dynamic_linkage
symlink_files.each do |file| symlink_files.each do |file|
link = file.readlink link = file.readlink
...@@ -15,21 +23,54 @@ class Keg ...@@ -15,21 +23,54 @@ class Keg
end end
alias generic_fix_dynamic_linkage fix_dynamic_linkage alias generic_fix_dynamic_linkage fix_dynamic_linkage
def relocate_dynamic_linkage(_old_prefix, _new_prefix, _old_cellar, _new_cellar) def relocate_dynamic_linkage(_relocation)
[] []
end end
def relocate_text_files(old_prefix, new_prefix, old_cellar, new_cellar, def replace_locations_with_placeholders
old_repository, new_repository) relocation = Relocation.new(
files = text_files | libtool_files old_prefix: HOMEBREW_PREFIX.to_s,
old_cellar: HOMEBREW_CELLAR.to_s,
old_repository: HOMEBREW_REPOSITORY.to_s,
new_prefix: PREFIX_PLACEHOLDER,
new_cellar: CELLAR_PLACEHOLDER,
new_repository: REPOSITORY_PLACEHOLDER
)
relocate_dynamic_linkage(relocation)
replace_text_in_files(relocation)
end
def replace_placeholders_with_locations(files)
relocation = Relocation.new(
old_prefix: PREFIX_PLACEHOLDER,
old_cellar: CELLAR_PLACEHOLDER,
old_repository: REPOSITORY_PLACEHOLDER,
new_prefix: HOMEBREW_PREFIX.to_s,
new_cellar: HOMEBREW_CELLAR.to_s,
new_repository: HOMEBREW_REPOSITORY.to_s
)
relocate_dynamic_linkage(relocation)
replace_text_in_files(relocation, files: files)
end
def replace_text_in_files(relocation, files: nil)
files ||= text_files | libtool_files
files.group_by { |f| f.stat.ino }.each_value do |first, *rest| changed_files = []
files.map(&path.method(:join)).group_by { |f| f.stat.ino }.each_value do |first, *rest|
s = first.open("rb", &:read) s = first.open("rb", &:read)
changed = s.gsub!(old_cellar, new_cellar)
changed = s.gsub!(old_prefix, new_prefix) || changed replacements = {
changed = s.gsub!(old_repository, new_repository) || changed relocation.old_prefix => relocation.new_prefix,
relocation.old_cellar => relocation.new_cellar,
relocation.old_repository => relocation.new_repository,
}
regexp = Regexp.union(replacements.keys)
changed = s.gsub!(regexp, replacements)
next unless changed next unless changed
changed_files << first.relative_path_from(path)
begin begin
first.atomic_write(s) first.atomic_write(s)
...@@ -41,6 +82,7 @@ class Keg ...@@ -41,6 +82,7 @@ class Keg
rest.each { |file| FileUtils.ln(first, file, force: true) } rest.each { |file| FileUtils.ln(first, file, force: true) }
end end
end end
changed_files
end end
def detect_cxx_stdlibs(_options = {}) def detect_cxx_stdlibs(_options = {})
......
class Metafiles require "set"
module Metafiles
# https://github.com/github/markup#markups # https://github.com/github/markup#markups
EXTENSIONS = %w[ EXTENSIONS = Set.new %w[
.adoc .asc .asciidoc .creole .html .markdown .md .mdown .mediawiki .mkdn .adoc .asc .asciidoc .creole .html .markdown .md .mdown .mediawiki .mkdn
.org .pod .rdoc .rst .rtf .textile .txt .wiki .org .pod .rdoc .rst .rtf .textile .txt .wiki
].freeze ].freeze
BASENAMES = %w[ BASENAMES = Set.new %w[
about authors changelog changes copying copyright history license licence about authors changelog changes copying copyright history license licence
news notes notice readme todo news notes notice readme todo
].freeze ].freeze
def self.list?(file) module_function
def list?(file)
return false if %w[.DS_Store INSTALL_RECEIPT.json].include?(file) return false if %w[.DS_Store INSTALL_RECEIPT.json].include?(file)
!copy?(file) !copy?(file)
end end
def self.copy?(file) def copy?(file)
file = file.downcase file = file.downcase
ext = File.extname(file) ext = File.extname(file)
file = File.basename(file, ext) if EXTENSIONS.include?(ext) file = File.basename(file, ext) if EXTENSIONS.include?(ext)
......
...@@ -303,6 +303,7 @@ class Tab < OpenStruct ...@@ -303,6 +303,7 @@ class Tab < OpenStruct
"unused_options" => unused_options.as_flags, "unused_options" => unused_options.as_flags,
"built_as_bottle" => built_as_bottle, "built_as_bottle" => built_as_bottle,
"poured_from_bottle" => poured_from_bottle, "poured_from_bottle" => poured_from_bottle,
"changed_files" => changed_files && changed_files.map(&:to_s),
"time" => time, "time" => time,
"source_modified_time" => source_modified_time.to_i, "source_modified_time" => source_modified_time.to_i,
"HEAD" => self.HEAD, "HEAD" => self.HEAD,
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
], ],
"built_as_bottle": false, "built_as_bottle": false,
"poured_from_bottle": true, "poured_from_bottle": true,
"changed_files": [
"INSTALL_RECEIPT.json",
"bin/foo"
],
"time": 1403827774, "time": 1403827774,
"HEAD": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "HEAD": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"alias_path": "/usr/local/Library/Taps/homebrew/homebrew-core/Aliases/test-formula", "alias_path": "/usr/local/Library/Taps/homebrew/homebrew-core/Aliases/test-formula",
......
...@@ -11,6 +11,7 @@ class TabTests < Homebrew::TestCase ...@@ -11,6 +11,7 @@ class TabTests < Homebrew::TestCase
"unused_options" => @unused.as_flags, "unused_options" => @unused.as_flags,
"built_as_bottle" => false, "built_as_bottle" => false,
"poured_from_bottle" => true, "poured_from_bottle" => true,
"changed_files" => [],
"time" => nil, "time" => nil,
"source_modified_time" => 0, "source_modified_time" => 0,
"HEAD" => TEST_SHA1, "HEAD" => TEST_SHA1,
...@@ -33,6 +34,7 @@ class TabTests < Homebrew::TestCase ...@@ -33,6 +34,7 @@ class TabTests < Homebrew::TestCase
tab = Tab.empty tab = Tab.empty
assert_empty tab.unused_options assert_empty tab.unused_options
assert_empty tab.used_options assert_empty tab.used_options
assert_nil tab.changed_files
refute_predicate tab, :built_as_bottle refute_predicate tab, :built_as_bottle
refute_predicate tab, :poured_from_bottle refute_predicate tab, :poured_from_bottle
assert_predicate tab, :stable? assert_predicate tab, :stable?
...@@ -105,9 +107,11 @@ class TabTests < Homebrew::TestCase ...@@ -105,9 +107,11 @@ class TabTests < Homebrew::TestCase
tab = Tab.from_file(path) tab = Tab.from_file(path)
source_path = "/usr/local/Library/Taps/hombrew/homebrew-core/Formula/foo.rb" source_path = "/usr/local/Library/Taps/hombrew/homebrew-core/Formula/foo.rb"
runtime_dependencies = [{ "full_name" => "foo", "version" => "1.0" }] runtime_dependencies = [{ "full_name" => "foo", "version" => "1.0" }]
changed_files = %w[INSTALL_RECEIPT.json bin/foo]
assert_equal @used.sort, tab.used_options.sort assert_equal @used.sort, tab.used_options.sort
assert_equal @unused.sort, tab.unused_options.sort assert_equal @unused.sort, tab.unused_options.sort
assert_equal changed_files, tab.changed_files
refute_predicate tab, :built_as_bottle refute_predicate tab, :built_as_bottle
assert_predicate tab, :poured_from_bottle assert_predicate tab, :poured_from_bottle
assert_predicate tab, :stable? assert_predicate tab, :stable?
...@@ -187,6 +191,7 @@ class TabTests < Homebrew::TestCase ...@@ -187,6 +191,7 @@ class TabTests < Homebrew::TestCase
assert_equal @tab.unused_options.sort, tab.unused_options.sort assert_equal @tab.unused_options.sort, tab.unused_options.sort
assert_equal @tab.built_as_bottle, tab.built_as_bottle assert_equal @tab.built_as_bottle, tab.built_as_bottle
assert_equal @tab.poured_from_bottle, tab.poured_from_bottle assert_equal @tab.poured_from_bottle, tab.poured_from_bottle
assert_equal @tab.changed_files, tab.changed_files
assert_equal @tab.tap, tab.tap assert_equal @tab.tap, tab.tap
assert_equal @tab.spec, tab.spec assert_equal @tab.spec, tab.spec
assert_equal @tab.time, tab.time assert_equal @tab.time, tab.time
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment