satorix 0.0.1 → 1.6.0
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.
- checksums.yaml +5 -5
- data/.gitignore +4 -1
- data/.gitlab-ci.yml +45 -0
- data/.rspec +2 -1
- data/.rubocop.yml +11 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +25 -0
- data/Procfile +1 -0
- data/README.md +93 -1
- data/Rakefile +8 -4
- data/bin/console +3 -3
- data/bin/satorix +8 -0
- data/lib/satorix.rb +338 -2
- data/lib/satorix/CI/deploy/flynn.rb +129 -0
- data/lib/satorix/CI/deploy/flynn/environment_variables.rb +121 -0
- data/lib/satorix/CI/deploy/flynn/resources.rb +77 -0
- data/lib/satorix/CI/deploy/flynn/routes.rb +266 -0
- data/lib/satorix/CI/deploy/flynn/scale.rb +52 -0
- data/lib/satorix/CI/shared/buildpack_manager.rb +213 -0
- data/lib/satorix/CI/shared/buildpack_manager/buildpack.rb +153 -0
- data/lib/satorix/CI/shared/ruby/gem_manager.rb +79 -0
- data/lib/satorix/CI/shared/yarn_manager.rb +22 -0
- data/lib/satorix/CI/test/python/django_test.rb +35 -0
- data/lib/satorix/CI/test/python/safety.rb +27 -0
- data/lib/satorix/CI/test/ruby/brakeman.rb +32 -0
- data/lib/satorix/CI/test/ruby/bundler_audit.rb +32 -0
- data/lib/satorix/CI/test/ruby/cucumber.rb +26 -0
- data/lib/satorix/CI/test/ruby/rails_test.rb +26 -0
- data/lib/satorix/CI/test/ruby/rspec.rb +26 -0
- data/lib/satorix/CI/test/ruby/rubocop.rb +98 -0
- data/lib/satorix/CI/test/shared/database.rb +74 -0
- data/lib/satorix/shared/console.rb +180 -0
- data/lib/satorix/version.rb +1 -1
- data/satorix.gemspec +13 -11
- data/satorix/CI/deploy/ie_gem_server.rb +76 -0
- data/satorix/CI/deploy/rubygems.rb +77 -0
- data/satorix/custom.rb +21 -0
- metadata +57 -29
- data/.travis.yml +0 -5
@@ -0,0 +1,22 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Shared
|
4
|
+
|
5
|
+
module YarnManager
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Installing yarn dependencies...') { run_command(%w[yarn install]) }
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Python
|
5
|
+
module DjangoTest
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Python version...') { run_command(%w[python --version]) }
|
14
|
+
log_bench('Running tests...') { run_tests }
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def run_tests
|
19
|
+
run_command([manage, 'collectstatic'])
|
20
|
+
run_command([manage, 'test', 'public'])
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
|
27
|
+
def manage
|
28
|
+
File.join(Satorix.app_dir, 'public', 'manage.py')
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Python
|
5
|
+
module Safety
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Python version...') { run_command(%w[python --version]) }
|
14
|
+
log_bench('Installing Safety...') { run_command(%w[pip install safety]) }
|
15
|
+
log_bench('Auditing requirements.txt...') { run_scan }
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def run_scan
|
20
|
+
run_command(%w[safety check -r requirements.txt])
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module Brakeman
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Installing Brakeman...') { install_gem }
|
15
|
+
log_bench('Running Brakeman scan...') { run_scan }
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def install_gem
|
20
|
+
run_command(['gem', 'install', 'brakeman', '--no-document', '--bindir', Satorix.bin_dir])
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def run_scan
|
25
|
+
run_command(['brakeman', '-z', '--table-width', '1200', '--exit-on-error', '--path', Satorix.app_dir])
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module BundlerAudit
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Installing bundler-audit...') { install_gem }
|
15
|
+
log_bench('Auditing Gemfile.lock...') { run_scan }
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def install_gem
|
20
|
+
run_command(['gem', 'install', 'bundler-audit', '--no-document', '--bindir', Satorix.bin_dir])
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def run_scan
|
25
|
+
run_command(%w[bundle-audit check --update])
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module Cucumber
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Running Cucumber...') { run_cucumber }
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def run_cucumber
|
19
|
+
run_command(%w[bundle exec cucumber])
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module RailsTest
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Running Rails test...') { run_scan }
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def run_scan
|
19
|
+
run_command(%w[rails test])
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module Rspec
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Running specs...') { run_specs }
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def run_specs
|
19
|
+
run_command(%w[rspec spec])
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Ruby
|
5
|
+
module Rubocop
|
6
|
+
|
7
|
+
include Satorix::Shared::Console
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def go
|
13
|
+
log_bench('Displaying current Ruby version...') { run_command(%w[ruby -v]) }
|
14
|
+
log_bench('Installing Rubocop...') { install_gems }
|
15
|
+
log_bench('Configuring Rubocop...') { create_rubocop_config }
|
16
|
+
log_bench('Running Rubocop inspection...') { run_scan }
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def install_gems
|
21
|
+
run_command(['gem', 'install', 'rubocop', '--no-document', '--bindir', Satorix.bin_dir])
|
22
|
+
run_command(['gem', 'install', 'rubocop-performance', '--no-document', '--bindir', Satorix.bin_dir])
|
23
|
+
run_command(['gem', 'install', 'rubocop-rails_config', '--no-document', '--bindir', Satorix.bin_dir]) if Satorix.rails_app?
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def create_rubocop_config
|
28
|
+
if config_exist?
|
29
|
+
log 'Using existing .rubocop.yml file from project.'
|
30
|
+
else
|
31
|
+
log 'A .rubocop.yml file was not found, generating a default configuration file for this project.'
|
32
|
+
content = Satorix.rails_app? ? config_content_rails : config_content_default
|
33
|
+
save_rubocop_config content
|
34
|
+
end
|
35
|
+
log 'For more information, please refer to https://www.satorix.com/docs/articles/app_using_ruby_on_rails#rubocop.'
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def run_scan
|
40
|
+
command = %w[rubocop --require rubocop-performance --display-cop-names --extra-details --display-style-guide --parallel]
|
41
|
+
command.concat(%w[--require rubocop-rails]) if Satorix.rails_app?
|
42
|
+
|
43
|
+
run_command(command)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
|
50
|
+
def rubocop_config_file
|
51
|
+
File.join(Satorix.app_dir, '.rubocop.yml')
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def save_rubocop_config(config)
|
56
|
+
File.open(rubocop_config_file, 'w') { |f| f.write(config) }
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def config_exist?
|
61
|
+
File.exist? rubocop_config_file
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def ruby_version
|
66
|
+
version = run_command(%w[bundle platform --ruby], quiet: true)
|
67
|
+
version.match(/\d+\.\d+\.\d+/)[0]
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def config_content_default
|
72
|
+
<<~CONTENT
|
73
|
+
AllCops:
|
74
|
+
TargetRubyVersion: #{ ruby_version }
|
75
|
+
Exclude:
|
76
|
+
- '**/tmp/**/*'
|
77
|
+
- '**/templates/**/*'
|
78
|
+
- '**/vendor/**/*'
|
79
|
+
CONTENT
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def config_content_rails
|
84
|
+
<<~CONTENT
|
85
|
+
inherit_gem:
|
86
|
+
rubocop-rails_config:
|
87
|
+
- config/rails.yml
|
88
|
+
|
89
|
+
AllCops:
|
90
|
+
TargetRubyVersion: #{ ruby_version }
|
91
|
+
CONTENT
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Test
|
4
|
+
module Shared
|
5
|
+
module Database
|
6
|
+
|
7
|
+
|
8
|
+
include Satorix::Shared::Console
|
9
|
+
|
10
|
+
|
11
|
+
extend self
|
12
|
+
|
13
|
+
|
14
|
+
def host
|
15
|
+
ENV['DB_HOST'].to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def name
|
20
|
+
name_key.empty? ? '' : ENV[name_key].to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def name_key
|
25
|
+
{
|
26
|
+
mariadb: 'MYSQL_DATABASE',
|
27
|
+
mysql: 'MYSQL_DATABASE',
|
28
|
+
postgres: 'POSTGRES_DB'
|
29
|
+
}[host.to_sym].to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def password
|
34
|
+
password_key.empty? ? '' : ENV[password_key].to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def password_key
|
39
|
+
{
|
40
|
+
mariadb: 'MYSQL_ROOT_PASSWORD',
|
41
|
+
mysql: 'MYSQL_ROOT_PASSWORD',
|
42
|
+
postgres: 'POSTGRES_PASSWORD'
|
43
|
+
}[host.to_sym].to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def url
|
48
|
+
unset = [host, user, password, name].select(&:empty?)
|
49
|
+
if unset.empty?
|
50
|
+
"#{ host }://#{ user }:#{ password }@#{ host }/#{ name }"
|
51
|
+
else
|
52
|
+
log 'No database has been configured.'
|
53
|
+
log 'If you would like to use a database for this job, ensure that your gitlab-config.yml is configured.'
|
54
|
+
log 'Most databases require you to specify a type, host, database, username, and password.'
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def user
|
61
|
+
(ENV[user_key] || 'root').to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def user_key
|
66
|
+
"#{ host.upcase }_USER"
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Satorix
|
2
|
+
module Shared
|
3
|
+
module Console
|
4
|
+
|
5
|
+
require 'benchmark'
|
6
|
+
require 'English' # http://ruby-doc.org/stdlib-2.0.0/libdoc/English/rdoc/English.html
|
7
|
+
require 'shellwords'
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
|
12
|
+
def colorize(text, color = nil)
|
13
|
+
"\033[#{ colors[color] }m#{ text }\033[0m"
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def colors
|
18
|
+
Hash.new(39).merge(red: '0;31', light_red: '1;31',
|
19
|
+
green: '0;32', light_green: '1;32',
|
20
|
+
yellow: '0;33', light_yellow: '1;33',
|
21
|
+
blue: '0;34', light_blue: '1;34',
|
22
|
+
magenta: '0;35', light_magenta: '1;35',
|
23
|
+
cyan: '0;36', light_cyan: '1;36',
|
24
|
+
white: '0;37', light_white: '1;37')
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def humanize_time(seconds)
|
29
|
+
return 'less than 1 second' if seconds < 1
|
30
|
+
[[60, :second], [60, :minute], [24, :hour], [1000, :day]].map do |count, name|
|
31
|
+
if seconds > 0
|
32
|
+
seconds, n = seconds.divmod(count)
|
33
|
+
n = n.to_i
|
34
|
+
"#{ n } #{ name }#{ 's' if n > 1 }" if n > 0
|
35
|
+
end
|
36
|
+
end.compact.reverse.join(' ')
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def log(text, color = nil)
|
41
|
+
puts color ? colorize(text, color) : text
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def log_command(text)
|
46
|
+
log text, :cyan
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def log_duration(text)
|
51
|
+
log text, :light_cyan
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def log_header(text)
|
56
|
+
log("\n#{ text }", :light_green)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def log_error(text)
|
61
|
+
log text, :light_red
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def log_error_and_abort(text)
|
66
|
+
log_error text
|
67
|
+
abort text
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def log_bench(message)
|
72
|
+
log_header message
|
73
|
+
result = nil
|
74
|
+
log_duration "Time elapsed: #{ humanize_time Benchmark.realtime { result = yield } }."
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# The preferred way to use this method is by passing an array containing the command.
|
80
|
+
# This will ensure that items are properly escaped.
|
81
|
+
# It is also possible to use nested arrays. See tests for example use cases.
|
82
|
+
#
|
83
|
+
# If you want to see how your string command translates into an arry, you can use shellsplit method.
|
84
|
+
#
|
85
|
+
# For example:
|
86
|
+
# 'ruby -v'.shellsplit
|
87
|
+
# => ["ruby", "-v"]
|
88
|
+
#
|
89
|
+
# If, for some reason, you need to supply a string that is already escaped or should not be escaped, it is
|
90
|
+
# possible to supply a string argument instead of an array. If you do this, you will need to supply
|
91
|
+
# an additional parameter of string_verified_safe, to ensure that the operation is deliberate.
|
92
|
+
def run_command(command, filtered_text: [], quiet: false, string_verified_safe: false)
|
93
|
+
# This method is used *EVERYWHERE*.
|
94
|
+
# Seemingly small changes can have far-ranging and extreme consequences.
|
95
|
+
# Modify only with extreme caution.
|
96
|
+
#
|
97
|
+
# Note: Many applications (like echo and the Flynn CLI) append a newline to their output.
|
98
|
+
# If you are using the command result, it may be desirable to chomp the trailing
|
99
|
+
# newline. It is left to the implementing call to handle this, as it proved
|
100
|
+
# cumbersome to handle in this method in a way that worked perfectly in all cases.
|
101
|
+
raise('Potentially unsafe or problematic command. Please refer to the method documentation for more information.') if command.is_a?(String) && !string_verified_safe
|
102
|
+
|
103
|
+
command = normalized_command(command)
|
104
|
+
logged_command = logged_command(command, filtered_text)
|
105
|
+
log_command(logged_command) unless quiet
|
106
|
+
|
107
|
+
''.tap do |output|
|
108
|
+
IO.popen(bash(command)) do |io|
|
109
|
+
until io.eof?
|
110
|
+
line = io.gets
|
111
|
+
puts line unless quiet || line.empty?
|
112
|
+
$stdout.flush
|
113
|
+
output.concat line
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
handle_run_command_error(logged_command, quiet) unless $CHILD_STATUS.success?
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# http://stackoverflow.com/questions/1197224/source-shell-script-into-environment-within-a-ruby-script
|
123
|
+
# TODO : reduce / consolidate?
|
124
|
+
# Find variables changed as a result of sourcing the given file, and update in ENV.
|
125
|
+
def source_env_from(file)
|
126
|
+
bash_source(file).each { |k, v| ENV[k] = v }
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
|
133
|
+
def bash(command)
|
134
|
+
['bash -c', escaped_command(command), '2>&1'].join(' ')
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def logged_command(command, filtered_text)
|
139
|
+
filtered_text = [filtered_text].flatten.delete_if { |text| text.nil? || text.strip.empty? }
|
140
|
+
unescaped_command = command.shellsplit.join(' ')
|
141
|
+
unescaped_command.gsub(Regexp.union(filtered_text.sort_by(&:length).reverse), '[MASKED]')
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def escaped_command(command)
|
146
|
+
command.shellescape
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def normalized_command(command)
|
151
|
+
command.is_a?(Array) ? command.flatten.shelljoin : command
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
def handle_run_command_error(logged_command, quiet)
|
156
|
+
error_message = "\nAn error has occurred while running the following command:\n#{ logged_command }\n"
|
157
|
+
quiet ? abort : log_error_and_abort(error_message)
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# http://stackoverflow.com/questions/1197224/source-shell-script-into-environment-within-a-ruby-script
|
162
|
+
# TODO : reduce / consolidate?
|
163
|
+
# Read in the bash environment, after an optional command. Returns Array of key/value pairs.
|
164
|
+
def bash_env(cmd = nil)
|
165
|
+
env_cmd = bash("#{ cmd + ';' if cmd } printenv")
|
166
|
+
env = `#{ env_cmd }`
|
167
|
+
env.split(/\n/).map { |l| l.split(/=/, 2) }
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# http://stackoverflow.com/questions/1197224/source-shell-script-into-environment-within-a-ruby-script
|
172
|
+
# TODO : reduce / consolidate?
|
173
|
+
# Source a given file, and compare environment before and after. Returns Hash of any keys that have changed.
|
174
|
+
def bash_source(file)
|
175
|
+
Hash[bash_env("source #{ File.realpath file }") - bash_env]
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|