From ae49b0660052e88e53ebffc6e33dd48052d7cc2f Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Thu, 29 Apr 2021 17:52:10 +0100 Subject: [PATCH] keg_relocate: replace Perl shebangs --- .../Homebrew/extend/os/linux/keg_relocate.rb | 4 +- .../Homebrew/extend/os/mac/keg_relocate.rb | 40 +++++-- Library/Homebrew/keg_relocate.rb | 103 ++++++++++++------ 3 files changed, 102 insertions(+), 45 deletions(-) diff --git a/Library/Homebrew/extend/os/linux/keg_relocate.rb b/Library/Homebrew/extend/os/linux/keg_relocate.rb index 728f36e067..280f8046c1 100644 --- a/Library/Homebrew/extend/os/linux/keg_relocate.rb +++ b/Library/Homebrew/extend/os/linux/keg_relocate.rb @@ -11,9 +11,11 @@ class Keg # Patching patchelf using itself fails with "Text file busy" or SIGBUS. return if name == "patchelf" + old_prefix, new_prefix = relocation.replacement_pair_for(:prefix) + elf_files.each do |file| file.ensure_writable do - change_rpath(file, relocation.old_prefix, relocation.new_prefix) + change_rpath(file, old_prefix, new_prefix) end end end diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index 50a65f4d78..be5f51814b 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -19,18 +19,21 @@ class Keg undef relocate_dynamic_linkage def relocate_dynamic_linkage(relocation) + old_prefix, new_prefix = relocation.replacement_pair_for(:prefix) + old_cellar, new_cellar = relocation.replacement_pair_for(:cellar) + mach_o_files.each do |file| file.ensure_writable do if file.dylib? - id = dylib_id_for(file).sub(relocation.old_prefix, relocation.new_prefix) + id = dylib_id_for(file).sub(old_prefix, new_prefix) change_dylib_id(id, file) end each_install_name_for(file) do |old_name| - if old_name.start_with? relocation.old_cellar - new_name = old_name.sub(relocation.old_cellar, relocation.new_cellar) - elsif old_name.start_with? relocation.old_prefix - new_name = old_name.sub(relocation.old_prefix, relocation.new_prefix) + if old_name.start_with? old_cellar + new_name = old_name.sub(old_cellar, new_cellar) + elsif old_name.start_with? old_prefix + new_name = old_name.sub(old_prefix, new_prefix) end change_install_name(old_name, new_name, file) if new_name @@ -38,10 +41,10 @@ class Keg if ENV["HOMEBREW_RELOCATE_RPATHS"] each_rpath_for(file) do |old_name| - new_name = if old_name.start_with? relocation.old_cellar - old_name.sub(relocation.old_cellar, relocation.new_cellar) - elsif old_name.start_with? relocation.old_prefix - old_name.sub(relocation.old_prefix, relocation.new_prefix) + new_name = if old_name.start_with? old_cellar + old_name.sub(old_cellar, new_cellar) + elsif old_name.start_with? old_prefix + old_name.sub(old_prefix, new_prefix) end change_rpath(old_name, new_name, file) if new_name @@ -172,6 +175,25 @@ class Keg mach_o_files end + def prepare_relocation_to_locations + relocation = generic_prepare_relocation_to_locations + + brewed_perl = runtime_dependencies&.any? { |dep| dep["full_name"] == "perl" && dep["declared_directly"] } + perl_path = if brewed_perl + "#{HOMEBREW_PREFIX}/opt/perl/bin/perl" + else + perl_version = if tab["built_on"].present? + tab["built_on"]["preferred_perl"] + else + MacOS.preferred_perl_version + end + "/usr/bin/perl#{perl_version}" + end + relocation.add_replacement_pair(:perl, PERL_PLACEHOLDER, perl_path) + + relocation + end + def recursive_fgrep_args # Don't recurse into symlinks; the man page says this is the default, but # it's wrong. -O is a BSD-grep-only option. diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index fd363aa429..661752ef58 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -6,12 +6,44 @@ class Keg CELLAR_PLACEHOLDER = "@@HOMEBREW_CELLAR@@" REPOSITORY_PLACEHOLDER = "@@HOMEBREW_REPOSITORY@@" LIBRARY_PLACEHOLDER = "@@HOMEBREW_LIBRARY@@" + PERL_PLACEHOLDER = "@@HOMEBREW_PERL@@" - Relocation = Struct.new(:old_prefix, :old_cellar, :old_repository, :old_library, - :new_prefix, :new_cellar, :new_repository, :new_library) do - # Use keyword args instead of positional args for initialization. - def initialize(**kwargs) - super(*members.map { |k| kwargs[k] }) + class Relocation + extend T::Sig + + def initialize + @replacement_map = {} + end + + def freeze + @replacement_map.freeze + super + end + + sig { params(key: Symbol, old_value: T.any(String, Regexp), new_value: String).void } + def add_replacement_pair(key, old_value, new_value) + @replacement_map[key] = [old_value, new_value] + end + + sig { params(key: Symbol).returns(T::Array[T.any(String, Regexp)]) } + def replacement_pair_for(key) + @replacement_map.fetch(key) + end + + sig { params(text: String).void } + def replace_text(text) + replacements = @replacement_map.values.to_h + + sorted_keys = replacements.keys.sort_by do |key| + key.is_a?(String) ? key.length : 999 + end.reverse + + any_changed = false + sorted_keys.each do |key| + changed = text.gsub!(key, replacements[key]) + any_changed ||= changed + end + any_changed end end @@ -36,32 +68,42 @@ class Keg [] end + def prepare_relocation_to_placeholders + relocation = Relocation.new + relocation.add_replacement_pair(:prefix, HOMEBREW_PREFIX.to_s, PREFIX_PLACEHOLDER) + relocation.add_replacement_pair(:cellar, HOMEBREW_CELLAR.to_s, CELLAR_PLACEHOLDER) + # when HOMEBREW_PREFIX == HOMEBREW_REPOSITORY we should use HOMEBREW_PREFIX for all relocations to avoid + # being unable to differentiate between them. + if HOMEBREW_PREFIX != HOMEBREW_REPOSITORY + relocation.add_replacement_pair(:repository, HOMEBREW_REPOSITORY.to_s, REPOSITORY_PLACEHOLDER) + end + relocation.add_replacement_pair(:library, HOMEBREW_LIBRARY.to_s, LIBRARY_PLACEHOLDER) + relocation.add_replacement_pair(:perl, + %r{\A#!(/usr/bin/perl\d\.\d+|#{HOMEBREW_PREFIX}/opt/perl/bin/perl)$}o, + "#!#{PERL_PLACEHOLDER}") + relocation + end + alias generic_prepare_relocation_to_placeholders prepare_relocation_to_placeholders + def replace_locations_with_placeholders - relocation = Relocation.new( - old_prefix: HOMEBREW_PREFIX.to_s, - old_cellar: HOMEBREW_CELLAR.to_s, - new_prefix: PREFIX_PLACEHOLDER, - new_cellar: CELLAR_PLACEHOLDER, - old_repository: HOMEBREW_REPOSITORY.to_s, - new_repository: REPOSITORY_PLACEHOLDER, - old_library: HOMEBREW_LIBRARY.to_s, - new_library: LIBRARY_PLACEHOLDER, - ) + relocation = prepare_relocation_to_placeholders.freeze relocate_dynamic_linkage(relocation) replace_text_in_files(relocation) end + def prepare_relocation_to_locations + relocation = Relocation.new + relocation.add_replacement_pair(:prefix, PREFIX_PLACEHOLDER, HOMEBREW_PREFIX.to_s) + relocation.add_replacement_pair(:cellar, CELLAR_PLACEHOLDER, HOMEBREW_CELLAR.to_s) + relocation.add_replacement_pair(:repository, REPOSITORY_PLACEHOLDER, HOMEBREW_REPOSITORY.to_s) + relocation.add_replacement_pair(:library, LIBRARY_PLACEHOLDER, HOMEBREW_LIBRARY.to_s) + relocation.add_replacement_pair(:perl, PERL_PLACEHOLDER, "#{HOMEBREW_PREFIX}/opt/perl/bin/perl") + relocation + end + alias generic_prepare_relocation_to_locations prepare_relocation_to_locations + def replace_placeholders_with_locations(files, skip_linkage: false) - relocation = Relocation.new( - old_prefix: PREFIX_PLACEHOLDER, - old_cellar: CELLAR_PLACEHOLDER, - old_repository: REPOSITORY_PLACEHOLDER, - old_library: LIBRARY_PLACEHOLDER, - new_prefix: HOMEBREW_PREFIX.to_s, - new_cellar: HOMEBREW_CELLAR.to_s, - new_repository: HOMEBREW_REPOSITORY.to_s, - new_library: HOMEBREW_LIBRARY.to_s, - ) + relocation = prepare_relocation_to_locations.freeze relocate_dynamic_linkage(relocation) unless skip_linkage replace_text_in_files(relocation, files: files) end @@ -73,16 +115,7 @@ class Keg files.map(&path.method(:join)).group_by { |f| f.stat.ino }.each_value do |first, *rest| s = first.open("rb", &:read) - replacements = { - relocation.old_prefix => relocation.new_prefix, - relocation.old_cellar => relocation.new_cellar, - relocation.old_library => relocation.new_library, - }.compact - # when HOMEBREW_PREFIX == HOMEBREW_REPOSITORY we should use HOMEBREW_PREFIX for all relocations to avoid - # being unable to differentiate between them. - replacements[relocation.old_repository] = relocation.new_repository if HOMEBREW_PREFIX != HOMEBREW_REPOSITORY - changed = s.gsub!(Regexp.union(replacements.keys.sort_by(&:length).reverse), replacements) - next unless changed + next unless relocation.replace_text(s) changed_files += [first, *rest].map { |file| file.relative_path_from(path) }