diff options
| author | Andrew Janke | 2016-04-17 21:25:11 -0400 | 
|---|---|---|
| committer | Andrew Janke | 2016-04-18 13:37:34 -0400 | 
| commit | da34fba151ee33c1a2e14ab21ee0dc4ea451cc0f (patch) | |
| tree | 1b585d81636dc9fb11a1c9c46b360a20c78212bc /Library/Homebrew/dev-cmd/linkage.rb | |
| parent | c3c233dd809f9c358ba8aa5268b64c335202bc56 (diff) | |
| download | brew-da34fba151ee33c1a2e14ab21ee0dc4ea451cc0f.tar.bz2 | |
test-bot: check all dependents for broken dylibs
Pulls 'brew linkage' in to main brew repo as a dev-cmd, and has test-bot
use it to detect dylib breakage, which usually means a revision bump is
needed. Checks all dependents, not just those with a 'test do' block
defined, since we can do this without formula support.
Closes #107.
Signed-off-by: Andrew Janke <andrew@apjanke.net>
Diffstat (limited to 'Library/Homebrew/dev-cmd/linkage.rb')
| -rw-r--r-- | Library/Homebrew/dev-cmd/linkage.rb | 125 | 
1 files changed, 125 insertions, 0 deletions
diff --git a/Library/Homebrew/dev-cmd/linkage.rb b/Library/Homebrew/dev-cmd/linkage.rb new file mode 100644 index 000000000..82474fd9a --- /dev/null +++ b/Library/Homebrew/dev-cmd/linkage.rb @@ -0,0 +1,125 @@ +# +# Description: check linkage of installed keg +# Usage: +#   brew linkage <formulae> +# +# Only works on installed formulae. An error is raised if it is run on uninstalled +# formulae. +# +# Options: +#  --test      - testing version: only display broken libs; exit non-zero if any +#                breakage was found. + +require "set" +require "keg" +require "formula" + +module Homebrew + +  def linkage +    found_broken_dylibs = false +    ARGV.kegs.each do |keg| +      ohai "Checking #{keg.name} linkage" if ARGV.kegs.size > 1 +      result = LinkageChecker.new(keg) +      if ARGV.include?("--test") +        result.display_test_output +      else +        result.display_normal_output +      end +      found_broken_dylibs = true if !result.broken_dylibs.empty? +    end +    if ARGV.include?("--test") && found_broken_dylibs +      exit 1 +    end +  end + +  class LinkageChecker +    attr_reader :keg +    attr_reader :broken_dylibs + +    def initialize(keg) +      @keg = keg +      @brewed_dylibs = Hash.new { |h, k| h[k] = Set.new } +      @system_dylibs = Set.new +      @broken_dylibs = Set.new +      @variable_dylibs = Set.new +      check_dylibs +    end + +    def check_dylibs +      @keg.find do |file| +        next unless file.dylib? || file.mach_o_executable? || file.mach_o_bundle? +        file.dynamically_linked_libraries.each do |dylib| +          if dylib.start_with? "@" +            @variable_dylibs << dylib +          else +            begin +              owner = Keg.for Pathname.new(dylib) +            rescue NotAKegError +              @system_dylibs << dylib +            rescue Errno::ENOENT +              @broken_dylibs << dylib +            else +              @brewed_dylibs[owner.name] << dylib +            end +          end +        end +      end + +      begin +        f = Formula[keg.name] +        @undeclared_deps = @brewed_dylibs.keys - f.deps.map(&:name) +        @undeclared_deps -= [f.name] +      rescue FormulaUnavailableError +        opoo "Formula unavailable: #{keg.name}" +        @undeclared_deps = [] +      end + +    end + +    def display_normal_output +      unless @system_dylibs.empty? +        display_items "System libraries", @system_dylibs +      end +      unless @brewed_dylibs.empty? +        display_items "Homebrew libraries", @brewed_dylibs +      end +      unless @variable_dylibs.empty? +        display_items "Variable-referenced libraries", @variable_dylibs +      end +      unless @broken_dylibs.empty? +        display_items "Missing libraries", @broken_dylibs +      end +      unless @undeclared_deps.empty? +        display_items "Possible undeclared dependencies", @undeclared_deps +      end +    end + +    def display_test_output +      if @broken_dylibs.empty? +        puts "No broken dylib links" +      else +        display_items "Missing libraries", @broken_dylibs +      end +    end + +    private + +    # Display a list of things. +    # Things may either be an array, or a hash of (label -> array) +    def display_items(label, things) +      puts "#{label}:" +      if things.is_a? Hash +        things.sort.each do |label, list| +          list.sort.each do |item| +            puts "  #{item} (#{label})" +          end +        end +      else +        things.sort.each do |item| +          puts "  #{item}" +        end +      end +    end +  end +end
\ No newline at end of file  | 
