You are not logged in.

#1 2009-03-16 16:03:23

hbekel
Member
Registered: 2008-10-04
Posts: 311

pkgdeps.rb -- find package deps for ruby programs

Today i had the need to find out exactly which of my installed arch packages a ruby program depends on.

This script intercepts all require calls of a ruby program, resolves the absolute path to the file that gets loaded by ruby and determines the package it belongs to using pkgfile. After the program exist, a list of dependencies is generated, as well as a list of files that were not found in any of the installed arch packages.

For example, if you run a program that uses mysql and gnome2 like this:

ruby -r/path/to/pkgdebs.rb program.rb

then after it exists, pkgdeps will give ypu

--------------------------------------------------------------------------------
Resolving package dependencies for 'program.rb' ...
--------------------------------------------------------------------------------
/usr/lib/ruby/1.8/i686-linux/rbconfig.rb -> ruby
/usr/lib/ruby/1.8/English.rb -> ruby
/usr/lib/ruby/site_ruby/1.8/i686-linux/glib2.so -> ruby-glib2
[...]
--------------------------------------------------------------------------------
Found 11 package dependencies:
--------------------------------------------------------------------------------

'mysql-ruby'
'ruby'
'ruby-atk'
'ruby-gdkpixbuf2'
'ruby-glib2'
'ruby-gnome2'
'ruby-gnomecanvas'
'ruby-gtk2'
'ruby-libart'
'ruby-pango'
'ruby-rcairo'

pkgdeps.rb:

require 'pathname'

class ArchLinuxDependencies 

  @@required = []
  @@depends = []
  @@missing = []

  def self.collect(required)
    
    # collect absolute paths to the files loaded by ruby

    if Pathname.new(required).absolute?

      # check which file this path resolves to and add it

      ["", ".rb", ".so"].each do |extension|
        file = required + extension
        if File.exists? file
          @@required << file unless @@required.include? file
          break
        end
      end
    else
      
      # not an absolute pathname, search $: just like ruby does

      extglob = "{.rb,.so}"
      extglob = "" if required =~ /\.[^.]+$/
    
      $:.each do |inc|
        found = Dir["#{inc}/#{required}#{extglob}"]
        unless found.empty?
          file = File.expand_path(found[0])
          @@required << file unless @@required.include? file         
        end  
      end
    end

  end

  def self.resolve()

    # resolve package this file belongs to using pkgfile

    puts "-"*80
    puts "Resolving package dependencies for '#{$0}' ..."
    puts "-"*80

    @@required.each do |file|
      print "#{file} -> "
      STDOUT.flush()
      package = `pkgfile #{file} 2> /dev/null`.chomp.split("/")[1]
      if package
        @@depends << package unless @@depends.include? package      
        puts package
      else
        @@missing << file unless @@missing.include? file
        puts "?"
      end
    end
    puts self
  end

  def self.to_s

    s = ("-"*80) + "\n"
    s += "Found #{@@depends.length} package dependencies:\n"
    s += ("-"*80) + "\n\n"

    s+= (@@depends.sort.map { |d| "'#{d}'\n" }.join("")) + "\n"

    unless @@missing.empty?

      s += ("-"*80) + "\n"
      s += "Required files not found in any installed package:\n"
      s += ("-"*80) + "\n\n"
      
      @@missing.each do |m|
        s += "#{m}\n"
      end
      s += "\n"
    end

    s += ("-"*80) + "\n"
    return s
  end
  
end

class Object
  def require(arg)
    if super(arg)
      ArchLinuxDependencies.collect(arg)
    end
  end
end

at_exit do
  ArchLinuxDependencies.resolve()
end

I've tested this with a bunch of my own ruby programs and so far it seems to work very well.

Offline

Board footer

Powered by FluxBB