climatic 0.2.26
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/.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,46 @@
|
|
1
|
+
require 'climatic/config_layers/command_line_manager_binder'
|
2
|
+
|
3
|
+
module Climatic
|
4
|
+
module ConfigLayers
|
5
|
+
|
6
|
+
class CommandLineLayer < SuperStack::Layer
|
7
|
+
|
8
|
+
include Climatic::ConfigLayers::CommandLineManagerBinder
|
9
|
+
|
10
|
+
CONFIG_ROOT_DIR = %w(etc config).freeze
|
11
|
+
DEFAULT_COMMAND_LINE_DEFINITION_FILE = 'command_line.yml'.freeze
|
12
|
+
COMMAND_LINE_MANAGER_CLASS = UltraCommandLine::Manager::Base
|
13
|
+
|
14
|
+
def initialize(command_line_manager = self.class.default_command_line_manager)
|
15
|
+
# raise UltraCommandLine::Error, 'Invalid command line manager !' unless command_line_manager.is_a? MANAGER_CLASS
|
16
|
+
@command_line_manager = command_line_manager
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.default_command_line_manager
|
22
|
+
begin
|
23
|
+
CONFIG_ROOT_DIR.each do |sub_dir|
|
24
|
+
default_definition_file = File.join Climatic::ConfigLayers::ExecutableGemLayer.executable_gem_config_root, sub_dir, DEFAULT_COMMAND_LINE_DEFINITION_FILE
|
25
|
+
if File.readable? default_definition_file
|
26
|
+
return build_command_line_manager default_definition_file
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue => e
|
30
|
+
Climatic.logger.debug "#{e.message}\nBacktrace:\n#{e.backtrace.join("\n\t")}"
|
31
|
+
end
|
32
|
+
UltraCommandLine::Manager::Base.new
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def self.build_command_line_manager(definition_file)
|
37
|
+
mngr = COMMAND_LINE_MANAGER_CLASS.from_yaml_file definition_file
|
38
|
+
mngr.definition_hash_to_commands
|
39
|
+
mngr
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
module CommandLineManagerBinder
|
5
|
+
|
6
|
+
SUB_COMMANDS_HELP_HEADER = [
|
7
|
+
'',
|
8
|
+
'-' * 80,
|
9
|
+
' Following subcommands exist too:',
|
10
|
+
' For more information you can always issue sub_command_name --help...',
|
11
|
+
'-' * 80
|
12
|
+
]
|
13
|
+
|
14
|
+
attr_accessor :command_line_manager
|
15
|
+
|
16
|
+
def cmd_line_args
|
17
|
+
command_line_manager.cmd_line_args
|
18
|
+
end
|
19
|
+
|
20
|
+
def cmd_line_args=(args)
|
21
|
+
command_line_manager.cmd_line_args = args
|
22
|
+
reload
|
23
|
+
end
|
24
|
+
|
25
|
+
def extra_parameters
|
26
|
+
with_selected_command {|c| c.extra_arguments }
|
27
|
+
end
|
28
|
+
|
29
|
+
def load
|
30
|
+
with_selected_command do |c|
|
31
|
+
replace c.params_hash
|
32
|
+
@file_name = :none
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
alias reload load
|
37
|
+
|
38
|
+
def help
|
39
|
+
with_selected_command do |c|
|
40
|
+
if c.root_command?
|
41
|
+
res = c.help
|
42
|
+
sub_commands = command_line_manager.commands.select {|command| not command.root_command?}
|
43
|
+
unless sub_commands.empty?
|
44
|
+
res.concat SUB_COMMANDS_HELP_HEADER
|
45
|
+
sub_commands.each do |command|
|
46
|
+
# command_summary = "#{command.help[0][0,60].tr("\n", ' ')}..."
|
47
|
+
res << " * #{command.name}: #{command_summary command}"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
res
|
52
|
+
else
|
53
|
+
c.help
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def command_summary(command)
|
61
|
+
text = command.help[0][0,60].tr("\n", ' ')
|
62
|
+
text.match(/^\s*(?<sentence>[^\s][^\.]+)\./) do |md|
|
63
|
+
return "#{md['sentence']} ..."
|
64
|
+
end
|
65
|
+
text
|
66
|
+
end
|
67
|
+
|
68
|
+
def with_selected_command(&block)
|
69
|
+
selected_command = nil
|
70
|
+
begin
|
71
|
+
selected_command = command_line_manager.command
|
72
|
+
rescue UltraCommandLine::Error => e
|
73
|
+
UltraCommandLine.logger.debug 'No valid command found !'
|
74
|
+
end
|
75
|
+
unless selected_command.nil?
|
76
|
+
block.call selected_command
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class EnvLayer < SuperStack::Layer
|
5
|
+
|
6
|
+
attr_reader :filter
|
7
|
+
|
8
|
+
def initialize(filter=nil)
|
9
|
+
self.filter = filter
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter=(filter)
|
13
|
+
raise 'Invalid filter' unless [NilClass, String, Array, Regexp].include? filter.class
|
14
|
+
@filter = filter
|
15
|
+
load
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(*args)
|
19
|
+
self.replace read_filtered_environment
|
20
|
+
@file_name = :none
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def read_filtered_environment
|
27
|
+
return ENV.to_hash if filter.nil?
|
28
|
+
|
29
|
+
if filter.is_a? Array
|
30
|
+
ENV.to_hash.select {|k, v| filter.include?(k) }
|
31
|
+
elsif filter.is_a? Regexp
|
32
|
+
ENV.to_hash.select {|k, v| k =~ filter }
|
33
|
+
elsif filter.is_a? String
|
34
|
+
ENV.to_hash.select {|k, v| k == filter }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class ExecutableGemLayer < Climatic::ConfigLayers::GenericLayer
|
5
|
+
|
6
|
+
|
7
|
+
def self.executable_gem_config_root
|
8
|
+
return nil unless $PROGRAM_NAME
|
9
|
+
|
10
|
+
Gem.loaded_specs.each_pair do |name, spec|
|
11
|
+
executable_basename = File.basename($PROGRAM_NAME)
|
12
|
+
return spec.full_gem_path if spec.executables.include? executable_basename
|
13
|
+
end
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def executable_gem_config_root
|
18
|
+
self.class.executable_gem_config_root
|
19
|
+
end
|
20
|
+
|
21
|
+
def possible_sources
|
22
|
+
[
|
23
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## etc ##PROGRAM_NAME##.##EXTENSION##),
|
24
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## etc ##PROGRAM_NAME## config.##EXTENSION##),
|
25
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## etc ##PROGRAM_NAME## ##PROGRAM_NAME##.##EXTENSION##),
|
26
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## config ##PROGRAM_NAME##.##EXTENSION##),
|
27
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## config ##PROGRAM_NAME## config.##EXTENSION##),
|
28
|
+
%w(##EXECUTABLE_GEM_CONFIG_ROOT## config ##PROGRAM_NAME## ##PROGRAM_NAME##.##EXTENSION##)
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def perform_substitutions path_part
|
33
|
+
return nil unless executable_gem_config_root
|
34
|
+
res = path_part.dup
|
35
|
+
res.gsub! '##EXECUTABLE_GEM_CONFIG_ROOT##', executable_gem_config_root
|
36
|
+
exec_name = manager.nil? ? Climatic::LayersManager.default_config_file_base_name : manager.config_file_base_name
|
37
|
+
res.gsub! '##PROGRAM_NAME##', exec_name
|
38
|
+
res
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class GemLayer < Climatic::ConfigLayers::GenericLayer
|
5
|
+
|
6
|
+
attr_reader :gem_name
|
7
|
+
|
8
|
+
def self.gem_config_root(gem_name)
|
9
|
+
return nil unless gem_name
|
10
|
+
Gem.loaded_specs.each_pair do |name, spec|
|
11
|
+
return spec.full_gem_path if name == gem_name
|
12
|
+
end
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def gem_config_root
|
17
|
+
self.class.gem_config_root gem_name
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def gem_name=(gem_name)
|
22
|
+
@gem_name = gem_name.to_s
|
23
|
+
rescan
|
24
|
+
reload
|
25
|
+
end
|
26
|
+
|
27
|
+
def possible_sources
|
28
|
+
[
|
29
|
+
%w(##GEM_CONFIG_ROOT## etc ##GEM_NAME##.##EXTENSION##),
|
30
|
+
%w(##GEM_CONFIG_ROOT## etc ##GEM_NAME## config.##EXTENSION##),
|
31
|
+
%w(##GEM_CONFIG_ROOT## etc ##GEM_NAME## ##GEM_NAME##.##EXTENSION##),
|
32
|
+
%w(##GEM_CONFIG_ROOT## config ##GEM_NAME##.##EXTENSION##),
|
33
|
+
%w(##GEM_CONFIG_ROOT## config ##GEM_NAME## config.##EXTENSION##),
|
34
|
+
%w(##GEM_CONFIG_ROOT## config ##GEM_NAME## ##GEM_NAME##.##EXTENSION##)
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
def perform_substitutions path_part
|
39
|
+
return nil unless gem_config_root
|
40
|
+
res = path_part.dup
|
41
|
+
res.gsub! '##GEM_CONFIG_ROOT##', gem_config_root
|
42
|
+
res.gsub! '##GEM_NAME##', gem_name if self.respond_to? :gem_name
|
43
|
+
res
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class GenericLayer < SuperStack::Layer
|
5
|
+
|
6
|
+
include Climatic::ConfigLayers::SourceHelper
|
7
|
+
|
8
|
+
def rescan
|
9
|
+
set_config_file possible_sources
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
rescan
|
14
|
+
end
|
15
|
+
|
16
|
+
def possible_config_files(places=possible_sources)
|
17
|
+
result = {}
|
18
|
+
already_found = false
|
19
|
+
browse_files(places) do |file|
|
20
|
+
exists = File.readable?(file)
|
21
|
+
used = false
|
22
|
+
already_found = used = true if exists and not already_found
|
23
|
+
result[file] = {
|
24
|
+
exists: exists,
|
25
|
+
used: used,
|
26
|
+
layer: [name]
|
27
|
+
}
|
28
|
+
end
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def set_config_file(places)
|
35
|
+
@file_name = nil
|
36
|
+
browse_files(places) do |file|
|
37
|
+
if File.readable? file
|
38
|
+
@file_name = file
|
39
|
+
return @file_name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def browse_files(places, &block)
|
45
|
+
places.each do |path_array|
|
46
|
+
begin
|
47
|
+
potential_config_file = File.join(path_array.map { |path_part| perform_substitutions path_part })
|
48
|
+
rescue
|
49
|
+
# do nothing
|
50
|
+
end
|
51
|
+
return unless potential_config_file
|
52
|
+
EXTENSIONS.each do |extension|
|
53
|
+
file = potential_config_file.gsub '##EXTENSION##', extension
|
54
|
+
yield file
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class GlobalLayer < Climatic::ConfigLayers::SystemLayer
|
5
|
+
def possible_sources
|
6
|
+
[
|
7
|
+
['##SYSTEM_CONFIG_ROOT##', '##PROGRAM_NAME##.##EXTENSION##' ],
|
8
|
+
['##SYSTEM_CONFIG_ROOT##', '##PROGRAM_NAME##', 'config.##EXTENSION##' ],
|
9
|
+
['##SYSTEM_CONFIG_ROOT##', '##PROGRAM_NAME##', '##PROGRAM_NAME##.##EXTENSION##' ]
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform_substitutions(path_part)
|
14
|
+
res = path_part.dup
|
15
|
+
res.gsub! '##SYSTEM_CONFIG_ROOT##', system_config_root
|
16
|
+
|
17
|
+
exec_name = manager.nil? ? Climatic::LayersManager.default_config_file_base_name : manager.config_file_base_name
|
18
|
+
res.gsub! '##PROGRAM_NAME##', exec_name
|
19
|
+
|
20
|
+
res
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
module ProgramDescriptionHelper
|
5
|
+
|
6
|
+
attr_reader :config_file_base_name, :app_name, :app_version, :app_description
|
7
|
+
|
8
|
+
def add_command_line_section(title='Script specific', &block)
|
9
|
+
command_line_layer.add_command_line_section title, &block
|
10
|
+
end
|
11
|
+
|
12
|
+
def config_file_base_name=(config_file_base_name)
|
13
|
+
return if config_file_base_name.nil?
|
14
|
+
@config_file_base_name = config_file_base_name
|
15
|
+
rescan_layers
|
16
|
+
reload_layers
|
17
|
+
end
|
18
|
+
|
19
|
+
def app_name=(app_name)
|
20
|
+
return if app_name.nil?
|
21
|
+
@app_name = app_name
|
22
|
+
command_line_layer.reload
|
23
|
+
end
|
24
|
+
|
25
|
+
def app_version=(app_version)
|
26
|
+
return if app_version.nil?
|
27
|
+
@app_version = app_version
|
28
|
+
command_line_layer.reload
|
29
|
+
end
|
30
|
+
|
31
|
+
def app_description=(app_description)
|
32
|
+
return if app_description.nil?
|
33
|
+
@app_description = app_description
|
34
|
+
command_line_layer.reload
|
35
|
+
end
|
36
|
+
|
37
|
+
def rescan_layers
|
38
|
+
layers.values.each do |layer|
|
39
|
+
if layer.respond_to? :rescan
|
40
|
+
layer.clear
|
41
|
+
layer.rescan
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def detailed_layers_info
|
49
|
+
info, sep = [], '-' * 80
|
50
|
+
info << sep
|
51
|
+
layers.values.sort {|a, b| a.priority <=> b.priority}.each do |layer|
|
52
|
+
info << layer.name
|
53
|
+
if layer.file_name.nil?
|
54
|
+
info << 'There is no file attached to this level.'
|
55
|
+
else
|
56
|
+
info << "Using '#{layer.file_name}' as config file for this layer."
|
57
|
+
end
|
58
|
+
if layer.empty?
|
59
|
+
info << 'There is no data in this layer'
|
60
|
+
else
|
61
|
+
info << 'This layer contains the following data:'
|
62
|
+
info << layer.to_yaml
|
63
|
+
end
|
64
|
+
info << sep
|
65
|
+
end
|
66
|
+
info.join "\n"
|
67
|
+
end
|
68
|
+
|
69
|
+
def detailed_config_files_info
|
70
|
+
merger = SuperStack::Manager.new
|
71
|
+
merger.merge_policy = SuperStack::MergePolicies::FullMergePolicy
|
72
|
+
layers.values.each do |layer|
|
73
|
+
merger << layer.possible_config_files if layer.respond_to? :possible_config_files
|
74
|
+
end
|
75
|
+
merger[]
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def command_line_help
|
80
|
+
command_line_layer.help
|
81
|
+
end
|
82
|
+
|
83
|
+
def describes_application(options = {})
|
84
|
+
self.app_name = options.fetch(:app_name, nil)
|
85
|
+
self.app_version = options.fetch(:app_version, nil)
|
86
|
+
self.app_description = options.fetch(:app_description, nil)
|
87
|
+
self.config_file_base_name = options.fetch(:config_file_base_name, nil)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class ProjectLayer < SuperStack::Layer
|
5
|
+
|
6
|
+
attr_reader :started_from_directory, :project_file_basename
|
7
|
+
|
8
|
+
def initialize(file_or_directory, project_file_basename=nil)
|
9
|
+
if Dir.exists? file_or_directory
|
10
|
+
raise 'You have to provide the basename of the project file !' if project_file_basename.nil?
|
11
|
+
@started_from_directory = File.expand_path file_or_directory
|
12
|
+
self.project_file_basename = project_file_basename
|
13
|
+
else
|
14
|
+
raise "Invalid project file '#{file_or_directory}' !" unless File.readable? file_or_directory
|
15
|
+
normalized = File.expand_path file_or_directory
|
16
|
+
@started_from_directory = File.dirname normalized
|
17
|
+
self.project_file_basename = File.basename normalized
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def file_name
|
22
|
+
@file_name ||= find_root_file project_file_basename, started_from_directory
|
23
|
+
end
|
24
|
+
|
25
|
+
def project_root
|
26
|
+
File.dirname file_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def project_file_basename=(file)
|
30
|
+
@file_name = nil
|
31
|
+
@project_file_basename = file
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def find_root_file(file_basename, initial_directory)
|
37
|
+
prev_dir = nil
|
38
|
+
cur_dir = initial_directory
|
39
|
+
found_file = nil
|
40
|
+
file_basename = file_basename.to_s
|
41
|
+
|
42
|
+
raise Climatic::Error, "Invalid directory '#{initial_directory}'" unless File.readable? initial_directory
|
43
|
+
|
44
|
+
while found_file.nil? and cur_dir != prev_dir
|
45
|
+
candidate_file = File.join cur_dir, file_basename
|
46
|
+
if File.readable? candidate_file
|
47
|
+
found_file = candidate_file
|
48
|
+
end
|
49
|
+
prev_dir = cur_dir
|
50
|
+
cur_dir = File.expand_path '..', cur_dir
|
51
|
+
end
|
52
|
+
|
53
|
+
raise Climatic::Error, "Cannot find any root file named '#{file_basename}' starting from '#{initial_directory}'." if found_file.nil?
|
54
|
+
|
55
|
+
found_file
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class ProvidedConfigFileLayer < SuperStack::Layer
|
5
|
+
|
6
|
+
|
7
|
+
def managed
|
8
|
+
if manager[:'config-file']
|
9
|
+
if File.readable? manager[:'config-file']
|
10
|
+
@file_name = manager[:'config-file']
|
11
|
+
self.merge_policy = SuperStack::MergePolicies::OverridePolicy if manager[:'config-override']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def config_filepath
|
19
|
+
File.expand_path File.join('..', '..', '..', '..', 'etc', 'default_cmd_line_options.yml'), __FILE__
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
module SourceHelper
|
5
|
+
|
6
|
+
OS_FLAVOURS = {
|
7
|
+
mingw32: :windows,
|
8
|
+
linux: :unix
|
9
|
+
}
|
10
|
+
DEFAULT_OS_FLAVOUR = :unix
|
11
|
+
|
12
|
+
|
13
|
+
EXTENSIONS = %w(conf CONF cfg CFG yml YML yaml YAML)
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend ClassMethods
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def os_flavour
|
21
|
+
Climatic::ConfigLayers::SourceHelper.os_flavour
|
22
|
+
end
|
23
|
+
|
24
|
+
def supported_oses
|
25
|
+
Climatic::ConfigLayers::SourceHelper.supported_oses
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.os_flavour
|
30
|
+
OS_FLAVOURS[RbConfig::CONFIG['target_os'].to_sym] || DEFAULT_OS_FLAVOUR
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.supported_oses
|
34
|
+
OS_FLAVOURS.values.sort.uniq
|
35
|
+
end
|
36
|
+
|
37
|
+
def os_flavour
|
38
|
+
@os_flavour ||= self.class.os_flavour
|
39
|
+
end
|
40
|
+
|
41
|
+
def supported_oses
|
42
|
+
self.class.supported_oses
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class SystemLayer < Climatic::ConfigLayers::GenericLayer
|
5
|
+
|
6
|
+
SYSTEM_CONFIG_ROOT = {
|
7
|
+
windows: [File.join(ENV['systemRoot'] || '', 'Config')],
|
8
|
+
unix: '/etc'
|
9
|
+
}
|
10
|
+
|
11
|
+
def self.system_config_root
|
12
|
+
SYSTEM_CONFIG_ROOT[os_flavour]
|
13
|
+
end
|
14
|
+
|
15
|
+
def system_config_root
|
16
|
+
self.class.system_config_root
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def possible_sources
|
21
|
+
[
|
22
|
+
['##SYSTEM_CONFIG_ROOT##', 'stacked_config.##EXTENSION##' ],
|
23
|
+
['##SYSTEM_CONFIG_ROOT##', 'stacked_config', 'config.##EXTENSION##' ]
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def perform_substitutions path_part
|
28
|
+
res = path_part.dup
|
29
|
+
res.gsub! '##SYSTEM_CONFIG_ROOT##', system_config_root
|
30
|
+
res
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Climatic
|
2
|
+
module ConfigLayers
|
3
|
+
|
4
|
+
class UserLayer < Climatic::ConfigLayers::GenericLayer
|
5
|
+
|
6
|
+
|
7
|
+
def self.user_config_root
|
8
|
+
Dir.home
|
9
|
+
end
|
10
|
+
|
11
|
+
def user_config_root
|
12
|
+
self.class.user_config_root
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def possible_sources
|
17
|
+
[
|
18
|
+
['##USER_CONFIG_ROOT##', '.##PROGRAM_NAME##.##EXTENSION##' ],
|
19
|
+
['##USER_CONFIG_ROOT##', '.config', '##PROGRAM_NAME##.##EXTENSION##' ],
|
20
|
+
['##USER_CONFIG_ROOT##', '.config', '##PROGRAM_NAME##', 'config.##EXTENSION##' ],
|
21
|
+
['##USER_CONFIG_ROOT##', '.config', '##PROGRAM_NAME##', '##PROGRAM_NAME##.##EXTENSION##' ],
|
22
|
+
['##USER_CONFIG_ROOT##', '.##PROGRAM_NAME##', 'config.##EXTENSION##' ],
|
23
|
+
['##USER_CONFIG_ROOT##', '.##PROGRAM_NAME##', '##PROGRAM_NAME##.##EXTENSION##' ]
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def perform_substitutions path_part
|
28
|
+
res = path_part.dup
|
29
|
+
res.gsub! '##USER_CONFIG_ROOT##', user_config_root
|
30
|
+
|
31
|
+
exec_name = manager.nil? ? Climatic::LayersManager.default_config_file_base_name : manager.config_file_base_name
|
32
|
+
res.gsub! '##PROGRAM_NAME##', exec_name
|
33
|
+
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|