vop 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +66 -0
  5. data/README.md +2 -0
  6. data/Rakefile +6 -0
  7. data/bin/vop.rb +28 -0
  8. data/bin/vop.sh +4 -0
  9. data/exe/vop +28 -0
  10. data/lib/vop.rb +242 -0
  11. data/lib/vop/command.rb +168 -0
  12. data/lib/vop/command_loader.rb +47 -0
  13. data/lib/vop/entity.rb +61 -0
  14. data/lib/vop/loader.rb +35 -0
  15. data/lib/vop/plugin.rb +141 -0
  16. data/lib/vop/plugin_loader.rb +88 -0
  17. data/lib/vop/plugins/core/commands/clear_context.rb +3 -0
  18. data/lib/vop/plugins/core/commands/collect_contributions.rb +31 -0
  19. data/lib/vop/plugins/core/commands/edit.rb +12 -0
  20. data/lib/vop/plugins/core/commands/help.rb +38 -0
  21. data/lib/vop/plugins/core/commands/identity.rb +4 -0
  22. data/lib/vop/plugins/core/commands/list_contributors.rb +8 -0
  23. data/lib/vop/plugins/core/commands/list_entities.rb +3 -0
  24. data/lib/vop/plugins/core/commands/pry.rb +9 -0
  25. data/lib/vop/plugins/core/commands/reset.rb +5 -0
  26. data/lib/vop/plugins/core/commands/show_context.rb +3 -0
  27. data/lib/vop/plugins/core/commands/source.rb +5 -0
  28. data/lib/vop/plugins/core/commands/system_call.rb +5 -0
  29. data/lib/vop/plugins/core/core.plugin +4 -0
  30. data/lib/vop/plugins/core/helpers/command_loader/command_syntax.rb +45 -0
  31. data/lib/vop/plugins/core/helpers/command_loader/contributions.rb +28 -0
  32. data/lib/vop/plugins/core/helpers/command_loader/entities.rb +57 -0
  33. data/lib/vop/plugins/core/helpers/helper.rb +3 -0
  34. data/lib/vop/plugins/core/helpers/plugin_loader/plugin_syntax.rb +0 -0
  35. data/lib/vop/plugins/meta/commands/add_search_path.rb +6 -0
  36. data/lib/vop/plugins/meta/commands/delete_plugin.rb +13 -0
  37. data/lib/vop/plugins/meta/commands/list_commands.rb +17 -0
  38. data/lib/vop/plugins/meta/commands/list_plugins.rb +8 -0
  39. data/lib/vop/plugins/meta/commands/new_command.rb +14 -0
  40. data/lib/vop/plugins/meta/commands/new_plugin.rb +25 -0
  41. data/lib/vop/plugins/meta/commands/show_search_path.rb +3 -0
  42. data/lib/vop/plugins/meta/commands/who_provides.rb +5 -0
  43. data/lib/vop/plugins/meta/meta.plugin +1 -0
  44. data/lib/vop/plugins/ssh/commands/scp.rb +11 -0
  45. data/lib/vop/plugins/ssh/commands/ssh.rb +19 -0
  46. data/lib/vop/plugins/ssh/ssh.plugin +1 -0
  47. data/lib/vop/shell.rb +52 -0
  48. data/lib/vop/shell/backend.rb +28 -0
  49. data/lib/vop/shell/base_shell.rb +112 -0
  50. data/lib/vop/shell/formatter.rb +46 -0
  51. data/lib/vop/shell/vop_shell_backend.rb +257 -0
  52. data/lib/vop/version.rb +3 -0
  53. data/vop.gemspec +31 -0
  54. metadata +223 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5225000e9764e0e3a47151ecfbbd7cd02d58e58
4
+ data.tar.gz: 26bd6366f5abff2a055feb239d6f85e4aa1ddefd
5
+ SHA512:
6
+ metadata.gz: 40e2acbd8735da52baafb4c01a6df32b514573d8c8cb4490401132c199554a370c687e69a041f167363b25f7865f44e9f4e58bc2d1717243a8d0d3153165d60e
7
+ data.tar.gz: dfde831a155f30531cec4396eff46870ba9ba22fc622c3f9a9087732276187993c99a1dea045c3b0a42d0d15a1435ad5dff0dcbc0f1812ecb034e48beeb8066d
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vop (0.3.0)
5
+ activesupport
6
+ docopt
7
+ net-scp
8
+ net-ssh
9
+ pry
10
+ terminal-table
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ activesupport (5.0.0.1)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ coderay (1.1.1)
21
+ concurrent-ruby (1.0.2)
22
+ diff-lcs (1.2.5)
23
+ docopt (0.5.0)
24
+ i18n (0.7.0)
25
+ method_source (0.8.2)
26
+ minitest (5.10.1)
27
+ net-scp (1.2.1)
28
+ net-ssh (>= 2.6.5)
29
+ net-ssh (3.2.0)
30
+ pry (0.10.3)
31
+ coderay (~> 1.1.0)
32
+ method_source (~> 0.8.1)
33
+ slop (~> 3.4)
34
+ rake (11.3.0)
35
+ rspec (3.4.0)
36
+ rspec-core (~> 3.4.0)
37
+ rspec-expectations (~> 3.4.0)
38
+ rspec-mocks (~> 3.4.0)
39
+ rspec-core (3.4.1)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-expectations (3.4.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.4.0)
44
+ rspec-mocks (3.4.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.4.0)
47
+ rspec-support (3.4.1)
48
+ slop (3.6.0)
49
+ terminal-table (1.7.3)
50
+ unicode-display_width (~> 1.1.1)
51
+ thread_safe (0.3.5)
52
+ tzinfo (1.2.2)
53
+ thread_safe (~> 0.1)
54
+ unicode-display_width (1.1.1)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ bundler (~> 1.10)
61
+ rake
62
+ rspec
63
+ vop!
64
+
65
+ BUNDLED WITH
66
+ 1.10.6
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # vop
2
+ new and improved, now with twice the vitamins!
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/vop.rb ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+
5
+ $: << File.join(Pathname.new(File.join(File.dirname(__FILE__), '..')).realpath, 'lib')
6
+
7
+ require 'vop/shell'
8
+ require 'docopt'
9
+ require 'pp'
10
+
11
+ begin
12
+ shell = Vop::Shell::setup()
13
+ if shell.options["--execute"]
14
+ last_response = shell.execute(shell.options["--execute"])
15
+ else
16
+ last_response = shell.run_cli
17
+ end
18
+
19
+ # TODO exit_status = last_response && last_response.status == Vop.Status::OK ? 0 : 1
20
+ exit 0
21
+ rescue => detail
22
+ if detail.is_a? Docopt::Exit
23
+ puts detail.message
24
+ else
25
+ $stderr.puts "error : #{detail.message}\n#{detail.backtrace[0..9].join("\n")}"
26
+ exit 42
27
+ end
28
+ end
data/bin/vop.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4
+ ruby $DIR/vop.rb $*
data/exe/vop ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+
5
+ $: << File.join(Pathname.new(File.join(File.dirname(__FILE__), '..')).realpath, 'lib')
6
+
7
+ require 'vop/shell'
8
+ require 'docopt'
9
+ require 'pp'
10
+
11
+ begin
12
+ shell = Vop::Shell::setup()
13
+ if shell.options["--execute"]
14
+ last_response = shell.execute(shell.options["--execute"])
15
+ else
16
+ last_response = shell.run_cli
17
+ end
18
+
19
+ # TODO exit_status = last_response && last_response.status == Vop.Status::OK ? 0 : 1
20
+ exit 0
21
+ rescue => detail
22
+ if detail.is_a? Docopt::Exit
23
+ puts detail.message
24
+ else
25
+ $stderr.puts "error : #{detail.message}\n#{detail.backtrace[0..9].join("\n")}"
26
+ exit 42
27
+ end
28
+ end
data/lib/vop.rb ADDED
@@ -0,0 +1,242 @@
1
+ require 'pp'
2
+ require 'logger'
3
+ require 'pathname'
4
+
5
+ require 'vop/version'
6
+ require 'vop/plugin_loader'
7
+ require 'active_support/inflector'
8
+
9
+ module Vop
10
+
11
+ VOP_ROOT = Pathname.new(File.join(File.dirname(__FILE__), '..')).realpath
12
+ CORE_PLUGIN_PATH = Pathname.new(File.join(File.dirname(__FILE__), 'vop', 'plugins')).realpath
13
+ #CONFIG_PATH = '/etc/vop'
14
+ #PLUGIN_CONFIG_PATH = File.join(CONFIG_PATH, 'plugins.d')
15
+
16
+ class Vop
17
+
18
+ DEFAULTS = {
19
+ :search_path => [
20
+ File.join(VOP_ROOT, '..', 'plugins/standard'),
21
+ File.join(VOP_ROOT, '..', 'plugins/extended')
22
+ ],
23
+ :command_dir_name => 'commands',
24
+ :plugin_config => {
25
+
26
+ }
27
+ }
28
+
29
+ attr_reader :config
30
+
31
+ attr_reader :plugins
32
+ attr_reader :commands
33
+
34
+ def initialize(options = {})
35
+ at_exit {
36
+ self.shutdown
37
+ }
38
+
39
+ @version = ::Vop::VERSION
40
+
41
+ @config = DEFAULTS
42
+ @config.merge! options
43
+
44
+ $logger = Logger.new(STDOUT)
45
+ $logger.level = options['--verbose'] ? Logger::DEBUG : Logger::INFO
46
+
47
+ _reset
48
+
49
+ $logger.info "virtualop (#{@version}) init complete."
50
+ $logger.info "hello."
51
+ end
52
+
53
+ def _pry
54
+ binding.pry
55
+ end
56
+
57
+ def _reset
58
+ $logger.debug "loading..."
59
+
60
+ load_plugins
61
+
62
+ $logger.info "loaded #{@commands.size} commands from #{@plugins.size} plugins"
63
+ end
64
+
65
+ def _search_path
66
+ [ CORE_PLUGIN_PATH ] + config[:search_path]
67
+ end
68
+
69
+ def inspect
70
+ chunk_size = 25
71
+ plugin_string = @plugins.keys.sort[0..chunk_size-1].join(' ')
72
+ if @plugins.length > chunk_size
73
+ plugin_string += " + #{@plugins.length - chunk_size} more"
74
+ end
75
+ "vop #{@version} (#{plugin_string})"
76
+ end
77
+
78
+ def eat(command)
79
+ @commands[command.short_name] = command
80
+
81
+ self.class.send(:define_method, command.short_name) do |*args|
82
+ ruby_args = args.length > 0 ? args[0] : {}
83
+ self.execute(command.short_name, ruby_args)
84
+ end
85
+ end
86
+
87
+ def load_plugins
88
+ @plugins = {}
89
+ @commands = {}
90
+ @hooks = Hash.new { |h,k| h[k] = [] }
91
+
92
+ # step 1 : read plugins from all existing source dirs
93
+ candidates = _search_path
94
+ search_path = candidates.select { |path| File.exists? path }
95
+ search_path.each do |path|
96
+ PluginLoader.read(self, path)
97
+ end
98
+
99
+ # step 2 : activate plugins (in the right order)
100
+ ordered_plugins.each do |plugin|
101
+ plugin.init
102
+ end
103
+
104
+ # step 3 : expand entities
105
+ @plugins['core'].state[:entities].each do |entity|
106
+ entity_name = entity[:name]
107
+ entity_command = @commands[entity_name]
108
+ list_command_name = "list_#{entity_name.pluralize(42)}"
109
+ $logger.debug "generating #{list_command_name}"
110
+ list_command = Command.new(entity_command.plugin, list_command_name)
111
+
112
+ if entity[:options][:on]
113
+ list_command.params << {
114
+ :name => entity[:options][:on],
115
+ :multi => false,
116
+ :mandatory => true,
117
+ :default_param => true
118
+ }
119
+ end
120
+ list_command.block = entity_command.param(entity[:key])[:lookup]
121
+ eat(list_command)
122
+ # TODO add pseudo source code so that `source <list_command_name>` works
123
+ end
124
+
125
+ # TODO add pre-flight hook so that plugins can attach logic to execute here
126
+ end
127
+
128
+ def resolve(plugin, resolved, unresolved, level = 0)
129
+ unresolved << plugin.name
130
+
131
+ plugin.dependencies.each do |dep|
132
+ unless resolved.include? dep
133
+ if unresolved.include? dep
134
+ raise "running in circles #{plugin.name} -> #{dep}"
135
+ else
136
+ unless @plugins.has_key? dep
137
+ raise "missing dependency: #{plugin.name} depends on #{dep}"
138
+ end
139
+ dependency = @plugins[dep]
140
+ resolve(dependency, resolved, unresolved, level + 1)
141
+ end
142
+ end
143
+ end
144
+ resolved << plugin.name
145
+ end
146
+
147
+ def ordered_plugins
148
+ root_plugin = Plugin.new(self, '__root__', nil)
149
+ @plugins.values.each do |plugin|
150
+ root_plugin.dependencies << plugin.name
151
+ end
152
+ resolved = []
153
+ unresolved = []
154
+
155
+ resolve(root_plugin, resolved, unresolved)
156
+ resolved.delete_if { |x| x == root_plugin.name }
157
+
158
+ resolved.map { |x| @plugins[x] }
159
+ end
160
+
161
+ def command(name)
162
+ unless commands.has_key?(name)
163
+ raise "no such command : #{name}"
164
+ end
165
+
166
+ commands[name]
167
+ end
168
+
169
+ def core
170
+ @plugins['core']
171
+ end
172
+
173
+ def hook(name, plugin_name)
174
+ @hooks[name] << plugin_name
175
+ end
176
+
177
+ def call_hook(name, *payload)
178
+ @hooks[name].each do |plugin_name, block|
179
+ @plugins[plugin_name].call_hook(name, payload)
180
+ end
181
+ end
182
+
183
+ def before_execute(request)
184
+ #puts ">> #{request.command_name} #{request.param_values.keys}"
185
+ call_hook :before_execute, request
186
+ end
187
+
188
+ def after_execute(request, response)
189
+ #puts "<< #{request.command_name} #{response.result}"
190
+ call_hook :after_execute, request, response
191
+ end
192
+
193
+ def execute(command_name, param_values, extra = {})
194
+ request = Request.new(command_name, param_values, extra)
195
+ before_execute(request)
196
+
197
+ (result, context) = execute_command(command_name, param_values, extra)
198
+
199
+ response = Response.new(result, context)
200
+ after_execute(request, response)
201
+
202
+ result
203
+ end
204
+
205
+ def execute_command(command_name, param_values, extra = {})
206
+ $logger.debug "+++ #{command_name} +++"
207
+ command = @commands[command_name]
208
+
209
+ command.execute(param_values, extra)
210
+ end
211
+
212
+ def shutdown()
213
+ $logger.debug "shutting down..."
214
+ end
215
+
216
+ end
217
+
218
+ class Request
219
+
220
+ attr_reader :command_name, :param_values
221
+
222
+ def initialize(command_name, param_values, extra = {})
223
+ @command_name = command_name
224
+ @param_values = param_values
225
+ # fuck extra
226
+ end
227
+
228
+ end
229
+
230
+ class Response
231
+
232
+ attr_reader :result
233
+
234
+ def initialize(result, context)
235
+ @result = result
236
+ @context = context
237
+ end
238
+
239
+ end
240
+
241
+
242
+ end