Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

'bundle viz'

Removed silly 'puts' in cli

Fake Gem::Requirement.none? [not in Gem < 1.3.7]
  • Loading branch information...
commit f4148898f614032dbadfbd3b0aa9cbd1a757a489 1 parent 7ef704d
@kevmoo kevmoo authored
Showing with 156 additions and 0 deletions.
  1. +1 −0  lib/bundler.rb
  2. +25 −0 lib/bundler/cli.rb
  3. +130 −0 lib/bundler/graph.rb
View
1  lib/bundler.rb
@@ -11,6 +11,7 @@ module Bundler
autoload :Dependency, 'bundler/dependency'
autoload :Dsl, 'bundler/dsl'
autoload :Environment, 'bundler/environment'
+ autoload :Graph, 'bundler/graph'
autoload :Index, 'bundler/index'
autoload :Installer, 'bundler/installer'
autoload :LazySpecification, 'bundler/lazy_specification'
View
25 lib/bundler/cli.rb
@@ -212,6 +212,31 @@ def version
end
map %w(-v --version) => :version
+ desc 'viz', "Generates a visual dependency graph"
+ method_option :file, :type => :string, :default => 'gem_graph.png', :aliases => '-f', :banner => "Show the version with each gem name."
+ method_option :version, :type => :boolean, :default => false, :aliases => '-v', :banner => "Show the version with each gem name."
+ method_option :requirements, :type => :boolean, :default => false, :aliases => '-r', :banner => "Show the requirement for each dependency."
+ def viz
+ output_file = File.expand_path(options[:file])
+ graph = Graph.new( Bundler.load )
+
+ begin
+ graph.viz(output_file, options[:version], options[:requirements])
+ Bundler.ui.info output_file
+ rescue LoadError => e
+ Bundler.ui.error e.inspect
+ Bundler.ui.warn "Make sure you have the graphviz ruby gem"
+ Bundler.ui.warn "'gem install ruby-graphviz'"
+ rescue StandardError => e
+ if e.message.start_with? 'GraphViz not installed or dot not in PATH.'
+ Bundler.ui.error e.message
+ Bundler.ui.warn "The ruby graphviz gem requires GraphViz to be installed"
+ else
+ raise
+ end
+ end
+ end
+
private
def remove_lockfiles
View
130 lib/bundler/graph.rb
@@ -0,0 +1,130 @@
+module Bundler
+ class Graph
+
+ USER_OPTIONS = {:style => 'filled, bold', :fillcolor => '#cccccc'}.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, :dpi => 65 } )
+ 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 => 'folder', :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.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
Please sign in to comment.
Something went wrong with that request. Please try again.