balmora 0.0.1

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.
@@ -0,0 +1,45 @@
1
+ module Balmora::Extension::FileSecret
2
+
3
+ def options()
4
+ return super() + [:password]
5
+ end
6
+
7
+ def _copy_file()
8
+ if @action == 'pull'
9
+ @shell.run!(_source_contents() + [_expr('|'), *@shell.sudo(), 'tee',
10
+ _target_path()])
11
+ else
12
+ @shell.run!(['cat', _source_path(), _expr('|'), *_encrypt(), _expr('|'),
13
+ *@shell.sudo(), 'tee', _target_path()])
14
+ end
15
+ end
16
+
17
+ def _source_contents()
18
+ command = super()
19
+
20
+ if @action == 'pull'
21
+ command += [_expr('|')] + _decrypt()
22
+ end
23
+
24
+ return command
25
+ end
26
+
27
+ def _target_contents()
28
+ command = super()
29
+
30
+ if @action == 'push'
31
+ command += [_expr('|')] + _decrypt()
32
+ end
33
+
34
+ return command
35
+ end
36
+
37
+ def _decrypt()
38
+ return ['openssl', 'enc', '-aes-256-cbc', '-d', '-pass', option(:password)]
39
+ end
40
+
41
+ def _encrypt()
42
+ return ['openssl', 'enc', '-aes-256-cbc', '-e', '-pass', option(:password)]
43
+ end
44
+
45
+ end
@@ -0,0 +1,25 @@
1
+ require 'logger'
2
+
3
+ class Balmora::Logger < Logger
4
+
5
+ def self.factory(state)
6
+ logger = self.new(STDOUT)
7
+
8
+ if state.options[:debug] == true && state.options[:quite] == true
9
+ raise Error.new("Options --quite and --verbose can not be set " +
10
+ "simulataneously")
11
+ end
12
+
13
+
14
+ if state.options[:verbose] == true
15
+ logger.level = ::Logger::DEBUG
16
+ elsif state.options[:quiet] != true
17
+ logger.level = ::Logger::INFO
18
+ else
19
+ logger.level = ::Logger::ERROR
20
+ end
21
+
22
+ return logger
23
+ end
24
+
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'balmora/logger'
2
+ require 'balmora/extension'
3
+ require 'balmora/config'
4
+ require 'balmora/shell'
5
+ require 'balmora/variables'
6
+ require 'balmora/command'
7
+ require 'balmora/contexts'
8
+ require 'balmora/context'
9
+
10
+ require 'balmora/state'
11
+
12
+ globs = [
13
+ 'extension/**/*.rb',
14
+ 'command/**/*.rb',
15
+ 'variables/**/*.rb',
16
+ 'context/**/*.rb'
17
+ ]
18
+
19
+ Dir.chdir(File.dirname(__FILE__)) {
20
+ globs.each() { |glob|
21
+ Dir.glob(glob).each() { |file|
22
+ require ::File.join('balmora', file)
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,118 @@
1
+ require 'shellwords'
2
+
3
+ class Balmora::Shell
4
+
5
+ class Error < StandardError
6
+
7
+ attr_reader :status
8
+
9
+ def initialize(message, status)
10
+ super(message)
11
+ @status = status
12
+ end
13
+
14
+ end
15
+
16
+ class Expression
17
+
18
+ attr_reader :command
19
+
20
+ def initialize(command)
21
+ @command = command
22
+ end
23
+
24
+ end
25
+
26
+ attr_accessor :exec, :status
27
+ attr_reader :home, :user_id
28
+
29
+ def self.factory(state)
30
+ return self.new(state.logger)
31
+ end
32
+
33
+ def initialize(logger, home = nil)
34
+ @logger = logger
35
+ @run = ::Object.method(:'`')
36
+ @system = ::Object.method(:system)
37
+ @status = Proc.new() { $?.exitstatus }
38
+ @home = Dir.home()
39
+ @user_id ||= `id -un; id -gn`.strip().split("\n").join(':')
40
+ @sudo_stack = []
41
+ end
42
+
43
+ def expression(command)
44
+ Expression.new(command)
45
+ end
46
+
47
+ def sudo()
48
+ if @sudo_stack.length == 0
49
+ return []
50
+ end
51
+
52
+ if @sudo_stack[-1] == true
53
+ return ['sudo']
54
+ else
55
+ return ['sudo', '--user', @sudo_stack[-1]]
56
+ end
57
+ end
58
+
59
+ def run(command, options = {})
60
+ command = sudo() + command
61
+
62
+ shell_command =
63
+ command.
64
+ collect() { |part|
65
+ if part.instance_of?(Expression)
66
+ next part.command
67
+ end
68
+
69
+ next Shellwords.escape(part)
70
+ }.
71
+ join(' ')
72
+
73
+ if options[:verbose] != false
74
+ @logger.info(shell_command)
75
+ else
76
+ @logger.debug(shell_command)
77
+ end
78
+
79
+ method = @run
80
+ if options[:system] == true
81
+ method = @system
82
+ end
83
+
84
+ result = method.call(shell_command)
85
+ status = @status.call()
86
+
87
+ if options[:raise] == true && status != 0
88
+ raise Error.new("Failed to execute command: #{shell_command}",
89
+ status)
90
+ end
91
+
92
+ return status, result
93
+ end
94
+
95
+ def run!(command, options = {})
96
+ return run(command, options.merge(raise: true))[1]
97
+ end
98
+
99
+ def system(command, options = {})
100
+ return run(command, options.merge(raise: true, system: true))[1]
101
+ end
102
+
103
+ def expand(path)
104
+ if path.start_with?('~') || path.start_with?('/')
105
+ return ::File.expand_path(path)
106
+ end
107
+
108
+ return path
109
+ end
110
+
111
+ def sudo!(sudo)
112
+ @sudo_stack.push(sudo)
113
+ yield
114
+ ensure
115
+ @sudo_stack.pop()
116
+ end
117
+
118
+ end
@@ -0,0 +1,82 @@
1
+ class Balmora::State
2
+
3
+ attr_reader :options, :arguments, :logger, :balmora, :extension, :config
4
+ attr_reader :shell, :variables, :context
5
+
6
+ @@constants = [
7
+ Balmora::Logger,
8
+ Balmora::Extension,
9
+ Balmora::Shell,
10
+ Balmora::Variables,
11
+ Balmora::Config,
12
+ Balmora::Contexts,
13
+ Balmora,
14
+ ]
15
+
16
+ def self.create(options, arguments)
17
+ state = Balmora::State.new()
18
+ state.instance_variable_set(:@options, options)
19
+ state.instance_variable_set(:@arguments, arguments)
20
+
21
+ config = Balmora::Config.create(options[:config])
22
+ config.load()
23
+
24
+ state.instance_variable_set(:@config, config)
25
+
26
+ constants = @@constants.clone()
27
+ Balmora.constants.each() { |constant|
28
+ if !constants.include?(constant)
29
+ constants.push(constant)
30
+ end
31
+ }
32
+
33
+ constants.delete(Balmora::Config)
34
+
35
+ constants.each() { |constant|
36
+ if !constant.respond_to?(:factory)
37
+ next
38
+ end
39
+
40
+ name =
41
+ constant.
42
+ to_s().
43
+ split('::')[1..-1].
44
+ join('_').
45
+ split(/(?=[A-Z])/).
46
+ collect() { |word| word.downcase() }.
47
+ join('_').
48
+ to_sym()
49
+
50
+ if name == :''
51
+ name = :balmora
52
+ end
53
+
54
+ state.set(name, constant.factory(state))
55
+ }
56
+
57
+ config.variables = state.variables
58
+
59
+ return state
60
+ end
61
+
62
+ def set(name, instance)
63
+ if self.instance_variable_defined?(:"@#{name}")
64
+ raise Error.new("Can not set #{name.inspect()}: variable is already set")
65
+ end
66
+
67
+ self.instance_variable_set(:"@#{name}", instance)
68
+ end
69
+
70
+ def method_missing(method, *arguments)
71
+ if arguments.length > 1
72
+ super(method, *arguments)
73
+ end
74
+
75
+ if !self.instance_variable_defined?(:"@#{method}")
76
+ super(method, *arguments)
77
+ end
78
+
79
+ return self.instance_variable_get(:"@#{method}")
80
+ end
81
+
82
+ end
@@ -0,0 +1,110 @@
1
+ class Balmora::Variables
2
+
3
+ class Error < StandardError; end
4
+
5
+ def self.factory(state)
6
+ return self.new(state.extension, state.shell, state)
7
+ end
8
+
9
+ def initialize(extension, shell, state)
10
+ @extension = extension
11
+ @shell = shell
12
+ @state = state
13
+ end
14
+
15
+ def get(name)
16
+ if !name.instance_of?(::Array)
17
+ name = name.split('.').collect() { |part| part.to_sym() }
18
+ else
19
+ name = name.clone()
20
+ end
21
+
22
+ parts = []
23
+ provider = @extension.get(Balmora::Variables, name.shift()).factory(@state)
24
+
25
+ result =
26
+ name.
27
+ inject(provider) { |current, part|
28
+ parts.push(part)
29
+
30
+ if current.instance_of?(::Hash)
31
+ if !current.has_key?(part)
32
+ raise Error.new("Unknown variable #{parts.join('.')}")
33
+ end
34
+
35
+ next current[part]
36
+ end
37
+
38
+ if !current.respond_to?(part)
39
+ raise Error.new("Unknown variable #{parts.join('.')}")
40
+ end
41
+
42
+ next current.public_send(part)
43
+ }
44
+
45
+ return result
46
+ end
47
+
48
+ def inject(value, string = true)
49
+ result =
50
+ if value.instance_of?(::Array)
51
+ _inject_array(value, string)
52
+ elsif value.instance_of?(::Hash)
53
+ _inject_hash(value, string)
54
+ elsif value.instance_of?(::String) && string
55
+ _inject_string(value)
56
+ else
57
+ value
58
+ end
59
+
60
+ return result
61
+ end
62
+
63
+ def _inject_array(value, string)
64
+ result = []
65
+
66
+ value.each_with_index() { |item, index|
67
+ if item.instance_of?(::Hash) && item.keys() == [:'extend-variable']
68
+ result += get(item[:'extend-variable'])
69
+ else
70
+ result.push(inject(item, string))
71
+ end
72
+ }
73
+
74
+ return result
75
+ end
76
+
77
+ def _inject_hash(value, string)
78
+ result = {}
79
+ value.each() { |key, item|
80
+ if key == :'include-variable'
81
+ result.merge!(get(item))
82
+ else
83
+ result[key] = inject(item, string)
84
+ end
85
+ }
86
+
87
+ return result
88
+ end
89
+
90
+ def _inject_string(value)
91
+ value = value.gsub('\\\\', '{{__ESCAPED_SLASH__}}')
92
+
93
+ if value.match(/(?<!\\)\#\{/)
94
+ value = value.gsub('\\#', '#')
95
+ value = eval('"' + value + '"')
96
+ end
97
+
98
+ value = value.gsub(/(?<!\\)\${(.*?)}/) { |string | get(string[2...-1]) }
99
+ value = value.gsub(/(?<!\\)\%{(.*?)}/) { |string |
100
+ command = @shell.expression(string[2...-1])
101
+ @shell.run!([command], verbose: false, message: 'Executing embedded ' +
102
+ 'command: ').rstrip()
103
+ }
104
+
105
+ value = value.gsub('\\$', '$')
106
+ value = value.gsub('\\%', '%')
107
+ value = value.gsub('{{__ESCAPED_SLASH__}}', '\\')
108
+ end
109
+
110
+ end
@@ -0,0 +1,7 @@
1
+ class Balmora::Variables::Config
2
+
3
+ def self.factory(state)
4
+ return state.config.get([], variables: false)
5
+ end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class Balmora::Variables::Variables
2
+
3
+ def self.factory(state)
4
+ return state.config.get([:variables], variables: false)
5
+ end
6
+
7
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: balmora
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Leonid Shagabutdinov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Balmora - linux task runner
14
+ email: leonid@shagabutdinov.com
15
+ executables:
16
+ - balmora
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/balmora
21
+ - lib/balmora.rb
22
+ - lib/balmora/arguments.rb
23
+ - lib/balmora/cli.rb
24
+ - lib/balmora/command.rb
25
+ - lib/balmora/command/commands.rb
26
+ - lib/balmora/command/exec.rb
27
+ - lib/balmora/command/file.rb
28
+ - lib/balmora/command/files.rb
29
+ - lib/balmora/command/pacman.rb
30
+ - lib/balmora/command/reload_config.rb
31
+ - lib/balmora/command/restart.rb
32
+ - lib/balmora/command/set_variable.rb
33
+ - lib/balmora/command/stop.rb
34
+ - lib/balmora/command/yaourt.rb
35
+ - lib/balmora/config.rb
36
+ - lib/balmora/context.rb
37
+ - lib/balmora/context/config_changed.rb
38
+ - lib/balmora/context/exec.rb
39
+ - lib/balmora/context/exec_result.rb
40
+ - lib/balmora/contexts.rb
41
+ - lib/balmora/extension.rb
42
+ - lib/balmora/extension/file_secret.rb
43
+ - lib/balmora/logger.rb
44
+ - lib/balmora/require.rb
45
+ - lib/balmora/shell.rb
46
+ - lib/balmora/state.rb
47
+ - lib/balmora/variables.rb
48
+ - lib/balmora/variables/config.rb
49
+ - lib/balmora/variables/variables.rb
50
+ homepage: http://github.com/shagabutdinov/balmora
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.4.5
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: Balmora
74
+ test_files: []