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
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'commands/meta/template_command'
|
2
2
|
|
3
3
|
module Nutella
|
4
4
|
|
5
5
|
class Template < TemplateCommand
|
6
|
-
@description = '
|
6
|
+
@description = 'Creates and validates nutella components templates'
|
7
7
|
|
8
8
|
def run(args=nil)
|
9
9
|
|
@@ -30,9 +30,9 @@ module Nutella
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def display_help
|
33
|
-
console.
|
34
|
-
console.
|
35
|
-
console.
|
33
|
+
console.warn 'You need to specify a sub command.'
|
34
|
+
console.warn 'create <template_name> creates a template skeleton in the folder with the same name'
|
35
|
+
console.warn 'validate <temple_dir> validates a template that already exists'
|
36
36
|
end
|
37
37
|
|
38
38
|
|
@@ -45,73 +45,93 @@ module Nutella
|
|
45
45
|
end
|
46
46
|
|
47
47
|
|
48
|
-
def create_template_sub_command(
|
49
|
-
|
50
|
-
|
48
|
+
def create_template_sub_command( template_name )
|
49
|
+
@default_version = '0.1.0'
|
50
|
+
@default_type = 'bot'
|
51
|
+
# Get template parameters from command line
|
52
|
+
name = prompt_and_read_name template_name
|
53
|
+
version = prompt_and_read_version
|
54
|
+
type = prompt_and_read_type
|
55
|
+
description = prompt_and_read_description type
|
56
|
+
repo = prompt_and_read_repo
|
57
|
+
# Build JSON
|
58
|
+
json = build_nutella_json( name, version, type, description, repo )
|
59
|
+
# Show confirmation and read
|
60
|
+
prompt_and_read_confirm json
|
61
|
+
|
62
|
+
end
|
51
63
|
|
52
|
-
|
64
|
+
|
65
|
+
def prompt_and_read_name(template_name)
|
53
66
|
puts 'What is the name of your template?'
|
54
|
-
print "(#{
|
55
|
-
c = $stdin.gets.chomp!
|
56
|
-
name = c.empty? ? name_d : c
|
57
|
-
# Version
|
58
|
-
puts 'What is the version of your template?'
|
59
|
-
print "(#{ver_d}) "
|
67
|
+
print "(#{template_name}) "
|
60
68
|
c = $stdin.gets.chomp!
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
69
|
+
c.empty? ? template_name : c
|
70
|
+
end
|
71
|
+
|
72
|
+
def prompt_and_read_version
|
73
|
+
prompt_and_read 'What is the version of your template?', @default_version
|
74
|
+
end
|
75
|
+
|
76
|
+
def prompt_and_read_type
|
77
|
+
prompt_and_read 'Are you creating a template for a "bot" or "interface"?', @default_type
|
78
|
+
end
|
79
|
+
|
80
|
+
def prompt_and_read( prompt, default )
|
81
|
+
puts prompt
|
82
|
+
print "(#{default}) "
|
65
83
|
c = $stdin.gets.chomp!
|
66
|
-
|
67
|
-
|
84
|
+
c.empty? ? default : c
|
85
|
+
end
|
86
|
+
|
87
|
+
def prompt_and_read_description(type)
|
68
88
|
puts "Do you want to provide a short description for your #{type} template?"
|
69
89
|
print '(optional, hit enter if no description) '
|
70
|
-
|
71
|
-
|
90
|
+
$stdin.gets.chomp!
|
91
|
+
end
|
92
|
+
|
93
|
+
def prompt_and_read_repo
|
72
94
|
puts 'Do you want to provide a git repository for your template?'
|
73
95
|
print '(optional, hit enter if no repo) '
|
74
|
-
|
96
|
+
$stdin.gets.chomp!
|
97
|
+
end
|
75
98
|
|
76
|
-
|
99
|
+
def prompt_and_read_confirm(json)
|
77
100
|
puts 'Looks good?'
|
78
|
-
json = build_nutella_json( name, version, type, description, repo )
|
79
101
|
puts JSON.pretty_generate json
|
80
102
|
print '(yes/no) '
|
81
|
-
|
82
|
-
# If user confirms, create template
|
83
103
|
confirm = $stdin.gets.chomp!
|
84
104
|
if confirm=='yes'
|
85
|
-
|
105
|
+
create_template json
|
86
106
|
else
|
87
107
|
console.warn 'Template creation aborted'
|
88
108
|
end
|
89
|
-
|
90
109
|
end
|
91
110
|
|
92
|
-
|
93
|
-
def create_template_files( json )
|
111
|
+
def create_template( json )
|
94
112
|
# First validate the JSON
|
95
113
|
unless validate_nutella_file_json json
|
96
114
|
console.error 'Something was wrong with your nutella.json file. Template creation aborted'
|
97
115
|
return
|
98
116
|
end
|
99
|
-
#
|
117
|
+
# Check that the template directory doesn't already exist
|
100
118
|
template_dir = File.join( Dir.pwd, json['name'] )
|
101
|
-
|
102
|
-
if File.directory?(template_dir)
|
119
|
+
if File.directory? template_dir
|
103
120
|
console.error("The directory #{template_dir} already exists! Can't create template #{json[:name]}")
|
104
121
|
return
|
105
122
|
end
|
123
|
+
# Create template directory and files
|
124
|
+
create_template_files(json, template_dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
def create_template_files(json, template_dir)
|
106
128
|
# Create directory
|
107
129
|
Dir.mkdir template_dir
|
108
130
|
# Create nutella.json file
|
109
131
|
File.open("#{template_dir}/nutella.json", 'w') { |f| f.write(JSON.pretty_generate json) }
|
110
132
|
# Add bot/interface specific files
|
111
|
-
|
112
|
-
|
113
|
-
bot_specific_file = File.join( Nutella.config['nutella_home'], 'data/index.html' ) if json['type']=='interface'
|
114
|
-
FileUtils.copy( bot_specific_file, template_dir )
|
133
|
+
FileUtils.copy(File.join(Nutella::NUTELLA_HOME, 'data/startup'), template_dir) if json['type']=='bot'
|
134
|
+
FileUtils.copy(File.join(Nutella::NUTELLA_HOME, 'data/index.html'), template_dir) if json['type']=='interface'
|
115
135
|
console.success "Template #{json['name']} created successfully!"
|
116
136
|
end
|
117
137
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Nutella
|
4
|
+
|
5
|
+
# This module contains a series of utilities methods to handle the nutella
|
6
|
+
# application contained in the directory we are at this moment
|
7
|
+
module CurrentAppUtils
|
8
|
+
|
9
|
+
# Checks that the current directory is actually a nutella application
|
10
|
+
# @return [Boolean] true if the current directory is a nutella application, false otherwise
|
11
|
+
def CurrentAppUtils.exist?
|
12
|
+
cur_app_dir = Dir.pwd
|
13
|
+
nutella_json_file = "#{cur_app_dir}/nutella.json"
|
14
|
+
# Check that there is a nutella.json file in the main directory of the application
|
15
|
+
if File.exist? nutella_json_file
|
16
|
+
conf = JSON.parse( IO.read(nutella_json_file) )
|
17
|
+
if conf['nutella_version'].nil?
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
else
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Builds a PersistedHash of the application nutella.json file and returns it.
|
27
|
+
# This method is used to ease access to the app nutella.json file.
|
28
|
+
# @return [PersistedHash] the PersistedHash of the app nutella.json file
|
29
|
+
def CurrentAppUtils.config
|
30
|
+
cur_app_dir = Dir.pwd
|
31
|
+
nutella_json_file = "#{cur_app_dir}/nutella.json"
|
32
|
+
if File.exist? nutella_json_file
|
33
|
+
return PersistedHash.new(nutella_json_file)
|
34
|
+
else
|
35
|
+
raise 'The current directory is not a nutella app: impossible to read nutella.json file'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Calling this method (Nutella.current_app) simply returns
|
43
|
+
# a reference to the CurrentAppUtils module
|
44
|
+
def Nutella.current_app
|
45
|
+
CurrentAppUtils
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
@@ -4,12 +4,12 @@ require 'fileutils'
|
|
4
4
|
module Nutella
|
5
5
|
|
6
6
|
# This class behaves *similarly* to a regular Hash but it persists every operation
|
7
|
-
# to the
|
7
|
+
# to the file passed in the constructor. Not all Hash operations are supported
|
8
8
|
# and we added some of our own.
|
9
9
|
class PersistedHash
|
10
10
|
|
11
11
|
def initialize(file)
|
12
|
-
@
|
12
|
+
@file=file
|
13
13
|
end
|
14
14
|
|
15
15
|
def []( key )
|
@@ -69,7 +69,7 @@ module Nutella
|
|
69
69
|
# there is currently no value associated with the specified key.
|
70
70
|
# @return [Boolean] false if the key already exists, true if the
|
71
71
|
# <key, value> pair was added successfully
|
72
|
-
def
|
72
|
+
def add_key_value?(key, val)
|
73
73
|
hash = load_hash
|
74
74
|
return false if hash.key? key
|
75
75
|
hash[key] = val
|
@@ -81,37 +81,39 @@ module Nutella
|
|
81
81
|
# there is currently a value associated with the specified key.
|
82
82
|
# @return [Boolean] false if there is no value associated with
|
83
83
|
# the specified key, true otherwise
|
84
|
-
def
|
84
|
+
def delete_key_value?( key )
|
85
85
|
hash = load_hash
|
86
86
|
return false if hash.delete(key).nil?
|
87
87
|
store_hash hash
|
88
88
|
true
|
89
89
|
end
|
90
90
|
|
91
|
+
|
92
|
+
# Removes the file the hash is persisted to
|
93
|
+
def remove_file
|
94
|
+
File.delete(@file) if File.exist?(@file)
|
95
|
+
end
|
96
|
+
|
91
97
|
private
|
92
98
|
|
93
99
|
def store_hash(hash)
|
94
|
-
dirname = File.dirname(@
|
100
|
+
dirname = File.dirname(@file)
|
95
101
|
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
96
|
-
File.open(@
|
102
|
+
File.open(@file, 'w+') do |f|
|
97
103
|
f.write(JSON.pretty_generate(hash))
|
98
104
|
end
|
99
|
-
File.chmod(0777, @
|
105
|
+
File.chmod(0777, @file)
|
100
106
|
end
|
101
107
|
|
102
108
|
def load_hash
|
103
109
|
begin
|
104
|
-
return JSON.parse IO.read @
|
110
|
+
return JSON.parse IO.read @file
|
105
111
|
rescue
|
106
112
|
# File doesn't exist, return new empty Hash
|
107
113
|
Hash.new
|
108
114
|
end
|
109
115
|
end
|
110
116
|
|
111
|
-
def remove_file
|
112
|
-
File.delete(@config_file) if File.exist?(@config_file)
|
113
|
-
end
|
114
|
-
|
115
117
|
end
|
116
118
|
|
117
119
|
end
|
data/lib/config/runlist.rb
CHANGED
@@ -1,32 +1,132 @@
|
|
1
1
|
require 'config/persisted_hash'
|
2
2
|
|
3
3
|
module Nutella
|
4
|
-
|
5
|
-
class RunListHash < PersistedHash
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
# Manages the list of nutella applications and runs handled by the framework.
|
6
|
+
# The list has a structure similar this one:
|
7
|
+
# {
|
8
|
+
# "app_a": {
|
9
|
+
# "runs": [ "default", "run_1", "run_2" ],
|
10
|
+
# "path": "/path/to/app/a/files/"
|
11
|
+
# },
|
12
|
+
# "app_b": {
|
13
|
+
# "runs": [ "run_1", "run_3" ],
|
14
|
+
# "path": "/path/to/app/b/files/"
|
15
|
+
# }
|
16
|
+
# }
|
17
|
+
class RunListHash
|
18
|
+
|
19
|
+
def initialize( file )
|
20
|
+
@ph = PersistedHash.new file
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Returns all the +run_id+s for ALL applications
|
25
|
+
#
|
26
|
+
# @return [Array<String>] list of +run_id+s associated to the specified app_id
|
27
|
+
def all_runs
|
28
|
+
@ph.to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Returns all the +run_id+s for a certain application
|
33
|
+
#
|
34
|
+
# @param [String] app_id the id of the application we want to find run_ids for
|
35
|
+
# @return [Array<String>] list of +run_id+s associated to the specified app_id
|
36
|
+
def runs_for_app( app_id )
|
37
|
+
# If there is no app, then return false and do nothing
|
38
|
+
return [] if @ph[app_id].nil?
|
39
|
+
runs = @ph[app_id]['runs']
|
40
|
+
runs.nil? ? [] : runs
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Adds a run_id to the runlist
|
45
|
+
#
|
46
|
+
# @param [String] app_id the app_id the run_id belongs to
|
47
|
+
# @param [String] run_id the run_id we are trying to add to the runs list
|
48
|
+
# @param [String] path_to_app_files the path to the application files
|
49
|
+
# @return [Boolean] true if the run_id is added to the list (i.e. there is no other
|
50
|
+
# run_id with for the same app_id)
|
51
|
+
def add?( app_id, run_id, path_to_app_files )
|
52
|
+
# If no run_id is specified, we are adding the "default" run
|
53
|
+
run_id = 'default' if run_id.nil?
|
54
|
+
# Check if we are adding the first run for a certain application
|
55
|
+
if @ph.add_key_value?(app_id, Hash.new)
|
56
|
+
t = @ph[app_id]
|
57
|
+
# Add path and initialize runs
|
58
|
+
t['path'] = path_to_app_files
|
59
|
+
t['runs'] = [run_id]
|
60
|
+
else
|
61
|
+
t = @ph[app_id]
|
62
|
+
# Check a run with this name doesn't already exist
|
63
|
+
return false if t['runs'].include? run_id
|
64
|
+
# Add the run_id to list of runs
|
65
|
+
t['runs'].push(run_id)
|
66
|
+
end
|
67
|
+
@ph[app_id] = t
|
68
|
+
true
|
13
69
|
end
|
14
70
|
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
|
71
|
+
|
72
|
+
# Remove a run_id from the list
|
73
|
+
#
|
74
|
+
# @param [String] app_id the app_id the run_id belongs to
|
75
|
+
# @param [String] run_id the run_if we are trying to remove from the runs list
|
76
|
+
# @return [Boolean] true if the run_id is removed from the list (i.e. a run_id with that name exists
|
77
|
+
# and is successfully removed)
|
78
|
+
def delete?( app_id, run_id )
|
79
|
+
# If there is no app, then return false and do nothing
|
80
|
+
return false if @ph[app_id].nil?
|
81
|
+
t = @ph[app_id]
|
82
|
+
result = t['runs'].delete run_id
|
83
|
+
if t['runs'].empty?
|
84
|
+
# If run_id was the last run for this app, remove the app as well
|
85
|
+
@ph.delete_key_value? app_id
|
86
|
+
else
|
87
|
+
# otherwise write the hash back
|
88
|
+
@ph[app_id] = t
|
89
|
+
end
|
90
|
+
result.nil? ? false : true
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Returns true if the runs list is empty
|
95
|
+
# @return [Boolean] true if the list is empty, false otherwise
|
96
|
+
def empty?
|
97
|
+
@ph.empty?
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Removes the runs list file
|
102
|
+
def remove_file
|
103
|
+
@ph.remove_file
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# This method checks that the list reflects the actual
|
108
|
+
# state of the system. It does so by checking that there is
|
109
|
+
# still a tmux session with the run name. If that's not the case,
|
110
|
+
# it removes the missing runs from the list.
|
111
|
+
def clean_list
|
112
|
+
all_runs.each do |app, _|
|
113
|
+
runs_for_app(app).each do |run|
|
114
|
+
unless Tmux.session_exist? Tmux.session_name(app, run)
|
115
|
+
delete? app, run
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
21
119
|
end
|
22
|
-
|
23
120
|
|
24
121
|
end
|
25
122
|
|
123
|
+
|
26
124
|
# Calling this method (Nutella.runlist) simply returns and instance of
|
27
125
|
# RunListHash linked to file runlist.json in the nutella home directory
|
28
126
|
def Nutella.runlist
|
29
|
-
RunListHash.new( "#{ENV['HOME']}/.nutella/runlist.json" )
|
127
|
+
rl = RunListHash.new( "#{ENV['HOME']}/.nutella/runlist.json" )
|
128
|
+
rl.clean_list
|
129
|
+
rl
|
30
130
|
end
|
31
131
|
|
32
132
|
end
|
@@ -40,7 +40,7 @@ module Nutella
|
|
40
40
|
# Print nutella logo
|
41
41
|
def self.print_nutella_logo
|
42
42
|
console.info(NUTELLA_LOGO)
|
43
|
-
nutella_version = File.open("#{Nutella
|
43
|
+
nutella_version = File.open("#{Nutella::NUTELLA_HOME}VERSION", 'rb').read
|
44
44
|
console.info("Welcome to nutella version #{nutella_version}! For a complete lists of available commands type 'nutella help'\n")
|
45
45
|
# If nutella is not ready to be used (i.e. nobody has invoked the "nutella checkup" command yet),
|
46
46
|
# append warning/reminder message
|
data/lib/core/nutella_core.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Require all commands by iterating through all the files
|
2
2
|
# in the commands directory
|
3
|
-
Dir["#{File.dirname(__FILE__)}
|
3
|
+
Dir["#{File.dirname(__FILE__)}/../commands/*.rb"].each do |file|
|
4
4
|
# noinspection RubyResolve
|
5
|
-
require "
|
5
|
+
require "commands/#{File.basename(file, File.extname(file))}"
|
6
6
|
end
|
7
7
|
|
8
8
|
module Nutella
|
@@ -29,14 +29,10 @@ module Nutella
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# This method initializes the nutella configuration file (config.json) with:
|
32
|
-
# - nutella_home: the directory nutella is installed in
|
33
|
-
# - tmp_dir: temporary directory used when installing remote templates
|
34
32
|
# - config_dir: directory where the configuration files are stored in
|
35
33
|
# - broker_dir: directory where the local broker is installed in
|
36
34
|
# - main_interface_port: the port used to serve interfaces
|
37
35
|
def Nutella.init
|
38
|
-
Nutella.config['nutella_home'] = NUTELLA_HOME
|
39
|
-
Nutella.config['tmp_dir'] = "#{NUTELLA_HOME}.tmp/"
|
40
36
|
Nutella.config['config_dir'] = "#{ENV['HOME']}/.nutella/"
|
41
37
|
Nutella.config['broker_dir'] = "#{Nutella.config['config_dir']}broker/"
|
42
38
|
Nutella.config['main_interface_port'] = 57880
|
data/lib/nutella_framework.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# Import all the modules
|
2
2
|
require 'logging/nutella_logging'
|
3
3
|
require 'core/nutella_core'
|
4
|
+
require 'core/nutella_cli'
|
4
5
|
require 'config/config'
|
5
6
|
require 'config/runlist'
|
6
|
-
require 'config/
|
7
|
-
require 'cli/nutella_cli'
|
7
|
+
require 'config/current_app_utils'
|
8
8
|
|
9
9
|
module Nutella
|
10
|
-
|
10
|
+
|
11
|
+
# Initialize nutella home and temporary folder
|
11
12
|
home_dir = File.dirname(__FILE__)
|
12
13
|
NUTELLA_HOME = home_dir[0..-4]
|
14
|
+
NUTELLA_TMP = "#{NUTELLA_HOME}.tmp/"
|
13
15
|
|
14
16
|
# If the nutella configuration file (config.json) is empty (or doesn't exist) we're going to initialize it
|
15
17
|
# with nutella constants and defaults
|