balmora 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/balmora +6 -0
- data/lib/balmora.rb +77 -0
- data/lib/balmora/arguments.rb +175 -0
- data/lib/balmora/cli.rb +150 -0
- data/lib/balmora/command.rb +106 -0
- data/lib/balmora/command/commands.rb +21 -0
- data/lib/balmora/command/exec.rb +24 -0
- data/lib/balmora/command/file.rb +168 -0
- data/lib/balmora/command/files.rb +122 -0
- data/lib/balmora/command/pacman.rb +71 -0
- data/lib/balmora/command/reload_config.rb +13 -0
- data/lib/balmora/command/restart.rb +13 -0
- data/lib/balmora/command/set_variable.rb +41 -0
- data/lib/balmora/command/stop.rb +17 -0
- data/lib/balmora/command/yaourt.rb +8 -0
- data/lib/balmora/config.rb +190 -0
- data/lib/balmora/context.rb +98 -0
- data/lib/balmora/context/config_changed.rb +11 -0
- data/lib/balmora/context/exec.rb +26 -0
- data/lib/balmora/context/exec_result.rb +7 -0
- data/lib/balmora/contexts.rb +76 -0
- data/lib/balmora/extension.rb +58 -0
- data/lib/balmora/extension/file_secret.rb +45 -0
- data/lib/balmora/logger.rb +25 -0
- data/lib/balmora/require.rb +25 -0
- data/lib/balmora/shell.rb +118 -0
- data/lib/balmora/state.rb +82 -0
- data/lib/balmora/variables.rb +110 -0
- data/lib/balmora/variables/config.rb +7 -0
- data/lib/balmora/variables/variables.rb +7 -0
- metadata +74 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
class Balmora::Command::Commands < Balmora::Command
|
2
|
+
|
3
|
+
def options()
|
4
|
+
return super().concat([:commands])
|
5
|
+
end
|
6
|
+
|
7
|
+
def verify()
|
8
|
+
if @commands.nil?()
|
9
|
+
raise Error.new('"commands" should be set')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def run()
|
14
|
+
@balmora.run_commands(@state, @commands)
|
15
|
+
end
|
16
|
+
|
17
|
+
def _installed()
|
18
|
+
return @shell.run!(['pacman', '-Q'], verbose: false).split("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Balmora::Command::Exec < Balmora::Command
|
2
|
+
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
def options()
|
6
|
+
return super().concat([:exec])
|
7
|
+
end
|
8
|
+
|
9
|
+
def verify()
|
10
|
+
if @exec.nil?()
|
11
|
+
raise Error.new('"exec" should be defined')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def run()
|
16
|
+
exec = option(:exec)
|
17
|
+
if !exec.instance_of?(::Array)
|
18
|
+
exec = [@shell.expression(exec)]
|
19
|
+
end
|
20
|
+
|
21
|
+
@shell.system(exec)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
class Balmora::Command::File < Balmora::Command
|
2
|
+
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
OPTIONS = '-T'
|
6
|
+
|
7
|
+
def init()
|
8
|
+
super()
|
9
|
+
|
10
|
+
@action = @variables.inject(@action)
|
11
|
+
@file = @variables.inject(@file)
|
12
|
+
@source = @variables.inject(@source)
|
13
|
+
@storage = @variables.inject(@storage)
|
14
|
+
end
|
15
|
+
|
16
|
+
def options()
|
17
|
+
return super().concat([:file, :source, :storage, :action, :check_equal,
|
18
|
+
:options])
|
19
|
+
end
|
20
|
+
|
21
|
+
def run()
|
22
|
+
if !_run_required?()
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
_create_target_path()
|
27
|
+
_copy_file()
|
28
|
+
# _change_file_owner()
|
29
|
+
end
|
30
|
+
|
31
|
+
def verify()
|
32
|
+
if @file.nil?()
|
33
|
+
raise Error.new('"file" should be defined')
|
34
|
+
end
|
35
|
+
|
36
|
+
if !@storage.nil?() && !@source.nil?()
|
37
|
+
raise Error.new('"storage" and "source" could not be defined together')
|
38
|
+
end
|
39
|
+
|
40
|
+
if @storage.nil?() && @source.nil?()
|
41
|
+
raise Error.new('"storage" or "source" should be defined')
|
42
|
+
end
|
43
|
+
|
44
|
+
if @action.nil?()
|
45
|
+
raise Error.new('"action" should be set')
|
46
|
+
end
|
47
|
+
|
48
|
+
if !['pull', 'push'].include?(@action)
|
49
|
+
Error.new("Unknown action #{@action.inspect()}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def _create_target_path()
|
56
|
+
@shell.run!(['mkdir', '-p', ::File.dirname(_target_path())], verbose: false)
|
57
|
+
end
|
58
|
+
|
59
|
+
def _copy_file()
|
60
|
+
@shell.run!(['cp', option(:options) || OPTIONS, _source_path(),
|
61
|
+
_target_path()])
|
62
|
+
end
|
63
|
+
|
64
|
+
# def _change_file_owner()
|
65
|
+
# new_owner = _get_target_required_owner()
|
66
|
+
# if _get_target_actual_owner() == new_owner
|
67
|
+
# return
|
68
|
+
# end
|
69
|
+
|
70
|
+
# @shell.run!(['chown', new_owner, '-R', _target_path()])
|
71
|
+
# end
|
72
|
+
|
73
|
+
# def _get_target_actual_owner()
|
74
|
+
# owner =
|
75
|
+
# @shell.run!(['stat', '-c', '%U:%G', _target_path()], verbose: false).
|
76
|
+
# strip()
|
77
|
+
|
78
|
+
# return owner
|
79
|
+
# end
|
80
|
+
|
81
|
+
# def _get_target_required_owner()
|
82
|
+
# owner =
|
83
|
+
# if @action == 'pull'
|
84
|
+
# @owner
|
85
|
+
# elsif @action == 'push'
|
86
|
+
# @storage_owner
|
87
|
+
# else
|
88
|
+
# raise Error.new("Can not get owner for action #{@action}")
|
89
|
+
# end
|
90
|
+
|
91
|
+
# owner = owner || @shell.user_id()
|
92
|
+
|
93
|
+
# return owner
|
94
|
+
# end
|
95
|
+
|
96
|
+
def _run_required?()
|
97
|
+
# if @check_equal == false
|
98
|
+
# return true
|
99
|
+
# end
|
100
|
+
|
101
|
+
command = [
|
102
|
+
'test', '-e', _source_path(), _expr('&&'),
|
103
|
+
*@shell.sudo(), 'test', '-e', _target_path(), _expr('&&'),
|
104
|
+
_expr('[ "$('), *@shell.sudo(), *_source_contents(), _expr('| md5sum'),
|
105
|
+
_expr(')" = '),
|
106
|
+
_expr('"$('), *@shell.sudo(), *_target_contents(), _expr('| md5sum)" ]'),
|
107
|
+
]
|
108
|
+
|
109
|
+
return @shell.run(command, verbose: false)[0] != 0
|
110
|
+
end
|
111
|
+
|
112
|
+
def _source_contents()
|
113
|
+
return ['cat', _source_path()]
|
114
|
+
end
|
115
|
+
|
116
|
+
def _target_contents()
|
117
|
+
return ['cat', _target_path()]
|
118
|
+
end
|
119
|
+
|
120
|
+
def _source_path()
|
121
|
+
return _files()[0]
|
122
|
+
end
|
123
|
+
|
124
|
+
def _target_path()
|
125
|
+
return _files()[1]
|
126
|
+
end
|
127
|
+
|
128
|
+
def _expr(expression)
|
129
|
+
return @shell.expression(expression)
|
130
|
+
end
|
131
|
+
|
132
|
+
def _owner()
|
133
|
+
return @owner || ENV['USER']
|
134
|
+
end
|
135
|
+
|
136
|
+
def _storage_owner()
|
137
|
+
return @storage_owner || ENV['USER']
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def _files()
|
143
|
+
if @action == 'pull'
|
144
|
+
return _resolve_source_path(), @shell.expand(@file)
|
145
|
+
else
|
146
|
+
return @shell.expand(@file), _resolve_source_path()
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def _resolve_source_path()
|
151
|
+
if !@source.nil?()
|
152
|
+
return @shell.expand(@source)
|
153
|
+
end
|
154
|
+
|
155
|
+
storage = @shell.expand(@storage)
|
156
|
+
|
157
|
+
if @file.start_with?('~/')
|
158
|
+
result = ::File.join(storage, @file[1..-1])
|
159
|
+
elsif @file.start_with?('/')
|
160
|
+
result = ::File.join(storage, @file[1..-1])
|
161
|
+
else
|
162
|
+
result = ::File.join(storage, @file)
|
163
|
+
end
|
164
|
+
|
165
|
+
return result
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
class Balmora::Command::Files < Balmora::Command
|
2
|
+
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
def init()
|
6
|
+
super()
|
7
|
+
|
8
|
+
@files = @variables.inject(@files)
|
9
|
+
@storage = @variables.inject(@storage)
|
10
|
+
@exclude = @variables.inject(@exclude)
|
11
|
+
end
|
12
|
+
|
13
|
+
def options()
|
14
|
+
return super().concat([:action, :options, :files, :storage, :exclude])
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify()
|
18
|
+
if @files.nil?() && @storage.nil?()
|
19
|
+
raise Error.new('"files" or "storage" should be defined')
|
20
|
+
end
|
21
|
+
|
22
|
+
if @files.nil?() || @files.empty?()
|
23
|
+
raise Error.new('"files" should be defined')
|
24
|
+
end
|
25
|
+
|
26
|
+
if !@options.nil?() && @options.has_key?(:storage) && !@storage.nil?()
|
27
|
+
raise Error.new('"file.storage" and "storage" could not be defined ' +
|
28
|
+
'together')
|
29
|
+
end
|
30
|
+
|
31
|
+
if @action.nil?()
|
32
|
+
raise Error.new('"action" should be defined')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run()
|
37
|
+
_files().each() { |file|
|
38
|
+
command = _get_command(file)
|
39
|
+
@balmora.run_command(@state, command)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def _files()
|
44
|
+
files = _find_files()
|
45
|
+
files = _filter_files(files)
|
46
|
+
return files
|
47
|
+
end
|
48
|
+
|
49
|
+
def _find_files()
|
50
|
+
storage = @shell.expand(@storage)
|
51
|
+
|
52
|
+
files = []
|
53
|
+
@files.each() { |file|
|
54
|
+
path = file
|
55
|
+
if path.instance_of?(::Hash)
|
56
|
+
path = path[:file]
|
57
|
+
end
|
58
|
+
|
59
|
+
if @action == 'pull'
|
60
|
+
path = ::File.join(storage, path.gsub(/^(\~\/|\~$|\/)/, ''))
|
61
|
+
else
|
62
|
+
path = @shell.expand(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
command = ['test', '-d', path, @shell.expression('&&'), 'find', path,
|
66
|
+
'-type', 'f']
|
67
|
+
|
68
|
+
dir_status, dir_files = @shell.run(command, verbose: false)
|
69
|
+
if dir_status != 0
|
70
|
+
files.push(file)
|
71
|
+
next
|
72
|
+
end
|
73
|
+
|
74
|
+
dir_files.
|
75
|
+
strip().
|
76
|
+
split("\n").
|
77
|
+
each() { |found|
|
78
|
+
found = found[(path.length + 1)..-1]
|
79
|
+
if file.instance_of?(::Hash)
|
80
|
+
files.push(file.merge(file: ::File.join(file[:file], found)))
|
81
|
+
else
|
82
|
+
files.push(::File.join(file, found))
|
83
|
+
end
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
return files
|
88
|
+
end
|
89
|
+
|
90
|
+
def _filter_files(files)
|
91
|
+
if !@exclude.nil?()
|
92
|
+
exclude = Regexp.new('(' + @exclude.collect() { |part| "(#{part})" }.
|
93
|
+
join('|') + ')')
|
94
|
+
|
95
|
+
files = files.select() { |file|
|
96
|
+
result =
|
97
|
+
if file.instance_of?(::Hash)
|
98
|
+
!file[:file].match(exclude)
|
99
|
+
else
|
100
|
+
!file.match(exclude)
|
101
|
+
end
|
102
|
+
|
103
|
+
next result
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
return files
|
108
|
+
end
|
109
|
+
|
110
|
+
def _get_command(file)
|
111
|
+
command = (@options || {}).merge(command: 'file', file: file)
|
112
|
+
|
113
|
+
if file.instance_of?(::Hash)
|
114
|
+
command.merge!(file)
|
115
|
+
end
|
116
|
+
|
117
|
+
command.merge!(action: @action, storage: @storage)
|
118
|
+
|
119
|
+
return command
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Balmora::Command::Pacman < Balmora::Command
|
2
|
+
|
3
|
+
def initialize(state, command)
|
4
|
+
super(state, command)
|
5
|
+
@bin = ['sudo', 'pacman']
|
6
|
+
end
|
7
|
+
|
8
|
+
def init()
|
9
|
+
super()
|
10
|
+
@action = @variables.inject(@action)
|
11
|
+
@packages = @variables.inject(@packages)
|
12
|
+
@synchronize = @variables.inject(@synchronize)
|
13
|
+
end
|
14
|
+
|
15
|
+
def options()
|
16
|
+
return super().concat([:action, :packages, :synchronize])
|
17
|
+
end
|
18
|
+
|
19
|
+
def verify()
|
20
|
+
if @action.nil?()
|
21
|
+
raise Error.new('"action" should be set')
|
22
|
+
end
|
23
|
+
|
24
|
+
if !['install', 'update', 'remove'].include?(@action)
|
25
|
+
raise Error.new('wrong "action" value; allowed values: install, ' +
|
26
|
+
'update, remove')
|
27
|
+
end
|
28
|
+
|
29
|
+
if @packages.nil?() || @packages.empty?()
|
30
|
+
raise Error.new('"packages" should be set')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def run()
|
35
|
+
command = '-S'
|
36
|
+
|
37
|
+
if @synchronize != false
|
38
|
+
command += 'y'
|
39
|
+
end
|
40
|
+
|
41
|
+
if @action == 'install'
|
42
|
+
packages = @packages - _installed()
|
43
|
+
elsif @action == 'update'
|
44
|
+
packages = @packages
|
45
|
+
elsif @action == 'remove'
|
46
|
+
packages = @packages & _installed()
|
47
|
+
command = '-R'
|
48
|
+
else
|
49
|
+
raise Error.new("Wrong action #{@action.inspect()}")
|
50
|
+
end
|
51
|
+
|
52
|
+
if packages.length == 0
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
@shell.system([*@bin, command, *packages, '--noconfirm'])
|
57
|
+
end
|
58
|
+
|
59
|
+
def _installed()
|
60
|
+
packages =
|
61
|
+
@shell.
|
62
|
+
run!(['pacman', '-Q'], verbose: false).
|
63
|
+
split("\n").
|
64
|
+
collect() { |package|
|
65
|
+
package.split(' ')[0]
|
66
|
+
}
|
67
|
+
|
68
|
+
return packages
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Balmora::Command::SetVariable < Balmora::Command
|
2
|
+
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
def init()
|
6
|
+
super()
|
7
|
+
|
8
|
+
@variable = option(:variable)
|
9
|
+
@value = option(:value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def options()
|
13
|
+
return super().concat([:variable, :value])
|
14
|
+
end
|
15
|
+
|
16
|
+
def verify()
|
17
|
+
if @variable.nil?()
|
18
|
+
raise Error.new('"variable" should be defined')
|
19
|
+
end
|
20
|
+
|
21
|
+
if @value.nil?()
|
22
|
+
raise Error.new('"value" should be defined')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run()
|
27
|
+
parts = @variable.split('.').collect() { |part| part.to_sym() }
|
28
|
+
@config.config[:variables] ||= {}
|
29
|
+
parent = parts[0...-1].inject(@config.config[:variables]) { |current, variable|
|
30
|
+
if !current.instance_of?(::Hash)
|
31
|
+
raise Error.new("wrong variable name #{@variable}: target is not hash")
|
32
|
+
end
|
33
|
+
|
34
|
+
current[variable] ||= {}
|
35
|
+
next current[variable]
|
36
|
+
}
|
37
|
+
|
38
|
+
parent[parts[-1]] = @value
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|