lib/bundler/graph.rb
module Bundler class Graph USER_OPTIONS = {:style => 'filled', :fillcolor => '#B9B9D5'}.freeze def initialize(env) @env = env end def nodes populate @nodes end def groups populate @groups end def viz(output_file, show_gem_versions = false, show_dependency_requirements = false) require 'graphviz' populate graph_viz = GraphViz::new('Gemfile', {:concentrate => true, :normalize => true, :nodesep => 0.55}) graph_viz.edge[:fontname] = graph_viz.node[:fontname] = 'Arial, Helvetica, SansSerif' graph_viz.edge[:fontsize] = 12 viz_nodes = {} # populate all of the nodes nodes.each do |name, node| label = name.dup label << "\n#{node.version}" if show_gem_versions options = { :label => label } options.merge!( USER_OPTIONS ) if node.is_user viz_nodes[name] = graph_viz.add_node( name, options ) end group_nodes = {} @groups.each do |name, dependencies| group_nodes[name] = graph_viz.add_node(name.to_s, { :shape => 'box3d', :fontsize => 16 }.merge(USER_OPTIONS)) dependencies.each do |dependency| options = { :weight => 2 } if show_dependency_requirements && (dependency.requirement.to_s != ">= 0") options[:label] = dependency.requirement.to_s end graph_viz.add_edge( group_nodes[name], viz_nodes[dependency.name], options ) end end @groups.keys.select { |group| group != :default }.each do |group| graph_viz.add_edge( group_nodes[group], group_nodes[:default], { :weight => 2 } ) end viz_nodes.each do |name, node| nodes[name].dependencies.each do |dependency| options = { } if nodes[dependency.name].is_user options[:constraint] = false end if show_dependency_requirements && (dependency.requirement.to_s != ">= 0") options[:label] = dependency.requirement.to_s end graph_viz.add_edge( node, viz_nodes[dependency.name], options ) end end graph_viz.output( :png => output_file ) end private def populate return if @populated # hash of name => GraphNode @nodes = {} @groups = {} # Populate @nodes @env.specs.each { |spec| @nodes[spec.name] = GraphNode.new(spec.name, spec.version) } # For gems in Gemfile, add details @env.current_dependencies.each do |dependency| node = @nodes[dependency.name] node.is_user = true dependency.groups.each do |group| if @groups.has_key? group group = @groups[group] else group = @groups[group] = [] end group << dependency end end # walk though a final time and add edges @env.specs.each do |spec| from = @nodes[spec.name] spec.runtime_dependencies.each do |dependency| from.dependencies << dependency end end @nodes.freeze @groups.freeze @populated = true end end # Add version info class GraphNode def initialize(name, version) @name = name @version = version @is_user = false @dependencies = [] end attr_reader :name, :dependencies, :version attr_accessor :is_user end end