balmora 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ class Balmora::Command::Stop < Balmora::Command
2
+
3
+ class Error < StandardError; end
4
+
5
+ def options()
6
+ return super().concat([:status])
7
+ end
8
+
9
+ def verify()
10
+ return true
11
+ end
12
+
13
+ def run()
14
+ raise Balmora::Stop.new(nil, @status)
15
+ end
16
+
17
+ end
@@ -0,0 +1,8 @@
1
+ class Balmora::Command::Yaourt < Balmora::Command::Pacman
2
+
3
+ def initialize(state, command)
4
+ super(state, command)
5
+ @bin = ['yaourt']
6
+ end
7
+
8
+ end
@@ -0,0 +1,190 @@
1
+ require 'json'
2
+
3
+ class Balmora::Config
4
+
5
+ class Error < StandardError; end
6
+
7
+ attr_accessor :file, :dir, :require, :variables
8
+ attr_reader :old, :config
9
+
10
+ def self.factory(state)
11
+ return self.create(state.options[:config], state.variables)
12
+ end
13
+
14
+ def self.create(config = nil, variables = nil)
15
+ if config.nil?()
16
+ config = File.join(Dir.home(), '.config/balmora/balmora.conf')
17
+ end
18
+
19
+ if !File.exist?(config)
20
+ config = File.join('/etc/balmora/balmora.conf')
21
+ end
22
+
23
+ if !File.exist?(config)
24
+ raise Error.new('Config not found in ~/.config/balmora/balmora.conf ' +
25
+ 'and /etc/balmora/balmora.conf; you should create config to ' +
26
+ 'continue or use --config switch')
27
+ end
28
+
29
+ return self.new(config || '~/.config/balmora/balmora.conf', variables)
30
+ end
31
+
32
+ def initialize(path, variables = nil)
33
+ @file = File
34
+ @dir = Dir
35
+
36
+ @variables = variables
37
+ @path = path
38
+ @require = Object.method(:require)
39
+
40
+ @config = nil
41
+ end
42
+
43
+ def get(key = [], options = {})
44
+ if !key.instance_of?(::Array)
45
+ key = [key]
46
+ end
47
+
48
+ result =
49
+ key.
50
+ inject(@config) { |current, part|
51
+ begin
52
+ current = current.fetch(part)
53
+ rescue KeyError
54
+ if options[:default]
55
+ return options[:default]
56
+ end
57
+
58
+ raise "Config value #{key.inspect()} should be defined in " +
59
+ "#{@path.inspect()}"
60
+ end
61
+
62
+ next current
63
+ }
64
+
65
+ result = _deep_clone(result)
66
+ if options[:variables] != false
67
+ result = @variables.inject(result, false)
68
+ end
69
+
70
+ return result
71
+ end
72
+
73
+ def load()
74
+ @old = _deep_clone(@config)
75
+
76
+ Dir.chdir(File.dirname(@path)) {
77
+ @config = _load(@path)
78
+ }
79
+
80
+ @config[:config_dir] = File.dirname(@path)
81
+ @config[:config_path] = @path
82
+
83
+ get(:require, default: [], variables: false).each() { |file|
84
+ @require.call(file)
85
+ }
86
+ end
87
+
88
+ def _load(path)
89
+ contents = @file.read(@file.expand_path(path))
90
+ value = JSON.parse(contents, {symbolize_names: true})
91
+ value = _process(value)
92
+ return value
93
+ rescue => error
94
+ raise Error.new("Failed to read config file #{path}: #{error.to_s()}")
95
+ end
96
+
97
+ def _process(value)
98
+ result =
99
+ if value.instance_of?(::Array)
100
+ _process_array(value)
101
+ elsif value.instance_of?(::Hash)
102
+ _process_hash(value)
103
+ else
104
+ value
105
+ end
106
+
107
+ return result
108
+ end
109
+
110
+ def _process_array(value)
111
+ result = []
112
+ value.each() { |item|
113
+ if item.instance_of?(::Hash) && item.keys() == [:'extend-file']
114
+ files = item[:'extend-file']
115
+ if !files.instance_of?(::Array)
116
+ files = [files]
117
+ end
118
+
119
+ files.each() { |path|
120
+ _glob(path).each() { |file|
121
+ result.concat(_load(file))
122
+ }
123
+ }
124
+ else
125
+ result.push(_process(item))
126
+ end
127
+ }
128
+
129
+ return result
130
+ end
131
+
132
+ def _process_hash(value)
133
+ result = {}
134
+ value.each() { |key, item|
135
+ if key == :'include-file'
136
+ files = item
137
+ if !files.instance_of?(::Array)
138
+ files = [files]
139
+ end
140
+
141
+ files.each() { |path|
142
+ _glob(path).each() { |file|
143
+ result.merge!(_load(file))
144
+ }
145
+ }
146
+ else
147
+ result[key] = _process(item)
148
+ end
149
+ }
150
+
151
+ return result
152
+ end
153
+
154
+ def _glob(file)
155
+ if !file.include?('*')
156
+ return [file]
157
+ end
158
+
159
+ return @dir.glob(file)
160
+ end
161
+
162
+ def _deep_clone(value)
163
+ if value.instance_of?(::Array)
164
+ value = value.collect() { |item|
165
+ _deep_clone(item)
166
+ }
167
+ elsif value.instance_of?(::Hash)
168
+ value = Hash[
169
+ value.collect() { |key, item|
170
+ [_deep_clone(key), _deep_clone(item)]
171
+ }
172
+ ]
173
+ else
174
+ is_clonable = (
175
+ !value.is_a?(::Numeric) &&
176
+ !value.is_a?(::TrueClass) &&
177
+ !value.is_a?(::FalseClass) &&
178
+ !value.is_a?(::NilClass) &&
179
+ !value.is_a?(::Symbol)
180
+ )
181
+
182
+ if is_clonable
183
+ value = value.clone()
184
+ end
185
+ end
186
+
187
+ return value
188
+ end
189
+
190
+ end
@@ -0,0 +1,98 @@
1
+ class Balmora::Context < Balmora::Command
2
+
3
+ def initialize(state, context)
4
+ @state = state
5
+
6
+ @logger = state.logger
7
+ @shell = state.shell
8
+ @config = state.config
9
+ @variables = state.variables
10
+ @balmora = state.balmora
11
+
12
+ @context = context
13
+ end
14
+
15
+ def init()
16
+ if (@context.keys() - [:context] - options()).length != 0
17
+ raise Error.new("Unknown options #{(@context.keys() - [:context] -
18
+ options()).inspect()}")
19
+ end
20
+
21
+ options().each() { |key|
22
+ if self.instance_variable_defined?(:"@#{key}")
23
+ raise Error.new("Can not use #{key} as option")
24
+ end
25
+
26
+ option = @context.fetch(key, nil)
27
+ self.instance_variable_set(:"@#{key}", option)
28
+ }
29
+
30
+ verify()
31
+ end
32
+
33
+ def options()
34
+ return [:operator, :value]
35
+ end
36
+
37
+ def verify()
38
+ if @operator.nil?()
39
+ raise Error.new('"operator" should be defined')
40
+ end
41
+
42
+ if @value.nil?()
43
+ raise Error.new('"value" should be defined')
44
+ end
45
+ end
46
+
47
+ def execute()
48
+ result = run()
49
+
50
+ operator = @operator
51
+
52
+ is_not = false
53
+ if operator.start_with?('not-')
54
+ is_not = true
55
+ operator = operator[4..-1]
56
+ end
57
+
58
+ case operator
59
+ when 'match'
60
+ return _not(is_not, result.match(@value) != nil)
61
+ when 'equal'
62
+ return _not(is_not, result == @value)
63
+ when 'greater'
64
+ return _not(is_not, result > @value)
65
+ when 'greater-or-equal'
66
+ return _not(is_not, result >= @value)
67
+ when 'lesser'
68
+ return _not(is_not, result < @value)
69
+ when 'lesser-or-equal'
70
+ return _not(is_not, result <= @value)
71
+ end
72
+
73
+ raise Error.new("Unknown operator #{operator}")
74
+ rescue => error
75
+ @logger.error("#{error.inspect()}; failed to run " +
76
+ "context: #{@context.inspect()}")
77
+
78
+ raise error
79
+ end
80
+
81
+ def _not(is_not, result)
82
+ if is_not
83
+ return !result
84
+ end
85
+
86
+ return result
87
+ end
88
+
89
+ def run()
90
+ raise Error.new("run should be implemented in subclass")
91
+ end
92
+
93
+ def option(option)
94
+ return @variables.inject(self.instance_variable_get(:"@#{option}"))
95
+ end
96
+
97
+
98
+ end
@@ -0,0 +1,11 @@
1
+ class Balmora::Context::ConfigChanged < Balmora::Context
2
+
3
+ def run()
4
+ if @config.old.nil?() || @config.config.nil?()
5
+ return @config.config == @config.old
6
+ end
7
+
8
+ return JSON.generate(@config.config) != JSON.generate(@config.old)
9
+ end
10
+
11
+ end
@@ -0,0 +1,26 @@
1
+ class Balmora::Context::Exec < Balmora::Context
2
+
3
+ def options()
4
+ return super().concat([:exec])
5
+ end
6
+
7
+ def verify()
8
+ if !@exec
9
+ raise Error.new('"exec" should be defined')
10
+ end
11
+
12
+ super()
13
+ end
14
+
15
+ def run()
16
+ return @shell.run!(_exec(), verbose: false).rstrip()
17
+ end
18
+
19
+ def _exec()
20
+ exec = option(:exec)
21
+ if exec.instance_of?(::String)
22
+ exec = [@shell.expression(exec)]
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,7 @@
1
+ class Balmora::Context::ExecResult < Balmora::Context::Exec
2
+
3
+ def run()
4
+ return @shell.run(_exec(), verbose: false)[0]
5
+ end
6
+
7
+ end
@@ -0,0 +1,76 @@
1
+ class Balmora::Contexts
2
+
3
+ def self.factory(state)
4
+ return self.new(state.logger, state.extension, state.variables, state)
5
+ end
6
+
7
+ def initialize(logger, extension, variables, state)
8
+ @state = state
9
+ @logger = logger
10
+ @extension = extension
11
+ @variables = variables
12
+ end
13
+
14
+ def check(context)
15
+ if context.nil?()
16
+ return true
17
+ end
18
+
19
+ if context.instance_of?(::Array)
20
+ return _check_array(context)
21
+ end
22
+
23
+ if context.instance_of?(::String)
24
+ context = {
25
+ context: 'exec-result',
26
+ exec: context,
27
+ operator: 'equal',
28
+ value: 0,
29
+ }
30
+ end
31
+
32
+
33
+ context_class = @extension.get(Balmora::Context, context[:context])
34
+ context_instance = context_class.new(@state, context)
35
+ context_instance.init()
36
+
37
+ if !(context_class < Balmora::Context)
38
+ raise Error.new("Context #{context_class} should be subclass of context")
39
+ end
40
+
41
+ context_instance.verify()
42
+ result = context_instance.execute()
43
+ return result
44
+ end
45
+
46
+ def _check_array(contexts)
47
+ operator = :and
48
+ result = true
49
+ contexts.each() { |context|
50
+ if context == 'or'
51
+ operator = :or
52
+ next
53
+ end
54
+
55
+ if operator == :or
56
+ result = result || check(context)
57
+ operator = :and
58
+ else
59
+ if !result
60
+ next
61
+ end
62
+
63
+ result = result && check(context)
64
+ end
65
+ }
66
+
67
+ return result
68
+ end
69
+
70
+ end
71
+
72
+ # [
73
+ # {"context": "test -e folder/file1; echo $?", "operator": "equal", "value": "0"},
74
+ # "or",
75
+ # {"context": "test -e folder/file2; echo $?", "operator": "equal", "value": "0"},
76
+ # ]
@@ -0,0 +1,58 @@
1
+ class Balmora::Extension
2
+
3
+ class Error < StandardError; end
4
+
5
+ attr_accessor :command_constant, :extension_constant
6
+
7
+ def self.factory(state)
8
+ return self.new(state)
9
+ end
10
+
11
+ def initialize(state)
12
+ @command_constant = ::Balmora::Command
13
+ @extension_constant = ::Balmora::Extension
14
+ @state = state
15
+ end
16
+
17
+ def get(namespace, extension)
18
+ class_name =
19
+ extension.
20
+ to_s().
21
+ gsub(/(-|^)(\w)/) { |char | (char[1] || char[0]).upcase() }.
22
+ to_sym()
23
+
24
+ if !namespace.const_defined?(class_name, false)
25
+ raise Error.new("Extension #{class_name.inspect()} not found in " +
26
+ "namespace " + namespace.inspect())
27
+ end
28
+
29
+ return namespace.const_get(class_name, false)
30
+ end
31
+
32
+ def create_command(state, command)
33
+ if command.instance_of?(::String)
34
+ command = {command: 'exec', exec: command}
35
+ end
36
+
37
+ if command[:command].nil?()
38
+ raise Error.new("\"command\" should be defined in command " +
39
+ "#{command.inspect()}")
40
+ end
41
+
42
+ command_name = @state.variables.inject(command[:command])
43
+ command_class = get(@command_constant, command_name)
44
+ if !(command_class < @command_constant)
45
+ raise Error.new("Command should be instance of #{@command_constant}")
46
+ end
47
+
48
+ command_instance = command_class.new(state, command)
49
+
50
+ (command[:extensions] || []).each() { |extension|
51
+ extension_class = get(@extension_constant, extension)
52
+ command_instance.extend(extension_class)
53
+ }
54
+
55
+ return command_instance
56
+ end
57
+
58
+ end