climatic 0.2.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/climatic.gemspec +28 -0
- data/example/simple_app/.gitignore +12 -0
- data/example/simple_app/.rspec +2 -0
- data/example/simple_app/.ruby-version +1 -0
- data/example/simple_app/.travis.yml +5 -0
- data/example/simple_app/CODE_OF_CONDUCT.md +74 -0
- data/example/simple_app/Gemfile +6 -0
- data/example/simple_app/LICENSE.txt +21 -0
- data/example/simple_app/README.md +43 -0
- data/example/simple_app/Rakefile +6 -0
- data/example/simple_app/bin/console +14 -0
- data/example/simple_app/bin/setup +8 -0
- data/example/simple_app/etc/command_line.yml +52 -0
- data/example/simple_app/exe/user +57 -0
- data/example/simple_app/lib/tst_climatic/version.rb +3 -0
- data/example/simple_app/lib/tst_climatic.rb +5 -0
- data/example/simple_app/spec/spec_helper.rb +14 -0
- data/example/simple_app/spec/tst_climatic_spec.rb +11 -0
- data/example/simple_app/tst_climatic.gemspec +39 -0
- data/lib/climatic/config_layers/command_line_layer.rb +46 -0
- data/lib/climatic/config_layers/command_line_manager_binder.rb +84 -0
- data/lib/climatic/config_layers/env_layer.rb +41 -0
- data/lib/climatic/config_layers/executable_gem_layer.rb +45 -0
- data/lib/climatic/config_layers/gem_layer.rb +50 -0
- data/lib/climatic/config_layers/generic_layer.rb +62 -0
- data/lib/climatic/config_layers/global_layer.rb +28 -0
- data/lib/climatic/config_layers/program_description_helper.rb +94 -0
- data/lib/climatic/config_layers/project_layer.rb +61 -0
- data/lib/climatic/config_layers/provided_config_file_layer.rb +26 -0
- data/lib/climatic/config_layers/source_helper.rb +48 -0
- data/lib/climatic/config_layers/system_layer.rb +37 -0
- data/lib/climatic/config_layers/user_layer.rb +40 -0
- data/lib/climatic/initializer.rb +87 -0
- data/lib/climatic/layers_manager.rb +81 -0
- data/lib/climatic/logger/accumulator.rb +49 -0
- data/lib/climatic/logger/manager.rb +50 -0
- data/lib/climatic/logger/wrapper.rb +12 -0
- data/lib/climatic/processes/base.rb +51 -0
- data/lib/climatic/processes/command.rb +15 -0
- data/lib/climatic/processes/synchronous.rb +51 -0
- data/lib/climatic/processes/time_management.rb +21 -0
- data/lib/climatic/proxy.rb +27 -0
- data/lib/climatic/script/base.rb +65 -0
- data/lib/climatic/script/simple.rb +31 -0
- data/lib/climatic/script/unimplemented_processor.rb +19 -0
- data/lib/climatic/script.rb +4 -0
- data/lib/climatic/utils/error.rb +5 -0
- data/lib/climatic/utils/input.rb +65 -0
- data/lib/climatic/utils/safe_exec.rb +28 -0
- data/lib/climatic/utils/script_helper.rb +18 -0
- data/lib/climatic/version.rb +3 -0
- data/lib/climatic.rb +45 -0
- metadata +162 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module Climatic
|
2
|
+
|
3
|
+
module Initializer
|
4
|
+
|
5
|
+
include Climatic::Utils::ScriptHelper
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def bootstrap(cmd_line_args: ARGV.dup,
|
10
|
+
command_manager: Climatic::ConfigLayers::CommandLineLayer.default_command_line_manager)
|
11
|
+
raise Climatic::Error, 'You cannot bootstrap Climatic framework twice !' if climatic_bootstrapped?
|
12
|
+
@climatic_status = :bootstrapping
|
13
|
+
setup_initial_logger
|
14
|
+
Climatic.logger.debug 'Starting Climatic framework setup...'
|
15
|
+
# Get the config first to correctly setup the definitive logger
|
16
|
+
setup_config_manager cmd_line_args, command_manager
|
17
|
+
# Now we can setup the definitive logger
|
18
|
+
setup_logger
|
19
|
+
Climatic.logger.debug 'Climatic framework setup complete.'
|
20
|
+
@climatic_status = :bootstrapped
|
21
|
+
rescue Slop::UnknownOption
|
22
|
+
Climatic.logger.debug 'Climatic initialization failed (wrong command line options) !'
|
23
|
+
end
|
24
|
+
|
25
|
+
def climatic_bootstrapping?
|
26
|
+
@climatic_status == :bootstrapping
|
27
|
+
end
|
28
|
+
|
29
|
+
def climatic_bootstrapped?
|
30
|
+
@climatic_status == :bootstrapped
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def setup_config_manager(cmd_line_args, command_manager)
|
36
|
+
@config = Climatic::LayersManager.new
|
37
|
+
config.command_line_layer.command_line_manager = command_manager
|
38
|
+
config.command_line_layer.cmd_line_args = cmd_line_args
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup_initial_logger
|
42
|
+
@logger = Climatic::Logger::Accumulator.new
|
43
|
+
UltraCommandLine.logger = @logger
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup_logger
|
47
|
+
if config[:debug]
|
48
|
+
log_device = if config[:'log-file']
|
49
|
+
if File.exists? config[:'log-file']
|
50
|
+
if File.writable? config[:'log-file']
|
51
|
+
if config[:'truncate-log-file']
|
52
|
+
File.open(config[:'log-file'], 'w') do |log_file|
|
53
|
+
log_file.puts "Log truncated on #{Time.now}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
config[:'log-file']
|
57
|
+
else
|
58
|
+
STDERR.puts "WARNING: Log file '#{config[:'log-file']}' is not writable. Switching to STDERR..."
|
59
|
+
config[:'log-file'] = nil
|
60
|
+
STDERR
|
61
|
+
end
|
62
|
+
else
|
63
|
+
if File.writable? File.dirname(config[:'log-file'])
|
64
|
+
config[:'log-file']
|
65
|
+
else
|
66
|
+
STDERR.puts "WARNING: Cannot write log file in '#{File.dirname config[:'log-file']}'. Switching to STDERR..."
|
67
|
+
config[:'log-file'] = nil
|
68
|
+
STDERR
|
69
|
+
end
|
70
|
+
end
|
71
|
+
elsif config[:'debug-on-stderr']
|
72
|
+
STDERR
|
73
|
+
else
|
74
|
+
STDOUT
|
75
|
+
end
|
76
|
+
|
77
|
+
new_logger = ::Logger.new log_device
|
78
|
+
new_logger.level = config[:'log-level'] || Climatic::Logger::Manager::DEFAULT_LOG_LEVEL
|
79
|
+
self.logger = new_logger
|
80
|
+
else
|
81
|
+
self.logger = user_defined_logger
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Climatic
|
2
|
+
class LayersManager < SuperStack::Manager
|
3
|
+
|
4
|
+
include Climatic::ConfigLayers::ProgramDescriptionHelper
|
5
|
+
|
6
|
+
attr_reader :system_layer, :global_layer, :executable_gem_layer, :user_layer, :env_layer,
|
7
|
+
:command_line_layer, :provided_config_file_layer, :project_layer
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
self.merge_policy = SuperStack::MergePolicies::FullMergePolicy
|
12
|
+
setup_layers
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def self.default_config_file_base_name
|
17
|
+
File.basename($PROGRAM_NAME).gsub /\.[^\.]+$/, ''
|
18
|
+
end
|
19
|
+
|
20
|
+
def include_project_layer(file_or_directory, project_file_basename=nil, priority = 65)
|
21
|
+
@project_layer = Climatic::ConfigLayers::ProjectLayer.new file_or_directory, project_file_basename
|
22
|
+
project_layer.name = 'Project level'
|
23
|
+
project_layer.priority = priority
|
24
|
+
self << project_layer
|
25
|
+
end
|
26
|
+
|
27
|
+
def include_env_layer(filter = nil, priority = 70)
|
28
|
+
@env_layer = Climatic::ConfigLayers::EnvLayer.new filter
|
29
|
+
env_layer.name = 'Environment variables level'
|
30
|
+
env_layer.priority = priority
|
31
|
+
self << env_layer
|
32
|
+
end
|
33
|
+
|
34
|
+
def include_gem_layer_for(gem_name, priority = 30)
|
35
|
+
gem_layer = Climatic::ConfigLayers::GemLayer.new
|
36
|
+
gem_layer.gem_name = gem_name
|
37
|
+
raise "No config found in gem #{gem_name}" if gem_layer.file_name.nil?
|
38
|
+
gem_layer.name = "#{gem_name} Gem configuration level"
|
39
|
+
gem_layer.priority = priority
|
40
|
+
self << gem_layer
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def setup_layers
|
46
|
+
# The command line level.
|
47
|
+
@command_line_layer = setup_layer Climatic::ConfigLayers::CommandLineLayer, 'Command line configuration level', 100
|
48
|
+
|
49
|
+
# The system level
|
50
|
+
@system_layer = setup_layer Climatic::ConfigLayers::SystemLayer, 'System-wide configuration level', 10
|
51
|
+
|
52
|
+
# The executable gem level
|
53
|
+
@executable_gem_layer = setup_layer Climatic::ConfigLayers::ExecutableGemLayer, 'Gem associated to the executable running configuration level', 20
|
54
|
+
|
55
|
+
# The global level
|
56
|
+
@global_layer = setup_layer Climatic::ConfigLayers::GlobalLayer, 'Global configuration level', 40
|
57
|
+
|
58
|
+
# The user level
|
59
|
+
@user_layer = setup_layer Climatic::ConfigLayers::UserLayer, 'User configuration level', 50
|
60
|
+
|
61
|
+
# The specifically provided config file level
|
62
|
+
@provided_config_file_layer = setup_layer Climatic::ConfigLayers::ProvidedConfigFileLayer, 'Specific config file configuration level', 60
|
63
|
+
|
64
|
+
# The layer to write something
|
65
|
+
override_layer = setup_layer SuperStack::Layer, 'Overridden configuration level', 1000
|
66
|
+
self.write_layer = override_layer
|
67
|
+
|
68
|
+
reload_layers
|
69
|
+
end
|
70
|
+
|
71
|
+
def setup_layer(class_type, name, priority)
|
72
|
+
layer = class_type.new
|
73
|
+
layer.name = name
|
74
|
+
layer.priority = priority
|
75
|
+
self << layer
|
76
|
+
layer
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Logger
|
3
|
+
|
4
|
+
class Accumulator
|
5
|
+
|
6
|
+
STACK_OPS = %i(debug info warn error fatal unknown).freeze
|
7
|
+
|
8
|
+
attr_accessor :level
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@log_lines = [{op: :debug, args: ['Starting special temporary "accumulator" logger...']}]
|
12
|
+
end
|
13
|
+
|
14
|
+
def stack(op, *args)
|
15
|
+
log_lines << {op: op, args: args}
|
16
|
+
end
|
17
|
+
|
18
|
+
def transfer_content_to(other_logger)
|
19
|
+
debug "Transferring accumulated logs to logger '#{other_logger.inspect}'"
|
20
|
+
if other_logger.nil?
|
21
|
+
@log_lines = []
|
22
|
+
return
|
23
|
+
end
|
24
|
+
log_lines.each do |log_line|
|
25
|
+
other_logger.send log_line[:op], *log_line[:args]
|
26
|
+
end
|
27
|
+
@log_lines = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method_name, *args)
|
31
|
+
if STACK_OPS.include? method_name
|
32
|
+
stack method_name, *args
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def respond_to_missing?(method_name, include_private = false)
|
39
|
+
STACK_OPS.include?(method_name) || super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :log_lines
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
|
4
|
+
module Climatic
|
5
|
+
module Logger
|
6
|
+
|
7
|
+
module Manager
|
8
|
+
|
9
|
+
attr_reader :logger
|
10
|
+
|
11
|
+
def puts_and_logs(*args)
|
12
|
+
logger.puts_and_logs *args
|
13
|
+
end
|
14
|
+
|
15
|
+
def logger=(new_logger)
|
16
|
+
|
17
|
+
new_logger ||= DEVNULL_LOGGER
|
18
|
+
|
19
|
+
unless climatic_bootstrapped? or climatic_bootstrapping?
|
20
|
+
@user_defined_logger = new_logger
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
if climatic_bootstrapped?
|
25
|
+
new_logger.level = config[:'log-level'].nil? ? Climatic::Logger::Manager::DEFAULT_LOG_LEVEL : config[:'log-level']
|
26
|
+
end
|
27
|
+
|
28
|
+
new_logger.extend Climatic::Logger::Wrapper
|
29
|
+
|
30
|
+
if self.logger.respond_to? :transfer_content_to
|
31
|
+
self.logger.transfer_content_to new_logger
|
32
|
+
end
|
33
|
+
|
34
|
+
UltraCommandLine.logger = new_logger
|
35
|
+
@logger = new_logger
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
attr_reader :user_defined_logger
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
DEFAULT_LOG_LEVEL = ::Logger::Severity::WARN
|
45
|
+
DEVNULL_LOGGER = UltraCommandLine::Utils::BasicLogger::NullLogger.new
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Climatic
|
4
|
+
module Processes
|
5
|
+
|
6
|
+
class Base
|
7
|
+
|
8
|
+
include Climatic::Processes::Command
|
9
|
+
include Climatic::Processes::TimeManagement
|
10
|
+
|
11
|
+
attr_reader :process_state, :exit_status, :last_pid, :mode
|
12
|
+
attr_accessor :show_output, :log_output
|
13
|
+
|
14
|
+
def initialize(command = nil, mode = :synchronous)
|
15
|
+
self.command = command
|
16
|
+
self.process_state = :not_started
|
17
|
+
self.mode = mode
|
18
|
+
self.creation_time = Time.now
|
19
|
+
end
|
20
|
+
|
21
|
+
def mode=(mode)
|
22
|
+
mode_processor = Object.const_get "Climatic::Processes::#{mode.to_s.capitalize}"
|
23
|
+
self.extend mode_processor
|
24
|
+
@mode = mode.to_sym
|
25
|
+
rescue
|
26
|
+
raise "Invalid process mode '#{mode}'"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_writer :process_state, :exit_status, :last_pid
|
32
|
+
|
33
|
+
def report(message, to_stdout = true)
|
34
|
+
if show_output
|
35
|
+
to_stdout ? puts(message) : STDERR.puts(message)
|
36
|
+
end
|
37
|
+
if log_output
|
38
|
+
log_line = "[subprocess #{last_pid}] - #{message}"
|
39
|
+
if to_stdout
|
40
|
+
Climatic.logger.debug log_line
|
41
|
+
else
|
42
|
+
Climatic.logger.warn log_line
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Processes
|
3
|
+
|
4
|
+
module Synchronous
|
5
|
+
|
6
|
+
def execute
|
7
|
+
self.exit_status = nil
|
8
|
+
self.last_pid = nil
|
9
|
+
self.process_state = :running
|
10
|
+
self.start_time = Time.now
|
11
|
+
Open3.popen3(command) do |stdin, stdout, stderr, wait_thread|
|
12
|
+
stdin.close
|
13
|
+
self.last_pid = wait_thread.pid
|
14
|
+
begin
|
15
|
+
monitored_streams = [stdout, stderr]
|
16
|
+
loop do
|
17
|
+
begin
|
18
|
+
readables, writables = IO.select(monitored_streams)
|
19
|
+
writables.each(&:close)
|
20
|
+
readables.each do |io|
|
21
|
+
begin
|
22
|
+
buffer = ''
|
23
|
+
buffer << io.read_nonblock(1) while buffer[-1] != "\n"
|
24
|
+
report buffer, io == stdout
|
25
|
+
rescue IO::WaitReadable
|
26
|
+
next
|
27
|
+
rescue EOFError => e
|
28
|
+
monitored_streams.delete io
|
29
|
+
monitored_streams.empty? ? raise(e) : next
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue EOFError
|
33
|
+
report "End of process #{wait_thread.value.pid}"
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
rescue Errno::EAGAIN
|
38
|
+
retry
|
39
|
+
end
|
40
|
+
self.exit_status = wait_thread.value
|
41
|
+
return self.exit_status
|
42
|
+
end
|
43
|
+
ensure
|
44
|
+
self.end_time = Time.now
|
45
|
+
self.process_state = :terminated
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Climatic
|
4
|
+
module Processes
|
5
|
+
|
6
|
+
module TimeManagement
|
7
|
+
|
8
|
+
attr_reader :creation_time, :start_time, :end_time
|
9
|
+
|
10
|
+
def duration
|
11
|
+
end_time - start_time
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_writer :creation_time, :start_time, :end_time
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Climatic
|
2
|
+
|
3
|
+
module Proxy
|
4
|
+
|
5
|
+
def config
|
6
|
+
Climatic.config
|
7
|
+
end
|
8
|
+
|
9
|
+
def logger
|
10
|
+
Climatic.logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def command_line_manager
|
14
|
+
config.command_line_layer.command_line_manager
|
15
|
+
end
|
16
|
+
|
17
|
+
def help
|
18
|
+
config.command_line_layer.help
|
19
|
+
end
|
20
|
+
|
21
|
+
def puts_and_logs(*args)
|
22
|
+
Climatic.logger.puts_and_logs *args
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Script
|
3
|
+
|
4
|
+
module Base
|
5
|
+
|
6
|
+
include Climatic::Utils::ScriptHelper
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
def start
|
11
|
+
script = new
|
12
|
+
script.run
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
# logging startup configuration
|
19
|
+
Climatic.config.command_line_layer.cmd_line_args = ARGV.dup
|
20
|
+
Climatic.logger.debug "Config layers ->\n#{Climatic.config.detailed_layers_info}"
|
21
|
+
Climatic.logger.debug "Merged config -> #{Climatic.config[].to_yaml}"
|
22
|
+
# Displaying (and exiting) command line help
|
23
|
+
display_help_and_exit if Climatic.config[:help]
|
24
|
+
check_config
|
25
|
+
Climatic.logger.info 'Application is starting...'
|
26
|
+
do_process
|
27
|
+
Climatic.logger.info 'Application ended normally...'
|
28
|
+
rescue => e
|
29
|
+
display_exit_error e
|
30
|
+
exit_code = e.respond_to?(:exit_code) ? e.exit_code : 1
|
31
|
+
exit exit_code
|
32
|
+
ensure
|
33
|
+
Climatic.logger.info 'Exiting...'
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.included(base)
|
37
|
+
base.extend ClassMethods
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def display_help_and_exit
|
43
|
+
puts Climatic.config.command_line_help
|
44
|
+
exit 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def do_process
|
48
|
+
cmd_line_mngr.processor.execute
|
49
|
+
end
|
50
|
+
|
51
|
+
def cmd_line_mngr
|
52
|
+
Climatic.config.command_line_layer.command_line_manager
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_config
|
56
|
+
# Check options validity in terms of dependencies
|
57
|
+
cmd_line_mngr.command.valid? raise_error: true
|
58
|
+
# Delegates to the processor the functional checks of the config
|
59
|
+
cmd_line_mngr.processor.check_params cmd_line_mngr.cmd_line_args_for_command(cmd_line_mngr.command)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Climatic
|
2
|
+
|
3
|
+
module Script
|
4
|
+
|
5
|
+
class Simple
|
6
|
+
|
7
|
+
include Climatic::Script::UnimplementedProcessor
|
8
|
+
include Climatic::Script::Base
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
register_processor
|
12
|
+
end
|
13
|
+
|
14
|
+
def register_processor(commands = cmd_line_mngr.commands, processor = self)
|
15
|
+
commands = [commands] unless commands.is_a? Array
|
16
|
+
commands.each do |command|
|
17
|
+
cmd_line_mngr.register_processor command, processor
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def cmd_line_mngr
|
24
|
+
Climatic.config.command_line_layer.command_line_manager
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Climatic
|
2
|
+
|
3
|
+
module Script
|
4
|
+
|
5
|
+
module UnimplementedProcessor
|
6
|
+
|
7
|
+
def check_params(command_args)
|
8
|
+
Climatic.logger.debug Climatic.config[].inspect
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
raise Climatic::Error, 'Not yet implemented !'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module Input
|
5
|
+
|
6
|
+
DEFAULT_CONFIRMATION_CHOICES = {
|
7
|
+
true => %w(Yes y),
|
8
|
+
false => %w(No n)
|
9
|
+
}
|
10
|
+
|
11
|
+
def get_user_confirmation(choices: DEFAULT_CONFIRMATION_CHOICES,
|
12
|
+
default_choice: 'No',
|
13
|
+
prompt: 'Are you sure ?',
|
14
|
+
strict: false)
|
15
|
+
|
16
|
+
raise Climatic::Error, 'Invalid choices !' unless choices.is_a? Hash
|
17
|
+
values = choices.values.flatten
|
18
|
+
raise Climatic::Error, "Invalid default choice '#{default_choice}' !" unless values.include? default_choice
|
19
|
+
if Climatic.config[:auto]
|
20
|
+
yield if block_given?
|
21
|
+
return true
|
22
|
+
end
|
23
|
+
full_prompt = '%s (%s): ' % [prompt, choices_string(values, default_choice)]
|
24
|
+
STDOUT.print full_prompt
|
25
|
+
STDOUT.flush
|
26
|
+
input = nil
|
27
|
+
until values.include? input
|
28
|
+
input = STDIN.gets.chomp
|
29
|
+
input = default_choice if input.nil? || input.empty?
|
30
|
+
unless strict
|
31
|
+
input = default_choice unless values.include? input
|
32
|
+
end
|
33
|
+
end
|
34
|
+
choices.each_pair do |res, possible_choices|
|
35
|
+
if possible_choices.include? input
|
36
|
+
if res and block_given?
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
return res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
raise 'Something wrong happened !'
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def get_user_input(prompt, default=nil)
|
47
|
+
full_prompt = (default.nil? or default.empty?) ? "#{prompt}: " : "#{prompt} (default: #{default}): "
|
48
|
+
STDOUT.print full_prompt
|
49
|
+
STDOUT.flush
|
50
|
+
STDIN.gets.chomp
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
|
56
|
+
def choices_string(choices, default_choice, highlight= %w([ ]))
|
57
|
+
choices
|
58
|
+
.map { |choice| choice == default_choice ? "#{highlight.first}#{choice}#{highlight.last}" : choice }
|
59
|
+
.join '/'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module SafeExec
|
5
|
+
|
6
|
+
def safely_exec_code(*args, message: nil, &block)
|
7
|
+
if self.config[:simulate]
|
8
|
+
Climatic.logger.puts_and_logs "[SIMULATION MODE]: #{message}" unless message.nil?
|
9
|
+
else
|
10
|
+
Climatic.logger.puts_and_logs message
|
11
|
+
block.call *args
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def safely_exec_command(command, message: nil, show_output: false, log_output: true)
|
16
|
+
safely_exec_code command, message: message do |cmd|
|
17
|
+
process = Climatic::Processes::Base.new cmd
|
18
|
+
process.show_output = show_output
|
19
|
+
process.log_output = log_output
|
20
|
+
process.execute
|
21
|
+
process
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Climatic
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module ScriptHelper
|
5
|
+
|
6
|
+
def display_exit_error(e)
|
7
|
+
puts "Program aborted with message: '#{e.message}'."
|
8
|
+
if Climatic.config[:debug]
|
9
|
+
Climatic.logger.fatal "#{e.message}\nBacktrace:\n#{e.backtrace.join("\n\t")}"
|
10
|
+
else
|
11
|
+
puts ' Use --debug option for more detail (see --help).'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|