nutella_framework 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +5 -0
- data/Gemfile +17 -0
- data/LICENSE +20 -0
- data/README.md +11 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bin/nutella +5 -0
- data/lib/cli/nutella_cli.rb +44 -0
- data/lib/config/config.rb +72 -0
- data/lib/config/project.rb +53 -0
- data/lib/config/runlist.rb +91 -0
- data/lib/core/command.rb +12 -0
- data/lib/core/commands/broker.rb +58 -0
- data/lib/core/commands/checkup.rb +91 -0
- data/lib/core/commands/help.rb +22 -0
- data/lib/core/commands/install.rb +153 -0
- data/lib/core/commands/new.rb +62 -0
- data/lib/core/commands/runs.rb +42 -0
- data/lib/core/commands/start.rb +101 -0
- data/lib/core/commands/stop.rb +62 -0
- data/lib/core/nutella_core.rb +32 -0
- data/lib/core/tmux.rb +33 -0
- data/lib/logging/nutella_logger-remote.rb +31 -0
- data/lib/logging/nutella_logger.rb +42 -0
- data/lib/logging/nutella_logging.rb +35 -0
- data/lib/nutella_framework.rb +17 -0
- data/test/config/test_config.rb +47 -0
- data/test/config/test_project.rb +32 -0
- data/test/config/test_runlist.rb +46 -0
- data/test/helper.rb +36 -0
- data/test/logging/test_logging.rb +16 -0
- data/test/test_nutella_framework.rb +30 -0
- metadata +239 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'core/command'
|
2
|
+
require 'core/tmux'
|
3
|
+
|
4
|
+
module Nutella
|
5
|
+
class Stop < Command
|
6
|
+
@description = "Stops all or some of the bots in the current project"
|
7
|
+
|
8
|
+
def run(args=nil)
|
9
|
+
# Is current directory a nutella prj?
|
10
|
+
if !Nutella.currentProject.exist?
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
# Extract runid
|
15
|
+
runid = args[0].to_s.empty? ? Nutella.currentProject.config["name"] : Nutella.currentProject.config["name"] + "_" + args[0]
|
16
|
+
|
17
|
+
# Remove from the list of runs
|
18
|
+
if Nutella.runlist.delete?(runid).nil?
|
19
|
+
console.warn "Run #{runid} doesn't exist. Impossible to stop it."
|
20
|
+
return
|
21
|
+
end
|
22
|
+
# Are we using the internal broker? If yes, stop it
|
23
|
+
if Nutella.runlist.empty? and Nutella.config['broker'] == "localhost"
|
24
|
+
stopBroker
|
25
|
+
end
|
26
|
+
|
27
|
+
# Extract project directory
|
28
|
+
@prj_dir = Nutella.currentProject.dir
|
29
|
+
|
30
|
+
# Stops all the bots
|
31
|
+
Tmux.killSession(runid)
|
32
|
+
|
33
|
+
# Deletes bots config file if it exists
|
34
|
+
File.delete("#{@prj_dir}/.botsconfig.json") if File.exist?("#{@prj_dir}/.botsconfig.json")
|
35
|
+
|
36
|
+
# Output success message
|
37
|
+
if runid == Nutella.currentProject.config["name"]
|
38
|
+
console.success "Project #{Nutella.currentProject.config["name"]} stopped"
|
39
|
+
else
|
40
|
+
console.success "Project #{Nutella.currentProject.config["name"]}, run #{args[0]} stopped"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
|
48
|
+
def stopBroker
|
49
|
+
pidFile = "#{Nutella.config["broker_dir"]}/bin/.pid"
|
50
|
+
if File.exist?(pidFile) # Does the broker pid file exist?
|
51
|
+
pidF = File.open(pidFile, "rb")
|
52
|
+
pid = pidF.read.to_i
|
53
|
+
pidF.close()
|
54
|
+
Process.kill("SIGKILL", pid)
|
55
|
+
File.delete(pidFile)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Include all commands
|
2
|
+
Dir[File.dirname(__FILE__)+"/commands/*.rb"].each do |file|
|
3
|
+
require "core/commands/#{File.basename(file, File.extname(file))}"
|
4
|
+
end
|
5
|
+
|
6
|
+
module Nutella
|
7
|
+
|
8
|
+
# Execute command. Returns nil if all is good, otherwise it exceptions out
|
9
|
+
def Nutella.executeCommand (command, args=nil)
|
10
|
+
# Check that the command exists
|
11
|
+
if commandExists?(command)
|
12
|
+
Object::const_get("Nutella::#{command.capitalize}").new.run(args)
|
13
|
+
else
|
14
|
+
console.error "Unknown command #{command}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Check that a command exists
|
19
|
+
def Nutella.commandExists?(command)
|
20
|
+
return Nutella.const_get("Nutella::#{command.capitalize}").is_a?(Class)
|
21
|
+
rescue NameError
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initialize
|
26
|
+
def Nutella.init
|
27
|
+
Nutella.config["nutella_home"] = NUTELLA_HOME
|
28
|
+
Nutella.config["tmp_dir"] = NUTELLA_HOME+".tmp"
|
29
|
+
Nutella.config["broker_dir"] = NUTELLA_HOME+"broker"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/core/tmux.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nutella
|
2
|
+
|
3
|
+
class Tmux
|
4
|
+
|
5
|
+
def initialize(runId)
|
6
|
+
@runId = runId
|
7
|
+
end
|
8
|
+
|
9
|
+
def newWindow(bot)
|
10
|
+
if !defined?(@sessions)
|
11
|
+
# If I have no sessions I'm gonna create one and, at the same time, create a new window for the bot
|
12
|
+
`tmux new-session -d -s #{@runId} -n #{bot} &> /dev/null`
|
13
|
+
@sessions = [bot]
|
14
|
+
else
|
15
|
+
# Create new window `bot`
|
16
|
+
# -k destroys it if it can't be created
|
17
|
+
# Pring info about creation of window
|
18
|
+
`tmux new-window -kP -n #{bot} &> /dev/null`
|
19
|
+
@sessions.push(bot)
|
20
|
+
end
|
21
|
+
# Select window
|
22
|
+
`tmux select-window -t #{@runId}:#{@sessions.length-1} &> /dev/null`
|
23
|
+
# Start bot
|
24
|
+
`tmux send-keys "cd bots/#{bot};./startup #{@runId}" C-m`
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.killSession(runId)
|
28
|
+
`tmux kill-session -t #{runId} &> /dev/null`
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Nutella
|
2
|
+
|
3
|
+
class NutellaLoggerRemote < NutellaLogger
|
4
|
+
|
5
|
+
def debug(message, code=nil)
|
6
|
+
@log.debug(message)
|
7
|
+
code
|
8
|
+
end
|
9
|
+
|
10
|
+
def info(message, code=nil)
|
11
|
+
@log.info(message)
|
12
|
+
code
|
13
|
+
end
|
14
|
+
|
15
|
+
def success(message, code=nil)
|
16
|
+
@log.info(ANSI.green + message + ANSI.reset)
|
17
|
+
code
|
18
|
+
end
|
19
|
+
|
20
|
+
def warn(message, code=nil)
|
21
|
+
@log.warn(ANSI.yellow + message + ANSI.reset)
|
22
|
+
code
|
23
|
+
end
|
24
|
+
|
25
|
+
def error(message, code=nil)
|
26
|
+
@log.error(ANSI.red + message + ANSI.reset)
|
27
|
+
code
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ansi/code'
|
2
|
+
require 'logging'
|
3
|
+
|
4
|
+
module Nutella
|
5
|
+
|
6
|
+
class NutellaLogger
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@log = Logging.logger[name]
|
10
|
+
@log.add_appenders(Logging.appenders.stdout(
|
11
|
+
:layout => Logging.layouts.pattern(:pattern => '%m\n')
|
12
|
+
)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def debug(message, code=nil)
|
17
|
+
@log.debug(ANSI.cyan + message + ANSI.reset)
|
18
|
+
code
|
19
|
+
end
|
20
|
+
|
21
|
+
def info(message, code=nil)
|
22
|
+
@log.info(message)
|
23
|
+
code
|
24
|
+
end
|
25
|
+
|
26
|
+
def success(message, code=nil)
|
27
|
+
@log.info(ANSI.green + message + ANSI.reset)
|
28
|
+
code
|
29
|
+
end
|
30
|
+
|
31
|
+
def warn(message, code=nil)
|
32
|
+
@log.warn(ANSI.yellow + message + ANSI.reset)
|
33
|
+
code
|
34
|
+
end
|
35
|
+
|
36
|
+
def error(message, code=nil)
|
37
|
+
@log.error(ANSI.red + message + ANSI.reset)
|
38
|
+
code
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'logging/nutella_logger'
|
3
|
+
require 'logging/nutella_logger-remote'
|
4
|
+
|
5
|
+
module Nutella
|
6
|
+
|
7
|
+
class NutellaLogging
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
console = NutellaLogger.new("console")
|
12
|
+
log = NutellaLoggerRemote.new("log")
|
13
|
+
@loggers = {"log" => log, "console" => console}
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger(name)
|
17
|
+
@loggers[name]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
module Kernel
|
26
|
+
|
27
|
+
def console
|
28
|
+
Nutella::NutellaLogging.instance.logger('console')
|
29
|
+
end
|
30
|
+
|
31
|
+
def log
|
32
|
+
Nutella::NutellaLogging.instance.logger('log')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Nutella main script
|
2
|
+
require 'logging/nutella_logging'
|
3
|
+
require 'core/nutella_core'
|
4
|
+
require 'cli/nutella_cli'
|
5
|
+
require 'config/config'
|
6
|
+
require 'config/runlist'
|
7
|
+
require 'config/project'
|
8
|
+
|
9
|
+
module Nutella
|
10
|
+
NUTELLA_HOME = File.dirname(__FILE__)+"/../"
|
11
|
+
|
12
|
+
# Store some constants and defaults in the configuration file
|
13
|
+
if Nutella.config.empty?
|
14
|
+
Nutella.init
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
class TestNutellaConfig < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Nutella.config.send(:removeConfigFile)
|
9
|
+
end
|
10
|
+
|
11
|
+
should "set a key value" do
|
12
|
+
assert_equal "value1", Nutella.config["key1"]="value1"
|
13
|
+
end
|
14
|
+
|
15
|
+
should "return 'nil' if a key doesn't exist" do
|
16
|
+
assert_nil Nutella.config["fakekey"]
|
17
|
+
end
|
18
|
+
|
19
|
+
should "return the value associated with a key whenever that key exists" do
|
20
|
+
Nutella.config["key2"]="value2"
|
21
|
+
assert_equal "value2", Nutella.config["key2"]
|
22
|
+
end
|
23
|
+
|
24
|
+
should "retun true if a key exists" do
|
25
|
+
Nutella.config["key3"]="value3"
|
26
|
+
assert Nutella.config.has_key?("key3")
|
27
|
+
end
|
28
|
+
|
29
|
+
should "retun false if a key doens't exist" do
|
30
|
+
refute Nutella.config.has_key?("key4")
|
31
|
+
end
|
32
|
+
|
33
|
+
should "access nested hashes" do
|
34
|
+
Nutella.config["key5"]={"k55" => "v55"}
|
35
|
+
assert_equal "v55", Nutella.config["key5"]["k55"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
Nutella.config.send(:removeConfigFile)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
class TestProject < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Nutella.executeCommand "new", ["test_project"]
|
9
|
+
Dir.chdir NUTELLA_HOME + "test_project"
|
10
|
+
end
|
11
|
+
|
12
|
+
should "return true if the dir is a nutella project" do
|
13
|
+
assert Nutella.currentProject.exist?
|
14
|
+
end
|
15
|
+
|
16
|
+
should "return false if the dir is not a nutella project" do
|
17
|
+
Dir.chdir NUTELLA_HOME
|
18
|
+
refute Nutella.currentProject.exist?
|
19
|
+
end
|
20
|
+
|
21
|
+
should "return the correct version of nutella as read from the project configuration file" do
|
22
|
+
assert_equal File.open(NUTELLA_HOME+"VERSION", "rb").read, Nutella.currentProject.config["nutella_version"]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
FileUtils.rm_rf(NUTELLA_HOME + "test_project")
|
28
|
+
Dir.chdir NUTELLA_HOME
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
class TestRunList < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Nutella.runlist.send(:removeRunListFile)
|
9
|
+
end
|
10
|
+
|
11
|
+
should "return true if the list is empty" do
|
12
|
+
assert Nutella.runlist.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
should "return false if the list is not empty" do
|
16
|
+
refute_nil Nutella.runlist.add? "run1"
|
17
|
+
refute Nutella.runlist.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return empty array if the list is empty" do
|
21
|
+
assert_empty Nutella.runlist.to_a
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return an array of runs in the list if not empty" do
|
25
|
+
refute_nil Nutella.runlist.add? "run1"
|
26
|
+
refute_nil Nutella.runlist.add? "run2"
|
27
|
+
assert_equal ["run1", "run2"], Nutella.runlist.to_a
|
28
|
+
end
|
29
|
+
|
30
|
+
should "return nil if trying to add the same element twice" do
|
31
|
+
refute_nil Nutella.runlist.add? "run1"
|
32
|
+
assert_nil Nutella.runlist.add? "run1"
|
33
|
+
end
|
34
|
+
|
35
|
+
should "return properly when deleting an item" do
|
36
|
+
refute_nil Nutella.runlist.add? "run1"
|
37
|
+
refute_nil Nutella.runlist.delete? "run1"
|
38
|
+
assert_nil Nutella.runlist.delete? "run1"
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown
|
42
|
+
Nutella.runlist.send(:removeRunListFile)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
module SimpleCov::Configuration
|
4
|
+
def clean_filters
|
5
|
+
@filters = []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
SimpleCov.configure do
|
10
|
+
clean_filters
|
11
|
+
load_profile 'test_frameworks'
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV["COVERAGE"] && SimpleCov.start do
|
15
|
+
add_filter "/.rvm/"
|
16
|
+
end
|
17
|
+
require 'rubygems'
|
18
|
+
require 'bundler'
|
19
|
+
begin
|
20
|
+
Bundler.setup(:default, :development)
|
21
|
+
rescue Bundler::BundlerError => e
|
22
|
+
$stderr.puts e.message
|
23
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
24
|
+
exit e.status_code
|
25
|
+
end
|
26
|
+
require 'minitest/autorun'
|
27
|
+
require 'shoulda'
|
28
|
+
|
29
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
30
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
31
|
+
require 'nutella_framework'
|
32
|
+
|
33
|
+
class MiniTest::Test
|
34
|
+
end
|
35
|
+
|
36
|
+
MiniTest.autorun
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
class TestNutellaLogger < MiniTest::Test
|
5
|
+
|
6
|
+
# should "log to console with color and error code" do
|
7
|
+
# assert_equal(453, console.error("This is the message that needs to be logged", 453))
|
8
|
+
# end
|
9
|
+
|
10
|
+
# shuold "log to appenders and not console" do
|
11
|
+
# log.error("This is an error message that needs to be logged", 354)
|
12
|
+
# end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|