cobra_commander 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "cobra_commander/component_tree"
4
-
5
- module CobraCommander
6
- # Represents a dependency tree in a given context, built from a cache
7
- class CachedComponentTree < ComponentTree
8
- attr_reader :dependencies
9
-
10
- def self.from_cache_file(cache_file)
11
- cache = JSON.parse(File.read(cache_file), symbolize_names: true)
12
- new(cache)
13
- end
14
-
15
- def initialize(cache)
16
- super(cache[:name], cache[:path])
17
- @type = cache[:type]
18
- @ancestry = Set.new(cache[:ancestry])
19
- @dependencies = (cache[:dependencies] || []).map do |dep|
20
- CachedComponentTree.new(dep)
21
- end
22
- end
23
- end
24
- end
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "cobra_commander/component_tree"
4
-
5
- module CobraCommander
6
- # Represents a dependency tree in a given context
7
- class CalculatedComponentTree < ComponentTree
8
- attr_reader :name, :path
9
-
10
- def initialize(name, path, ancestry = Set.new)
11
- super(name, path)
12
- @ancestry = ancestry
13
- @ruby = Ruby.new(path)
14
- @js = Js.new(path)
15
- @type = type_of_component
16
- end
17
-
18
- def dependencies
19
- @deps ||= begin
20
- deps = @ruby.dependencies + @js.dependencies
21
- deps.sort_by { |dep| dep[:name] }
22
- .map(&method(:dep_representation))
23
- end
24
- end
25
-
26
- private
27
-
28
- def type_of_component
29
- return "Ruby & JS" if @ruby.gem? && @js.node?
30
- return "Ruby" if @ruby.gem?
31
- return "JS" if @js.node?
32
- end
33
-
34
- def dep_representation(dep)
35
- full_path = File.expand_path(File.join(path, dep[:path]))
36
- ancestry = @ancestry + [{ name: @name, path: path, type: @type }]
37
- CalculatedComponentTree.new(dep[:name], full_path, ancestry)
38
- end
39
-
40
- # Calculates ruby dependencies
41
- class Ruby
42
- def initialize(root_path)
43
- @root_path = root_path
44
- end
45
-
46
- def dependencies
47
- @deps ||= begin
48
- return [] unless gem?
49
- gems = bundler_definition.dependencies.select { |dep| path?(dep.source) }
50
- format(gems)
51
- end
52
- end
53
-
54
- def path?(source)
55
- return if source.nil?
56
- source_has_path = source.respond_to?(:path?) ? source.path? : source.is_a_path?
57
- source_has_path && source.path.to_s != "."
58
- end
59
-
60
- def format(deps)
61
- deps.map do |dep|
62
- path = File.join(dep.source.path, dep.name)
63
- { name: dep.name, path: path }
64
- end
65
- end
66
-
67
- def gem?
68
- @gem ||= File.exist?(gemfile_path)
69
- end
70
-
71
- def bundler_definition
72
- ::Bundler::Definition.build(gemfile_path, gemfile_lock_path, nil)
73
- end
74
-
75
- def gemfile_path
76
- File.join(@root_path, "Gemfile")
77
- end
78
-
79
- def gemfile_lock_path
80
- File.join(@root_path, "Gemfile.lock")
81
- end
82
- end
83
-
84
- # Calculates js dependencies
85
- class Js
86
- def initialize(root_path)
87
- @root_path = root_path
88
- end
89
-
90
- def dependencies
91
- @deps ||= begin
92
- return [] unless node?
93
- json = JSON.parse(File.read(package_json_path))
94
- combined_deps(json)
95
- end
96
- end
97
-
98
- def format_dependencies(deps)
99
- return [] if deps.nil?
100
- linked_deps = deps.select { |_, v| v.start_with? "link:" }
101
- linked_deps.map do |_, v|
102
- relational_path = v.split("link:")[1]
103
- dep_name = relational_path.split("/")[-1]
104
- { name: dep_name, path: relational_path }
105
- end
106
- end
107
-
108
- def node?
109
- @node ||= File.exist?(package_json_path)
110
- end
111
-
112
- def package_json_path
113
- File.join(@root_path, "package.json")
114
- end
115
-
116
- def combined_deps(json)
117
- worskpace_dependencies = build_workspaces(json["workspaces"])
118
- dependencies = format_dependencies Hash(json["dependencies"]).merge(Hash(json["devDependencies"]))
119
- (dependencies + worskpace_dependencies).uniq
120
- end
121
-
122
- def build_workspaces(workspaces)
123
- return [] if workspaces.nil?
124
- workspaces.map do |workspace|
125
- glob = "#{@root_path}/#{workspace}/package.json"
126
- workspace_dependencies = Dir.glob(glob)
127
- workspace_dependencies.map do |wd|
128
- { name: component_name(wd), path: component_path(wd) }
129
- end
130
- end.flatten
131
- end
132
-
133
- private
134
-
135
- def component_name(dir)
136
- component_path(dir).split("/")[-1]
137
- end
138
-
139
- def component_path(dir)
140
- return dir.split("/package.json")[0] if @root_path == "."
141
-
142
- dir.split(@root_path)[-1].split("/package.json")[0]
143
- end
144
- end
145
- end
146
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler"
4
- require "json"
5
-
6
- module CobraCommander
7
- # Represents a dependency tree in a given context
8
- class ComponentTree
9
- attr_reader :name, :path
10
-
11
- def initialize(name, path)
12
- @name = name
13
- @path = path
14
- end
15
-
16
- def flatten
17
- _flatten(self)
18
- end
19
-
20
- def subtree(name)
21
- _subtree(name, self)
22
- end
23
-
24
- def depends_on?(component_name)
25
- dependencies.any? do |component|
26
- component.name == component_name || component.depends_on?(component_name)
27
- end
28
- end
29
-
30
- def dependents_of(component_name)
31
- depends = depends_on?(component_name) ? self : nil
32
- dependents_below = dependencies.map do |component|
33
- component.dependents_of(component_name)
34
- end
35
- [depends, dependents_below].flatten.compact.uniq(&:name)
36
- end
37
-
38
- def to_h(json_compatible: false)
39
- {
40
- name: @name,
41
- path: path,
42
- type: @type,
43
- ancestry: json_compatible ? @ancestry.to_a : @ancestry,
44
- dependencies: dependencies.map { |dep| dep.to_h(json_compatible: json_compatible) },
45
- }
46
- end
47
-
48
- def to_json
49
- JSON.dump(to_h(json_compatible: true))
50
- end
51
-
52
- private
53
-
54
- def _flatten(component)
55
- component.dependencies.map do |dep|
56
- [dep] + _flatten(dep)
57
- end.flatten.uniq(&:name)
58
- end
59
-
60
- def _subtree(name, tree)
61
- return tree if tree.name == name
62
- tree.dependencies.each do |component|
63
- presence = _subtree(name, component)
64
- return presence if presence
65
- end
66
- nil
67
- end
68
- end
69
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "graphviz"
4
-
5
- module CobraCommander
6
- # Generates graphs of components
7
- class Graph
8
- def initialize(tree, format)
9
- @format = format
10
- @tree = tree.to_h
11
- end
12
-
13
- def generate!
14
- return unless valid_format?
15
-
16
- g = GraphViz.new(:G, type: :digraph, concentrate: true)
17
-
18
- app_node = g.add_nodes(@tree[:name])
19
- map_nodes(g, app_node, @tree)
20
- output(g)
21
- end
22
-
23
- private
24
-
25
- def map_nodes(g, parent_node, tree)
26
- tree[:dependencies].each do |dep|
27
- node = g.find_node(dep[:name]) || g.add_nodes(dep[:name])
28
- g.add_edges(parent_node, node)
29
- map_nodes(g, node, dep)
30
- end
31
- end
32
-
33
- def output(g)
34
- graph = "graph.#{@format}"
35
- g.output(@format => graph)
36
- puts "Graph generated at #{`pwd`.chomp}/#{graph}"
37
- end
38
-
39
- def valid_format?
40
- return true if @format == "png" || @format == "dot"
41
- puts "FORMAT must be 'png' or 'dot'"
42
- false
43
- end
44
- end
45
- end