nutella_framework 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -3
- data/VERSION +1 -1
- data/actors/main_interface/main_interface_bot.rb +148 -0
- data/actors/main_interface/public/index.html +47 -0
- data/actors/main_interface/startup +5 -0
- data/actors/main_interface/views/index.erb +45 -0
- data/actors/main_interface/views/not_found_404.erb +37 -0
- data/lib/cli/nutella_cli.rb +24 -15
- data/lib/config/config.rb +5 -67
- data/lib/config/current_project.rb +58 -0
- data/lib/config/persisted_hash.rb +114 -0
- data/lib/config/runlist.rb +19 -83
- data/lib/core/command.rb +2 -2
- data/lib/core/commands/broker.rb +23 -24
- data/lib/core/commands/checkup.rb +36 -37
- data/lib/core/commands/help.rb +3 -3
- data/lib/core/commands/install.rb +3 -4
- data/lib/core/commands/new.rb +26 -28
- data/lib/core/commands/runs.rb +22 -31
- data/lib/core/commands/start.rb +134 -121
- data/lib/core/commands/stop.rb +62 -48
- data/lib/core/nutella_core.rb +23 -12
- data/lib/core/run_command.rb +44 -0
- data/lib/core/tmux.rb +20 -18
- data/lib/logging/nutella_logging.rb +5 -5
- data/lib/nutella_framework.rb +8 -6
- data/nutella_framework.gemspec +15 -12
- data/test/config/test_config.rb +23 -22
- data/test/config/test_project.rb +13 -12
- data/test/config/test_runlist.rb +30 -22
- metadata +15 -12
- data/lib/config/project.rb +0 -53
- data/lib/extra/config.ru +0 -2
- data/lib/extra/interfaces_list.erubis +0 -14
- data/lib/extra/main_interface.rb +0 -9
- data/test/test_nutella_framework.rb +0 -31
data/lib/config/runlist.rb
CHANGED
@@ -1,96 +1,32 @@
|
|
1
|
-
|
2
|
-
# The list is uniquely maintained inside a file
|
3
|
-
require 'singleton'
|
4
|
-
require 'json'
|
5
|
-
require 'set'
|
1
|
+
require 'config/persisted_hash'
|
6
2
|
|
7
3
|
module Nutella
|
8
4
|
|
9
|
-
class
|
10
|
-
|
11
|
-
RUN_LIST_FILE=File.dirname(__FILE__)+"/../../runlist.json"
|
12
|
-
|
13
|
-
include Singleton
|
14
|
-
|
15
|
-
def add?(runid)
|
16
|
-
begin
|
17
|
-
result = JSON.parse(IO.read(RUN_LIST_FILE)).to_set.add? runid
|
18
|
-
rescue
|
19
|
-
# No file, create one
|
20
|
-
result = [runid].to_set
|
21
|
-
end
|
22
|
-
writeFile(result)
|
23
|
-
end
|
24
|
-
|
25
|
-
def delete?(runid)
|
26
|
-
begin
|
27
|
-
result = JSON.parse(IO.read(RUN_LIST_FILE)).to_set.delete? runid
|
28
|
-
rescue
|
29
|
-
removeRunListFile
|
30
|
-
result = nil # List is empty, so nil
|
31
|
-
end
|
32
|
-
writeFile(result)
|
33
|
-
end
|
5
|
+
class RunListHash < PersistedHash
|
34
6
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
7
|
+
# Returns the +run_id+ names for a certain project
|
8
|
+
# If no project is specified, +run_id+s for all projects are returned
|
9
|
+
# @param [String] project_name the name of the project we want to find run names for
|
10
|
+
# @return [Array<String>] list of +run_id+s associated to the specified project
|
11
|
+
def runs_by_project( project_name=nil )
|
12
|
+
(project_name == nil) ? keys : keys.select { |run| run.start_with?(project_name) }
|
41
13
|
end
|
42
14
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
def to_a(projectName=nil)
|
52
|
-
begin
|
53
|
-
list = JSON.parse(IO.read(RUN_LIST_FILE))
|
54
|
-
# filter by project
|
55
|
-
if projectName == nil
|
56
|
-
return list
|
57
|
-
else
|
58
|
-
return list.select { |run| run.start_with?(projectName) }
|
59
|
-
end
|
60
|
-
rescue
|
61
|
-
Array.new # There is no file or something went wrong
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def length
|
66
|
-
to_a.length
|
67
|
-
end
|
68
|
-
|
69
|
-
def extractRunId(run)
|
70
|
-
run.to_s.empty? ? Nutella.currentProject.config["name"] : Nutella.currentProject.config["name"] + "_" + run
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def removeRunListFile
|
76
|
-
File.delete(RUN_LIST_FILE) if File.exist?(RUN_LIST_FILE)
|
77
|
-
end
|
78
|
-
|
79
|
-
def writeFile(result)
|
80
|
-
if result!=nil
|
81
|
-
File.open(RUN_LIST_FILE, "w+") do |f|
|
82
|
-
f.write(JSON.pretty_generate(result.to_a))
|
83
|
-
end
|
84
|
-
File.chmod(0777, RUN_LIST_FILE)
|
85
|
-
end
|
86
|
-
result
|
15
|
+
# Extracts the +run_id+ from the run name (specified at command line)
|
16
|
+
# @param [String] run_name
|
17
|
+
# @return [String] the +run_id+ which is either the +project_name+ (if no +run_name+
|
18
|
+
# was specified) or the concatenation of +project_name+ and +run_name+
|
19
|
+
def extract_run_id( run_name )
|
20
|
+
run_name.to_s.empty? ? Nutella.current_project.config['name'] : "#{Nutella.current_project.config['name']}_#{run_name}"
|
87
21
|
end
|
88
22
|
|
23
|
+
|
89
24
|
end
|
90
|
-
|
91
|
-
|
25
|
+
|
26
|
+
# Calling this method (Nutella.runlist) simply returns and instance of
|
27
|
+
# RunListHash linked to file runlist.json in the nutella home directory
|
92
28
|
def Nutella.runlist
|
93
|
-
|
29
|
+
RunListHash.new( "#{File.dirname(__FILE__)}/../../runlist.json" )
|
94
30
|
end
|
95
31
|
|
96
32
|
end
|
data/lib/core/command.rb
CHANGED
@@ -5,8 +5,8 @@ module Nutella
|
|
5
5
|
class << self; attr_accessor :description end
|
6
6
|
|
7
7
|
# Commands overload this method to execute
|
8
|
-
def run
|
9
|
-
console.error
|
8
|
+
def run( args=nil )
|
9
|
+
console.error 'Running the generic command!!! WAT?'
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/lib/core/commands/broker.rb
CHANGED
@@ -3,53 +3,52 @@ require 'socket'
|
|
3
3
|
|
4
4
|
module Nutella
|
5
5
|
class Broker < Command
|
6
|
-
@description =
|
6
|
+
@description = 'Displays information about the broker and allows to change it'
|
7
7
|
|
8
8
|
def run(args=nil)
|
9
|
-
|
9
|
+
|
10
|
+
# If no argument then we just display info about the broker
|
10
11
|
if args==nil || args.empty?
|
11
|
-
|
12
|
+
print_broker_info
|
12
13
|
return
|
13
14
|
end
|
14
15
|
# If there are arguments we are doing manipulations
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# startBroker
|
20
|
-
# when "stop"
|
21
|
-
# stopBroker
|
16
|
+
sub_command = args[0]
|
17
|
+
sum_command_param = args[1]
|
18
|
+
if sub_command=='set'
|
19
|
+
change_broker sum_command_param
|
22
20
|
else
|
23
|
-
console.warn "Unknown
|
21
|
+
console.warn "Unknown 'nutella broker' option #{sub_command}. Try 'nutella broker' or 'nutella broker set <new_broker>' instead"
|
24
22
|
end
|
25
|
-
|
26
23
|
end
|
27
24
|
|
28
25
|
private
|
29
26
|
|
30
|
-
def
|
31
|
-
if Nutella.config[
|
32
|
-
console.warn
|
27
|
+
def print_broker_info
|
28
|
+
if Nutella.config['broker'].nil?
|
29
|
+
console.warn 'No broker has been specified yet. Please, run `nutella broker set <broker>` to specify a broker'
|
33
30
|
else
|
34
|
-
console.info"Currently using broker: #{Nutella.config[
|
31
|
+
console.info "Currently using broker: #{Nutella.config['broker']}"
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
38
35
|
|
39
|
-
def
|
36
|
+
def change_broker( new_broker )
|
40
37
|
# Check that there are no runs hinging on this broker
|
41
|
-
|
42
|
-
console.warn
|
38
|
+
unless Nutella.runlist.empty?
|
39
|
+
console.warn 'You are currently running some projects on this broker. You can\'t change the broker while running.'
|
43
40
|
return
|
44
41
|
end
|
45
|
-
#
|
42
|
+
# Try to parse the hostname and switch to the new broker
|
46
43
|
begin
|
47
|
-
IPSocket.getaddress
|
44
|
+
IPSocket.getaddress new_broker
|
48
45
|
rescue
|
49
|
-
console.warn "
|
46
|
+
console.warn "#{new_broker} is not a valid hostname for a broker"
|
47
|
+
return
|
50
48
|
end
|
51
|
-
Nutella.config[
|
52
|
-
|
49
|
+
Nutella.config['broker'] = new_broker
|
50
|
+
# Print a confirmation message
|
51
|
+
console.success "Now using broker: #{Nutella.config['broker']}"
|
53
52
|
end
|
54
53
|
|
55
54
|
end
|
@@ -3,51 +3,53 @@ require 'semantic'
|
|
3
3
|
|
4
4
|
module Nutella
|
5
5
|
class Checkup < Command
|
6
|
-
@description =
|
6
|
+
@description = 'Checks that all the dependencies are installed and prepares nutella to run'
|
7
7
|
|
8
|
-
def run(args=nil)
|
8
|
+
def run( args=nil )
|
9
|
+
|
9
10
|
# First check that we have all the tools we need to run nutella
|
10
|
-
|
11
|
-
return
|
12
|
-
end
|
11
|
+
return unless all_dependencies_installed?
|
13
12
|
|
14
|
-
# Check if we have a broker
|
15
|
-
if
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
# Check if we have a local broker installed
|
14
|
+
# and install one if we don't
|
15
|
+
if File.directory? Nutella.config['broker_dir']
|
16
|
+
console.info 'You have a local broker installed. Yay!'
|
17
|
+
else
|
18
|
+
console.warn 'You don\'t seem to have a local broker installed so we are going to go ahead and install one for you. This might take some time...'
|
19
|
+
unless install_local_broker
|
20
|
+
console.error 'Whoops...something went wrong while installing the broker'
|
19
21
|
return
|
20
22
|
end
|
21
|
-
else
|
22
|
-
console.info "You have a local broker installed. Yay!"
|
23
23
|
end
|
24
24
|
|
25
|
-
# Set
|
26
|
-
Nutella.config[
|
27
|
-
|
25
|
+
# Set ready flag in config.json
|
26
|
+
Nutella.config['ready'] = true
|
27
|
+
|
28
|
+
# Output success message
|
29
|
+
console.success 'All systems go! You are ready to use nutella!'
|
28
30
|
end
|
29
31
|
|
30
32
|
|
31
33
|
private
|
32
34
|
|
33
35
|
|
34
|
-
def
|
36
|
+
def install_local_broker
|
35
37
|
# Clone, cd and npm install
|
36
|
-
out1 = system "git clone git://github.com/mcollina/mosca.git #{Nutella.config[
|
37
|
-
Dir.chdir(Nutella.config[
|
38
|
-
out2 = system
|
38
|
+
out1 = system "git clone git://github.com/mcollina/mosca.git #{Nutella.config['broker_dir']} > /dev/null 2>&1"
|
39
|
+
Dir.chdir(Nutella.config['broker_dir'])
|
40
|
+
out2 = system 'npm install > /dev/null 2>&1'
|
39
41
|
|
40
|
-
# Add startup script
|
41
|
-
File.open(
|
42
|
-
File.chmod(0755,
|
42
|
+
# Add startup script and make it executable
|
43
|
+
File.open('startup', 'w') { |file| file.write("#!/bin/sh\n\nBASEDIR=$(dirname $0)\n$BASEDIR/bin/mosca --http-port 1884 &\necho $! > $BASEDIR/bin/.pid\n") }
|
44
|
+
File.chmod( 0755, 'startup' )
|
43
45
|
|
44
|
-
#
|
45
|
-
Nutella.config[
|
46
|
-
|
46
|
+
# Write configuration into config.json
|
47
|
+
Nutella.config['broker'] = 'localhost'
|
48
|
+
out1 && out2
|
47
49
|
end
|
48
50
|
|
49
51
|
|
50
|
-
def
|
52
|
+
def all_dependencies_installed?
|
51
53
|
# Node version lambda
|
52
54
|
node_semver = lambda do
|
53
55
|
out = `node --version`
|
@@ -67,34 +69,31 @@ module Nutella
|
|
67
69
|
Semantic::Version.new "#{out[0..2]}.0"
|
68
70
|
end
|
69
71
|
# Check versions
|
70
|
-
if
|
71
|
-
|
72
|
-
and checkVersion?("tmux", "1.8.0", tmux_semver)
|
73
|
-
return true
|
74
|
-
end
|
72
|
+
return true if check_version?('node', '0.10.0', node_semver) && check_version?('git', '1.8.0', git_semver) && check_version?('tmux', '1.8.0', tmux_semver)
|
73
|
+
# If even one of the checks fails, return false
|
75
74
|
false
|
76
75
|
end
|
77
76
|
|
78
77
|
|
79
|
-
def
|
78
|
+
def check_version?(dep, req_version, lambda)
|
80
79
|
begin
|
81
80
|
actual_version = lambda.call
|
82
81
|
rescue
|
83
|
-
console.warn "Doesn't look like #{dep} is installed in your system. " +
|
84
|
-
"
|
82
|
+
console.warn "Doesn't look like #{dep} is installed in your system. " +
|
83
|
+
"Unfortunately nutella can't do much unless all the dependencies are installed :("
|
85
84
|
return
|
86
85
|
end
|
87
86
|
required_version = Semantic::Version.new req_version
|
88
87
|
if actual_version < required_version
|
89
88
|
console.warn "Your version of #{dep} is a little old (#{actual_version}). Nutella requires #{required_version}. Please upgrade!"
|
90
|
-
|
89
|
+
false
|
91
90
|
else
|
92
91
|
console.info "Your #{dep} version is #{actual_version}. Yay!"
|
93
92
|
true
|
94
93
|
end
|
95
94
|
end
|
96
|
-
|
97
|
-
|
95
|
+
|
98
96
|
end
|
97
|
+
|
99
98
|
end
|
100
99
|
|
data/lib/core/commands/help.rb
CHANGED
@@ -3,11 +3,11 @@ require 'core/command'
|
|
3
3
|
module Nutella
|
4
4
|
|
5
5
|
class Help < Command
|
6
|
-
@description =
|
6
|
+
@description = 'Displays what every command does and how to use it'
|
7
7
|
|
8
8
|
def run(args=nil)
|
9
|
-
message=
|
10
|
-
Dir[File.dirname(__FILE__)
|
9
|
+
message=''
|
10
|
+
Dir["#{File.dirname(__FILE__)}/*.rb"].each do |file|
|
11
11
|
message += "#{File.basename(file, File.extname(file))}\t\t"
|
12
12
|
message += Object::const_get("Nutella::#{File.basename(file, File.extname(file)).capitalize}").description
|
13
13
|
message += "\n"
|
@@ -10,7 +10,7 @@ module Nutella
|
|
10
10
|
|
11
11
|
def run(args=nil)
|
12
12
|
# Is current directory a nutella prj?
|
13
|
-
return unless Nutella.
|
13
|
+
return unless Nutella.current_project.exist?
|
14
14
|
|
15
15
|
# Check args
|
16
16
|
if args.empty?
|
@@ -21,7 +21,7 @@ module Nutella
|
|
21
21
|
destination_dir = args.length==2 ? args[1] : nil
|
22
22
|
|
23
23
|
# Extract project directory
|
24
|
-
prj_dir = Nutella.
|
24
|
+
prj_dir = Nutella.current_project.dir
|
25
25
|
|
26
26
|
# What kind of template are we handling?
|
27
27
|
if is_template_a_local_dir? template
|
@@ -91,10 +91,9 @@ module Nutella
|
|
91
91
|
# If all is good, copy the template to dest_dir...
|
92
92
|
FileUtils.copy_entry template_dir, dest_dir
|
93
93
|
|
94
|
-
# ... and remove nutella.json
|
94
|
+
# ... and remove nutella.json and .git folder if they exist
|
95
95
|
File.delete "#{dest_dir}/nutella.json" if File.exist? "#{dest_dir}/nutella.json"
|
96
96
|
FileUtils.rm_rf "#{dest_dir}/.git"
|
97
|
-
File.delete "#{dest_dir}/.gitignore" if File.exist? "#{dest_dir}/.gitignore"
|
98
97
|
|
99
98
|
# Make the user feel happy and accomplished! :)
|
100
99
|
console.success("Installed template: #{template} as #{dest_dir_name}")
|
data/lib/core/commands/new.rb
CHANGED
@@ -3,60 +3,58 @@ require 'fileutils'
|
|
3
3
|
|
4
4
|
module Nutella
|
5
5
|
class New < Command
|
6
|
-
@description =
|
6
|
+
@description = 'Creates a new project'
|
7
7
|
|
8
8
|
def run(args=nil)
|
9
|
-
|
9
|
+
cur_prj_dir = args[0]
|
10
10
|
|
11
11
|
# If no other arguments, show help and quit here
|
12
12
|
if args.empty?
|
13
|
-
console.warn
|
13
|
+
console.warn 'You need to specify a name for your new project'
|
14
14
|
return
|
15
15
|
end
|
16
16
|
|
17
|
-
#
|
18
|
-
if
|
19
|
-
|
20
|
-
|
17
|
+
# Check that a directory (i.e. project) with the same name doesn't already exist
|
18
|
+
# If it does it looks into it to see if there is a nutella.json file and displays
|
19
|
+
# the proper error message
|
20
|
+
if File.directory? cur_prj_dir
|
21
|
+
if File.exist? "#{cur_prj_dir}/nutella.json"
|
22
|
+
console.warn "A project named #{cur_prj_dir} already exists"
|
21
23
|
return
|
22
24
|
else
|
23
|
-
console.warn "A directory named #{
|
25
|
+
console.warn "A directory named #{cur_prj_dir} already exists"
|
24
26
|
return
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
Dir.chdir @prj_dir # CD into the project
|
30
|
+
# If all seems good, generate the project structure
|
31
|
+
create_dir_structure cur_prj_dir
|
32
|
+
|
32
33
|
# Display a nice success message and return
|
33
|
-
console.success "Your new project #{
|
34
|
+
console.success "Your new project #{cur_prj_dir} is ready!"
|
34
35
|
end
|
35
36
|
|
36
37
|
|
37
38
|
private
|
38
39
|
|
39
40
|
|
40
|
-
def
|
41
|
-
|
42
|
-
FileUtils.mkdir_p("#{
|
43
|
-
FileUtils.mkdir_p("#{
|
44
|
-
#
|
41
|
+
def create_dir_structure( cur_prj_dir )
|
42
|
+
# Create directories
|
43
|
+
FileUtils.mkdir_p("#{cur_prj_dir}/bots")
|
44
|
+
FileUtils.mkdir_p("#{cur_prj_dir}/interfaces")
|
45
|
+
# Create nutella.json hash
|
45
46
|
config_file_hash = {
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
:name => cur_prj_dir,
|
48
|
+
:version => '0.1.0',
|
49
|
+
:nutella_version => File.open("#{NUTELLA_HOME}VERSION", 'rb').read,
|
50
|
+
:type => 'project',
|
51
|
+
:description => 'A quick description of your project'
|
49
52
|
}
|
50
|
-
|
53
|
+
# Write nutella.json hash
|
54
|
+
File.open("#{cur_prj_dir}/nutella.json", 'w') do |f|
|
51
55
|
f.write(JSON.pretty_generate(config_file_hash))
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
|
-
def removeDirStructure
|
56
|
-
Dir.chdir @cur_dir
|
57
|
-
console.info "Removing project #{@prj_dir}"
|
58
|
-
FileUtils.rm_rf(@prj_dir)
|
59
|
-
end
|
60
|
-
|
61
59
|
end
|
62
60
|
end
|
data/lib/core/commands/runs.rb
CHANGED
@@ -3,18 +3,18 @@ require 'core/command'
|
|
3
3
|
|
4
4
|
module Nutella
|
5
5
|
class Runs < Command
|
6
|
-
@description =
|
6
|
+
@description = 'Displays list of runs for current project or all projects'
|
7
7
|
|
8
8
|
def run(args=nil)
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
|
10
|
+
# If invoked with "all" it will show all the runs under this instance of nutella
|
11
|
+
if args[0]=='all'
|
12
|
+
display_all_runs
|
12
13
|
else
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
displayProjectRuns
|
14
|
+
# If current dir is not a nutella project, return
|
15
|
+
return unless Nutella.current_project.exist?
|
16
|
+
# Display list of runs for current nutella project
|
17
|
+
display_project_runs
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -22,35 +22,26 @@ module Nutella
|
|
22
22
|
private
|
23
23
|
|
24
24
|
|
25
|
-
def
|
25
|
+
def display_all_runs
|
26
26
|
if Nutella.runlist.empty?
|
27
|
-
console.info
|
27
|
+
console.info 'You are not running any projects'
|
28
28
|
else
|
29
|
-
console.info
|
30
|
-
Nutella.runlist.
|
29
|
+
console.info 'Currently running:'
|
30
|
+
Nutella.runlist.runs_by_project.each { |run| console.info " #{run}" }
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
runs = Nutella.runlist.to_a project_name
|
38
|
-
if runs.empty?
|
39
|
-
console.info "Currently running #{runs.length} instances of project #{project_name}"
|
40
|
-
return
|
41
|
-
end
|
42
|
-
printProjectRuns(project_name, runs)
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
def printProjectRuns(project_name, runs)
|
34
|
+
def display_project_runs
|
35
|
+
project_name = Nutella.current_project.config['name']
|
36
|
+
runs = Nutella.runlist.runs_by_project project_name
|
47
37
|
console.info "Currently running #{runs.length} instances of project #{project_name}:"
|
48
|
-
runs.
|
49
|
-
run.
|
50
|
-
|
51
|
-
|
38
|
+
runs.each do |run|
|
39
|
+
run_id = run.dup
|
40
|
+
run_id.slice! "#{project_name}_"
|
41
|
+
if run_id.empty?
|
42
|
+
console.info " #{project_name}"
|
52
43
|
else
|
53
|
-
console.info " #{run}"
|
44
|
+
console.info " #{run}"
|
54
45
|
end
|
55
46
|
end
|
56
47
|
end
|