class DepCheck::DepChecker
Public Class Methods
arguments()
click to toggle source
Calls superclass method
# File lib/dep_check/DepChecker.rb, line 29 def self.arguments [ CLAide::Argument.new('PODSPEC_NAME', true), CLAide::Argument.new('REPO_NAME', false) ].concat(super) end
new(argv)
click to toggle source
Calls superclass method
# File lib/dep_check/DepChecker.rb, line 36 def initialize(argv) @podspec_name = argv.shift_argument @repo_name = argv.shift_argument @repo_update = argv.flag?('repo-update', false) @produce_graphviz_output = argv.flag?('graphviz', false) @produce_image_output = argv.flag?('image', false) if @repo_name @repo = Pod::Config.instance.sources_manager.sources([@repo_name]).first else @repo = Pod::Config.instance.sources_manager.sources(['master']).first end super end
options()
click to toggle source
Calls superclass method
# File lib/dep_check/DepChecker.rb, line 21 def self.options [ ['--repo-update', 'Fetch external podspecs and run `pod repo update` before calculating the dependency graph'], ['--graphviz', 'Outputs the dependency graph in Graphviz format to <podspec name>.gv or Podfile.gv'], ['--image', 'Outputs the dependency graph as an image to <podsepc name>.png or Podfile.png'], ].concat(super) end
Public Instance Methods
dep_graph_build(repo,spec,builded,nodes)
click to toggle source
构建依赖关系图 @param [Source] repo 依赖关系图建立过程中使用的podspec仓库 @param [Specification] spec 待构建的spec @param [Array<Node>] builded 已经构建完成的Node数组 @param [Array<Node>] nodes 已经存在的Node数组
# File lib/dep_check/DepChecker.rb, line 135 def dep_graph_build(repo,spec,builded,nodes) node = unique_node(spec.attributes_hash['name'],nodes) # puts "resolving " + node.name builded.push(node) tunples = spec.all_dependencies.map { |dep| {:node => unique_node(dep.name,nodes),:dep => dep} } tunples.each { |t| node.addEdge(t[:node]) } tunples.each { |t| dep_spec = podspec_with_name(repo,t[:dep].name) if builded.count(t[:node]) == 0 dep_graph_build(repo,dep_spec,builded,nodes) end } return builded end
dep_resolve(node, resolved, unresolved)
click to toggle source
循环依赖检测算法实现
# File lib/dep_check/DepChecker.rb, line 159 def dep_resolve(node, resolved, unresolved) unresolved.push(node) node.edges.each { |edge| if resolved.count(edge) == 0 #if edge not in resolved if unresolved.count(edge) != 0 #if edge in unresolved path = [] unresolved.each { |n| path << n.name } Pod::UI.puts "ERROR: Circular dependency detected! #{node.name} <---> #{edge.name}".red raise CircularDependencyError.new(node.name,edge.name,path) end dep_resolve(edge, resolved, unresolved) end } resolved.push(node) unresolved.delete(node) end
graph_dot_output(graph, output_file_basename)
click to toggle source
以.gv格式输出一个依赖关系图
# File lib/dep_check/DepChecker.rb, line 215 def graph_dot_output(graph, output_file_basename) graph.output( :dot => "#{output_file_basename}.gv") Pod::UI.puts "Graph file: #{output_file_basename}.gv... \n" end
graph_image_out(graph, output_file_basename)
click to toggle source
以.png格式输出一个依赖关系图
# File lib/dep_check/DepChecker.rb, line 208 def graph_image_out(graph, output_file_basename) graph.output( :png => "#{output_file_basename}.png") Pod::UI.puts "Graph file: #{output_file_basename}.png... \n" end
graphviz_data(builded, output_file_basename)
click to toggle source
利用 GraphViz 构建可视化图数据
# File lib/dep_check/DepChecker.rb, line 190 def graphviz_data(builded, output_file_basename) @graphviz ||= begin require 'graphviz' graph = GraphViz::new(output_file_basename, :type => :digraph) builded.each { |node| graph_node_from = graph.add_node(node.name) if !node.edges.empty? node.edges.each { |subNode| graph_node_to = graph.add_node(subNode.name) graph.add_edge(graph_node_from,graph_node_to) } end } graph end end
podspec_with_name(repo, name)
click to toggle source
通过模块名称或者模块podspec文件路径 得到一个spec对象
# File lib/dep_check/DepChecker.rb, line 119 def podspec_with_name(repo, name) if name path = Pathname.new("#{name}.podspec") if path.exist? podspec = Pod::Specification.from_file(path) else podspec = repo.specification(name,repo.versions(name).first) end end end
run()
click to toggle source
# File lib/dep_check/DepChecker.rb, line 72 def run builded = [] Pod::UI.puts "1. Buiding dependency graph for #{@podspec_name}... \n ".green Pod::UI.puts "All dependencies : \n".blue Pod::UI.puts dep_graph_build(@repo,@podspec,builded,[]) Pod::UI.puts "Done! \n".blue Pod::UI.puts "2. Circular dependency check #{@podspec_name}... \n".green unresolved = [] begin dep_resolve(builded.first,[],unresolved) rescue Exception => e Pod::UI.puts e.to_s.red circular_found = true circular_path = String.new e.path.each { |name| circular_path << name + '--->' } circular_path << e.to circular_from = e.from circular_to = e.to end if !circular_found Pod::UI.puts "No Circular dependency found! \n".green end Pod::UI.puts "Done! \n".blue if @produce_image_output || @produce_graphviz_output Pod::UI.puts "3. Visualizing graph for #{@podspec_name}... \n".green end graph_image_out(graphviz_data(builded,@podspec_name),@podspec_name) if @produce_image_output graph_dot_output(graphviz_data(builded,@podspec_name),@podspec_name) if @produce_graphviz_output Pod::UI.puts "Done. \n".blue {"circular" => !!circular_found , "root_spec_name" => @podspec_name, "circular_from" => circular_from ? circular_from : '' , "circular_to" => circular_to ? circular_to : '' , "circular_path" => circular_path ? circular_path : '', "memo" => 'For more infomation , try $ dep_check --help' } end
unique_node(name,nodes)
click to toggle source
通过节点名称获得一个唯一的节点
# File lib/dep_check/DepChecker.rb, line 177 def unique_node(name,nodes) exist_nodes = nodes.select { |n| n.name == name } if exist_nodes.empty? node = Node.new(name) nodes.push(node) else node = exist_nodes.first end node end
validate!()
click to toggle source
Calls superclass method
# File lib/dep_check/DepChecker.rb, line 50 def validate! super if @podspec_name require 'pathname' path = Pathname.new("#{@podspec_name}.podspec") if path.exist? @podspec = Pod::Specification.from_file(path) else @podspec = Pod::Config.instance.sources_manager.search(Pod::Dependency.new(@podspec_name)).specification.subspec_by_name(@podspec_name) end Pod::UI.puts "Analyzing #{@podspec} (in repo #{@repo})..." else raise 'Nothing to check. ' end if (@produce_image_output || @produce_graphviz_output) && Pod::Executable.which('dot').nil? raise Informative, 'GraphViz must be installed and `dot` must be in ' \ '$PATH to produce image or graphviz output.' end end