vop 0.3.5 → 0.3.6

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.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +39 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile.lock +34 -47
  5. data/README.md +118 -16
  6. data/bin/sidekiq.sh +10 -0
  7. data/exe/vop +2 -2
  8. data/lib/core/cache/cache.plugin +0 -0
  9. data/lib/core/cache/commands/invalidate_cache.rb +9 -0
  10. data/lib/core/{structure → meta}/commands/list_commands.rb +2 -1
  11. data/lib/core/meta/commands/list_filters.rb +3 -0
  12. data/lib/core/meta/commands/list_plugins.rb +3 -0
  13. data/lib/core/meta/commands/new_plugin.rb +3 -7
  14. data/lib/core/shell/commands/detail.rb +21 -0
  15. data/lib/core/shell/commands/edit.rb +5 -2
  16. data/lib/core/shell/commands/help.rb +1 -1
  17. data/lib/core/shell/commands/source.rb +10 -4
  18. data/lib/core/structure/commands/collect_contributions.rb +8 -2
  19. data/lib/core/structure/commands/generate_entity_commands.rb +19 -10
  20. data/lib/core/structure/commands/generate_invalidation_commands.rb +19 -9
  21. data/lib/core/structure/commands/list_contribution_targets.rb +9 -0
  22. data/lib/core/structure/commands/list_contributors.rb +1 -1
  23. data/lib/core/structure/structure.plugin +1 -1
  24. data/lib/vop/objects/chain.rb +6 -3
  25. data/lib/vop/objects/command.rb +14 -5
  26. data/lib/vop/objects/command_param.rb +22 -0
  27. data/lib/vop/objects/entities.rb +8 -8
  28. data/lib/vop/objects/entity.rb +57 -16
  29. data/lib/vop/objects/entity_definition.rb +22 -0
  30. data/lib/vop/objects/plugin.rb +46 -4
  31. data/lib/vop/objects/request.rb +9 -5
  32. data/lib/vop/parts/dependency_resolver.rb +0 -4
  33. data/lib/vop/parts/entity_loader.rb +0 -3
  34. data/lib/vop/parts/executor.rb +33 -8
  35. data/lib/vop/parts/plugin_finder.rb +6 -16
  36. data/lib/vop/search_path.rb +12 -0
  37. data/lib/vop/shell/shell.rb +134 -87
  38. data/lib/vop/shell/shell_formatter.rb +32 -17
  39. data/lib/vop/shell/shell_input_readline.rb +3 -0
  40. data/lib/vop/shell/shell_input_testable.rb +9 -3
  41. data/lib/vop/syntax/command_syntax.rb +22 -17
  42. data/lib/vop/syntax/entity_syntax.rb +21 -6
  43. data/lib/vop/syntax/plugin_syntax.rb +6 -0
  44. data/lib/vop/util/pluralizer.rb +9 -1
  45. data/lib/vop/version.rb +1 -1
  46. data/lib/vop/vop.rb +70 -44
  47. data/lib/vop.rb +11 -1
  48. data/vop.gemspec +8 -6
  49. metadata +103 -28
  50. data/lib/core/meta/commands/search_gems_for_plugins.rb +0 -38
  51. data/lib/core/meta/commands/search_path.rb +0 -6
  52. data/lib/core/structure/commands/list_plugins.rb +0 -3
  53. data/lib/vop/util/worker.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2e82b43bd88a68ea52a0cc6fa550fa47fb063cbd
4
- data.tar.gz: d88c69b59fb9b4e44d8b17f5d8f8b369ad40cf15
2
+ SHA256:
3
+ metadata.gz: 701c7d9de56bad966ff63365cd24f6feecf5f63314b0dfbd480a5890f23a98b8
4
+ data.tar.gz: 83f8ac7420c3d9a95bb5087c19d70ebaf6ebd228716201588b693f6b89667818
5
5
  SHA512:
6
- metadata.gz: b1eba461ca7c2c0ec1ec030f0bfaa2918adc9e74678284daaf215ec16f69bbb5a8f2be5292253a9d55b6bfc86a5404b50e02761146a7a1e1ff0fcd21d4e52e3e
7
- data.tar.gz: b871a90a6488754cf5e5f984cbe893766a2d775e9f75fb86b0619c361354de36a749b619b2f62c42ba73aceb1567afdfb3a35866732a7d5da61469957750ac0e
6
+ metadata.gz: 8acbbc85ce5502380b618116fbe386675c804997e7bb72cd8f81bbec23ed16d06bd7d308dac28d7c3496d7c8f5cdfa0b9a220f9a509815a3629396b695e5ed3a
7
+ data.tar.gz: ed870d852b55a179bf4cd47d72058eeb111f81c456d5e338af1e086f9596a90021bc83b109dee537b0ea49cdbfa4ce0d931148229e4936b3f08c2b808a504a6b
@@ -0,0 +1,39 @@
1
+ # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-ruby
2
+
3
+ name: CI
4
+
5
+ on:
6
+ push:
7
+ branches:
8
+ - master
9
+ - and-tonic
10
+ pull_request:
11
+ branches: [ master, and-tonic ]
12
+
13
+ jobs:
14
+ test:
15
+ runs-on: ubuntu-latest
16
+
17
+ services:
18
+ # https://docs.github.com/en/actions/using-containerized-services/creating-redis-service-containers
19
+ redis:
20
+ image: redis
21
+ # Set health checks to wait until redis has started
22
+ options: >-
23
+ --health-cmd "redis-cli ping"
24
+ --health-interval 10s
25
+ --health-timeout 5s
26
+ --health-retries 5
27
+ ports:
28
+ - 6379:6379
29
+
30
+ steps:
31
+ - uses: actions/checkout@v3
32
+ - name: Set up Ruby
33
+ uses: ruby/setup-ruby@359bebbc29cbe6c87da6bc9ea3bc930432750108
34
+ with:
35
+ ruby-version: '3.1'
36
+ - name: Install dependencies
37
+ run: bundle install
38
+ - name: Run tests
39
+ run: bundle exec rake
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.2
data/Gemfile.lock CHANGED
@@ -1,67 +1,54 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- vop (0.3.5)
5
- net-scp
6
- net-ssh
7
- redis
8
- sidekiq
4
+ vop (0.3.6)
5
+ byebug
6
+ json (~> 2.3)
9
7
  terminal-table
10
8
  xml-simple
11
9
 
12
10
  GEM
13
11
  remote: https://rubygems.org/
14
12
  specs:
15
- concurrent-ruby (1.0.5)
16
- connection_pool (2.2.1)
17
- diff-lcs (1.2.5)
18
- docile (1.1.5)
19
- json (1.8.6)
20
- net-scp (1.2.1)
21
- net-ssh (>= 2.6.5)
22
- net-ssh (4.2.0)
23
- rack (2.0.3)
24
- rack-protection (2.0.0)
25
- rack
26
- rake (10.5.0)
27
- redis (4.0.1)
28
- rspec (3.4.0)
29
- rspec-core (~> 3.4.0)
30
- rspec-expectations (~> 3.4.0)
31
- rspec-mocks (~> 3.4.0)
32
- rspec-core (3.4.1)
33
- rspec-support (~> 3.4.0)
34
- rspec-expectations (3.4.0)
13
+ byebug (11.1.3)
14
+ diff-lcs (1.5.0)
15
+ docile (1.4.0)
16
+ json (2.7.1)
17
+ rake (13.1.0)
18
+ rexml (3.2.6)
19
+ rspec (3.12.0)
20
+ rspec-core (~> 3.12.0)
21
+ rspec-expectations (~> 3.12.0)
22
+ rspec-mocks (~> 3.12.0)
23
+ rspec-core (3.12.2)
24
+ rspec-support (~> 3.12.0)
25
+ rspec-expectations (3.12.3)
35
26
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.4.0)
37
- rspec-mocks (3.4.0)
27
+ rspec-support (~> 3.12.0)
28
+ rspec-mocks (3.12.6)
38
29
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.4.0)
40
- rspec-support (3.4.1)
41
- sidekiq (5.0.5)
42
- concurrent-ruby (~> 1.0)
43
- connection_pool (~> 2.2, >= 2.2.0)
44
- rack-protection (>= 1.5.0)
45
- redis (>= 3.3.4, < 5)
46
- simplecov (0.11.2)
47
- docile (~> 1.1.0)
48
- json (~> 1.8)
49
- simplecov-html (~> 0.10.0)
50
- simplecov-html (0.10.0)
51
- terminal-table (1.8.0)
52
- unicode-display_width (~> 1.1, >= 1.1.1)
53
- unicode-display_width (1.3.0)
54
- xml-simple (1.1.5)
30
+ rspec-support (~> 3.12.0)
31
+ rspec-support (3.12.1)
32
+ simplecov (0.22.0)
33
+ docile (~> 1.1)
34
+ simplecov-html (~> 0.11)
35
+ simplecov_json_formatter (~> 0.1)
36
+ simplecov-html (0.12.3)
37
+ simplecov_json_formatter (0.1.4)
38
+ terminal-table (3.0.2)
39
+ unicode-display_width (>= 1.1.1, < 3)
40
+ unicode-display_width (2.5.0)
41
+ xml-simple (1.1.9)
42
+ rexml
55
43
 
56
44
  PLATFORMS
57
- ruby
45
+ x86_64-linux
58
46
 
59
47
  DEPENDENCIES
60
- bundler (~> 1.15)
61
- rake (~> 10.0)
48
+ rake
62
49
  rspec (~> 3.0)
63
50
  simplecov
64
51
  vop!
65
52
 
66
53
  BUNDLED WITH
67
- 1.16.0
54
+ 2.4.10
data/README.md CHANGED
@@ -1,25 +1,23 @@
1
+ The vop is a scripting framework.
1
2
 
2
-
3
- The vop is a systems automation scripting framework.
4
-
5
- It organizes (ruby) scripts into commands living in plugins, defines services that can be installed and managed, and comes with a shell and a web interface.
6
-
7
- # Status: WIP
8
-
9
- This is work in progress. Do not assume everything you read to be totally accurate and/or stable.
3
+ It organizes ruby scripts as *commands* living in *plugins*, defines and manages *services*, and can be accessed from the command line or a web interface.
10
4
 
11
5
  # Installation
12
6
 
13
7
  ## as a gem:
14
8
 
15
- $ gem install vop
9
+ $ gem install vop
10
+
11
+ ## from source
12
+
13
+ * checkout the following repos from github.com/virtualop: vop, plugins, bundle
14
+ * install Ruby >= 3.1.2
15
+ * run `bundle install` in all working copies
16
16
 
17
17
  # Usage
18
18
 
19
19
  Call `vop` to start the shell.
20
20
 
21
- Use the tab key for completion, type "help" for more info, `list_plugins` and `list_commands` for an overview.
22
-
23
21
  # Syntax
24
22
 
25
23
  ## Plugins
@@ -51,27 +49,42 @@ hook :after_execute do |payload|
51
49
  end
52
50
  ```
53
51
 
52
+ config:
53
+ ```
54
+ config_param "foo" [, { options }]
55
+ config_param! "snafoo" [, { options }]
56
+ ```
57
+
58
+ accessing plugin config inside command:
59
+ ```
60
+ run do |plugin|
61
+ plugin.config["foo"]
62
+ end
63
+ ```
64
+
54
65
  ## Commands
55
66
 
56
67
  ...are loaded from the `commands` folder in a plugin.
57
68
 
58
- minimal:
69
+ Minimally, a command needs only a run block:
59
70
  ```
60
71
  run { 42 }
61
72
  ```
62
73
 
63
- optional:
74
+ Also, you can use any of these:
64
75
  ```
65
76
  description "Roses are red."
66
77
 
67
78
  read_only # => cacheable
79
+
80
+ dont_log
68
81
  ```
69
82
 
70
- defining param(eter)s:
83
+ A command can define parameters
71
84
  ```
72
85
  param "snafoo" # optional
73
86
  param! "snafoo" # mandatory
74
- param! :snafoo # entity
87
+ param! :snafoo # mandatory entity
75
88
  ```
76
89
  param syntax:
77
90
  ```
@@ -106,12 +119,38 @@ run do |machine|
106
119
  end
107
120
  ```
108
121
 
122
+ There is special handling in place for block parameters.
123
+
124
+ Declare one with
125
+ ```
126
+ block_param
127
+ ```
128
+ or
129
+ ```
130
+ block_param!
131
+ ```
132
+ and a block can be passed to the command like this:
133
+ ```
134
+ @op.foo do
135
+ # whatever you need to do
136
+ end
137
+ ```
138
+ From inside your command, you can access the block through the parameter called `block`.
139
+
109
140
  contribute:
110
141
  ```
111
142
  contribute to: "other_command" do |params|
112
143
  end
113
144
  ```
114
145
 
146
+ collect contributions:
147
+ ```
148
+ @op.collect_contributions(
149
+ command_name: "other_command",
150
+ raw_params: {}
151
+ )
152
+ ```
153
+
115
154
 
116
155
  show (display options for shell output):
117
156
  ```
@@ -139,7 +178,18 @@ deploy package: <foo>
139
178
  deploy package: [ <foo>, <bar>, <baz> ]
140
179
  ```
141
180
 
142
- install (configuration for) a package repository:
181
+ install a virtualop service:
182
+ ```
183
+ deploy service: "plugin.service"
184
+ ```
185
+
186
+ deploy configuration from a template:
187
+ ```
188
+ deploy template: "foo.conf.erb",
189
+ to: "/etc/foo/conf.d/foo.conf"
190
+ ```
191
+
192
+ install (configuration for) a debian package repository:
143
193
  ```
144
194
  deploy repository: {
145
195
  alias: "funny-name",
@@ -157,6 +207,58 @@ deploy do |machine|
157
207
  end
158
208
  ```
159
209
 
210
+ ## Entities
211
+
212
+ Each entity is a file in the `/entities` subfolder of a plugin.
213
+
214
+ A minimal entity is an array of hashes, each with a unique "name" attribute:
215
+
216
+ ```
217
+ entity do
218
+ [
219
+ {
220
+ "name" => "foo"
221
+ }
222
+ ]
223
+ end
224
+ ```
225
+
226
+ Instead of "name", a differing key attribute can be specified with `key`:
227
+ ```
228
+ key "path"
229
+
230
+ entity do
231
+ [
232
+ {
233
+ "path" => "/bin/false"
234
+ }
235
+ ]
236
+ end
237
+ ```
238
+
239
+ The `on` keyword allows to stack entities onto another, e.g. the `log` entity living on a machine:
240
+ ```
241
+ key "path"
242
+
243
+ on :machine
244
+
245
+ entity do |machine|
246
+ # ...
247
+ end
248
+ ```
249
+ A stacked entity (or rather, the list command generated from the entity) automatically has a parameter for the entity it is stacked on - in the log example:
250
+ ```
251
+ >> logs?
252
+
253
+ logs
254
+
255
+ syntax:
256
+ logs <machine>
257
+
258
+ parameters:
259
+ machine
260
+ ```
261
+
160
262
  # Development
161
263
 
162
264
  ## required dependencies
data/bin/sidekiq.sh ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ VOP_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )
4
+
5
+ cd $VOP_DIR
6
+
7
+ export VOP_ORIGIN="sidekiq"
8
+ bundle exec sidekiq -r ./lib/boot.rb
9
+
10
+ cd - >/dev/null
data/exe/vop CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  require "vop"
4
4
 
5
- @op = Vop.boot()
6
- Vop::Shell.run(@op)
5
+ @op = Vop.boot(origin: "shell:#{Process.pid}@#{`hostname`.strip}")
6
+ Vop::Shell.run(@op, ARGV.join(" "))
File without changes
@@ -0,0 +1,9 @@
1
+ param! "command"
2
+ param! "raw_params", default: {}
3
+
4
+ run do |params|
5
+ @op.collect_contributions(
6
+ command_name: "invalidate_cache",
7
+ raw_params: params
8
+ )
9
+ end
@@ -1,4 +1,5 @@
1
- param "plugin_filter", description: "name of a plugin by which commands should be filtered"
1
+ param "plugin_filter", description: "name of a plugin by which commands should be filtered",
2
+ lookup: lambda { @op.list_plugins }
2
3
 
3
4
  run do |plugin_filter|
4
5
  result = @op.commands.values
@@ -0,0 +1,3 @@
1
+ run do
2
+ @op.filters.keys
3
+ end
@@ -0,0 +1,3 @@
1
+ run do |plugin|
2
+ @op.plugins.map(&:name).sort
3
+ end
@@ -18,25 +18,21 @@ run do |params|
18
18
 
19
19
  raise "no such path: #{params["path"]}" unless File.exists? params["path"]
20
20
 
21
- pp params
22
-
23
- # a plugin is a directory
21
+ # create a new plugin: a plugin is a directory
24
22
  plugin_path = File.join(params["path"], params["name"])
25
23
  puts "plugin path : #{plugin_path}"
26
24
  Dir.mkdir(plugin_path)
27
25
 
28
- # with subfolders for commands and helpers
26
+ # ...with subfolders for commands and helpers
29
27
  %w|commands helpers|.each do |thing|
30
28
  Dir.mkdir(File.join(plugin_path, thing))
31
29
  end
32
30
 
33
- # and a metadata file called "<name>.plugin"
31
+ # ...and a metadata file called "<name>.plugin"
34
32
  plugin_file = params["name"] + ".plugin"
35
33
  full_name = File.join(plugin_path, plugin_file)
36
34
  FileUtils.touch full_name
37
35
 
38
- # TODO content is [] - should probably be nil, though
39
- #puts "content: >>#{params["content"].pretty_inspect}<<"
40
36
  unless params["content"].nil?
41
37
  IO.write(full_name, params["content"])
42
38
  end
@@ -0,0 +1,21 @@
1
+ param "index"
2
+
3
+ show display_type: :raw
4
+
5
+ run do |shell, index|
6
+ last_result = shell.last_response&.result
7
+
8
+ result = if last_result
9
+ if last_result.is_a?(Array) && index
10
+ last_result[index.to_i]
11
+ else
12
+ last_result
13
+ end
14
+ end
15
+
16
+ if result.is_a? ::Vop::Entity
17
+ result.data
18
+ else
19
+ result
20
+ end
21
+ end
@@ -2,10 +2,13 @@ param! "name", lookup: lambda { @op.commands.keys }
2
2
 
3
3
  run do |params, name|
4
4
  has_vim = `which vim`
5
- editor = ENV["EDITOR"] || "vim" if has_vim
5
+ editor = ENV["EDITOR"]
6
+ if editor.nil?
7
+ editor = "vim" if has_vim
8
+ end
6
9
  raise "please set the EDITOR environment variable" unless editor
7
10
 
8
- command_file = @op.commands[name].source[:file_name]
11
+ command_file = @op.commands[name].source[:file_name]
9
12
  system("#{editor} #{command_file}")
10
13
 
11
14
  @op.reset
@@ -1,6 +1,6 @@
1
1
  param! "name",
2
2
  description: "a command for which help should be displayed",
3
- lookup: lambda { |params| @op.list_commands.split }
3
+ lookup: lambda { |params| @op.list_commands }
4
4
 
5
5
  run do |params, name|
6
6
  command = @op.commands[params["name"]]
@@ -1,6 +1,7 @@
1
1
  param! "name", lookup: lambda { @op.commands.keys + @op.entities.keys + @op.filters.keys }
2
+ param "numbers", default: true
2
3
 
3
- run do |name|
4
+ run do |name, numbers|
4
5
  (source, thing) = if @op.commands.keys.include? name
5
6
  [ :commands, @op.commands[name] ]
6
7
  elsif @op.entities.keys.include? name
@@ -13,9 +14,14 @@ run do |name|
13
14
 
14
15
  result = []
15
16
  result << " "
16
- code.lines.each_with_index { |line, idx|
17
- result << "%02d %s" % [idx+1, line.chomp]
18
- }
17
+ code.lines.each_with_index do |line, idx|
18
+ line.chomp!
19
+ line = numbers ?
20
+ "%02d %s" % [idx+1, line] :
21
+ line
22
+
23
+ result << line
24
+ end
19
25
  result << " "
20
26
  result.join("\n")
21
27
  end
@@ -31,11 +31,17 @@ run do |command_name, raw_params|
31
31
  contribution = @op.execute(short_name, raw_params)
32
32
 
33
33
  if contribution.nil?
34
- $logger.warn "command #{short_name} contributes a nil value"
34
+ $logger.debug "command #{short_name} contributes a nil value"
35
35
  else
36
36
  case display_type
37
37
  when :table
38
- result += contribution
38
+ if contribution.is_a? Array
39
+ result += contribution
40
+ else
41
+ if target.show_options[:display_type] == :table
42
+ $logger.warn "contribution from #{short_name} is not an Array (but a #{contribution.class}), though the :table display type would imply that (ignoring)"
43
+ end
44
+ end
39
45
  when :hash
40
46
  result.merge! contribution
41
47
  end
@@ -4,21 +4,23 @@ run do
4
4
  result = []
5
5
 
6
6
  @op.entities.each do |entity_name, definition|
7
- list_command_name = definition.name.carefully_pluralize
8
- $logger.debug "generating entity list command #{list_command_name} (#{definition.plugin.name})"
7
+ $logger.debug "generating entity list command #{definition.list_command_name} (#{definition.plugin.name})"
9
8
 
10
9
  plugin = definition.plugin
11
10
 
12
- list_command = Command.new(plugin, list_command_name)
13
- # TODO list_command.read_only = true
11
+ list_command = Command.new(plugin, definition.list_command_name)
12
+ list_command.read_only = definition.read_only
13
+ list_command.dont_log = true
14
+ list_command.show_options = definition.show_options
14
15
 
15
16
  if definition.on
16
- list_command.add_param(definition.on.to_s, mandatory: true)
17
+ list_command.add_param(definition.on.to_s, mandatory: true, entity: true)
17
18
  end
18
19
 
19
20
  list_command.block = lambda do |params, request, context, plugin|
20
21
  ex = Executor.new(@op)
21
22
  block_param_names = definition.block.parameters.map { |x| x.last }
23
+
22
24
  payload = ex.prepare_payload(request, context, block_param_names)
23
25
 
24
26
  hash_array = definition.block.call(*payload)
@@ -31,11 +33,15 @@ run do
31
33
  entity_array = []
32
34
  unless hash_array.empty?
33
35
  first = hash_array.first
34
- unless first.is_a? Hash
35
- raise "entity '#{definition.name}' returned unexpected data type : found #{first.class}, expected Hash"
36
- end
37
- entity_array = hash_array.map do |row|
38
- Entity.new(@op, definition.short_name, definition.key, row)
36
+ if first.is_a? Entity
37
+ entity_array = hash_array
38
+ else
39
+ unless first.is_a? Hash
40
+ raise "entity '#{definition.name}' returned unexpected data type : found #{first.class}, expected Hash"
41
+ end
42
+ entity_array = hash_array.map do |row|
43
+ Entity.new(@op, definition, row)
44
+ end
39
45
  end
40
46
  end
41
47
 
@@ -43,6 +49,9 @@ run do
43
49
  ::Vop::Entities.new(entity_array)
44
50
  end
45
51
  end
52
+
53
+ list_command.invalidation_block = definition.invalidation_block
54
+
46
55
  result << list_command
47
56
  end
48
57
 
@@ -2,26 +2,36 @@ description "all read-only commands get <command>! commands that invalidate auto
2
2
 
3
3
  run do
4
4
  count = 0
5
- @op.commands.values.each do |command|
6
- # actually, all read-only commands *and* all commands with an invalidation block
7
- if command.read_only || command.invalidation_block
8
- invalidation_command_name = "#{command.short_name}!"
5
+
6
+ def setup_invalidation_command(thing, invalidation_command_name, command_name)
7
+ if thing.read_only || thing.invalidation_block
9
8
  $logger.debug "generating invalidation command #{invalidation_command_name}"
10
9
 
11
- invalidation_command = Command.new(command.plugin, invalidation_command_name)
12
- invalidation_command.params = command.params
10
+ invalidation_command = Command.new(thing.plugin, invalidation_command_name)
11
+ invalidation_command.params = thing.params
13
12
 
14
13
  invalidation_command.block = lambda do |params|
15
14
  @op.invalidate_cache(
16
- "command" => command.short_name,
15
+ "command" => command_name,
17
16
  "raw_params" => params
18
17
  )
19
- @op.execute(command.short_name, params)
18
+ @op.execute(command_name, params)
20
19
  end
21
20
 
22
21
  @op << invalidation_command
23
- count += 1
24
22
  end
25
23
  end
24
+
25
+ @op.commands.values.each do |command|
26
+ setup_invalidation_command(command, "#{command.short_name}!", command.short_name)
27
+ count += 1
28
+ end
29
+
30
+ # not needed at the moment (because entity list commands are generated with an invalidation block)
31
+ # @op.entities.values.each do |entity|
32
+ # setup_invalidation_command(entity, "#{entity.list_command_name}!", entity.list_command_name)
33
+ # count += 1
34
+ # end
35
+
26
36
  count
27
37
  end
@@ -0,0 +1,9 @@
1
+ description "lists the target commands that a given command contributes to (the contributees so to speak)"
2
+
3
+ param! "source_command"
4
+
5
+ run do |plugin, source_command|
6
+ registry = plugin.state[:contributions] || {}
7
+
8
+ registry.select { |k,v| v.include? source_command.to_s.carefully_pluralize }.keys
9
+ end
@@ -3,7 +3,7 @@ param "command_name", description: "command for which contributors should be dis
3
3
  run do |plugin, command_name|
4
4
  registry = plugin.state[:contributions] || {}
5
5
  if command_name
6
- registry[command_name]
6
+ registry[command_name] || []
7
7
  else
8
8
  registry
9
9
  end
@@ -1,4 +1,4 @@
1
- hook :loading_finished do
1
+ hook :init_complete do
2
2
  @op.generate_entity_commands
3
3
  @op.generate_invalidation_commands
4
4
  end