nutella_framework 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/README.md +3 -4
  4. data/VERSION +1 -1
  5. data/data/startup +3 -3
  6. data/framework_components/example_framework_interface/dandelion-flowers-card.jpg +0 -0
  7. data/framework_components/example_framework_interface/index.html +18 -0
  8. data/framework_components/main_interface/main_interface_bot.rb +183 -0
  9. data/framework_components/main_interface/public/index.html +54 -0
  10. data/framework_components/main_interface/views/index.erb +63 -0
  11. data/framework_components/order.json.example +6 -0
  12. data/framework_components/runs_list_bot/app_runs_list_bot.rb +15 -0
  13. data/lib/{core/commands → commands}/broker.rb +2 -2
  14. data/lib/{core/commands → commands}/checkup.rb +2 -2
  15. data/lib/commands/compile.rb +13 -0
  16. data/lib/commands/dependencies.rb +13 -0
  17. data/lib/commands/help.rb +35 -0
  18. data/lib/{core/commands → commands}/install.rb +19 -15
  19. data/lib/commands/meta/command.rb +19 -0
  20. data/lib/commands/meta/run_command.rb +114 -0
  21. data/lib/{core → commands/meta}/template_command.rb +1 -1
  22. data/lib/commands/new.rb +60 -0
  23. data/lib/commands/runs.rb +54 -0
  24. data/lib/commands/start.rb +321 -0
  25. data/lib/commands/stop.rb +101 -0
  26. data/lib/{core/commands → commands}/template.rb +59 -39
  27. data/lib/config/current_app_utils.rb +51 -0
  28. data/lib/config/persisted_hash.rb +14 -12
  29. data/lib/config/runlist.rb +116 -16
  30. data/lib/{cli → core}/nutella_cli.rb +1 -1
  31. data/lib/core/nutella_core.rb +2 -6
  32. data/lib/nutella_framework.rb +5 -3
  33. data/lib/nutella_lib_framework/api.rb +333 -0
  34. data/lib/tmux/tmux.rb +76 -0
  35. data/nutella_framework.gemspec +42 -29
  36. data/test/commands/test_cmd_cli_params_parsing.rb +56 -0
  37. data/test/commands/test_command_template.rb +31 -0
  38. data/test/config/test_current_app_utils.rb +34 -0
  39. data/test/config/test_persisted_hash.rb +48 -0
  40. data/test/config/test_runlist.rb +15 -23
  41. data/test/framework_apis/test_framework_api.rb +74 -0
  42. metadata +74 -27
  43. data/actors/main_interface/main_interface_bot.rb +0 -163
  44. data/actors/main_interface/public/index.html +0 -51
  45. data/actors/main_interface/views/index.erb +0 -45
  46. data/lib/config/current_project.rb +0 -58
  47. data/lib/core/command.rb +0 -12
  48. data/lib/core/commands/compile.rb +0 -21
  49. data/lib/core/commands/dependencies.rb +0 -21
  50. data/lib/core/commands/help.rb +0 -28
  51. data/lib/core/commands/new.rb +0 -60
  52. data/lib/core/commands/runs.rb +0 -52
  53. data/lib/core/commands/start.rb +0 -271
  54. data/lib/core/commands/stop.rb +0 -100
  55. data/lib/core/run_command.rb +0 -106
  56. data/lib/core/tmux.rb +0 -38
  57. data/test/config/test_config.rb +0 -48
  58. data/test/config/test_project.rb +0 -34
  59. data/test/test_run_command.rb +0 -54
  60. /data/{actors → framework_components}/main_interface/startup +0 -0
  61. /data/{actors → framework_components}/main_interface/views/not_found_404.erb +0 -0
@@ -0,0 +1,333 @@
1
+ require 'nutella_lib'
2
+ require 'config/runlist'
3
+
4
+ module Nutella
5
+
6
+
7
+ # Initializes this component as a framework component
8
+ # @param [String] broker_hostname
9
+ # @param [String] component_id
10
+ def self.init_as_f_component( broker_hostname, component_id )
11
+ @app_id = nil
12
+ @run_id = nil
13
+ @component_id = component_id
14
+ @resource_id = nil
15
+ @mqtt = SimpleMQTTClient.new broker_hostname
16
+ end
17
+
18
+
19
+ # Parse command line arguments for framework level components
20
+ #
21
+ # @param [Array] args command line arguments array
22
+ # @return [String] broker
23
+ def self.parse_f_component_args(args)
24
+ if args.length < 1
25
+ STDERR.puts 'Couldn\'t read broker address from the command line, impossible to initialize component!'
26
+ return
27
+ end
28
+ return args[0]
29
+ end
30
+
31
+
32
+ module Net
33
+
34
+ # Provides access to the net.app sub-module
35
+ def Net.f; Nutella::Net::Framework end
36
+
37
+
38
+ # This module implements the pub/sub and request/response APIs at the framework-level
39
+ module Framework
40
+
41
+
42
+ # @!group Framework-level communication APIs
43
+
44
+ # Subscribes to a channel or to a set of channels at the framework-level.
45
+ #
46
+ # @param [String] channel the framework-level channel or filter we are subscribing to. Can contain wildcard(s)
47
+ # @param [Proc] callback a lambda expression that is fired whenever a message is received.
48
+ # The passed callback takes the following parameters:
49
+ # - [String] message: the received message. Messages that are not JSON are discarded.
50
+ # - [String] channel: the framework-level channel the message was received on (optional, only for wildcard subscriptions)
51
+ # - [Hash] from: the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
52
+ def self.subscribe (channel, callback)
53
+ Nutella::Net.subscribe_to(channel, callback, nil, nil)
54
+ end
55
+
56
+
57
+ # Un-subscribes from a framework-level channel
58
+ #
59
+ # @param [String] channel the framework-level channel we want to unsubscribe from. Can contain wildcard(s).
60
+ def self.unsubscribe( channel )
61
+ Nutella::Net.unsubscribe_to(channel, nil, nil)
62
+ end
63
+
64
+
65
+ # Publishes a message to an framework-level channel
66
+ #
67
+ # @param [String] channel the framework-level channel we want to publish the message to. *CANNOT* contain wildcard(s)!
68
+ # @param [Object] message the message we are publishing. This can be,
69
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
70
+ def self.publish(channel, message=nil)
71
+ Nutella::Net.publish_to(channel, message, nil, nil)
72
+ end
73
+
74
+
75
+ # Performs a synchronous request at the framework-level
76
+ #
77
+ # @param [String] channel the framework-level channel we want to make the request to. *CANNOT* contain wildcard(s)!
78
+ # @param [Object] message the body of request. This can be,
79
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
80
+ def self.sync_request ( channel, message=nil )
81
+ Nutella::Net.sync_request_to(channel, message, nil, nil)
82
+ end
83
+
84
+
85
+ # Performs an asynchronous request at the framework-level
86
+ #
87
+ # @param [String] channel the framework-level channel we want to make the request to. *CANNOT* contain wildcard(s)!
88
+ # @param [Object] message the body of request. This can be,
89
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
90
+ # @param [Proc] callback the callback that is fired whenever a response is received. It takes one parameter (response).
91
+ def self.async_request ( channel, message=nil, callback )
92
+ Nutella::Net.async_request_to(channel, message, callback, nil, nil)
93
+ end
94
+
95
+
96
+ # Handles requests on a certain framework-level channel
97
+ #
98
+ # @param [String] channel tha framework-level channel we want to listen for requests on. Can contain wildcard(s).
99
+ # @param [Proc] callback a lambda expression that is fired whenever a message is received.
100
+ # The passed callback takes the following parameters:
101
+ # - [String] the received message (payload). Messages that are not JSON are discarded.
102
+ # - [Hash] the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
103
+ # - [*returns* Hash] The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
104
+ def self.handle_requests( channel, callback )
105
+ Nutella::Net.handle_requests_on(channel, callback, nil, nil)
106
+ end
107
+
108
+ # @!endgroup
109
+
110
+ # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
111
+
112
+ # @!group Framework-level APIs to communicate at the run-level
113
+
114
+ # Allows framework-level APIs to subscribe to a run-level channel within a specific run
115
+ #
116
+ # @param [String] app_id the specific application we are subscribing to
117
+ # @param [String] run_id the specific run we are subscribing to
118
+ # @param [String] channel the run-level channel we are subscribing to. Can be wildcard.
119
+ # @param [Proc] callback the callback that is fired whenever a message is received on the channel.
120
+ # The passed callback takes the following parameters:
121
+ # - [String] message: the received message. Messages that are not JSON are discarded.
122
+ # - [String] channel: the framework-level channel the message was received on (optional, only for wildcard subscriptions)
123
+ # - [Hash] from: the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
124
+ def self.subscribe_to_run( app_id, run_id, channel, callback )
125
+ Nutella::Net.subscribe_to(channel, callback, app_id, run_id)
126
+ end
127
+
128
+
129
+ # Allows framework-level APIs to unsubscribe from a run-level channel within a specific run
130
+ #
131
+ # @param [String] app_id the specific application we are un-subscribing from
132
+ # @param [String] run_id the specific run we are un-subscribing from
133
+ # @param [String] channel the run-level channel we want to unsubscribe from. Can contain wildcard(s).
134
+ def self.unsubscribe_to_run( app_id, run_id, channel )
135
+ Nutella::Net.unsubscribe_to(channel, app_id, run_id)
136
+ end
137
+
138
+
139
+ # Allows framework-level APIs to publish to a run-level channel within a specific run
140
+ #
141
+ # @param [String] app_id the specific application we are publishing to
142
+ # @param [String] run_id the specific run we are publishing to
143
+ # @param [String] channel the run-level channel we want to publish the message to. *CANNOT* contain wildcard(s)!
144
+ # @param [String] message the message we are publishing. This can be,
145
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
146
+ def self.publish_to_run( app_id, run_id, channel, message )
147
+ Nutella::Net.publish_to(channel, message, app_id, run_id)
148
+ end
149
+
150
+
151
+ # Allows framework-level APIs to make a synchronous request to a run-level channel within a specific run
152
+ #
153
+ # @param [String] app_id the specific application we are making the request to
154
+ # @param [String] run_id the specific run we are making the request to
155
+ # @param [String] channel the channel we want to make the request to. *CANNOT* contain wildcard(s)!
156
+ # @param [Object] request the body of request. This can be,
157
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
158
+ def self.sync_request_to_run( app_id, run_id, channel, request)
159
+ Nutella::Net.sync_request_to(channel, request, app_id, run_id)
160
+ end
161
+
162
+
163
+ # Allows framework-level APIs to make an asynchronous request to a run-level channel within a specific run
164
+ #
165
+ # @param [String] app_id the specific application we are making the request to
166
+ # @param [String] run_id the specific run we are making the request to
167
+ # @param [String] channel the channel we want to make the request to. *CANNOT* contain wildcard(s)!
168
+ # @param [Object] request the body of request. This can be,
169
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
170
+ # @param [Proc] callback the callback that is fired whenever a response is received. It takes one parameter (response).
171
+ def self.async_request_to_run( app_id, run_id, channel, request, callback)
172
+ Nutella::Net.async_request_to(channel, request, callback, app_id, run_id)
173
+ end
174
+
175
+
176
+ # Allows framework-level APIs to handle requests on a run-level channel within a specific run
177
+ #
178
+ # @param [String] app_id the specific application requests are coming from
179
+ # @param [String] run_id the specific run requests are coming from
180
+ # @param [String] channel we want to listen for requests on. Can contain wildcard(s).
181
+ # @param [Proc] callback a lambda expression that is fired whenever a message is received.
182
+ # The passed callback takes the following parameters:
183
+ # - [String] the received message (payload). Messages that are not JSON are discarded.
184
+ # - [Hash] the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
185
+ # - [*returns* Hash] The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
186
+ def self.handle_requests_on_run( app_id, run_id, channel, callback )
187
+ Nutella::Net.handle_requests_on(channel, callback, app_id, run_id)
188
+ end
189
+
190
+ # @!endgroup
191
+
192
+ # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
193
+
194
+ # @!group Framework-level APIs to communicate at the run-level (broadcast)
195
+
196
+ # Allows framework-level APIs to subscribe to a run-level channel *for ALL runs*
197
+ #
198
+ # @param [String] channel the run-level channel we are subscribing to. Can be wildcard.
199
+ # @param [Proc] callback the callback that is fired whenever a message is received on the channel.
200
+ # The passed callback takes the following parameters:
201
+ # - [String] message: the received message. Messages that are not JSON are discarded.
202
+ # - [String] app_id: the app_id of the channel the message was sent on
203
+ # - [String] run_id: the run_id of the channel the message was sent on
204
+ # - [Hash] from: the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
205
+ def self.subscribe_to_all_runs( channel, callback )
206
+ # Check the passed callback has the right number of arguments
207
+ raise 'You need to pass a callback with 4 parameters (payload, app_id, run_id, from) when subscribing to all runs!' if callback.parameters.length!=4
208
+ # Pad channel
209
+ padded_channel = Nutella::Net.pad_channel(channel, '+', '+')
210
+ mqtt_cb = lambda do |mqtt_message, mqtt_channel|
211
+ begin
212
+ type, from, payload, _ = Nutella::Net.extract_fields_from_message mqtt_message
213
+ app_id, run_id = self.extract_run_id_and_app_id mqtt_channel
214
+ callback.call(payload, app_id, run_id, from) if type=='publish'
215
+ rescue JSON::ParserError
216
+ # Make sure the message is JSON, if not drop the message
217
+ return
218
+ rescue
219
+ # Check the passed callback has the right number of arguments
220
+ STDERR.puts "The callback you passed to subscribe has the #{$!}: it needs 'payload', 'app_id', 'run_id' and 'from'"
221
+ end
222
+ end
223
+ # Add to subscriptions, save mqtt callback and subscribe
224
+ Nutella::Net.subscriptions.push padded_channel
225
+ Nutella::Net.callbacks.push mqtt_cb
226
+ Nutella.mqtt.subscribe( padded_channel, mqtt_cb )
227
+ end
228
+
229
+
230
+ # Allows framework-level APIs to unsubscribe from a run-level channel *for ALL runs*
231
+ #
232
+ # @param [String] channel the run-level channel we want to unsubscribe from. Can contain wildcard(s).
233
+ def self.unsubscribe_from_all_runs( channel )
234
+ Nutella::Net.unsubscribe_to(channel, '+', '+')
235
+ end
236
+
237
+
238
+ # Allows framework-level APIs to publish a message to a run-level channel *for ALL runs*
239
+ #
240
+ # @param [String] channel the run-level channel we want to publish the message to. *CANNOT* contain wildcard(s)!
241
+ # @param [Object] message the message we are publishing. This can be,
242
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
243
+ def self.publish_to_all_runs( channel, message )
244
+ Nutella.runlist.all_runs.each do |app_id, _|
245
+ Nutella.runlist.runs_for_app(app_id).each do |run_id|
246
+ Nutella::Net.publish_to(channel, message, app_id, run_id)
247
+ end
248
+ end
249
+ end
250
+
251
+
252
+ # Allows framework-level APIs to send a request to a run-level channel *for ALL runs*
253
+ #
254
+ # @param [String] channel the run-level channel we want to make the request to. *CANNOT* contain wildcard(s)!
255
+ # @param [Object] request the body of request. This can be,
256
+ # nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
257
+ # @param [Proc] callback the callback that is fired whenever a response is received. It takes one parameter (response).
258
+ def self.async_request_to_all_runs(channel, request, callback)
259
+ Nutella.runlist.all_runs.each do |app_id, _|
260
+ Nutella.runlist.runs_for_app(app_id).each do |run_id|
261
+ Nutella::Net.async_request_to(channel, request, callback, app_id, run_id)
262
+ end
263
+ end
264
+ end
265
+
266
+
267
+ # Allows framework-level APIs to handle requests to a run-level channel *for ALL runs*
268
+ #
269
+ # @param [String] channel tha run-level channel we want to listen for requests on. Can contain wildcard(s).
270
+ # @param [Proc] callback a lambda expression that is fired whenever a message is received.
271
+ # The passed callback takes the following parameters:
272
+ # - [String] the received message (request). Messages that are not JSON are discarded.
273
+ # - [String] app_id: the app_id of the channel the request was sent on
274
+ # - [String] run_id: the run_id of the channel the request was sent on
275
+ # - [Hash] the sender's identifiers (from containing, run_id, app_id, component_id and optionally resource_id)
276
+ # - [*returns* Hash] The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
277
+ def self.handle_requests_on_all_runs(channel, callback)
278
+ # Check the passed callback has the right number of arguments
279
+ raise 'You need to pass a callback with 4 parameters (request, run_id, from) when handling requests!' if callback.parameters.length!=4
280
+ # Pad channel
281
+ padded_channel = Nutella::Net.pad_channel(channel, '+', '+')
282
+ mqtt_cb = lambda do |request, mqtt_channel|
283
+ begin
284
+ # Extract nutella fields
285
+ type, from, payload, id = Nutella::Net.extract_fields_from_message request
286
+ app_id, run_id = self.extract_run_id_and_app_id mqtt_channel
287
+ # Only handle requests that have proper id set
288
+ return if type!='request' || id.nil?
289
+ # Execute callback and send response
290
+ m = Net.prepare_message_for_response( callback.call( payload, app_id, run_id, from), id )
291
+ Nutella.mqtt.publish( mqtt_channel, m )
292
+ rescue JSON::ParserError
293
+ # Make sure that request contains JSON, if not drop the message
294
+ return
295
+ rescue
296
+ # Check the passed callback has the right number of arguments
297
+ STDERR.puts "The callback you passed to subscribe has the #{$!}: it needs 'request', 'app_id', 'run_id' and 'from'"
298
+ end
299
+ end
300
+ # Subscribe to the channel
301
+ Nutella.mqtt.subscribe( padded_channel, mqtt_cb )
302
+ end
303
+
304
+ # @!endgroup
305
+
306
+ # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
307
+
308
+ # @!group Framework-level APIs to communicate at the application-level
309
+
310
+ # TODO
311
+
312
+ # @!endgroup
313
+
314
+ # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
315
+
316
+ # @!group Framework-level APIs to communicate at the application-level (broadcast)
317
+
318
+ # TODO
319
+
320
+ # @!endgroup
321
+
322
+ private
323
+
324
+ def self.extract_run_id_and_app_id( mqtt_channel )
325
+ sp = mqtt_channel.sub('/nutella/apps/', '').split('/')
326
+ return sp[0], sp[2]
327
+ end
328
+
329
+
330
+ end
331
+
332
+ end
333
+ end
data/lib/tmux/tmux.rb ADDED
@@ -0,0 +1,76 @@
1
+ module Nutella
2
+
3
+ class Tmux
4
+
5
+ def initialize( app_id, run_id )
6
+ @app_id = app_id
7
+ @run_id = run_id
8
+ end
9
+
10
+ # Creates a new window (and session if necessary) to start a run-level bot
11
+ def new_bot_window( bot )
12
+ # Create session name
13
+ sn = Tmux.session_name(@app_id, @run_id)
14
+ # Create session
15
+ create_tmux_window(sn, bot)
16
+ # Start bot
17
+ `tmux send-keys "cd bots/#{bot};./startup #{Nutella.config['broker']} #{@app_id} #{@run_id}" C-m`
18
+ end
19
+
20
+ # Creates a new window (and session if necessary) to start an app-level bot
21
+ def new_app_bot_window( bot )
22
+ # Create session name
23
+ sn = Tmux.app_bot_session_name(@app_id)
24
+ # Create session
25
+ create_tmux_window(sn, bot)
26
+ # Start bot
27
+ `tmux send-keys "cd bots/#{bot};./startup #{Nutella.config['broker']} #{@app_id}" C-m`
28
+ end
29
+
30
+ # Removes a run-level session associated to a particular run
31
+ def self.kill_run_session( app_id, run_id )
32
+ `tmux kill-session -t #{session_name(app_id, run_id)} &> /dev/null`
33
+ end
34
+
35
+ # Removes the app-level session associated to a particular application
36
+ def self.kill_app_session( app_id )
37
+ `tmux kill-session -t #{app_bot_session_name( app_id )} &> /dev/null`
38
+ end
39
+
40
+ # Returns true if a tmux session with a certain id exists
41
+ def self.session_exist?( session_id )
42
+ system( "tmux has-session -t #{session_id} &> /dev/null" )
43
+ end
44
+
45
+ # Builds a session name for run-level session
46
+ def self.session_name( app_id, run_id )
47
+ "#{app_id}/#{run_id}"
48
+ end
49
+
50
+ # Builds a session name for an app-level session
51
+ def self.app_bot_session_name( app_id )
52
+ "#{app_id}-app-bots"
53
+ end
54
+
55
+
56
+ private
57
+
58
+ def create_tmux_window( session_name, bot )
59
+ # If a session already exists, simply create a new window (-n) for 'bot'.
60
+ # -k destroys the window if it can't be created
61
+ # -P prints info about creation of window
62
+ # If there is no sessions, let's create one (-s) and, at the same time, create a new window for the bot
63
+ if defined? @windows
64
+ `tmux new-window -kP -n #{bot} &> /dev/null`
65
+ @windows.push bot
66
+ else
67
+ `tmux new-session -d -s #{session_name} -n #{bot} &> /dev/null`
68
+ @windows = [bot]
69
+ end
70
+ # Select the last window we launched
71
+ `tmux select-window -t #{session_name}:#{@windows.length-1} &> /dev/null`
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: nutella_framework 0.3.1 ruby lib
5
+ # stub: nutella_framework 0.4.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "nutella_framework"
9
- s.version = "0.3.1"
9
+ s.version = "0.4.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Alessandro Gnoli"]
14
- s.date = "2015-02-26"
14
+ s.date = "2015-03-13"
15
15
  s.description = "Nutella is a framework to create and run classroom narratives"
16
16
  s.email = "tebemis@gmail.com"
17
17
  s.executables = ["nutella"]
@@ -27,46 +27,53 @@ Gem::Specification.new do |s|
27
27
  "README.md",
28
28
  "Rakefile",
29
29
  "VERSION",
30
- "actors/main_interface/main_interface_bot.rb",
31
- "actors/main_interface/public/index.html",
32
- "actors/main_interface/startup",
33
- "actors/main_interface/views/index.erb",
34
- "actors/main_interface/views/not_found_404.erb",
35
30
  "bin/nutella",
36
31
  "data/index.html",
37
32
  "data/startup",
38
- "lib/cli/nutella_cli.rb",
33
+ "framework_components/example_framework_interface/dandelion-flowers-card.jpg",
34
+ "framework_components/example_framework_interface/index.html",
35
+ "framework_components/main_interface/main_interface_bot.rb",
36
+ "framework_components/main_interface/public/index.html",
37
+ "framework_components/main_interface/startup",
38
+ "framework_components/main_interface/views/index.erb",
39
+ "framework_components/main_interface/views/not_found_404.erb",
40
+ "framework_components/order.json.example",
41
+ "framework_components/runs_list_bot/app_runs_list_bot.rb",
42
+ "lib/commands/broker.rb",
43
+ "lib/commands/checkup.rb",
44
+ "lib/commands/compile.rb",
45
+ "lib/commands/dependencies.rb",
46
+ "lib/commands/help.rb",
47
+ "lib/commands/install.rb",
48
+ "lib/commands/meta/command.rb",
49
+ "lib/commands/meta/run_command.rb",
50
+ "lib/commands/meta/template_command.rb",
51
+ "lib/commands/new.rb",
52
+ "lib/commands/runs.rb",
53
+ "lib/commands/start.rb",
54
+ "lib/commands/stop.rb",
55
+ "lib/commands/template.rb",
39
56
  "lib/config/config.rb",
40
- "lib/config/current_project.rb",
57
+ "lib/config/current_app_utils.rb",
41
58
  "lib/config/persisted_hash.rb",
42
59
  "lib/config/runlist.rb",
43
- "lib/core/command.rb",
44
- "lib/core/commands/broker.rb",
45
- "lib/core/commands/checkup.rb",
46
- "lib/core/commands/compile.rb",
47
- "lib/core/commands/dependencies.rb",
48
- "lib/core/commands/help.rb",
49
- "lib/core/commands/install.rb",
50
- "lib/core/commands/new.rb",
51
- "lib/core/commands/runs.rb",
52
- "lib/core/commands/start.rb",
53
- "lib/core/commands/stop.rb",
54
- "lib/core/commands/template.rb",
60
+ "lib/core/nutella_cli.rb",
55
61
  "lib/core/nutella_core.rb",
56
- "lib/core/run_command.rb",
57
- "lib/core/template_command.rb",
58
- "lib/core/tmux.rb",
59
62
  "lib/logging/nutella_logger-remote.rb",
60
63
  "lib/logging/nutella_logger.rb",
61
64
  "lib/logging/nutella_logging.rb",
62
65
  "lib/nutella_framework.rb",
66
+ "lib/nutella_lib_framework/api.rb",
67
+ "lib/tmux/tmux.rb",
63
68
  "nutella_framework.gemspec",
64
- "test/config/test_config.rb",
65
- "test/config/test_project.rb",
69
+ "test/commands/test_cmd_cli_params_parsing.rb",
70
+ "test/commands/test_command_template.rb",
71
+ "test/config/test_current_app_utils.rb",
72
+ "test/config/test_persisted_hash.rb",
66
73
  "test/config/test_runlist.rb",
74
+ "test/framework_apis/test_framework_api.rb",
67
75
  "test/helper.rb",
68
- "test/logging/test_logging.rb",
69
- "test/test_run_command.rb"
76
+ "test/logging/test_logging.rb"
70
77
  ]
71
78
  s.homepage = "https://github.com/nutella-framework/nutella_framework"
72
79
  s.licenses = ["MIT"]
@@ -82,8 +89,10 @@ Gem::Specification.new do |s|
82
89
  s.add_runtime_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
83
90
  s.add_runtime_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
84
91
  s.add_runtime_dependency(%q<sinatra>, [">= 1.4.5", "~> 1.4.5"])
92
+ s.add_runtime_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
85
93
  s.add_runtime_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
86
94
  s.add_runtime_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
95
+ s.add_runtime_dependency(%q<nutella_lib>, [">= 0.4.0", "~> 0.4.0"])
87
96
  s.add_development_dependency(%q<shoulda>, [">= 3", "~> 3"])
88
97
  s.add_development_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
89
98
  s.add_development_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
@@ -96,8 +105,10 @@ Gem::Specification.new do |s|
96
105
  s.add_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
97
106
  s.add_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
98
107
  s.add_dependency(%q<sinatra>, [">= 1.4.5", "~> 1.4.5"])
108
+ s.add_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
99
109
  s.add_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
100
110
  s.add_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
111
+ s.add_dependency(%q<nutella_lib>, [">= 0.4.0", "~> 0.4.0"])
101
112
  s.add_dependency(%q<shoulda>, [">= 3", "~> 3"])
102
113
  s.add_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
103
114
  s.add_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
@@ -111,8 +122,10 @@ Gem::Specification.new do |s|
111
122
  s.add_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
112
123
  s.add_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
113
124
  s.add_dependency(%q<sinatra>, [">= 1.4.5", "~> 1.4.5"])
125
+ s.add_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
114
126
  s.add_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
115
127
  s.add_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
128
+ s.add_dependency(%q<nutella_lib>, [">= 0.4.0", "~> 0.4.0"])
116
129
  s.add_dependency(%q<shoulda>, [">= 3", "~> 3"])
117
130
  s.add_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
118
131
  s.add_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
@@ -0,0 +1,56 @@
1
+ require 'helper'
2
+
3
+ module Nutella
4
+
5
+ class TestCmdCLIParamsParsing < MiniTest::Test
6
+
7
+ def setup
8
+ @run_cmd = RunCommand.new
9
+ end
10
+
11
+
12
+ should 'parse app long argument' do
13
+ params = @run_cmd.parse_cli_parameters ['--with=bot1,bot2,bot3']
14
+ assert_equal %w(bot1 bot2 bot3), params[:with]
15
+ end
16
+
17
+ should 'parse without long argument' do
18
+ params = @run_cmd.parse_cli_parameters ['--without=botA,botB,botC']
19
+ assert_equal %w(botA botB botC), params[:without]
20
+ end
21
+
22
+ should 'parse with long argument' do
23
+ params = @run_cmd.parse_cli_parameters ['--with=botX,botY,botZ']
24
+ assert_equal %w(botX botY botZ), params[:with]
25
+ end
26
+
27
+ should 'parse one short argument' do
28
+ params = @run_cmd.parse_cli_parameters ['-w=bot1,bot2,bot3']
29
+ assert_equal %w(bot1 bot2 bot3), params[:with]
30
+ end
31
+
32
+ should 'parse two long arguments' do
33
+ params = @run_cmd.parse_cli_parameters %w(--with=bot1,bot2,bot3 --without=botA,botB,botC)
34
+ assert_equal %w(bot1 bot2 bot3), params[:with]
35
+ assert_equal %w(botA botB botC), params[:without]
36
+ end
37
+
38
+ should 'parse two short arguments' do
39
+ params = @run_cmd.parse_cli_parameters %w(-wo=bot1,bot2,bot3 -w=botA,botB,botC)
40
+ assert_equal %w(bot1 bot2 bot3), params[:without]
41
+ assert_equal %w(botA botB botC), params[:with]
42
+ end
43
+
44
+ should 'parse one short and one long argument' do
45
+ params = @run_cmd.parse_cli_parameters %w(--with=bot1,bot2,bot3 -wo=botA,botB,botC)
46
+ assert_equal %w(bot1 bot2 bot3), params[:with]
47
+ assert_equal %w(botA botB botC), params[:without]
48
+ end
49
+
50
+ should 'raise an exception when trying to parse params that do not exist' do
51
+ assert_raises (StandardError) { @run_cmd.parse_cli_parameters %w(--wit=bot1,bot2,bot3 -o=botA,botB,botC) }
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,31 @@
1
+ require 'helper'
2
+
3
+ module Nutella
4
+
5
+ class TestCommandTemplate < MiniTest::Test
6
+
7
+ # 1. Create a fake app
8
+ # New.new.run ['test_app']
9
+ # Dir.chdir 'test_app'
10
+ # Nutella::Install.new.run ['basic-ruby-bot', 'bot1']
11
+ # Dir.chdir '..'
12
+
13
+ # 2. Perform tests
14
+ # should 'this is my first test' do
15
+ # Dir.chdir 'test_app'
16
+ # # Test code here
17
+ # Dir.chdir '..'
18
+ # end
19
+ #
20
+ # should 'this is my second test' do
21
+ # Dir.chdir 'test_app'
22
+ # # Test code here
23
+ # Dir.chdir '..'
24
+ # end
25
+
26
+ # 3. Cleanup
27
+ # MiniTest.after_run { FileUtils.rm_r 'test_app' }
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,34 @@
1
+ require 'helper'
2
+
3
+ module Nutella
4
+
5
+ class TestCurrentAppUtils < MiniTest::Test
6
+
7
+ # def setup
8
+ # Dir.chdir NUTELLA_HOME
9
+ # Nutella.execute_command( 'new', ['test_app'] )
10
+ # Dir.chdir "#{NUTELLA_HOME}test_app"
11
+ # end
12
+ #
13
+ #
14
+ # should 'return true if the dir is a nutella app' do
15
+ # assert Nutella.current_app.exist?
16
+ # end
17
+ #
18
+ # should 'return false if the dir is not a nutella app' do
19
+ # Dir.chdir NUTELLA_HOME
20
+ # refute Nutella.current_app.exist?
21
+ # end
22
+ #
23
+ # should 'return the correct version of nutella as read from the app configuration file' do
24
+ # assert_equal File.open("#{NUTELLA_HOME}VERSION", "rb").read, Nutella.current_app.config['nutella_version']
25
+ # end
26
+ #
27
+ #
28
+ # def teardown
29
+ # FileUtils.rm_rf "#{NUTELLA_HOME}test_app"
30
+ # Dir.chdir NUTELLA_HOME
31
+ # end
32
+
33
+ end
34
+ end