diff --git a/Library/Homebrew/dev-cmd/linkage.rb b/Library/Homebrew/dev-cmd/linkage.rb index c5d43a48dc403f7127d61f277659f58c76eb4531..87a0d9143e378bfd3b4feb63d596656e61590836 100644 --- a/Library/Homebrew/dev-cmd/linkage.rb +++ b/Library/Homebrew/dev-cmd/linkage.rb @@ -23,8 +23,7 @@ module Homebrew ARGV.kegs.each do |keg| ohai "Checking #{keg.name} linkage" if ARGV.kegs.size > 1 - result = LinkageChecker.new(keg, database_cache) - result.flush_cache_and_check_dylibs if ARGV.include?("--rebuild") + result = LinkageChecker.new(keg, database_cache, ARGV.include?("--rebuild")) if ARGV.include?("--test") result.display_test_output diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb index 0386beb9a4ef4fd8947b63be7e33c15eb8a486dc..2b62e6bca73fe560ba12b3452475774f70fe1c5d 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -65,10 +65,7 @@ module FormulaCellarChecks return unless formula.prefix.directory? keg = Keg.new(formula.prefix) - DatabaseCache.new(:linkage) do |database_cache| - checker = LinkageChecker.new(keg, database_cache, formula) - checker.flush_cache_and_check_dylibs - end + DatabaseCache.new(:linkage) { |database_cache| LinkageChecker.new(keg, database_cache, true, formula) } return unless checker.broken_dylibs? output = <<~EOS diff --git a/Library/Homebrew/os/mac/cache_store.rb b/Library/Homebrew/os/mac/cache_store.rb index fa919d4b4c3688dc5404b871b257c6f1b649bee8..70868dce0cbc3ebbbc850ae6346788cf9d64a9fb 100644 --- a/Library/Homebrew/os/mac/cache_store.rb +++ b/Library/Homebrew/os/mac/cache_store.rb @@ -6,13 +6,13 @@ require "json" # residing in the `HOMEBREW_CACHE` # class DatabaseCache - # Users have read and write, but not execute permissions - DATABASE_MODE = 0666 + # The mode of any created files will be 0664 (that is, readable and writable + # by the owner and the group, and readable by everyone else) + DATABASE_MODE = 0664 # Opens and yields a database in read/write mode - # - # DBM::WRCREAT: Creates the database if it does not already exist def initialize(name) + # DBM::WRCREAT: Creates the database if it does not already exist @db = DBM.open("#{HOMEBREW_CACHE}/#{name}.db", DATABASE_MODE, DBM::WRCREAT) yield(@db) @db.close @@ -47,16 +47,24 @@ class CacheStore protected + # @return [DBM] attr_reader :database_cache - # Parses `DBM` stored `String` into ruby `Hash` - # # DBM stores ruby objects as a ruby `String`. Hence, when fetching the data, # to convert the ruby string back into a ruby `Hash`, the string is converted - # into a JSON compatible string, where it may be parsed by the JSON.parse - # function - def string_to_hash(string) - JSON.parse(string.gsub("=>", ":")) + # into a JSON compatible string in `ruby_hash_to_json_string`, where it may + # later be parsed by `JSON.parse` in the `json_string_to_ruby_hash` method + # + # @param [Hash] + # @return [String] + def ruby_hash_to_json_string(hash) + hash.to_json + end + + # @param [String] + # @return [Hash] + def json_string_to_ruby_hash(string) + JSON.parse(string) end end @@ -73,7 +81,7 @@ class LinkageStore < CacheStore end def update!( - path_values: { + array_values: { system_dylibs: %w[], variable_dylibs: %w[], broken_dylibs: %w[], @@ -86,17 +94,17 @@ class LinkageStore < CacheStore reverse_links: {}, } ) - database_cache[keg_name] = { - "path_values" => format_path_values(path_values), - "hash_values" => format_hash_values(hash_values), - } + database_cache[keg_name] = ruby_hash_to_json_string( + array_values: format_array_values(array_values), + hash_values: format_hash_values(hash_values), + ) end def fetch_type(type) if HASH_LINKAGE_TYPES.include?(type) fetch_hash_values(type: type) else - fetch_path_values(type: type) + fetch_array_values(type: type) end end @@ -108,28 +116,33 @@ class LinkageStore < CacheStore attr_reader :keg_name - def fetch_path_values(type:) - return [] if !database_cache.key?(keg_name) || database_cache[keg_name].nil? - string_to_hash(database_cache[keg_name])["path_values"][type.to_s] + def fetch_array_values(type:) + return [] unless database_cache.key?(keg_name) + json_string_to_ruby_hash(database_cache[keg_name])["array_values"][type.to_s] end def fetch_hash_values(type:) - return {} if !database_cache.key?(keg_name) || database_cache[keg_name].nil? - string_to_hash(database_cache[keg_name])["hash_values"][type.to_s] + return {} unless database_cache.key?(keg_name) + json_string_to_ruby_hash(database_cache[keg_name])["hash_values"][type.to_s] end - # Formats the linkage data for `path_values` into a kind which can be parsed - # by the `string_to_hash` method. Converts ruby `Set`s to `Array`s - def format_path_values(hash) - hash.each_with_object({}) { |(k, v), h| h[k.to_s] = v.to_a } + # Formats the linkage data for `array_values` into a kind which can be parsed + # by the `json_string_to_ruby_hash` method. Internally converts ruby `Set`s to + # `Array`s + # + # @return [String] + def format_array_values(hash) + hash.each_with_object({}) { |(k, v), h| h[k] = v.to_a } end # Formats the linkage data for `hash_values` into a kind which can be parsed - # by the `string_to_hash` method. Converts ruby `Set`s to `Array`s, and + # by the `json_string_to_ruby_hash` method. Converts ruby `Set`s to `Array`s, and # converts ruby `Pathname`s to `String`s + # + # @return [String] def format_hash_values(hash) hash.each_with_object({}) do |(outer_key, outer_values), outer_hash| - outer_hash[outer_key.to_s] = outer_values.each_with_object({}) do |(k, v), h| + outer_hash[outer_key] = outer_values.each_with_object({}) do |(k, v), h| h[k] = v.to_a.map(&:to_s) end end diff --git a/Library/Homebrew/os/mac/linkage_checker.rb b/Library/Homebrew/os/mac/linkage_checker.rb index 650cea0e9f40ff0408ca3c35ee578e19d8b0555e..ed5eb8acd027f5874859a27f8e5d2610cb583d6e 100644 --- a/Library/Homebrew/os/mac/linkage_checker.rb +++ b/Library/Homebrew/os/mac/linkage_checker.rb @@ -6,10 +6,11 @@ require "os/mac/cache_store" class LinkageChecker attr_reader :keg, :formula, :store - def initialize(keg, db, formula = nil) + def initialize(keg, db, rebuild_cache = false, formula = nil) @keg = keg @formula = formula || resolve_formula(keg) @store = LinkageStore.new(keg.name, db) + flush_cache_and_check_dylibs if rebuild_cache end # 'Hash-type' cache values @@ -222,7 +223,7 @@ class LinkageChecker # Updates data store with package path values def store_dylibs! store.update!( - path_values: { + array_values: { system_dylibs: @system_dylibs, variable_dylibs: @variable_dylibs, broken_dylibs: @broken_dylibs,