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,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
|