Skip to content

Instantly share code, notes, and snippets.

@octplane

octplane/gems.rb

Created Oct 27, 2011
Embed
What would you like to do?
List gems, show dependencies, show broken gems. Uses trollop gem.
#!/usr/bin/env ruby
require 'rubygems'
require 'trollop'
require 'pp'
opts = Trollop::options do
opt :list, "List local installed gems in shell friendly format", :type => :boolean
opt :info, "Display Dependency information about gem", :type => :string
opt :check, "Check All installed gems and return broken dependencies", :type=> :boolean
end
class Node
include Enumerable
attr_reader :name, :missing
attr_accessor :is_dependency_of
@@nodes ||= []
def Node.build(name, missing=false)
match = @@nodes.find {|n| n.name == name}
return match || Node.new(name, missing)
end
def initialize(name, missing=false)
@name = name
@nodes = []
@is_dependency_of = []
@missing = missing
@@nodes << self
end
def <=>(other)
return @name <=> other.name
end
def add_parent(node)
if not @nodes.include?(node)
@nodes << node
node.is_dependency_of << self
end
end
STEP = 4
def dump(style = :normal, indent_level=0)
if style == :normal
sout = ""
margin = ''
0.upto(indent_level/STEP-1) { |p| margin += (p==0 ? ' ' : '|') + ' '*(STEP - 1) }
margin += '|' + '-'*(STEP - 2)
sout += margin + "gem: #{@name}\n"
@nodes.each do |child|
sout += child.dump(style, indent_level+STEP)
end
return sout
elsif style == :dot
sout = ""
if @dumped == true
return ""
end
@nodes.each do |child|
sout += ' '*(STEP - 1) +"\"#{@name}\" -> \"#{child.name}\"\n"
end
is_dependency_of.each do |parent|
sout += ' '*(STEP - 1) +"\"#{parent.name}\" -> \"#{@name}\"\n"
end
# I have been dumped, so mark me
@dumped = true
@nodes.each do |child|
sout += child.dump(style, indent_level+STEP)
end
return sout
elsif style == :missing_only
sout = ""
@@nodes.each do |node|
if node.missing
sout += "Missing: #{node.name} (#{node.is_dependency_of.map{|g| g.name}.join(", ")})\n"
end
end
return sout
elsif style == :parentless
sout = "Gem having no parents\n"
@@nodes.select{ |n| n.is_dependency_of.length == 0}.each do |n|
sout += "- #{n.name}\n"
end
return sout
end
end
end
def get_gem(name_regex = /.*/, req = Gem::Requirement.default)
dep = Gem::Dependency.new name_regex, Gem::Requirement.default
specs = Gem.source_index.search dep
end
def dependency_graph(spec)
$stderr.puts "Graphing:"+spec.map{|s| s.name+' '+s.version.to_s}.join("\n") if spec.is_a? Array
n = Node.build(spec.name+" "+(spec.version.to_s))
(spec.dependencies rescue []).each do |dependency|
next if dependency.type == :development
begin
ispecs =get_gem(dependency.name, *dependency.requirement)
rescue Exception => e
$stderr.puts "Exception while trying to get Gem for dependencies of :"+ spec.inspect
raise e
end
ispecs.each do |ispec|
dependency = dependency_graph(ispec)
n.add_parent(dependency)
end
if ispecs.length == 0
# The Gem is not available locally. This sucks.
dependency = Node.build(dependency.name, true)
n.add_parent(dependency)
end
end
return n
end
def gem_name(spec)
"#{spec.name}\t#{spec.version}"
end
if opts[:list]
specs = get_gem()
specs.each do |spec|
puts gem_name(spec)
end
elsif opts[:info]
m = dependency_graph(get_gem(opts[:info])[0])
puts m.dump(:normal, 3)
elsif opts[:check]
m = nil
get_gem().each do |spec|
m = dependency_graph(spec)
end
# At least one gem
if m != nil
puts m.dump(:missing_only)
end
else
$stderr.puts "Not doing anything --help for help."
end
@octplane

This comment has been minimized.

Copy link
Owner Author

@octplane octplane commented Oct 27, 2011

Information Display.

Show all dependencies of a given gem, in a tree.
All gem version satisfying the gem dependencies are displayed in the tree.

Output sample:

./gems.rb -i nfo-resque-mongo

|--gem: nfo-resque-mongo 1.17.2
    |--gem: mongo 1.3.0
    |   |--gem: bson 1.3.1
    |   |--gem: bson 1.4.1
    |--gem: vegas 0.1.7
    |   |--gem: rack 1.1.0
    |   |--gem: rack 1.3.5
    |--gem: sinatra 1.0
    |   |--gem: rack 1.1.0
    |   |--gem: rack 1.3.5
    |--gem: multi_json 1.0.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.