cobra_commander 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +9 -5
- data/lib/cobra_commander.rb +6 -1
- data/lib/cobra_commander/change.rb +1 -1
- data/lib/cobra_commander/cli.rb +33 -9
- data/lib/cobra_commander/component_tree.rb +125 -97
- data/lib/cobra_commander/executor.rb +30 -0
- data/lib/cobra_commander/graph.rb +1 -1
- data/lib/cobra_commander/output.rb +74 -0
- data/lib/cobra_commander/version.rb +1 -1
- metadata +5 -4
- data/lib/cobra_commander/formatted_output.rb +0 -76
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a05f3e1ab4ccff9ca040dcf4d694aebc28df0f50160067cf73eaea89f4bad59
|
4
|
+
data.tar.gz: d0132e226b7527e72ebb84e3844116dd3a0c2ed8ecc1394d9df5f7fad5f777d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cb90f61448f1bc69088418fc86dafbc25fce09d069507e22fc22f0a2d9a63eccf95ce3edeb13b6ee2657e19303489c2b59087944ddc07597c7d0e201c36a307
|
7
|
+
data.tar.gz: '023961e1f0abe297e0d0cacc169b3da23fac68f833627d01d480f06d0822019877cd1ac78bb20bf7f951b2bbdce04a0c0ddbb7b3b444a90669f18c967a43775c'
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Version 0.5.0 - 2018-09-20
|
6
|
+
|
7
|
+
* Renames `dependencies_of` to `dependents_of`. PR [#25](https://github.com/powerhome/cobra_commander/pull/25)
|
8
|
+
* Add `dependencies_of` command list the direct and indirect dependencies of one component. PR [#25](https://github.com/powerhome/cobra_commander/pull/25)
|
9
|
+
* Add `do` command allow executing a command in the context of each component. PR [#26](https://github.com/powerhome/cobra_commander/pull/26)
|
10
|
+
|
5
11
|
## Version 0.4.0 - 2018-09-06
|
6
12
|
|
7
13
|
* Add `dependencies_of` command to permit listing or counting the dependencies of a particular component. PR [#24](https://github.com/powerhome/cobra_commander/pull/24)
|
data/README.md
CHANGED
@@ -28,11 +28,15 @@ Or install it yourself as:
|
|
28
28
|
|
29
29
|
```bash
|
30
30
|
Commands:
|
31
|
-
cobra changes APP_PATH [--results=RESULTS] [--branch=BRANCH]
|
32
|
-
cobra graph APP_PATH [--format=FORMAT]
|
33
|
-
cobra help [COMMAND]
|
34
|
-
cobra ls APP_PATH
|
35
|
-
cobra version
|
31
|
+
cobra changes APP_PATH [--results=RESULTS] [--branch=BRANCH] # Prints list of changed files
|
32
|
+
cobra graph APP_PATH [--format=FORMAT] # Outputs graph
|
33
|
+
cobra help [COMMAND] # Describe available commands or one specific command
|
34
|
+
cobra ls APP_PATH [--format=list|tree] # Prints tree of components for an app
|
35
|
+
cobra version # Prints version
|
36
|
+
cobra do [command] # Executes the command in the context of each component
|
37
|
+
cobra dependencies_of [component] [--app=/path/to/app] [--format=list|tree] # Lists the dependencies of the component in the app context
|
38
|
+
cobra dependents_of [component] [--app=/path/to/app] [--format=list|count] # Lists or counts the components that depend directly or indirectly on the given component
|
39
|
+
cobra version # Prints version
|
36
40
|
```
|
37
41
|
|
38
42
|
## Development
|
data/lib/cobra_commander.rb
CHANGED
@@ -3,14 +3,19 @@
|
|
3
3
|
require "cobra_commander/cli"
|
4
4
|
require "cobra_commander/component_tree"
|
5
5
|
require "cobra_commander/version"
|
6
|
-
require "cobra_commander/formatted_output"
|
7
6
|
require "cobra_commander/graph"
|
8
7
|
require "cobra_commander/change"
|
9
8
|
require "cobra_commander/affected"
|
9
|
+
require "cobra_commander/output"
|
10
|
+
require "cobra_commander/executor"
|
10
11
|
|
11
12
|
# Tools for working with Component Based Rails Apps (see http://shageman.github.io/cbra.info/).
|
12
13
|
# Includes tools for graphing the components of an app and their relationships, as well as selectively
|
13
14
|
# testing components based on changes made.
|
14
15
|
module CobraCommander
|
15
16
|
UMBRELLA_APP_NAME = "App"
|
17
|
+
|
18
|
+
def self.umbrella_tree(path)
|
19
|
+
ComponentTree.new(UMBRELLA_APP_NAME, path)
|
20
|
+
end
|
16
21
|
end
|
@@ -13,7 +13,7 @@ module CobraCommander
|
|
13
13
|
@root_dir = Dir.chdir(path) { `git rev-parse --show-toplevel`.chomp }
|
14
14
|
@results = results
|
15
15
|
@branch = branch
|
16
|
-
@tree =
|
16
|
+
@tree = CobraCommander.umbrella_tree(path).to_h
|
17
17
|
@affected = Affected.new(@tree, changes, path)
|
18
18
|
end
|
19
19
|
|
data/lib/cobra_commander/cli.rb
CHANGED
@@ -5,16 +5,40 @@ require "thor"
|
|
5
5
|
module CobraCommander
|
6
6
|
# Implements the tool's CLI
|
7
7
|
class CLI < Thor
|
8
|
-
desc "
|
9
|
-
|
10
|
-
|
8
|
+
desc "do [command]", "Executes the command in the context of each component in [app]"
|
9
|
+
method_option :app, default: Dir.pwd, aliases: "-a", desc: "App path (default: CWD)"
|
10
|
+
def do(command)
|
11
|
+
tree = CobraCommander.umbrella_tree(options.app)
|
12
|
+
executor = Executor.new(tree)
|
13
|
+
executor.exec(command)
|
11
14
|
end
|
12
15
|
|
13
|
-
desc "
|
14
|
-
method_option :
|
16
|
+
desc "ls [app_path]", "Prints tree of components for an app"
|
17
|
+
method_option :app, default: Dir.pwd, aliases: "-a", desc: "App path (default: CWD)"
|
18
|
+
method_option :format, default: "tree", aliases: "-f", desc: "Format (list or tree, default: list)"
|
19
|
+
def ls(app_path = nil)
|
20
|
+
Output.print(
|
21
|
+
CobraCommander.umbrella_tree(app_path || options.app),
|
22
|
+
options.format
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "dependents_of [component]", "Outputs count of components in [app] dependent on [component]"
|
27
|
+
method_option :app, default: Dir.pwd, aliases: "-a", desc: "Path to the root app where the component is mounted"
|
15
28
|
method_option :format, default: "count", aliases: "-f", desc: "count or list"
|
16
|
-
def
|
17
|
-
|
29
|
+
def dependents_of(component)
|
30
|
+
dependents = CobraCommander.umbrella_tree(options.app).dependents_of(component)
|
31
|
+
puts "list" == options.format ? dependents.map(&:name) : dependents.size
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "dependencies_of [component]", "Outputs a list of components that [component] depends on within [app] context"
|
35
|
+
method_option :app, default: Dir.pwd, aliases: "-a", desc: "App path (default: CWD)"
|
36
|
+
method_option :format, default: "list", aliases: "-f", desc: "Format (list or tree, default: list)"
|
37
|
+
def dependencies_of(component)
|
38
|
+
Output.print(
|
39
|
+
CobraCommander.umbrella_tree(options.app).subtree(component),
|
40
|
+
options.format
|
41
|
+
)
|
18
42
|
end
|
19
43
|
|
20
44
|
desc "version", "Prints version"
|
@@ -25,14 +49,14 @@ module CobraCommander
|
|
25
49
|
desc "graph APP_PATH [--format=FORMAT]", "Outputs graph"
|
26
50
|
method_option :format, default: "png", aliases: "-f", desc: "Accepts png or dot"
|
27
51
|
def graph(app_path)
|
28
|
-
Graph.new(app_path,
|
52
|
+
Graph.new(app_path, options.format).generate!
|
29
53
|
end
|
30
54
|
|
31
55
|
desc "changes APP_PATH [--results=RESULTS] [--branch=BRANCH]", "Prints list of changed files"
|
32
56
|
method_option :results, default: "test", aliases: "-r", desc: "Accepts test, full, name or json"
|
33
57
|
method_option :branch, default: "master", aliases: "-b", desc: "Specified target to calculate against"
|
34
58
|
def changes(app_path)
|
35
|
-
Change.new(app_path,
|
59
|
+
Change.new(app_path, options.results, options.branch).run!
|
36
60
|
end
|
37
61
|
end
|
38
62
|
end
|
@@ -1,139 +1,167 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler"
|
3
4
|
require "json"
|
4
5
|
|
5
6
|
module CobraCommander
|
6
|
-
#
|
7
|
+
# Represents a dependency tree in a given context
|
7
8
|
class ComponentTree
|
8
|
-
|
9
|
-
|
9
|
+
attr_reader :name, :path
|
10
|
+
|
11
|
+
def initialize(name, path, ancestry = Set.new)
|
12
|
+
@name = name
|
13
|
+
@path = path
|
14
|
+
@ancestry = ancestry
|
15
|
+
@ruby = Ruby.new(path)
|
16
|
+
@js = Js.new(path)
|
17
|
+
@type = type_of_component
|
18
|
+
end
|
19
|
+
|
20
|
+
def flatten
|
21
|
+
_flatten(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def subtree(name)
|
25
|
+
_subtree(name, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def depends_on?(component_name)
|
29
|
+
dependencies.any? do |component|
|
30
|
+
component.name == component_name || component.depends_on?(component_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dependents_of(component_name)
|
35
|
+
depends = depends_on?(component_name) ? self : nil
|
36
|
+
dependents_below = dependencies.map do |component|
|
37
|
+
component.dependents_of(component_name)
|
38
|
+
end
|
39
|
+
[depends, dependents_below].flatten.compact.uniq(&:name)
|
10
40
|
end
|
11
41
|
|
12
42
|
def to_h
|
13
|
-
|
43
|
+
{
|
44
|
+
name: @name,
|
45
|
+
path: path,
|
46
|
+
type: @type,
|
47
|
+
ancestry: @ancestry,
|
48
|
+
dependencies: dependencies.map(&:to_h),
|
49
|
+
}
|
14
50
|
end
|
15
51
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@ancestry = ancestry
|
22
|
-
@ruby = Ruby.new(path)
|
23
|
-
@js = Js.new(path)
|
24
|
-
@type = type_of_component
|
52
|
+
def dependencies
|
53
|
+
@deps ||= begin
|
54
|
+
deps = @ruby.dependencies + @js.dependencies
|
55
|
+
deps.sort_by { |dep| dep[:name] }
|
56
|
+
.map(&method(:dep_representation))
|
25
57
|
end
|
58
|
+
end
|
26
59
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
60
|
+
private
|
61
|
+
|
62
|
+
def _flatten(component)
|
63
|
+
component.dependencies.map do |dep|
|
64
|
+
[dep] + _flatten(dep)
|
65
|
+
end.flatten.uniq(&:name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def _subtree(name, tree)
|
69
|
+
return tree if tree.name == name
|
70
|
+
tree.dependencies.each do |component|
|
71
|
+
return _subtree(name, component)
|
35
72
|
end
|
73
|
+
end
|
36
74
|
|
37
|
-
|
75
|
+
def type_of_component
|
76
|
+
return "Ruby & JS" if @ruby.gem? && @js.node?
|
77
|
+
return "Ruby" if @ruby.gem?
|
78
|
+
return "JS" if @js.node?
|
79
|
+
end
|
38
80
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
81
|
+
def dep_representation(dep)
|
82
|
+
full_path = File.expand_path(File.join(path, dep[:path]))
|
83
|
+
ancestry = @ancestry + [{ name: @name, path: path, type: @type }]
|
84
|
+
ComponentTree.new(dep[:name], full_path, ancestry)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Calculates ruby dependencies
|
88
|
+
class Ruby
|
89
|
+
def initialize(root_path)
|
90
|
+
@root_path = root_path
|
43
91
|
end
|
44
92
|
|
45
93
|
def dependencies
|
46
94
|
@deps ||= begin
|
47
|
-
|
48
|
-
|
95
|
+
return [] unless gem?
|
96
|
+
gems = bundler_definition.dependencies.select { |dep| path?(dep.source) }
|
97
|
+
format(gems)
|
49
98
|
end
|
50
99
|
end
|
51
100
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
101
|
+
def path?(source)
|
102
|
+
return if source.nil?
|
103
|
+
source_has_path = source.respond_to?(:path?) ? source.path? : source.is_a_path?
|
104
|
+
source_has_path && source.path.to_s != "."
|
56
105
|
end
|
57
106
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def dependencies
|
65
|
-
@deps ||= begin
|
66
|
-
return [] unless gem?
|
67
|
-
gems = bundler_definition.dependencies.select { |dep| path?(dep.source) }
|
68
|
-
format(gems)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def path?(source)
|
73
|
-
return if source.nil?
|
74
|
-
source_has_path = source.respond_to?(:path?) ? source.path? : source.is_a_path?
|
75
|
-
source_has_path && source.path.to_s != "."
|
76
|
-
end
|
77
|
-
|
78
|
-
def format(deps)
|
79
|
-
deps.map do |dep|
|
80
|
-
path = File.join(dep.source.path, dep.name)
|
81
|
-
{ name: dep.name, path: path }
|
82
|
-
end
|
107
|
+
def format(deps)
|
108
|
+
deps.map do |dep|
|
109
|
+
path = File.join(dep.source.path, dep.name)
|
110
|
+
{ name: dep.name, path: path }
|
83
111
|
end
|
112
|
+
end
|
84
113
|
|
85
|
-
|
86
|
-
|
87
|
-
|
114
|
+
def gem?
|
115
|
+
@gem ||= File.exist?(gemfile_path)
|
116
|
+
end
|
88
117
|
|
89
|
-
|
90
|
-
|
91
|
-
|
118
|
+
def bundler_definition
|
119
|
+
::Bundler::Definition.build(gemfile_path, gemfile_lock_path, nil)
|
120
|
+
end
|
92
121
|
|
93
|
-
|
94
|
-
|
95
|
-
|
122
|
+
def gemfile_path
|
123
|
+
File.join(@root_path, "Gemfile")
|
124
|
+
end
|
96
125
|
|
97
|
-
|
98
|
-
|
99
|
-
end
|
126
|
+
def gemfile_lock_path
|
127
|
+
File.join(@root_path, "Gemfile.lock")
|
100
128
|
end
|
129
|
+
end
|
101
130
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
131
|
+
# Calculates js dependencies
|
132
|
+
class Js
|
133
|
+
def initialize(root_path)
|
134
|
+
@root_path = root_path
|
135
|
+
end
|
107
136
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
137
|
+
def dependencies
|
138
|
+
@deps ||= begin
|
139
|
+
return [] unless node?
|
140
|
+
json = JSON.parse(File.read(package_json_path))
|
141
|
+
format combined_deps(json)
|
114
142
|
end
|
143
|
+
end
|
115
144
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
145
|
+
def format(deps)
|
146
|
+
return [] if deps.nil?
|
147
|
+
linked_deps = deps.select { |_, v| v.start_with? "link:" }
|
148
|
+
linked_deps.map do |_, v|
|
149
|
+
relational_path = v.split("link:")[1]
|
150
|
+
dep_name = relational_path.split("/")[-1]
|
151
|
+
{ name: dep_name, path: relational_path }
|
124
152
|
end
|
153
|
+
end
|
125
154
|
|
126
|
-
|
127
|
-
|
128
|
-
|
155
|
+
def node?
|
156
|
+
@node ||= File.exist?(package_json_path)
|
157
|
+
end
|
129
158
|
|
130
|
-
|
131
|
-
|
132
|
-
|
159
|
+
def package_json_path
|
160
|
+
File.join(@root_path, "package.json")
|
161
|
+
end
|
133
162
|
|
134
|
-
|
135
|
-
|
136
|
-
end
|
163
|
+
def combined_deps(json)
|
164
|
+
Hash(json["dependencies"]).merge(Hash(json["devDependencies"]))
|
137
165
|
end
|
138
166
|
end
|
139
167
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
# Execute commands on all components of a ComponentTree
|
5
|
+
class Executor
|
6
|
+
def initialize(tree)
|
7
|
+
@tree = tree
|
8
|
+
end
|
9
|
+
|
10
|
+
def exec(command, printer = $stdout)
|
11
|
+
@tree.flatten.each do |component|
|
12
|
+
printer.puts "===> #{component.name} (#{component.path})"
|
13
|
+
output, = run_in_component(component, command)
|
14
|
+
printer.puts output
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def run_in_component(component, command)
|
21
|
+
Dir.chdir(component.path) do
|
22
|
+
Open3.capture2e(env_vars(component), command)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def env_vars(component)
|
27
|
+
{ "CURRENT_COMPONENT" => component.name, "CURRENT_COMPONENT_PATH" => component.path }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CobraCommander
|
4
|
+
# Module for pretty printing dependency trees
|
5
|
+
module Output
|
6
|
+
def self.print(tree, format)
|
7
|
+
output = format == "list" ? Output::FlatList.new(tree) : Output::Tree.new(tree)
|
8
|
+
puts output.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
# Flattens a tree and prints unique items
|
12
|
+
class FlatList
|
13
|
+
def initialize(tree)
|
14
|
+
@tree = tree
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
@tree.flatten.map(&:name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Prints the tree in a nice tree form
|
23
|
+
class Tree
|
24
|
+
attr_accessor :tree
|
25
|
+
|
26
|
+
SPACE = " "
|
27
|
+
BAR = "│ "
|
28
|
+
TEE = "├── "
|
29
|
+
CORNER = "└── "
|
30
|
+
|
31
|
+
def initialize(tree)
|
32
|
+
@tree = tree
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
StringIO.new.tap do |io|
|
37
|
+
io.puts @tree.name
|
38
|
+
list_dependencies(io, @tree)
|
39
|
+
end.string
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def list_dependencies(io, deps, outdents = [])
|
45
|
+
deps.dependencies.each do |dep|
|
46
|
+
decide_on_line(io, deps, dep, outdents)
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def decide_on_line(io, parent, dep, outdents)
|
52
|
+
if parent.dependencies.last != dep
|
53
|
+
add_tee(io, outdents, dep)
|
54
|
+
else
|
55
|
+
add_corner(io, outdents, dep)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_tee(io, outdents, dep)
|
60
|
+
io.puts line(outdents, TEE, dep.name)
|
61
|
+
list_dependencies(io, dep, (outdents + [BAR]))
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_corner(io, outdents, dep)
|
65
|
+
io.puts line(outdents, CORNER, dep.name)
|
66
|
+
list_dependencies(io, dep, (outdents + [SPACE]))
|
67
|
+
end
|
68
|
+
|
69
|
+
def line(outdents, sym, name)
|
70
|
+
(outdents + [sym] + [name]).join
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cobra_commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Langfeld
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-09-
|
12
|
+
date: 2018-09-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -170,8 +170,9 @@ files:
|
|
170
170
|
- lib/cobra_commander/change.rb
|
171
171
|
- lib/cobra_commander/cli.rb
|
172
172
|
- lib/cobra_commander/component_tree.rb
|
173
|
-
- lib/cobra_commander/
|
173
|
+
- lib/cobra_commander/executor.rb
|
174
174
|
- lib/cobra_commander/graph.rb
|
175
|
+
- lib/cobra_commander/output.rb
|
175
176
|
- lib/cobra_commander/version.rb
|
176
177
|
homepage: http://tech.powerhrg.com/cobra_commander/
|
177
178
|
licenses:
|
@@ -193,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
194
|
version: '0'
|
194
195
|
requirements: []
|
195
196
|
rubyforge_project:
|
196
|
-
rubygems_version: 2.7.
|
197
|
+
rubygems_version: 2.7.7
|
197
198
|
signing_key:
|
198
199
|
specification_version: 4
|
199
200
|
summary: Tools for working with Component Based Rails Apps
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "cobra_commander/component_tree"
|
4
|
-
|
5
|
-
module CobraCommander
|
6
|
-
# Formats CLI ls output
|
7
|
-
class FormattedOutput
|
8
|
-
attr_accessor :tree
|
9
|
-
|
10
|
-
SPACE = " "
|
11
|
-
BAR = "│ "
|
12
|
-
TEE = "├── "
|
13
|
-
CORNER = "└── "
|
14
|
-
|
15
|
-
def initialize(app_path)
|
16
|
-
@tree = ComponentTree.new(app_path).to_h
|
17
|
-
end
|
18
|
-
|
19
|
-
def run!
|
20
|
-
puts @tree[:name]
|
21
|
-
list_dependencies(@tree)
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def dependencies_of!(component_name, format)
|
26
|
-
@component_name = component_name
|
27
|
-
|
28
|
-
results = @tree[:dependencies].map do |component|
|
29
|
-
if @component_name == component[:name]
|
30
|
-
@tree[:name]
|
31
|
-
elsif dependency?(component)
|
32
|
-
component[:name]
|
33
|
-
end
|
34
|
-
end.compact
|
35
|
-
|
36
|
-
"list" == format ? results : results.size
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def dependency?(deps)
|
42
|
-
deps[:dependencies].each do |dep|
|
43
|
-
return true if @component_name == dep[:name] || dependency?(dep)
|
44
|
-
end
|
45
|
-
false
|
46
|
-
end
|
47
|
-
|
48
|
-
def list_dependencies(deps, outdents = [])
|
49
|
-
deps[:dependencies].each do |dep|
|
50
|
-
decide_on_line(deps, dep, outdents)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def decide_on_line(parent, dep, outdents)
|
55
|
-
if parent[:dependencies].last != dep
|
56
|
-
add_tee(outdents, dep)
|
57
|
-
else
|
58
|
-
add_corner(outdents, dep)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def add_tee(outdents, dep)
|
63
|
-
puts line(outdents, TEE, dep[:name])
|
64
|
-
list_dependencies(dep, (outdents + [BAR]))
|
65
|
-
end
|
66
|
-
|
67
|
-
def add_corner(outdents, dep)
|
68
|
-
puts line(outdents, CORNER, dep[:name])
|
69
|
-
list_dependencies(dep, (outdents + [SPACE]))
|
70
|
-
end
|
71
|
-
|
72
|
-
def line(outdents, sym, name)
|
73
|
-
(outdents + [sym] + [name]).join
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|