rake-pro 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f63cac62f28dd2f2eb0b2eff0fa951ecd5954418
4
+ data.tar.gz: 00d40a32a74cf8825d716f4ebcfd9a23402892f5
5
+ SHA512:
6
+ metadata.gz: fde4d66bf7f5536bad3ca5a01ab282bbe9608fee7b1af773e1013516bb048fcfc8bb33f2abe177702947928a54a60cffa2605b28601a91faa9dd4b120ac15086
7
+ data.tar.gz: 73d4987dae92dc995dd9af00c10178e87a0de3845318091cb6877d7f2721676e72022492fbd5a3bc8b3d5463d3d990de1976d890130d2ab4a276a2103ce0c0c6
@@ -0,0 +1,10 @@
1
+ require "rake/pro/version"
2
+ require "rake/pro/hashex"
3
+ require "rake/pro/ssh_tunnel"
4
+ require "rake/pro/keystore"
5
+
6
+ module Rake
7
+ module Pro
8
+ # Your code goes here...
9
+ end
10
+ end
@@ -0,0 +1,135 @@
1
+ class Hash
2
+ def recursive_merge(new_hash)
3
+ self.merge(new_hash) do |k, old_val, new_val|
4
+ if new_val.respond_to?(:blank) && new_val.blank?
5
+ old_val
6
+ elsif (old_val.kind_of?(Hash) and new_val.kind_of?(Hash))
7
+ old_val.recursive_merge(new_val)
8
+ else
9
+ new_val
10
+ end
11
+ end
12
+ end
13
+
14
+ def recursive_merge!(new_hash)
15
+ self.merge!(new_hash) do |k, old_val, new_val|
16
+ if new_val.respond_to?(:blank) && new_val.blank?
17
+ old_val
18
+ elsif (old_val.kind_of?(Hash) and new_val.kind_of?(Hash))
19
+ old_val.recursive_merge!(new_val)
20
+ else
21
+ new_val
22
+ end
23
+ end
24
+ end
25
+
26
+ def match strings
27
+ select { |key,val|
28
+ is_match = false
29
+ strings.each { |findstr|
30
+ is_match ||= key.downcase.include?(findstr) || val.downcase.include?(findstr)
31
+ }
32
+ is_match
33
+ }
34
+ end
35
+
36
+ def symbolize_keys
37
+ inject({}) { |memo,(k,v)|
38
+ memo[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v;
39
+ memo
40
+ }
41
+ end
42
+
43
+
44
+ # CASE
45
+ # admin@dev,prod:
46
+ # username: abc
47
+ # password
48
+ # returns
49
+ # scopes : [dev, prod]
50
+ # sub_key : admin
51
+ # admin:
52
+ # username: abc
53
+ #
54
+ # CASE:
55
+ # dev:
56
+ # url: abc
57
+ #
58
+ # returns
59
+ # scopes: [dev]
60
+ # subkey: nil
61
+ #
62
+ # CASE:
63
+ # url@dev: abc
64
+ #
65
+ # returns:
66
+ # scopes: [dev]
67
+ # subkey: url
68
+ #
69
+ # CASE:
70
+ # dev:
71
+ # url: abc
72
+ #
73
+
74
+ def key_details(k)
75
+ subkey = scopes = nil
76
+ sk = k.to_s
77
+ skp = sk.split('@')
78
+ subkey = skp.shift.to_sym if (skp.length > 1)
79
+ scopes = skp[0].split(/\s*[&,\|]\s*/)
80
+ [scopes.map { |scope| scope.to_sym }, subkey]
81
+ end
82
+
83
+ def promote_key pk
84
+ pk = pk.to_sym
85
+ coh = {}
86
+ promoted = false
87
+ self.each_pair { |k, v|
88
+ scopes, subkey = key_details(k)
89
+ if (scopes.include?(pk))
90
+ promoted = true
91
+ if subkey.nil?
92
+ v.each_pair { |sk, sv|
93
+ coh[sk] = sv
94
+ }
95
+ coh[k] = v
96
+ else
97
+ coh[subkey] =v
98
+ end
99
+ else
100
+ if v.is_a?(Hash)
101
+ coh[k], subpromo = v.promote_key(pk)
102
+ promoted |= subpromo
103
+ else
104
+ coh[k] = v
105
+ end
106
+ end
107
+ }
108
+ [coh, promoted]
109
+ end
110
+
111
+ def prune_keys pks
112
+ coh = {}
113
+ self.each_pair { |k, v|
114
+ scopes, subkey = key_details(k)
115
+ prune = false
116
+ scopes.each { |scope| prune |= pks.include?(scope) }
117
+ if prune
118
+ scopes.each { |scope|
119
+ if !pks.include?(scope)
120
+ if (subkey.nil?)
121
+ coh[scope] = v
122
+ else
123
+ coh[scope] = {}
124
+ coh[scope][subkey] = v
125
+ end
126
+ end
127
+ }
128
+ else
129
+ coh[k] = v.is_a?(Hash) ? v.prune_keys(pks) : v
130
+ end
131
+ }
132
+ coh
133
+ end
134
+
135
+ end
@@ -0,0 +1,152 @@
1
+ require 'rake'
2
+ require 'yaml'
3
+ require 'etc'
4
+ require_relative './hashex'
5
+
6
+ module Rake
7
+ class Application
8
+ attr_accessor :cfg
9
+ attr_accessor :scopes
10
+ attr_accessor :active_dir
11
+
12
+ class KeySpace
13
+ def initialize
14
+ @cfg_files = []
15
+ @kvp_stack = []
16
+ @kvp = {}
17
+ end
18
+
19
+ def [](key)
20
+ @kvp[key]
21
+ end
22
+
23
+ def values()
24
+ @kvp
25
+ end
26
+
27
+ def home()
28
+ Etc.getpwuid.dir;
29
+ end
30
+
31
+ def root()
32
+ Rake.original_dir
33
+ end
34
+
35
+ def rpath(*paths)
36
+ return File.join(paths)
37
+ end
38
+
39
+ def push_scope scope
40
+ (@scopes ||= []).push(scope)
41
+ end
42
+
43
+ def pop_scope
44
+ @scopes.pop
45
+ end
46
+
47
+ def push_cfg cfg_file
48
+ #puts "Loading cfg file: #{cfg_file}..."
49
+ cfg = YAML.load_file(cfg_file).symbolize_keys
50
+ source = if (cfg.has_key?(:default))
51
+ cfg[:default]
52
+ elsif (cfg.has_key?(:source))
53
+ cfg[:source]
54
+ elsif (cfg.has_key?(:system))
55
+ cfg[:system]
56
+ elsif(cfg.has_key?(:target))
57
+ cfg[:target]
58
+ end
59
+
60
+ push_scope(source.to_sym) if source
61
+ @kvp_stack.push(cfg)
62
+ end
63
+
64
+ def pop_cfg
65
+ @kvp_stack.pop
66
+ end
67
+
68
+ def load_once(cfg_file)
69
+ unless @cfg_files.include?(cfg_file)
70
+ if (File.file?(cfg_file))
71
+ Rake.application.active_dir = File.dirname(cfg_file)
72
+ push_cfg(cfg_file)
73
+ end
74
+ @cfg_files.push(cfg_file)
75
+ end
76
+ end
77
+
78
+ def scope_siblings scope
79
+ siblings = nil
80
+ Rake.application.scopes.each { |scope_set|
81
+ siblings = scope_set if scope_set.include?(scope)
82
+ }
83
+ siblings
84
+ end
85
+
86
+ def before_invoke task_details
87
+ task_name = task_details[0]
88
+ parts = task_name.split(':')
89
+ push_scope(parts[0].to_sym) if parts.length == 1
90
+
91
+ load_paths = parts.reduce([
92
+ rpath(root, 'cfg.yml'),
93
+ rpath(root, '.cfg.yml'),
94
+ rpath(root, '.cfg-private.yml')
95
+ ]) { |paths, folder|
96
+ paths.push(rpath(root, folder, 'cfg.yml'))
97
+ paths.push(rpath(root, folder, '.cfg.yml'))
98
+ paths.push(rpath(root, folder, '.cfg-private.yml'))
99
+ paths
100
+ }
101
+ load_paths.push(rpath(home, '.cyborg.yml'))
102
+
103
+ load_paths.each { |path|
104
+ load_once(path)
105
+ }
106
+
107
+ # promote and prune the key space
108
+ pruned = false
109
+ pruned_stack = []
110
+ @kvp_stack.each_with_index { |kvp, index|
111
+ @scopes.each_with_index { |scope, i2|
112
+ kvp, didprune = kvp.promote_key(scope)
113
+ siblings = scope_siblings(scope)
114
+ kvp = kvp.prune_keys(scope_siblings(scope)) if siblings
115
+ pruned |= (didprune && scope == task_name.to_sym)
116
+ }
117
+ pruned_stack.push(kvp)
118
+ }
119
+
120
+ # merge the kvp stack entries into a single map
121
+ @kvp = pruned_stack.reduce({}) { |acc, kvp|
122
+ acc.recursive_merge(kvp)
123
+ }
124
+
125
+ [task_name, pruned]
126
+ end
127
+
128
+ def after_invoke task_details
129
+ task_name = task_details[0]
130
+ parts = task_name.split(':')
131
+ if parts.length > 1
132
+ pop_scope
133
+ pop_cfg
134
+ end
135
+ end
136
+
137
+ end
138
+ end
139
+
140
+ module Intercept
141
+ def invoke_task *args
142
+ task_name, pruned = (Rake.application.cfg ||= Application::KeySpace.new).before_invoke(parse_task_string args.first)
143
+ super if Rake::Task.task_defined?(task_name) || !pruned
144
+ Rake.application.cfg.after_invoke(parse_task_string args.first)
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ Rake::Application.class_eval do
151
+ prepend Rake::Intercept
152
+ end
@@ -0,0 +1,90 @@
1
+ require 'open4'
2
+
3
+ module Rake
4
+
5
+ class CommandNotFound < StandardError
6
+ end
7
+
8
+ class AbnormalExitStatus < StandardError
9
+ attr_reader :exit_status
10
+ def initialize(exit_status, error_lines)
11
+ @exit_status = exit_status
12
+ super error_lines
13
+ end
14
+ end
15
+
16
+ class Local
17
+
18
+ def sh command_line, opts = {}
19
+ native_output_only = command_line.include?('--terse') || opts[:terse]
20
+ if native_output_only
21
+ command_line.sub!(' --terse', '')
22
+ opts[:echo] = true
23
+ opts[:echo_cmd] = false
24
+ end
25
+ echo_command_output = opts[:echo] || true
26
+ command_line = "#{command_line}"
27
+ puts "$ #{command_line}"
28
+ command_output = ""
29
+ status = Open4::popen4(command_line) do |pid, stdin, stdout, stderr|
30
+ command_output = capture_output(stdout, stderr, echo_command_output, native_output_only)
31
+ end
32
+ if status.exitstatus != 0
33
+ raise AbnormalExitStatus.new(status.exitstatus, command_output) if opts[:raise_on_error]
34
+ end
35
+ command_output.strip
36
+ rescue AbnormalExitStatus
37
+ raise
38
+ rescue Errno::ENOENT
39
+ raise CommandNotFound, "Bash Error. Command or file arguments not found." if opts[:raise_on_error]
40
+ end
41
+
42
+ def capture_output stdout, stderr, echo_command_output, native_output_only
43
+ stdout_lines = ""
44
+ stderr_lines = ""
45
+ command_output = ""
46
+ loop do
47
+ begin
48
+ # check whether stdout, stderr or both are
49
+ # ready to be read from without blocking
50
+ IO.select([stdout,stderr]).flatten.compact.each { |io|
51
+ # stdout, if ready, goes to stdout_lines
52
+ stdout_lines += io.readpartial(1024) if io.fileno == stdout.fileno
53
+ # stderr, if ready, goes to stdout_lines
54
+ stderr_lines += io.readpartial(1024) if io.fileno == stderr.fileno
55
+ }
56
+ break if stdout.closed? && stderr.closed?
57
+ rescue EOFError
58
+ # Note, readpartial triggers the EOFError too soon. Continue to flush the
59
+ # pending io (via readpartial) until we have received all characters
60
+ # out from the IO socket.
61
+ break if stdout_lines.length == 0 && stderr_lines.length == 0
62
+ ensure
63
+ # if we acumulated any complete lines (\n-terminated)
64
+ # in either stdout/err_lines, output them now
65
+ stdout_lines.sub!(/.*\n/) {
66
+ command_output << $&
67
+ if echo_command_output
68
+ if native_output_only
69
+ puts $&.strip
70
+ else
71
+ puts $&.strip
72
+ end
73
+ end
74
+ }
75
+ stderr_lines.sub!(/.*\n/) {
76
+ command_output << $&
77
+ if echo_command_output
78
+ if native_output_only
79
+ puts $&.strip
80
+ else
81
+ puts $&.strip
82
+ end
83
+ end
84
+ }
85
+ end
86
+ end
87
+ command_output
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,109 @@
1
+ require 'openssl'
2
+ require 'net/ssh/gateway'
3
+ require 'open4'
4
+
5
+ module Rake
6
+
7
+ class Local
8
+
9
+ def sh command_line, opts = {}
10
+ native_output_only = command_line.include?('--terse') || opts[:terse]
11
+ if native_output_only
12
+ command_line.sub!(' --terse', '')
13
+ opts[:echo] = true
14
+ opts[:echo_cmd] = false
15
+ end
16
+ echo_command_output = opts[:echo] || true
17
+ command_line = "#{command_line}"
18
+ puts "$ #{command_line}"
19
+ command_output = ""
20
+ status = Open4::popen4(command_line) do |pid, stdin, stdout, stderr|
21
+ command_output = capture_output(stdout, stderr, echo_command_output, native_output_only)
22
+ end
23
+ if status.exitstatus != 0
24
+ raise AbnormalExitStatus.new(status.exitstatus, command_output) if opts[:raise_on_error]
25
+ end
26
+ command_output.strip
27
+ rescue AbnormalExitStatus
28
+ raise
29
+ rescue Errno::ENOENT
30
+ raise CommandNotFound, "Bash Error. Command or file arguments not found." if opts[:raise_on_error]
31
+ end
32
+
33
+ def capture_output stdout, stderr, echo_command_output, native_output_only
34
+ stdout_lines = ""
35
+ stderr_lines = ""
36
+ command_output = ""
37
+ loop do
38
+ begin
39
+ # check whether stdout, stderr or both are
40
+ # ready to be read from without blocking
41
+ IO.select([stdout,stderr]).flatten.compact.each { |io|
42
+ # stdout, if ready, goes to stdout_lines
43
+ stdout_lines += io.readpartial(1024) if io.fileno == stdout.fileno
44
+ # stderr, if ready, goes to stdout_lines
45
+ stderr_lines += io.readpartial(1024) if io.fileno == stderr.fileno
46
+ }
47
+ break if stdout.closed? && stderr.closed?
48
+ rescue EOFError
49
+ # Note, readpartial triggers the EOFError too soon. Continue to flush the
50
+ # pending io (via readpartial) until we have received all characters
51
+ # out from the IO socket.
52
+ break if stdout_lines.length == 0 && stderr_lines.length == 0
53
+ ensure
54
+ # if we acumulated any complete lines (\n-terminated)
55
+ # in either stdout/err_lines, output them now
56
+ stdout_lines.sub!(/.*\n/) {
57
+ command_output << $&
58
+ if echo_command_output
59
+ if native_output_only
60
+ puts $&.strip
61
+ else
62
+ puts $&.strip
63
+ end
64
+ end
65
+ }
66
+ stderr_lines.sub!(/.*\n/) {
67
+ command_output << $&
68
+ if echo_command_output
69
+ if native_output_only
70
+ puts $&.strip
71
+ else
72
+ puts $&.strip
73
+ end
74
+ end
75
+ }
76
+ end
77
+ end
78
+ command_output
79
+ end
80
+ end
81
+
82
+ class SSH
83
+ class << self
84
+ def tunnel
85
+ host = gateway = port = jump = nil
86
+ cfg = Rake.application.cfg.values
87
+ if cfg.has_key?(:jumpbox)
88
+ jump = cfg[:jumpbox]
89
+ gateway = Net::SSH::Gateway.new(
90
+ jump[:host], jump[:user],
91
+ :keys => [jump[:keyfile]] #, :verbose => :debug
92
+ )
93
+ host = "127.0.0.1"
94
+ port = gateway.open(cfg[:host], cfg[:port], jump[:port])
95
+ else
96
+ host = cfg[:host]
97
+ port = cfg[:port]
98
+ end
99
+ local = Rake::Local.new
100
+ yield(local, host, port) if block_given?
101
+ rescue Net::SSH::AuthenticationFailed => ex
102
+ puts "\nError: SSH Failed to Authenticate. You may need to run\n $ ssh-add ~/.ssh/#{jump[:keyfile]} # key file\n ** or add this line to your .bashrc.\n\n"
103
+ ensure
104
+ gateway.close(port) unless gateway.nil?
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,5 @@
1
+ module Rake
2
+ module Pro
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rake-pro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dean Hallman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: open4
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: openssl
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: net-ssh-gateway
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ description: Adds support for key/value store with template expansion, ssh tunneling,
98
+ local and remote shell improvements etc.
99
+ email:
100
+ - rdhallman@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - lib/rake/pro.rb
106
+ - lib/rake/pro/hashex.rb
107
+ - lib/rake/pro/keystore.rb
108
+ - lib/rake/pro/localsh.rb
109
+ - lib/rake/pro/ssh_tunnel.rb
110
+ - lib/rake/pro/version.rb
111
+ homepage: http://www.github.com/
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.6.13
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Enterprise extensions for Rake.
135
+ test_files: []