keg_relocate: replace Perl shebangs

This commit is contained in:
Bo Anderson 2021-04-29 17:52:10 +01:00
parent 91ab5fe0ce
commit ae49b06600
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
3 changed files with 102 additions and 45 deletions

View File

@ -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

View File

@ -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.

View File

@ -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) }