balmora 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []