nutella_framework 0.3.1 → 0.4.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/Gemfile +3 -0
- data/README.md +3 -4
- data/VERSION +1 -1
- data/data/startup +3 -3
- data/framework_components/example_framework_interface/dandelion-flowers-card.jpg +0 -0
- data/framework_components/example_framework_interface/index.html +18 -0
- data/framework_components/main_interface/main_interface_bot.rb +183 -0
- data/framework_components/main_interface/public/index.html +54 -0
- data/framework_components/main_interface/views/index.erb +63 -0
- data/framework_components/order.json.example +6 -0
- data/framework_components/runs_list_bot/app_runs_list_bot.rb +15 -0
- data/lib/{core/commands → commands}/broker.rb +2 -2
- data/lib/{core/commands → commands}/checkup.rb +2 -2
- data/lib/commands/compile.rb +13 -0
- data/lib/commands/dependencies.rb +13 -0
- data/lib/commands/help.rb +35 -0
- data/lib/{core/commands → commands}/install.rb +19 -15
- data/lib/commands/meta/command.rb +19 -0
- data/lib/commands/meta/run_command.rb +114 -0
- data/lib/{core → commands/meta}/template_command.rb +1 -1
- data/lib/commands/new.rb +60 -0
- data/lib/commands/runs.rb +54 -0
- data/lib/commands/start.rb +321 -0
- data/lib/commands/stop.rb +101 -0
- data/lib/{core/commands → commands}/template.rb +59 -39
- data/lib/config/current_app_utils.rb +51 -0
- data/lib/config/persisted_hash.rb +14 -12
- data/lib/config/runlist.rb +116 -16
- data/lib/{cli → core}/nutella_cli.rb +1 -1
- data/lib/core/nutella_core.rb +2 -6
- data/lib/nutella_framework.rb +5 -3
- data/lib/nutella_lib_framework/api.rb +333 -0
- data/lib/tmux/tmux.rb +76 -0
- data/nutella_framework.gemspec +42 -29
- data/test/commands/test_cmd_cli_params_parsing.rb +56 -0
- data/test/commands/test_command_template.rb +31 -0
- data/test/config/test_current_app_utils.rb +34 -0
- data/test/config/test_persisted_hash.rb +48 -0
- data/test/config/test_runlist.rb +15 -23
- data/test/framework_apis/test_framework_api.rb +74 -0
- metadata +74 -27
- data/actors/main_interface/main_interface_bot.rb +0 -163
- data/actors/main_interface/public/index.html +0 -51
- data/actors/main_interface/views/index.erb +0 -45
- data/lib/config/current_project.rb +0 -58
- data/lib/core/command.rb +0 -12
- data/lib/core/commands/compile.rb +0 -21
- data/lib/core/commands/dependencies.rb +0 -21
- data/lib/core/commands/help.rb +0 -28
- data/lib/core/commands/new.rb +0 -60
- data/lib/core/commands/runs.rb +0 -52
- data/lib/core/commands/start.rb +0 -271
- data/lib/core/commands/stop.rb +0 -100
- data/lib/core/run_command.rb +0 -106
- data/lib/core/tmux.rb +0 -38
- data/test/config/test_config.rb +0 -48
- data/test/config/test_project.rb +0 -34
- data/test/test_run_command.rb +0 -54
- /data/{actors → framework_components}/main_interface/startup +0 -0
- /data/{actors → framework_components}/main_interface/views/not_found_404.erb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98a1d74bc599d78623959deb2d80d7ef4b5527b0
|
4
|
+
data.tar.gz: 229db1d35c9f3000f6510fa44e075878e21b7f07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0673b2e12cd08dd77e2359b3aa05f7d0d9d6b36e415de55f0df13ef201887fd5c1e0303e695bef502cc2b877df6b72a4aa405d358375ff0498635a4178337322
|
7
|
+
data.tar.gz: 274b0ea11c7671bb8cb42f1d1179026f5a6cfb04d3af52a60d91b3e3a8d97d804457b248203733b821cc2b75bd7ff390c2e1089822627a5525bbea7a8640ae74
|
data/Gemfile
CHANGED
@@ -5,8 +5,10 @@ gem 'semantic', '~> 1.3', '>=1.3'
|
|
5
5
|
gem 'logging', '~> 1.8', '>=1.8.2'
|
6
6
|
gem 'git', '~> 1.2', '>=1.2.8'
|
7
7
|
gem 'sinatra', '~>1.4.5', '>=1.4.5'
|
8
|
+
gem 'thin', '~>1.6.3', '>=1.6.3'
|
8
9
|
gem 'nokogiri', '~>1.6.3', '>=1.6.3'
|
9
10
|
gem 'slop', '~>4.0.0', '>=4.0.0'
|
11
|
+
gem 'nutella_lib','~>0.4.0', '>=0.4.0'
|
10
12
|
|
11
13
|
|
12
14
|
group :development do
|
@@ -20,4 +22,5 @@ end
|
|
20
22
|
|
21
23
|
group :test do
|
22
24
|
gem 'rake'
|
25
|
+
gem 'fakefs', '~> 0.6.7', '>= 0.6'
|
23
26
|
end
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
|
2
2
|
[](http://badge.fury.io/rb/nutella_framework)
|
3
|
-
[](https://travis-ci.org/nutella-framework/nutella_framework)
|
4
|
-
[](https://gemnasium.com/nutella-framework/nutella_framework)
|
3
|
+
[](https://travis-ci.org/nutella-framework/nutella_framework)
|
5
4
|
[](https://codeclimate.com/github/nutella-framework/nutella_framework)
|
6
5
|
|
7
6
|
# Nutella
|
@@ -34,9 +33,9 @@ Congratulations! Nutella is ready to use!
|
|
34
33
|
|
35
34
|
|
36
35
|
# Where next?
|
37
|
-
If you already have
|
36
|
+
If you already have an application you want to tinker with (like [RoomQuake](https://github.com/ltg-uic/roomquake)) simply checkout the application to a local folder, `cd /to/my/local/folder` and start tinkering away. Not sure what to do? Check out our [nutella Command Line Tool man page](https://github.com/nutella-framework/nutella_framework/wiki/Nutella-Command-Line-Interface).
|
38
37
|
|
39
|
-
If you want to create your own
|
38
|
+
If you want to create your own application, check out the [new app tutorial](https://github.com/nutella-framework/nutella_framework/wiki/New-application-tutorial).
|
40
39
|
|
41
40
|
|
42
41
|
# Contributing
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/data/startup
CHANGED
@@ -6,8 +6,8 @@
|
|
6
6
|
BASEDIR=$(dirname $0)
|
7
7
|
|
8
8
|
|
9
|
-
# Remember
|
10
|
-
# command line parameters that you can access via $1 and $
|
9
|
+
# Remember: nutella passes the `broker address`, the `app_id` and the `run_id`
|
10
|
+
# as command line parameters that you can access via $1, $2 and $3 respectively.
|
11
11
|
|
12
12
|
# Start your bot here with something like (example in ruby):
|
13
|
-
# ruby $BASEDIR/my_bot.rb $1 $2
|
13
|
+
# ruby $BASEDIR/my_bot.rb $1 $2 $3
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head lang="en">
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>Example framework interface</title>
|
6
|
+
<!-- The description of this interfaces here -->
|
7
|
+
<meta name="description" content="This is an example framework interface">
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<h1>Example framework interface</h1>
|
11
|
+
<p>This is an example of a framework interface. It really doesn't belong here but for now this
|
12
|
+
is ok. Once we'll have real framework interfaces this is going to be be moved to a template.
|
13
|
+
</p>
|
14
|
+
<p>And just to make sure we are loading not just the index, here is a picture of dandelions</p>
|
15
|
+
<img src="dandelion-flowers-card.jpg" width="500">
|
16
|
+
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
# Configuration file and runlist (runlist as global)
|
6
|
+
config_file = ARGV[0]
|
7
|
+
$runlist_file = ARGV[1]
|
8
|
+
|
9
|
+
# Try to parse the both config file and runlist and terminate if we can't
|
10
|
+
begin
|
11
|
+
config_h = JSON.parse(IO.read(config_file))
|
12
|
+
JSON.parse(IO.read($runlist_file))
|
13
|
+
rescue
|
14
|
+
# something went wrong
|
15
|
+
abort 'Impossible to parse configuration and/or runlist files!'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set Sinatra to run in production mode
|
19
|
+
set :environment, :production
|
20
|
+
|
21
|
+
# Set Sinatra's port to nutella's main_interface_port
|
22
|
+
set :port, config_h['main_interface_port']
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
# Display the form to input the app_id and run_id
|
28
|
+
get '/' do
|
29
|
+
send_file 'public/index.html'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Redirect if there is no slash after the run_id
|
33
|
+
get '/:app_id/:run_id' do
|
34
|
+
redirect "#{request.url}/"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Renders the interfaces summary page for the run
|
39
|
+
get '/:app_id/:run_id/' do
|
40
|
+
# Parse the app_id and run_id from URL and extract the run path from runlist.json
|
41
|
+
@app_id = params[:app_id]
|
42
|
+
@run_id = params[:run_id]
|
43
|
+
@app_path = get_app_path @app_id
|
44
|
+
# If there is no app with this name, render error page
|
45
|
+
return erb( :not_found_404, :locals => {:not_found_type => 'run'} ) if @app_path.nil?
|
46
|
+
# To generate the 'index.erb' we need to load a bunch of details
|
47
|
+
# (folder, title/name, description) for each interface
|
48
|
+
@interfaces = load_interfaces_details @app_path
|
49
|
+
@framework_interfaces = load_framework_interfaces
|
50
|
+
# Render the interfaces summary page
|
51
|
+
erb :index
|
52
|
+
end
|
53
|
+
|
54
|
+
# Redirect if there is a slash after the interface
|
55
|
+
get '/:app_id/:run_id/:interface/' do
|
56
|
+
redirect "#{request.url[0..-2]}"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Serves the index.html file for each individual interface augmented with nutella query string parameters
|
61
|
+
get '/:app_id/:run_id/runs/:interface' do
|
62
|
+
# Parse the app_id and run_id from URL and extract the run path from runlist.json
|
63
|
+
app_id = params[:app_id]
|
64
|
+
run_id = params[:run_id]
|
65
|
+
interface = params[:interface]
|
66
|
+
app_path = get_app_path app_id
|
67
|
+
# Compose the path of interface index file passing the nutella parameters
|
68
|
+
index_file_path = "#{app_path}/interfaces/#{interface}/index.html"
|
69
|
+
# If the index file doesn't exist, render error page
|
70
|
+
return erb( :not_found_404, :locals => {:not_found_type => 'idx'} ) unless File.exist? index_file_path
|
71
|
+
# If the index file exists, compose query string and redirect
|
72
|
+
index_with_query_url = "#{request.path}/index.html?broker=#{config_h['broker']}&app_id=#{app_id}&run_id=#{run_id}"
|
73
|
+
redirect index_with_query_url
|
74
|
+
end
|
75
|
+
|
76
|
+
# Serves the files contained in each interface folder
|
77
|
+
get '/:app_id/:run_id/runs/:interface/*' do
|
78
|
+
# Parse the run_id, the interface name and the file_path from URL
|
79
|
+
app_id = params[:app_id]
|
80
|
+
interface = params[:interface]
|
81
|
+
relative_file_path = params[:splat][0]
|
82
|
+
app_path = get_app_path app_id
|
83
|
+
# Compose the path of the file we are trying to serve
|
84
|
+
file_path = "#{app_path}/interfaces/#{interface}/#{relative_file_path}"
|
85
|
+
# If the file we are trying to serve doesn't exist, render error page
|
86
|
+
return erb( :not_found_404, :locals => {:not_found_type => 'file'} ) unless File.exist? file_path
|
87
|
+
# If the file exists, render it
|
88
|
+
send_file file_path
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Serve the index file for a framework interface passing the nutella parameters
|
93
|
+
get '/:app_id/:run_id/framework/:interface' do
|
94
|
+
app_id = params[:app_id]
|
95
|
+
run_id = params[:run_id]
|
96
|
+
# Filesystem path to the index file
|
97
|
+
index_file_path = "#{File.dirname(__FILE__)}/../#{params[:interface]}/index.html"
|
98
|
+
# If the index file doesn't exist, render error page
|
99
|
+
return erb( :not_found_404, :locals => {:not_found_type => 'idx'} ) unless File.exist? index_file_path
|
100
|
+
# If the index file exists, compose query string and redirect
|
101
|
+
index_with_query_url = "#{request.path}/index.html?broker=#{config_h['broker']}&app_id=#{app_id}&run_id=#{run_id}"
|
102
|
+
redirect index_with_query_url
|
103
|
+
end
|
104
|
+
|
105
|
+
# Serves the files contained in each framework interface folder
|
106
|
+
get '/:app_id/:run_id/framework/:interface/*' do
|
107
|
+
# Fetch the relative file path
|
108
|
+
relative_file_path = params[:splat][0]
|
109
|
+
# Compose the path of the file we are trying to serve
|
110
|
+
file_path = "#{File.dirname(__FILE__)}/../#{params[:interface]}/#{relative_file_path}"
|
111
|
+
# If the file we are trying to serve doesn't exist, render error page
|
112
|
+
return erb( :not_found_404, :locals => {:not_found_type => 'file'} ) unless File.exist? file_path
|
113
|
+
# If the file exists, render it
|
114
|
+
send_file file_path
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Utility functions -------------------------------------------------------------------------
|
119
|
+
|
120
|
+
# Utility function:
|
121
|
+
# Gets the path associated with a certain application
|
122
|
+
def get_app_path( app_id )
|
123
|
+
begin
|
124
|
+
runs_h = JSON.parse(IO.read($runlist_file))
|
125
|
+
runs_h[app_id]['path']
|
126
|
+
rescue
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Utility function:
|
132
|
+
# Loads all the details for all interfaces and stores them into an array of hashes
|
133
|
+
def load_interfaces_details( app_path )
|
134
|
+
interfaces = Array.new
|
135
|
+
interfaces_path = "#{app_path}/interfaces/"
|
136
|
+
Dir.entries(interfaces_path).select {|entry| File.directory?(File.join(interfaces_path, entry)) && !(entry =='.' || entry == '..') }.each do |iface_dir|
|
137
|
+
interfaces.push extract_interface_info( interfaces_path, iface_dir )
|
138
|
+
end
|
139
|
+
interfaces
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def load_framework_interfaces
|
144
|
+
interfaces = Array.new
|
145
|
+
components_directory = "#{File.dirname(__FILE__)}/../"
|
146
|
+
Dir.entries(components_directory).select {|entry| File.directory?(File.join(components_directory, entry)) && !(entry =='.' || entry == '..') }.each do |iface_dir|
|
147
|
+
interfaces.push(extract_interface_info( components_directory, iface_dir)) if File.exist?("#{components_directory}#{iface_dir}/index.html")
|
148
|
+
end
|
149
|
+
interfaces
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Utility function:
|
154
|
+
# Extracts name, description and folder for a single interface from it's index.html
|
155
|
+
def extract_interface_info( interfaces_path, iface_dir )
|
156
|
+
iface_properties = Hash.new
|
157
|
+
index_path = "#{interfaces_path}#{iface_dir}/index.html"
|
158
|
+
unless File.exist? index_path
|
159
|
+
iface_properties[:name] = iface_dir
|
160
|
+
iface_properties[:description] = 'My designer was a bit lazy and didn\'t include an index.html file in the main interface directory :('
|
161
|
+
return iface_properties
|
162
|
+
end
|
163
|
+
|
164
|
+
# If file exists, parse it and extract info
|
165
|
+
f = File.open index_path
|
166
|
+
doc = Nokogiri::HTML f
|
167
|
+
f.close
|
168
|
+
# Extract interface name from title
|
169
|
+
iface_properties[:name] = (doc.css('title').empty? || doc.css('title').text.empty? ) ? iface_dir : doc.css('title').text
|
170
|
+
# Extract description from meta description tag
|
171
|
+
if doc.css("meta[name='description']").empty?
|
172
|
+
iface_properties[:description] = 'My designer was a bit lazy and didn\'t include a <meta name="description" content="Description of this interface"> tag in the index.html file :('
|
173
|
+
else
|
174
|
+
if doc.css("meta[name='description']").attribute('content').nil?
|
175
|
+
iface_properties[:description] = 'There was no attribute content in <meta name="description" content="Description of this interface"> tag in the index.html file :('
|
176
|
+
else
|
177
|
+
iface_properties[:description] = doc.css("meta[name='description']").attribute('content').text
|
178
|
+
end
|
179
|
+
end
|
180
|
+
# Extract URL from interface dir
|
181
|
+
iface_properties[:url] = iface_dir
|
182
|
+
iface_properties
|
183
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<title>Welcome to nutella</title>
|
8
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
9
|
+
|
10
|
+
<style type="text/css">
|
11
|
+
div {
|
12
|
+
margin-top: 4em;
|
13
|
+
text-align: center;
|
14
|
+
font-size: 3em;
|
15
|
+
}
|
16
|
+
.form-control {
|
17
|
+
height: 50px;
|
18
|
+
width: 20%;
|
19
|
+
text-align: center;
|
20
|
+
font-size: .7em;
|
21
|
+
display: inline-block;
|
22
|
+
}
|
23
|
+
.center form {
|
24
|
+
display:inline-block;
|
25
|
+
}
|
26
|
+
</style>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
|
30
|
+
<!-- Content -->
|
31
|
+
<div>
|
32
|
+
<p>What is your app id?
|
33
|
+
<input id="app_id_input" type="text" value="" class="form-control" autofocus>
|
34
|
+
</p>
|
35
|
+
<br />
|
36
|
+
<p>What is your run id?
|
37
|
+
<input id="run_id_input" type="text" value="" class="form-control" >
|
38
|
+
</p>
|
39
|
+
</div>
|
40
|
+
|
41
|
+
<!-- Scripts -->
|
42
|
+
<script>
|
43
|
+
app_id_el = document.getElementById('app_id_input');
|
44
|
+
run_id_el = document.getElementById('run_id_input');
|
45
|
+
run_id_el.addEventListener('change', function() {
|
46
|
+
var url = location.href
|
47
|
+
if (url.substr(url.length - 1)=="/")
|
48
|
+
window.location = url + app_id_el.value + '/' + this.value + '/';
|
49
|
+
else
|
50
|
+
window.location = url + '/' + app_id_el.value + '/'+ this.value + '/';
|
51
|
+
});
|
52
|
+
</script>
|
53
|
+
</body>
|
54
|
+
</html>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<title><%= @app_id %> interfaces</title>
|
8
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
9
|
+
|
10
|
+
<style type="text/css">
|
11
|
+
.row {
|
12
|
+
margin-bottom: 20px;
|
13
|
+
}
|
14
|
+
</style>
|
15
|
+
</head>
|
16
|
+
<body>
|
17
|
+
|
18
|
+
<!-- Content -->
|
19
|
+
<div class="container">
|
20
|
+
|
21
|
+
<!-- Title and prompt -->
|
22
|
+
<div class="page-header">
|
23
|
+
<% if @run_id == 'default' %>
|
24
|
+
<h1>Welcome to <em><%= @app_id %></em></h1>
|
25
|
+
<% else %>
|
26
|
+
<h1>Welcome to <em><%= @app_id %></em>, run <em><%= @run_id %></em></h1>
|
27
|
+
<% end %>
|
28
|
+
<p class="lead">Use the buttons below to launch a specific interface</p>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<!-- Run level interfaces -->
|
32
|
+
<% @interfaces.each do |i| %>
|
33
|
+
<div class="row">
|
34
|
+
<div class="col-xs-1 col-sm-1 col-lg-1"><a href="runs/<%= i[:url] %>" target="_blank" type="button" class="btn btn-danger">Launch!</a></div>
|
35
|
+
<div class="col-xs-2 col-sm-2 col-lg-2 text-center"><strong><%= i[:name] %></strong></div>
|
36
|
+
<div class="col-xs-9 col-sm-9 col-lg-9"><%= i[:description] %></div>
|
37
|
+
</div>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<!-- Framework level interfaces -->
|
41
|
+
|
42
|
+
<hr>
|
43
|
+
<div class="row">
|
44
|
+
<h2>Framework level interfaces</h2>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<% @framework_interfaces.each do |i| %>
|
48
|
+
<div class="row">
|
49
|
+
<div class="col-xs-1 col-sm-1 col-lg-1"><a href="framework/<%= i[:url] %>" target="_blank" type="button" class="btn btn-danger">Launch!</a></div>
|
50
|
+
<div class="col-xs-2 col-sm-2 col-lg-2 text-center"><strong><%= i[:name] %></strong></div>
|
51
|
+
<div class="col-xs-9 col-sm-9 col-lg-9"><%= i[:description] %></div>
|
52
|
+
</div>
|
53
|
+
<% end %>
|
54
|
+
|
55
|
+
|
56
|
+
</div>
|
57
|
+
|
58
|
+
<!-- Scripts -->
|
59
|
+
<script>
|
60
|
+
|
61
|
+
</script>
|
62
|
+
</body>
|
63
|
+
</html>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'nutella_lib'
|
2
|
+
|
3
|
+
# This needs to be initialized as framework component like so:
|
4
|
+
# nutella.init_as_app_component('localhost', 'app_runs_list_bot')
|
5
|
+
nutella.init('localhost', 'my_app_id', 'no_run_id', 'app_runs_list_bot')
|
6
|
+
|
7
|
+
# Listen for runs_list requests (done by app components when they connect)
|
8
|
+
nutella.net.app.handle_requests('app_runs_list', lambda do |req, from|
|
9
|
+
from['app_id'] # Use this info to fetch the appropriate runs
|
10
|
+
['run_1', 'run_2', 'run_3'] # Return an array of names!
|
11
|
+
end)
|
12
|
+
|
13
|
+
# Whenever the list is updated, fire an update to the right app
|
14
|
+
|
15
|
+
nutella.net.listen
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'commands/meta/command'
|
2
2
|
require 'socket'
|
3
3
|
|
4
4
|
module Nutella
|
@@ -36,7 +36,7 @@ module Nutella
|
|
36
36
|
def change_broker( new_broker )
|
37
37
|
# Check that there are no runs hinging on this broker
|
38
38
|
unless Nutella.runlist.empty?
|
39
|
-
console.warn 'You are currently running some
|
39
|
+
console.warn 'You are currently running some nutella applications on this broker. You can\'t change the broker while running.'
|
40
40
|
return
|
41
41
|
end
|
42
42
|
# Try to parse the hostname and switch to the new broker
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'commands/meta/command'
|
2
2
|
require 'semantic'
|
3
3
|
|
4
4
|
module Nutella
|
5
5
|
class Checkup < Command
|
6
|
-
@description = 'Checks that all the dependencies are installed
|
6
|
+
@description = 'Checks that all the framework dependencies are installed'
|
7
7
|
|
8
8
|
def run( args=nil )
|
9
9
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'commands/meta/run_command'
|
2
|
+
require 'tmux/tmux'
|
3
|
+
|
4
|
+
module Nutella
|
5
|
+
class Compile < RunCommand
|
6
|
+
@description = 'Compiles all the components that need compilation in the application'
|
7
|
+
|
8
|
+
def run(args=nil)
|
9
|
+
compile_and_dependencies 'compile', 'Compiling', 'components compiled'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'commands/meta/command'
|
2
|
+
require 'tmux/tmux'
|
3
|
+
|
4
|
+
module Nutella
|
5
|
+
class Dependencies < RunCommand
|
6
|
+
@description = 'Installs the dependencies for all components in the application'
|
7
|
+
|
8
|
+
def run(args=nil)
|
9
|
+
compile_and_dependencies 'dependencies', 'Installing dependencies for', 'dependencies installed'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'commands/meta/command'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
class Help < Command
|
6
|
+
@description = 'Displays what every command does and how to use it'
|
7
|
+
|
8
|
+
def run(args=nil)
|
9
|
+
message=''
|
10
|
+
Dir["#{File.dirname(__FILE__)}/*.rb"].each do |file|
|
11
|
+
message += add_cmd_help(file)
|
12
|
+
end
|
13
|
+
console.info message
|
14
|
+
console.success 'For more details on individual commands, see https://github.com/nutella-framework/nutella_framework/wiki/Nutella-Command-Line-Interface'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def add_cmd_help(file)
|
20
|
+
command = File.basename(file, File.extname(file))
|
21
|
+
if command.length > 7
|
22
|
+
message = "#{command}\t"
|
23
|
+
else
|
24
|
+
message = "#{command}\t\t"
|
25
|
+
end
|
26
|
+
message += Object::const_get("Nutella::#{command.capitalize}").description
|
27
|
+
message += "\n"
|
28
|
+
message
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
@@ -1,15 +1,19 @@
|
|
1
|
-
require '
|
1
|
+
require 'commands/meta/template_command'
|
2
2
|
require 'git'
|
3
3
|
require 'net/http'
|
4
4
|
|
5
5
|
module Nutella
|
6
6
|
|
7
7
|
class Install < TemplateCommand
|
8
|
-
@description = 'Copies an arbitrary template (from central DB, directory or URL) into the current
|
8
|
+
@description = 'Copies an arbitrary template (from central DB, directory or URL) into the current application'
|
9
9
|
|
10
10
|
def run(args=nil)
|
11
|
-
|
12
|
-
|
11
|
+
|
12
|
+
# If the current directory is not a nutella application, return
|
13
|
+
unless Nutella.current_app.exist?
|
14
|
+
console.warn 'The current directory is not a nutella application'
|
15
|
+
return
|
16
|
+
end
|
13
17
|
|
14
18
|
# Check args
|
15
19
|
if args.empty?
|
@@ -19,16 +23,16 @@ module Nutella
|
|
19
23
|
template = args[0]
|
20
24
|
destination_dir = args.length==2 ? args[1] : nil
|
21
25
|
|
22
|
-
# Extract
|
23
|
-
|
26
|
+
# Extract application directory
|
27
|
+
app_path =Dir.pwd
|
24
28
|
|
25
29
|
# What kind of template are we handling?
|
26
30
|
if is_template_a_local_dir? template
|
27
|
-
add_local_template( template, template,
|
31
|
+
add_local_template( template, template, app_path, destination_dir )
|
28
32
|
elsif is_template_a_git_repo? template
|
29
|
-
add_remote_template( template,
|
33
|
+
add_remote_template( template, app_path, destination_dir)
|
30
34
|
elsif is_template_in_db? template
|
31
|
-
add_central_template( template,
|
35
|
+
add_central_template( template, app_path, destination_dir)
|
32
36
|
else
|
33
37
|
console.warn 'The specified template is not a valid nutella template'
|
34
38
|
end
|
@@ -55,7 +59,7 @@ module Nutella
|
|
55
59
|
tmp_dest_dir = template_git_url[template_git_url.rindex('/')+1 .. template_git_url.length]
|
56
60
|
end
|
57
61
|
clone_template_from_repo_to( template_git_url, tmp_dest_dir )
|
58
|
-
return validate_template "#{Nutella
|
62
|
+
return validate_template "#{Nutella::NUTELLA_TMP}/#{tmp_dest_dir}"
|
59
63
|
rescue
|
60
64
|
return false
|
61
65
|
end
|
@@ -106,21 +110,21 @@ module Nutella
|
|
106
110
|
|
107
111
|
def add_remote_template ( template, prj_dir, dest_dir)
|
108
112
|
template_name = template[template.rindex('/')+1 .. template.length-5]
|
109
|
-
template_dir = "#{Nutella
|
113
|
+
template_dir = "#{Nutella::NUTELLA_TMP}/#{template_name}"
|
110
114
|
add_local_template( template, template_dir, prj_dir, dest_dir )
|
111
115
|
end
|
112
116
|
|
113
117
|
|
114
118
|
def add_central_template( template_name, prj_dir, dest_dir)
|
115
|
-
template_dir = "#{Nutella
|
119
|
+
template_dir = "#{Nutella::NUTELLA_TMP}/#{template_name}"
|
116
120
|
add_local_template( template_name, template_dir, prj_dir, dest_dir )
|
117
121
|
end
|
118
122
|
|
119
123
|
|
120
124
|
def clone_template_from_repo_to(template, dest_dir)
|
121
125
|
clean_tmp_dir
|
122
|
-
Dir.mkdir Nutella
|
123
|
-
Git.clone(template, dest_dir, :path => Nutella
|
126
|
+
Dir.mkdir Nutella::NUTELLA_TMP unless Dir.exists? Nutella::NUTELLA_TMP
|
127
|
+
Git.clone(template, dest_dir, :path => Nutella::NUTELLA_TMP)
|
124
128
|
end
|
125
129
|
|
126
130
|
|
@@ -132,7 +136,7 @@ module Nutella
|
|
132
136
|
|
133
137
|
|
134
138
|
def clean_tmp_dir
|
135
|
-
FileUtils.rm_rf "#{Nutella
|
139
|
+
FileUtils.rm_rf "#{Nutella::NUTELLA_TMP}"
|
136
140
|
end
|
137
141
|
|
138
142
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
# Nutella command
|
6
|
+
class Command
|
7
|
+
|
8
|
+
class << self;
|
9
|
+
attr_accessor :description
|
10
|
+
end
|
11
|
+
|
12
|
+
# Commands overload this method to execute
|
13
|
+
def run( args=nil )
|
14
|
+
console.error 'Running the generic command!!! WAT? https://www.destroyallsoftware.com/talks/wat'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|