Class: Keg
- Inherits:
-
Object
- Object
- Keg
- Extended by:
- Cachable, Forwardable
- Defined in:
- Library/Homebrew/keg.rb,
Library/Homebrew/os/mac/keg.rb,
Library/Homebrew/keg_relocate.rb,
Library/Homebrew/extend/os/mac/keg.rb,
Library/Homebrew/extend/os/mac/keg_relocate.rb,
Library/Homebrew/extend/os/linux/keg_relocate.rb
Overview
typed: true frozen_string_literal: true
Defined Under Namespace
Classes: AlreadyLinkedError, ConflictError, DirectoryNotWritableError, LinkError, Relocation
Constant Summary collapse
- LOCALEDIR_RX =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Locale-specific directories have the form
language[_territory][.codeset][@modifier]
%r{(locale|man)/([a-z]{2}|C|POSIX)(_[A-Z]{2})?(\.[a-zA-Z\-0-9]+(@.+)?)?}.freeze
- INFOFILE_RX =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%r{info/([^.].*?\.info|dir)$}.freeze
- KEG_LINK_DIRECTORIES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
(GENERIC_KEG_LINK_DIRECTORIES + ["Frameworks"]).freeze
- MUST_EXIST_SUBDIRECTORIES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
( GENERIC_MUST_EXIST_SUBDIRECTORIES + [HOMEBREW_PREFIX/"Frameworks"] ).sort.uniq.freeze
- MUST_EXIST_DIRECTORIES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Keep relatively in sync with https://github.com/Homebrew/install/blob/HEAD/install.sh
( GENERIC_MUST_EXIST_DIRECTORIES + [HOMEBREW_PREFIX/"Frameworks"] ).sort.uniq.freeze
- MUST_BE_WRITABLE_DIRECTORIES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
( GENERIC_MUST_BE_WRITABLE_DIRECTORIES + [HOMEBREW_PREFIX/"Frameworks"] ).sort.uniq.freeze
- SHARE_PATHS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
These paths relative to the keg's share directory should always be real directories in the prefix, never symlinks.
%w[ aclocal doc info java locale man man/man1 man/man2 man/man3 man/man4 man/man5 man/man6 man/man7 man/man8 man/cat1 man/cat2 man/cat3 man/cat4 man/cat5 man/cat6 man/cat7 man/cat8 applications gnome gnome/help icons mime-info pixmaps sounds postgresql ].freeze
- ELISP_EXTENSIONS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[.el .elc].freeze
- PYC_EXTENSIONS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[.pyc .pyo].freeze
- LIBTOOL_EXTENSIONS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%w[.la .lai].freeze
- PREFIX_PLACEHOLDER =
"@@[email protected]@"
- CELLAR_PLACEHOLDER =
"@@[email protected]@"
- REPOSITORY_PLACEHOLDER =
"@@[email protected]@"
- GENERIC_KEG_LINK_DIRECTORIES =
(remove_const :KEG_LINK_DIRECTORIES).freeze
- GENERIC_MUST_EXIST_SUBDIRECTORIES =
(remove_const :MUST_EXIST_SUBDIRECTORIES).freeze
- GENERIC_MUST_EXIST_DIRECTORIES =
(remove_const :MUST_EXIST_DIRECTORIES).freeze
- GENERIC_MUST_BE_WRITABLE_DIRECTORIES =
(remove_const :MUST_BE_WRITABLE_DIRECTORIES).freeze
- FRAMEWORK_RX =
Matches framework references like
XXX.framework/Versions/YYY/XXX
andXXX.framework/XXX
, both with or without a slash-delimited prefix. %r{(?:^|/)(([^/]+)\.framework/(?:Versions/[^/]+/)?\2)$}.freeze
Instance Attribute Summary collapse
- #linked_keg_record ⇒ Object readonly private
- #name ⇒ Object readonly private
- #opt_record ⇒ Object readonly private
Class Method Summary collapse
- .all ⇒ Object private
- .bottle_dependencies ⇒ Object
- .file_linked_libraries(file, string) ⇒ Object
-
.find_some_installed_dependents(kegs) ⇒ Object
private
Given an array of kegs, this method will try to find some other kegs that depend on them.
- .for(path) ⇒ Object private
- .relocation_formulae ⇒ Object
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?) private
- #aliases ⇒ Object private
- #apps ⇒ Object private
- #change_dylib_id(id, file) ⇒ Object
- #change_install_name(old, new, file) ⇒ Object
- #change_rpath(file, old_prefix, new_prefix) ⇒ Object
- #completion_installed?(shell) ⇒ Boolean private
- #delete_pyc_files! ⇒ Object private
-
#detect_cxx_stdlibs(options = {}) ⇒ Object
Detects the C++ dynamic libraries in-place, scanning the dynamic links of the files within the keg.
- #dylib_id_for(file) ⇒ Object
- #each_install_name_for(file, &block) ⇒ Object
- #each_unique_file_matching(string) ⇒ Object
- #elf_files ⇒ Object
- #elisp_installed? ⇒ Boolean private
- #empty_installation? ⇒ Boolean private
- #expand_rpath(file, bad_name) ⇒ Object
- #find_dylib(bad_name) ⇒ Object
- #find_dylib_suffix_from(bad_name) ⇒ Object
- #fix_dynamic_linkage ⇒ Object
-
#fixed_name(file, bad_name) ⇒ Object
If file is a dylib or bundle itself, look for the dylib named by bad_name relative to the lib directory, so that we can skip the more expensive recursive search if possible.
- #functions_installed?(shell) ⇒ Boolean private
- #generic_fix_dynamic_linkage ⇒ Object
- #generic_recursive_fgrep_args ⇒ Object
-
#initialize(path) ⇒ Keg
constructor
private
A new instance of Keg.
- #inspect ⇒ Object private
- #lib ⇒ Object
- #libexec ⇒ Object
- #libtool_files ⇒ Object
-
#link(**options) ⇒ Object
private
TODO: refactor to use keyword arguments.
- #linked? ⇒ Boolean private
- #lock(&block) ⇒ Object private
- #mach_o_files ⇒ Object
- #oldname_opt_record ⇒ Object private
- #optlink(**options) ⇒ Object private
- #optlinked? ⇒ Boolean private
- #plist_installed? ⇒ Boolean private
- #python_pth_files_installed? ⇒ Boolean private
- #python_site_packages_installed? ⇒ Boolean private
- #rack ⇒ Object private
- #recursive_fgrep_args ⇒ Object
- #relocate_dynamic_linkage(relocation) ⇒ Object
- #remove_linked_keg_record ⇒ Object private
- #remove_old_aliases ⇒ Object private
- #remove_oldname_opt_record ⇒ Object private
- #remove_opt_record ⇒ Object private
- #replace_locations_with_placeholders ⇒ Object
- #replace_placeholders_with_locations(files, skip_linkage: false) ⇒ Object
- #replace_text_in_files(relocation, files: nil) ⇒ Object
- #require_relocation? ⇒ Boolean private
- #runtime_dependencies ⇒ Object private
- #symlink_files ⇒ Object
- #tab ⇒ Object private
- #text_files ⇒ Object
- #to_formula ⇒ Object private
- #uninstall ⇒ Object private
-
#unlink(**options) ⇒ Object
private
TODO: refactor to use keyword arguments.
- #version ⇒ Object private
Methods included from Cachable
Constructor Details
#initialize(path) ⇒ Keg
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Keg.
211 212 213 214 215 216 217 218 219 220 221 |
# File 'Library/Homebrew/keg.rb', line 211 def initialize(path) path = path.resolved_path if path.to_s.start_with?("#{HOMEBREW_PREFIX}/opt/") raise "#{path} is not a valid keg" if path.parent.parent.realpath != HOMEBREW_CELLAR.realpath raise "#{path} is not a directory" unless path.directory? @path = path @name = path.parent.basename.to_s @linked_keg_record = HOMEBREW_LINKED_KEGS/name @opt_record = HOMEBREW_PREFIX/"opt/#{name}" @require_relocation = false end |
Instance Attribute Details
#linked_keg_record ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
201 202 203 |
# File 'Library/Homebrew/keg.rb', line 201 def linked_keg_record @linked_keg_record end |
#name ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
201 202 203 |
# File 'Library/Homebrew/keg.rb', line 201 def name @name end |
#opt_record ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
201 202 203 |
# File 'Library/Homebrew/keg.rb', line 201 def opt_record @opt_record end |
Class Method Details
.all ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
197 198 199 |
# File 'Library/Homebrew/keg.rb', line 197 def self.all Formula.racks.flat_map(&:subdirs).map { |d| new(d) } end |
.bottle_dependencies ⇒ Object
198 199 200 |
# File 'Library/Homebrew/keg_relocate.rb', line 198 def self.bottle_dependencies relocation_formulae end |
.file_linked_libraries(file, string) ⇒ Object
190 191 192 |
# File 'Library/Homebrew/keg_relocate.rb', line 190 def self.file_linked_libraries(_file, _string) [] end |
.find_some_installed_dependents(kegs) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Given an array of kegs, this method will try to find some other kegs that depend on them. If it does, it returns:
- some kegs in the passed array that have installed dependents
- some installed dependents of those kegs.
If it doesn't, it returns nil.
Note that nil will be returned if the only installed dependents in the passed kegs are other kegs in the array.
For efficiency, we don't bother trying to get complete data.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'Library/Homebrew/keg.rb', line 142 def self.find_some_installed_dependents(kegs) keg_names = kegs.select(&:optlinked?).map(&:name) keg_formulae = [] kegs_by_source = kegs.group_by do |keg| # First, attempt to resolve the keg to a formula # to get up-to-date name and tap information. f = keg.to_formula keg_formulae << f [f.name, f.tap] rescue # If the formula for the keg can't be found, # fall back to the information in the tab. [keg.name, keg.tab.tap] end all_required_kegs = Set.new all_dependents = [] # Don't include dependencies of kegs that were in the given array. formulae_to_check = Formula.installed - keg_formulae formulae_to_check.each do |dependent| required = dependent.missing_dependencies(hide: keg_names) required_kegs = required.map do |f| f_kegs = kegs_by_source[[f.name, f.tap]] next unless f_kegs f_kegs.max_by(&:version) end.compact next if required_kegs.empty? all_required_kegs += required_kegs all_dependents << dependent.to_s end return if all_required_kegs.empty? return if all_dependents.empty? [all_required_kegs.to_a, all_dependents.sort] end |
.for(path) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
185 186 187 188 189 190 191 192 193 194 195 |
# File 'Library/Homebrew/keg.rb', line 185 def self.for(path) original_path = path if original_path.exist? && (path = original_path.realpath) until path.root? return Keg.new(path) if path.parent.parent == HOMEBREW_CELLAR.realpath path = path.parent.realpath # realpath() prevents root? failing end end raise NotAKegError, "#{original_path} is not inside a keg" end |
.relocation_formulae ⇒ Object
194 195 196 |
# File 'Library/Homebrew/keg_relocate.rb', line 194 def self.relocation_formulae [] end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
233 234 235 |
# File 'Library/Homebrew/keg.rb', line 233 def ==(other) instance_of?(other.class) && path == other.path end |
#aliases ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
551 552 553 |
# File 'Library/Homebrew/keg.rb', line 551 def aliases tab.aliases || [] end |
#apps ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
426 427 428 429 |
# File 'Library/Homebrew/keg.rb', line 426 def apps app_prefix = optlinked? ? opt_record : path Pathname.glob("#{app_prefix}/{,libexec/}*.app") end |
#change_dylib_id(id, file) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'Library/Homebrew/os/mac/keg.rb', line 5 def change_dylib_id(id, file) return if file.dylib_id == id @require_relocation = true odebug "Changing dylib ID of #{file}\n from #{file.dylib_id}\n to #{id}" MachO::Tools.change_dylib_id(file, id, strict: false) rescue MachO::MachOError onoe <<~EOS Failed changing dylib ID of #{file} from #{file.dylib_id} to #{id} EOS raise end |
#change_install_name(old, new, file) ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'Library/Homebrew/os/mac/keg.rb', line 20 def change_install_name(old, new, file) return if old == new @require_relocation = true odebug "Changing install name in #{file}\n from #{old}\n to #{new}" MachO::Tools.change_install_name(file, old, new, strict: false) rescue MachO::MachOError onoe <<~EOS Failed changing install name in #{file} from #{old} to #{new} EOS raise end |
#change_rpath(file, old_prefix, new_prefix) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'Library/Homebrew/extend/os/linux/keg_relocate.rb', line 19 def change_rpath(file, old_prefix, new_prefix) return if !file.elf? || !file.dynamic_elf? updated = {} old_rpath = file.rpath new_rpath = if old_rpath rpath = old_rpath.split(":") .map { |x| x.sub(old_prefix, new_prefix) } .select { |x| x.start_with?(new_prefix, "$ORIGIN") } lib_path = "#{new_prefix}/lib" rpath << lib_path unless rpath.include? lib_path rpath.join(":") end updated[:rpath] = new_rpath if old_rpath != new_rpath old_interpreter = file.interpreter new_interpreter = if old_interpreter.nil? nil elsif File.readable? "#{new_prefix}/lib/ld.so" "#{new_prefix}/lib/ld.so" else old_interpreter.sub old_prefix, new_prefix end updated[:interpreter] = new_interpreter if old_interpreter != new_interpreter file.patch!(interpreter: updated[:interpreter], rpath: updated[:rpath]) end |
#completion_installed?(shell) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
390 391 392 393 394 395 396 397 398 399 |
# File 'Library/Homebrew/keg.rb', line 390 def completion_installed?(shell) dir = case shell when :bash then path/"etc/bash_completion.d" when :zsh dir = path/"share/zsh/site-functions" dir if dir.directory? && dir.children.any? { |f| f.basename.to_s.start_with?("_") } when :fish then path/"share/fish/vendor_completions.d" end dir&.directory? && !dir.children.empty? end |
#delete_pyc_files! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
570 571 572 573 |
# File 'Library/Homebrew/keg.rb', line 570 def delete_pyc_files! find { |pn| pn.delete if PYC_EXTENSIONS.include?(pn.extname) } find { |pn| FileUtils.rm_rf pn if pn.basename.to_s == "__pycache__" } end |
#detect_cxx_stdlibs(options = {}) ⇒ Object
Detects the C++ dynamic libraries in-place, scanning the dynamic links of the files within the keg. Note that this doesn't attempt to distinguish between libstdc++ versions, for instance between Apple libstdc++ and GNU libstdc++.
46 47 48 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 46 def detect_cxx_stdlibs( = {}) [] end |
#dylib_id_for(file) ⇒ Object
133 134 135 136 137 138 139 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 133 def dylib_id_for(file) # The new dylib ID should have the same basename as the old dylib ID, not # the basename of the file itself. basename = File.basename(file.dylib_id) relative_dirname = file.dirname.relative_path_from(path) (opt_record/relative_dirname/basename).to_s end |
#each_install_name_for(file, &block) ⇒ Object
126 127 128 129 130 131 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 126 def each_install_name_for(file, &block) dylibs = file.dynamically_linked_libraries dylibs.reject! { |fn| fn =~ /^@(loader|executable)_path/ } dylibs.reject! { |fn| fn =~ /^@rpath/ } unless ENV["HOMEBREW_RELOCATE_METAVARS"] dylibs.each(&block) end |
#each_unique_file_matching(string) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'Library/Homebrew/keg_relocate.rb', line 104 def each_unique_file_matching(string) Utils.popen_read("fgrep", recursive_fgrep_args, string, to_s) do |io| hardlinks = Set.new until io.eof? file = Pathname.new(io.readline.chomp) next if file.symlink? yield file if hardlinks.add? file.stat.ino end end end |
#elf_files ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'Library/Homebrew/extend/os/linux/keg_relocate.rb', line 63 def elf_files hardlinks = Set.new elf_files = [] path.find do |pn| next if pn.symlink? || pn.directory? next if !pn.dylib? && !pn.binary_executable? # If we've already processed a file, ignore its hardlinks (which have the # same dev ID and inode). This prevents relocations from being performed # on a binary more than once. next unless hardlinks.add? [pn.stat.dev, pn.stat.ino] elf_files << pn end elf_files end |
#elisp_installed? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
431 432 433 434 435 |
# File 'Library/Homebrew/keg.rb', line 431 def elisp_installed? return false unless (path/"share/emacs/site-lisp"/name).exist? (path/"share/emacs/site-lisp"/name).children.any? { |f| ELISP_EXTENSIONS.include? f.extname } end |
#empty_installation? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'Library/Homebrew/keg.rb', line 238 def empty_installation? Pathname.glob("#{path}/*") do |file| return false if file.directory? && !file.children.reject(&:ds_store?).empty? basename = file.basename.to_s next if Metafiles.copy?(basename) next if %w[.DS_Store INSTALL_RECEIPT.json].include?(basename) return false end true end |
#expand_rpath(file, bad_name) ⇒ Object
91 92 93 94 95 96 97 98 99 100 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 91 def (file, bad_name) suffix = bad_name.sub(/^@rpath/, "") file.rpaths.each do |rpath| return rpath/suffix if (rpath/suffix).exist? end opoo "Could not find library #{bad_name} for #{file}" bad_name end |
#find_dylib(bad_name) ⇒ Object
153 154 155 156 157 158 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 153 def find_dylib(bad_name) return unless lib.directory? suffix = "/#{find_dylib_suffix_from(bad_name)}" lib.find { |pn| break pn if pn.to_s.end_with?(suffix) } end |
#find_dylib_suffix_from(bad_name) ⇒ Object
145 146 147 148 149 150 151 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 145 def find_dylib_suffix_from(bad_name) if (framework = bad_name.match(FRAMEWORK_RX)) framework[1] else File.basename(bad_name) end end |
#fix_dynamic_linkage ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'Library/Homebrew/keg_relocate.rb', line 17 def fix_dynamic_linkage symlink_files.each do |file| link = file.readlink # Don't fix relative symlinks next unless link.absolute? link_starts_cellar = link.to_s.start_with?(HOMEBREW_CELLAR.to_s) link_starts_prefix = link.to_s.start_with?(HOMEBREW_PREFIX.to_s) next if !link_starts_cellar && !link_starts_prefix new_src = link.relative_path_from(file.parent) file.unlink FileUtils.ln_s(new_src, file) end end |
#fixed_name(file, bad_name) ⇒ Object
If file is a dylib or bundle itself, look for the dylib named by bad_name relative to the lib directory, so that we can skip the more expensive recursive search if possible.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 105 def fixed_name(file, bad_name) if bad_name.start_with? PREFIX_PLACEHOLDER bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX) elsif bad_name.start_with? CELLAR_PLACEHOLDER bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR) elsif (file.dylib? || file.mach_o_bundle?) && (file.dirname/bad_name).exist? "@loader_path/#{bad_name}" elsif file.mach_o_executable? && (lib/bad_name).exist? "#{lib}/#{bad_name}" elsif file.mach_o_executable? && (libexec/"lib"/bad_name).exist? "#{libexec}/lib/#{bad_name}" elsif bad_name.start_with?("@rpath") && ENV["HOMEBREW_RELOCATE_METAVARS"] file, bad_name elsif (abs_name = find_dylib(bad_name)) && abs_name.exist? abs_name.to_s else opoo "Could not fix #{bad_name} in #{file}" bad_name end end |
#functions_installed?(shell) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'Library/Homebrew/keg.rb', line 401 def functions_installed?(shell) case shell when :fish dir = path/"share/fish/vendor_functions.d" dir.directory? && !dir.children.empty? when :zsh # Check for non completion functions (i.e. files not started with an underscore), # since those can be checked separately dir = path/"share/zsh/site-functions" dir.directory? && dir.children.any? { |f| !f.basename.to_s.start_with?("_") } end end |
#generic_fix_dynamic_linkage ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'Library/Homebrew/keg_relocate.rb', line 32 def fix_dynamic_linkage symlink_files.each do |file| link = file.readlink # Don't fix relative symlinks next unless link.absolute? link_starts_cellar = link.to_s.start_with?(HOMEBREW_CELLAR.to_s) link_starts_prefix = link.to_s.start_with?(HOMEBREW_PREFIX.to_s) next if !link_starts_cellar && !link_starts_prefix new_src = link.relative_path_from(file.parent) file.unlink FileUtils.ln_s(new_src, file) end end |
#generic_recursive_fgrep_args ⇒ Object
102 103 104 105 |
# File 'Library/Homebrew/keg_relocate.rb', line 102 def recursive_fgrep_args # for GNU grep; overridden for BSD grep on OS X "-lr" end |
#inspect ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
229 230 231 |
# File 'Library/Homebrew/keg.rb', line 229 def inspect "#<#{self.class.name}:#{path}>" end |
#lib ⇒ Object
117 118 119 |
# File 'Library/Homebrew/keg_relocate.rb', line 117 def lib path/"lib" end |
#libexec ⇒ Object
121 122 123 |
# File 'Library/Homebrew/keg_relocate.rb', line 121 def libexec path/"libexec" end |
#libtool_files ⇒ Object
170 171 172 173 174 175 176 177 178 179 |
# File 'Library/Homebrew/keg_relocate.rb', line 170 def libtool_files libtool_files = [] path.find do |pn| next if pn.symlink? || pn.directory? || !Keg::LIBTOOL_EXTENSIONS.include?(pn.extname) libtool_files << pn end libtool_files end |
#link(**options) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO: refactor to use keyword arguments.
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
# File 'Library/Homebrew/keg.rb', line 455 def link(**) raise AlreadyLinkedError, self if linked_keg_record.directory? ObserverPathnameExtension.reset_counts! optlink(**) unless [:dry_run] # yeah indeed, you have to force anything you need in the main tree into # these dirs REMEMBER that *NOT* everything needs to be in the main tree link_dir("etc", **) { :mkpath } link_dir("bin", **) { :skip_dir } link_dir("sbin", **) { :skip_dir } link_dir("include", **) { :link } link_dir("share", **) do |relative_path| case relative_path.to_s when "locale/locale.alias" then :skip_file when INFOFILE_RX then :info when LOCALEDIR_RX then :mkpath when %r{^icons/.*/icon-theme\.cache$} then :skip_file # all icons subfolders should also mkpath when %r{^icons/} then :mkpath when /^zsh/ then :mkpath when /^fish/ then :mkpath # Lua, Lua51, Lua53 all need the same handling. when %r{^lua/} then :mkpath when %r{^guile/} then :mkpath when *SHARE_PATHS then :mkpath else :link end end link_dir("lib", **) do |relative_path| case relative_path.to_s when "charset.alias" then :skip_file # pkg-config database gets explicitly created when "pkgconfig" then :mkpath # cmake database gets explicitly created when "cmake" then :mkpath # lib/language folders also get explicitly created when "dtrace" then :mkpath when /^gdk-pixbuf/ then :mkpath when "ghc" then :mkpath when /^gio/ then :mkpath when "lua" then :mkpath when /^mecab/ then :mkpath when /^node/ then :mkpath when /^ocaml/ then :mkpath when /^perl5/ then :mkpath when "php" then :mkpath when /^python[23]\.\d/ then :mkpath when /^R/ then :mkpath when /^ruby/ then :mkpath # Everything else is symlinked to the cellar else :link end end link_dir("Frameworks", **) do |relative_path| # Frameworks contain symlinks pointing into a subdir, so we have to use # the :link strategy. However, for Foo.framework and # Foo.framework/Versions we have to use :mkpath so that multiple formulae # can link their versions into it and `brew [un]link` works. if relative_path.to_s.match?(%r{[^/]*\.framework(/Versions)?$}) :mkpath else :link end end make_relative_symlink(linked_keg_record, path, **) unless [:dry_run] rescue LinkError unlink(verbose: [:verbose]) raise else ObserverPathnameExtension.n end |
#linked? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
256 257 258 259 260 |
# File 'Library/Homebrew/keg.rb', line 256 def linked? linked_keg_record.symlink? && linked_keg_record.directory? && path == linked_keg_record.resolved_path end |
#lock(&block) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
380 381 382 383 384 385 386 387 388 |
# File 'Library/Homebrew/keg.rb', line 380 def lock(&block) FormulaLock.new(name).with_lock do if oldname_opt_record FormulaLock.new(oldname_opt_record.basename.to_s).with_lock(&block) else yield end end end |
#mach_o_files ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'Library/Homebrew/extend/os/mac/keg_relocate.rb', line 160 def mach_o_files hardlinks = Set.new mach_o_files = [] path.find do |pn| next if pn.symlink? || pn.directory? next unless pn.dylib? || pn.mach_o_bundle? || pn.mach_o_executable? # if we've already processed a file, ignore its hardlinks (which have the same dev ID and inode) # this prevents relocations from being performed on a binary more than once next unless hardlinks.add? [pn.stat.dev, pn.stat.ino] mach_o_files << pn end mach_o_files end |
#oldname_opt_record ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
446 447 448 449 450 451 452 |
# File 'Library/Homebrew/keg.rb', line 446 def oldname_opt_record @oldname_opt_record ||= if (opt_dir = HOMEBREW_PREFIX/"opt").directory? opt_dir.subdirs.find do |dir| dir.symlink? && dir != opt_record && path.parent == dir.resolved_path.parent end end end |
#optlink(**options) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'Library/Homebrew/keg.rb', line 555 def optlink(**) opt_record.delete if opt_record.symlink? || opt_record.exist? make_relative_symlink(opt_record, path, **) aliases.each do |a| alias_opt_record = opt_record.parent/a alias_opt_record.delete if alias_opt_record.symlink? || alias_opt_record.exist? make_relative_symlink(alias_opt_record, path, **) end return unless oldname_opt_record oldname_opt_record.delete make_relative_symlink(oldname_opt_record, path, **) end |
#optlinked? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
267 268 269 |
# File 'Library/Homebrew/keg.rb', line 267 def optlinked? opt_record.symlink? && path == opt_record.resolved_path end |
#plist_installed? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
414 415 416 |
# File 'Library/Homebrew/keg.rb', line 414 def plist_installed? !Dir["#{path}/*.plist"].empty? end |
#python_pth_files_installed? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
422 423 424 |
# File 'Library/Homebrew/keg.rb', line 422 def python_pth_files_installed? !Dir["#{path}/lib/python2.7/site-packages/*.pth"].empty? end |
#python_site_packages_installed? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
418 419 420 |
# File 'Library/Homebrew/keg.rb', line 418 def python_site_packages_installed? (path/"lib/python2.7/site-packages").directory? end |
#rack ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
223 224 225 |
# File 'Library/Homebrew/keg.rb', line 223 def rack path.parent end |
#recursive_fgrep_args ⇒ Object
98 99 100 101 |
# File 'Library/Homebrew/keg_relocate.rb', line 98 def recursive_fgrep_args # for GNU grep; overridden for BSD grep on OS X "-lr" end |
#relocate_dynamic_linkage(relocation) ⇒ Object
34 35 36 |
# File 'Library/Homebrew/keg_relocate.rb', line 34 def relocate_dynamic_linkage(_relocation) [] end |
#remove_linked_keg_record ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
262 263 264 265 |
# File 'Library/Homebrew/keg.rb', line 262 def remove_linked_keg_record linked_keg_record.unlink linked_keg_record.parent.rmdir_if_possible end |
#remove_old_aliases ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'Library/Homebrew/keg.rb', line 271 def remove_old_aliases opt = opt_record.parent linkedkegs = linked_keg_record.parent tap = begin to_formula.tap rescue # If the formula can't be found, just ignore aliases for now. nil end if tap bad_tap_opt = opt/tap.user FileUtils.rm_rf bad_tap_opt if !bad_tap_opt.symlink? && bad_tap_opt.directory? end aliases.each do |a| # versioned aliases are handled below next if a.match?(/[email protected]/) alias_opt_symlink = opt/a if alias_opt_symlink.symlink? && alias_opt_symlink.exist? alias_opt_symlink.delete if alias_opt_symlink.realpath == opt_record.realpath elsif alias_opt_symlink.symlink? || alias_opt_symlink.exist? alias_opt_symlink.delete end alias_linkedkegs_symlink = linkedkegs/a alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist? end Pathname.glob("#{opt_record}@*").each do |a| a = a.basename.to_s next if aliases.include?(a) alias_opt_symlink = opt/a if alias_opt_symlink.symlink? && alias_opt_symlink.exist? && rack == alias_opt_symlink.realpath.parent alias_opt_symlink.delete end alias_linkedkegs_symlink = linkedkegs/a alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist? end end |
#remove_oldname_opt_record ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
533 534 535 536 537 538 539 540 |
# File 'Library/Homebrew/keg.rb', line 533 def remove_oldname_opt_record return unless oldname_opt_record return if oldname_opt_record.resolved_path != path @oldname_opt_record.unlink @oldname_opt_record.parent.rmdir_if_possible @oldname_opt_record = nil end |
#remove_opt_record ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
316 317 318 319 |
# File 'Library/Homebrew/keg.rb', line 316 def remove_opt_record opt_record.unlink opt_record.parent.rmdir_if_possible end |
#replace_locations_with_placeholders ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'Library/Homebrew/keg_relocate.rb', line 38 def replace_locations_with_placeholders relocation = Relocation.new( 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 |
#replace_placeholders_with_locations(files, skip_linkage: false) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'Library/Homebrew/keg_relocate.rb', line 51 def replace_placeholders_with_locations(files, skip_linkage: false) 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) unless skip_linkage replace_text_in_files(relocation, files: files) end |
#replace_text_in_files(relocation, files: nil) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'Library/Homebrew/keg_relocate.rb', line 64 def replace_text_in_files(relocation, files: nil) files ||= text_files | libtool_files changed_files = [] 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_repository => relocation.new_repository, } changed = s.gsub!(Regexp.union(replacements.keys.sort_by(&:length).reverse), replacements) next unless changed changed_files += [first, *rest].map { |file| file.relative_path_from(path) } begin first.atomic_write(s) rescue SystemCallError first.ensure_writable do first.open("wb") { |f| f.write(s) } end else rest.each { |file| FileUtils.ln(first, file, force: true) } end end changed_files end |
#require_relocation? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
252 253 254 |
# File 'Library/Homebrew/keg.rb', line 252 def require_relocation? @require_relocation end |
#runtime_dependencies ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
546 547 548 549 |
# File 'Library/Homebrew/keg.rb', line 546 def runtime_dependencies Keg.cache[:runtime_dependencies] ||= {} Keg.cache[:runtime_dependencies][path] ||= tab.runtime_dependencies end |
#symlink_files ⇒ Object
181 182 183 184 185 186 187 188 |
# File 'Library/Homebrew/keg_relocate.rb', line 181 def symlink_files symlink_files = [] path.find do |pn| symlink_files << pn if pn.symlink? end symlink_files end |
#tab ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
542 543 544 |
# File 'Library/Homebrew/keg.rb', line 542 def tab Tab.for_keg(self) end |
#text_files ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'Library/Homebrew/keg_relocate.rb', line 125 def text_files text_files = [] return text_files unless which("file") && which("xargs") # file has known issues with reading files on other locales. Has # been fixed upstream for some time, but a sufficiently new enough # file with that fix is only available in macOS Sierra. # https://bugs.gw.com/view.php?id=292 with_custom_locale("C") do files = Set.new path.find.reject { |pn| next true if pn.symlink? next true if pn.directory? next false if pn.basename.to_s == "orig-prefix.txt" # for python virtualenvs next true if pn == self/".brew/#{name}.rb" next true if Metafiles::EXTENSIONS.include?(pn.extname) if pn.text_executable? text_files << pn next true end false } output, _status = Open3.capture2("xargs -0 file --no-dereference --print0", stdin_data: files.to_a.join("\0")) # `file` output sometimes contains data from the file, which may include # invalid UTF-8 entities, so tell Ruby this is just a bytestring output.force_encoding(Encoding::ASCII_8BIT) output.each_line do |line| path, info = line.split("\0", 2) # `file` sometimes prints more than one line of output per file; # subsequent lines do not contain a null-byte separator, so `info` # will be `nil` for those lines next unless info next unless info.include?("text") path = Pathname.new(path) next unless files.include?(path) text_files << path end end text_files end |
#to_formula ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
442 443 444 |
# File 'Library/Homebrew/keg.rb', line 442 def to_formula Formulary.from_keg(self) end |
#uninstall ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'Library/Homebrew/keg.rb', line 321 def uninstall CacheStoreDatabase.use(:linkage) do |db| break unless db.created? LinkageCacheStore.new(path, db).delete! end path.rmtree path.parent.rmdir_if_possible remove_opt_record if optlinked? remove_old_aliases remove_oldname_opt_record rescue Errno::EACCES, Errno::ENOTEMPTY odie <<~EOS Could not remove #{name} keg! Do so manually: sudo rm -rf #{path} EOS end |
#unlink(**options) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO: refactor to use keyword arguments.
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'Library/Homebrew/keg.rb', line 341 def unlink(**) ObserverPathnameExtension.reset_counts! dirs = [] keg_directories = KEG_LINK_DIRECTORIES.map { |d| path/d } .select(&:exist?) keg_directories.each do |dir| dir.find do |src| dst = HOMEBREW_PREFIX + src.relative_path_from(path) dst.extend(ObserverPathnameExtension) dirs << dst if dst.directory? && !dst.symlink? # check whether the file to be unlinked is from the current keg first next unless dst.symlink? next if src != dst.resolved_path if [:dry_run] puts dst Find.prune if src.directory? next end dst.uninstall_info if dst.to_s.match?(INFOFILE_RX) dst.unlink remove_old_aliases Find.prune if src.directory? end end unless [:dry_run] remove_linked_keg_record if linked? dirs.reverse_each(&:rmdir_if_possible) end ObserverPathnameExtension.n end |
#version ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
437 438 439 440 |
# File 'Library/Homebrew/keg.rb', line 437 def version require "pkg_version" PkgVersion.parse(path.basename.to_s) end |