nutella_framework 0.1.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 +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
|
+
|