envbash 1.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2bca49115032c8fb6edc53278935e9e42bd1a830
4
+ data.tar.gz: 181f42eadcbe69daf2359e035fe8de85538c8848
5
+ SHA512:
6
+ metadata.gz: daf5b11dd39333d815e5f67c8ddef1bef3b635bea7fd19a8dab29b2da052e842ebc5032de8bb8512571d9ca3990c1b1cd3b855c05f9f6d0b334d919041a7ca2b
7
+ data.tar.gz: ccd7ab68ad8e5df0c4d23e81273204010501b248235757fcf5dbdf047c6e70e9e38f5203a570b00932d77560bcf3d046ea9f7b810f3c1e66eabe9724232afc10
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ # Unix-style newlines with a newline ending every file
4
+ [*]
5
+ charset = utf-8
6
+ indent_style = space
7
+ indent_size = 4
8
+ tab_width = 8
9
+ end_of_line = lf
10
+ insert_final_newline = true
11
+ trim_trailing_whitespace = true
12
+
13
+ [*.{json,rb,yaml,yml}]
14
+ indent_size = 2
15
+
16
+ # Tab indents for Makefile
17
+ [Makefile]
18
+ indent_style = tab
@@ -0,0 +1,51 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/dest/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ # Used by dotenv library to load environment variables.
15
+ # .env
16
+
17
+ ## Specific to RubyMotion:
18
+ .dat*
19
+ .repl_history
20
+ build/
21
+ *.bridgesupport
22
+ build-iPhoneOS/
23
+ build-iPhoneSimulator/
24
+
25
+ ## Specific to RubyMotion (use of CocoaPods):
26
+ #
27
+ # We recommend against adding the Pods directory to your .gitignore. However
28
+ # you should judge for yourself, the pros and cons are mentioned at:
29
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
30
+ #
31
+ # vendor/Pods/
32
+
33
+ ## Documentation cache and generated files:
34
+ /.yardoc/
35
+ /_yardoc/
36
+ /doc/
37
+ /rdoc/
38
+
39
+ ## Environment normalization:
40
+ /.bundle/
41
+ /vendor/bundle
42
+ /lib/bundler/man/
43
+
44
+ # for a library or gem, you might want to ignore these files since the code is
45
+ # intended to run in multiple environments; otherwise, check them in:
46
+ Gemfile.lock
47
+ .ruby-version
48
+ .ruby-gemset
49
+
50
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
51
+ .rvmrc
@@ -0,0 +1,12 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.1
6
+ - 2.2
7
+ - 2.3.3
8
+ - 2.4.0
9
+ install:
10
+ - bundle
11
+ script:
12
+ - rake
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Scampersand LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # envbash
2
+
3
+ [![gem](https://img.shields.io/gem/v/envbash.svg?style=plastic)](https://rubygems.org/gems/envbash)
4
+ [![travis](https://img.shields.io/travis/scampersand/envbash-ruby/master.svg?style=plastic)](https://travis-ci.org/scampersand/envbash-ruby?branch=master)
5
+ [![codecov](https://img.shields.io/codecov/c/github/scampersand/envbash-ruby/master.svg?style=plastic)](https://codecov.io/gh/scampersand/envbash-ruby/branch/master)
6
+
7
+ Ruby gem for sourcing a bash script to augment the environment.
8
+
9
+ ## Rationale
10
+
11
+ [12-factor apps](https://12factor.net/) require
12
+ [configuration loaded from the environment](https://12factor.net/config).
13
+
14
+ That's [easy on a platform like Heroku](https://devcenter.heroku.com/articles/config-vars),
15
+ where the environment is preset by the user with commands like
16
+ `heroku config:set`. But it's messier in development and non-Heroku
17
+ deployments, where the environment might need to be loaded from a file.
18
+
19
+ This package provides a mechanism for sourcing a Bash script to update
20
+ Ruby's environment (`ENV`). There are reasons for using a Bash script
21
+ instead of another configuration language:
22
+
23
+ 1. Environment variable keys and values should always be strings. Using a Bash
24
+ script to update the environment enforces that restriction, so there won't
25
+ be surprises when you deploy into something like Heroku later on.
26
+
27
+ 2. Using a script means that the values can be sourced into a Bash shell,
28
+ something that's non-trivial if you use a different config language.
29
+
30
+ 3. For better or worse, using a script means that environment variables can be
31
+ set using the full power of the shell, including reading from other files.
32
+
33
+ Commonly the external file is called `env.bash`, hence the name of this project.
34
+
35
+ ## Installation
36
+
37
+ Install from [RubyGems](https://rubygems.org/gems/envbash)
38
+
39
+ gem install envbash
40
+
41
+ or in your Gemfile:
42
+
43
+ gem 'envbash'
44
+
45
+ ## Usage
46
+
47
+ Call `EnvBash.load` to source a Bash script into the current Ruby process.
48
+ Any variables that are set in the script, regardless of whether they are
49
+ explicitly exported, will be added to the process environment.
50
+
51
+ For example, given `env.bash` with the following content:
52
+
53
+ ```bash
54
+ FOO='bar baz qux'
55
+ ```
56
+
57
+ This can be loaded into Ruby:
58
+
59
+ ```ruby
60
+ require 'envbash'
61
+
62
+ EnvBash.load('env.bash')
63
+
64
+ puts ENV['FOO'] #=> bar baz qux
65
+ ```
66
+
67
+ ## Legal
68
+
69
+ Copyright 2017 [Scampersand LLC](https://scampersand.com)
70
+
71
+ Released under the [MIT license](https://github.com/scampersand/envbash-ruby/blob/master/LICENSE)
@@ -0,0 +1,13 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new(:test) do |test|
4
+ test.libs << 'lib' << 'test'
5
+ # make sure helper.rb is loaded first, to start simplecov
6
+ test.test_files = FileList['test/helper.rb', 'test/test*.rb']
7
+ end
8
+
9
+ task :default => :test
10
+
11
+ # this adds "rake build" to make pkg/envbash-*.gem
12
+ require 'bundler/setup'
13
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "envbash"
3
+ spec.summary = "Source env.bash script to update environment"
4
+ spec.version = "1.0.1"
5
+ spec.authors = ["Aron Griffis"]
6
+ spec.email = "aron@scampersand.com"
7
+ spec.homepage = "https://github.com/scampersand/envbash-ruby"
8
+ spec.licenses = ["MIT"]
9
+
10
+ spec.files = `git ls-files -z`.split("\x0")
11
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
12
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
13
+ spec.require_paths = ["lib"]
14
+
15
+ spec.add_development_dependency "codecov"
16
+ spec.add_development_dependency "minitest"
17
+ spec.add_development_dependency "minitest-assert_errors"
18
+ spec.add_development_dependency "rake"
19
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'envbash/load'
2
+ require_relative 'envbash/read'
@@ -0,0 +1,16 @@
1
+ require_relative 'read'
2
+
3
+
4
+ module EnvBash
5
+ def EnvBash.load(envbash, into: ENV, override: false, remove: false, **kwargs)
6
+ loaded = read(envbash, **kwargs)
7
+ is_env = into.equal? ENV
8
+ into = into.to_h if is_env
9
+ if loaded
10
+ into.select! {|k| loaded.include? k} if remove
11
+ loaded.reject! {|k| into.include? k} unless override
12
+ into.merge! loaded
13
+ end
14
+ ENV.replace into if is_env
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ require 'open3'
2
+ require 'shellwords'
3
+
4
+
5
+ module EnvBash
6
+
7
+ FIXUPS = %w{_ OLDPWD PWD SHLVL}
8
+
9
+ class ScriptExitedEarly < StandardError
10
+ end
11
+
12
+ def EnvBash.read(envbash, bash: 'bash', env: ENV, missing_ok: false, fixups: FIXUPS)
13
+ # make sure the file exists and is readable.
14
+ # alternatively we could test File.readable?(envbash) but this approach
15
+ # raises Errno::ENOENT or Errno::EACCES which is what we want.
16
+ begin
17
+ File.open(envbash).close
18
+ rescue Errno::ENOENT
19
+ return if missing_ok
20
+ raise
21
+ end
22
+
23
+ # construct an inline script which sources env.bash then prints the
24
+ # resulting environment so it can be eval'd back into this process.
25
+ inline = <<-EOT
26
+ set -a
27
+ source #{envbash.shellescape} >/dev/null
28
+ #{Gem.ruby.shellescape} -e 'p ENV'
29
+ EOT
30
+
31
+ # Process.spawn treats env as overriding ENV, and anything that should be
32
+ # omitted needs to have a nil value. If env == ENV then this is a noop.
33
+ env = Hash[ENV.keys.map {|k| [k, nil]}].merge(env)
34
+
35
+ # run the inline script with bash -c, capturing stdout. if there is any
36
+ # error output from env.bash, it will pass through to stderr.
37
+ # exit status is ignored.
38
+ output, _ = Open3.capture2(env, 'bash', '-c', inline, :in=>"/dev/null")
39
+
40
+ # the only stdout from the inline script should be
41
+ # `p ENV` so there should be no syntax errors eval'ing this. however there
42
+ # will be no output to eval if the sourced env.bash exited early, and that
43
+ # indicates script failure.
44
+ raise ScriptExitedEarly if output.empty?
45
+
46
+ # the eval'd output should return a hash.
47
+ nenv = eval(output)
48
+
49
+ # there are a few environment variables that vary between this process and
50
+ # running the inline script with bash -c, but are certainly not part of the
51
+ # intentional settings in env.bash.
52
+ for f in fixups
53
+ if env[f] # not .include? because env might have nil values
54
+ nenv[f] = env[f]
55
+ else
56
+ nenv.delete(f)
57
+ end
58
+ end
59
+
60
+ nenv
61
+ end
62
+ end
@@ -0,0 +1,10 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ if ENV['CI'] == 'true'
5
+ require 'codecov'
6
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
7
+ end
8
+
9
+ require 'minitest/autorun'
10
+ require 'minitest/assert_errors'
@@ -0,0 +1,74 @@
1
+ require_relative 'helper'
2
+ require 'envbash'
3
+
4
+
5
+ class TestLoad < Minitest::Test
6
+ def setup
7
+ @orig = ENV.to_h
8
+ ENV['A'] = 'A'
9
+ ENV['B'] = 'B'
10
+ ENV['C'] = 'C'
11
+ ENV.delete('D')
12
+ @loaded = ENV.to_h.merge('A'=>'a', 'D'=>'d')
13
+ @loaded.delete('B')
14
+ end
15
+
16
+ def teardown
17
+ ENV.replace(@orig)
18
+ end
19
+
20
+ def test_load_no_override_no_remove
21
+ EnvBash.stub :read, @loaded do
22
+ # the first argument doesn't matter since read is stubbed
23
+ EnvBash.load('')
24
+ end
25
+ assert_equal ENV['A'], 'A' # NOT overridden
26
+ assert_equal ENV['B'], 'B' # NOT removed
27
+ assert_equal ENV['C'], 'C' # inherited
28
+ assert_equal ENV['D'], 'd' # loaded
29
+ end
30
+
31
+ def test_load_override_no_remove
32
+ EnvBash.stub :read, @loaded do
33
+ # the first argument doesn't matter since read is stubbed
34
+ EnvBash.load('', override: true)
35
+ end
36
+ assert_equal ENV['A'], 'a' # overridden
37
+ assert_equal ENV['B'], 'B' # NOT removed
38
+ assert_equal ENV['C'], 'C' # inherited
39
+ assert_equal ENV['D'], 'd' # loaded
40
+ end
41
+
42
+ def test_load_no_override_remove
43
+ EnvBash.stub :read, @loaded do
44
+ # the first argument doesn't matter since read is stubbed
45
+ EnvBash.load('', remove: true)
46
+ end
47
+ assert_equal ENV['A'], 'A' # NOT overridden
48
+ assert ! ENV.include?('B') # removed
49
+ assert_equal ENV['C'], 'C' # inherited
50
+ assert_equal ENV['D'], 'd' # loaded
51
+ end
52
+
53
+ def test_load_override_remove
54
+ EnvBash.stub :read, @loaded do
55
+ # the first argument doesn't matter since read is stubbed
56
+ EnvBash.load('', override: true, remove: true)
57
+ end
58
+ assert_equal ENV['A'], 'a' # overridden
59
+ assert ! ENV.include?('B') # removed
60
+ assert_equal ENV['C'], 'C' # inherited
61
+ assert_equal ENV['D'], 'd' # loaded
62
+ end
63
+
64
+ def test_load_into
65
+ orig = ENV.to_h
66
+ into = {}
67
+ EnvBash.stub :read, {'A'=>'B'} do
68
+ # the first argument doesn't matter since read is stubbed
69
+ EnvBash.load('', into: into)
70
+ end
71
+ assert_equal into, {'A'=>'B'}
72
+ assert_equal ENV.to_h, orig
73
+ end
74
+ end
@@ -0,0 +1,95 @@
1
+ require_relative 'helper'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+ require 'envbash'
5
+
6
+
7
+ class TestRead < Minitest::Test
8
+ def setup
9
+ @tmpdir = Dir.mktmpdir
10
+ @envbash = File.join @tmpdir, 'env.bash'
11
+ @orig = ENV.to_h
12
+ end
13
+
14
+ def teardown
15
+ ENV.replace(@orig)
16
+ FileUtils.rm_rf(@tmpdir)
17
+ end
18
+
19
+ def test_read_missing_not_ok
20
+ assert_error_raised(nil, Errno::ENOENT) do
21
+ EnvBash.read @envbash
22
+ end
23
+ end
24
+
25
+ def test_read_missing_ok
26
+ assert_no_error do
27
+ EnvBash.read @envbash, missing_ok: true
28
+ end
29
+ end
30
+
31
+ def test_read_permission_error
32
+ FileUtils.chmod 0, @tmpdir
33
+ assert_error_raised(nil, Errno::EACCES) do
34
+ EnvBash.read @envbash
35
+ end
36
+ end
37
+
38
+ def test_read_empty
39
+ FileUtils.touch @envbash
40
+ result = EnvBash.read @envbash
41
+ assert_equal result, @orig
42
+ end
43
+
44
+ def test_read_normal
45
+ ENV.delete('FOO')
46
+ orig = ENV.to_h # separate from @orig
47
+ File.open(@envbash, 'w') do |f|
48
+ f.write 'FOO=BAR'
49
+ end
50
+ result = EnvBash.read @envbash
51
+ assert_equal result['FOO'], 'BAR'
52
+ result.delete('FOO')
53
+ assert_equal result, orig
54
+ end
55
+
56
+ def test_read_error
57
+ File.open(@envbash, 'w') do |f|
58
+ # stderr doesn't matter, nor does final status.
59
+ f.write "echo 'okay!' >&2\nfalse"
60
+ end
61
+ result = EnvBash.read @envbash
62
+ assert_equal result, @orig
63
+ end
64
+
65
+ def test_read_exit
66
+ File.open(@envbash, 'w') do |f|
67
+ f.write 'exit'
68
+ end
69
+ assert_error_raised(nil, EnvBash::ScriptExitedEarly) do
70
+ EnvBash.read @envbash
71
+ end
72
+ end
73
+
74
+ def test_read_env
75
+ File.open(@envbash, 'w') do |f|
76
+ f.write 'FOO=BAR'
77
+ end
78
+ result = EnvBash.read @envbash, env: {}
79
+ assert_equal result, {'FOO'=>'BAR'}
80
+ end
81
+
82
+ def test_read_fixups
83
+ File.open(@envbash, 'w') do |f|
84
+ f.write 'A=B; C=D; E=F; G=H'
85
+ end
86
+ myenv = {'A'=>'Z', 'E'=>'F'}
87
+ result = EnvBash.read @envbash, env: myenv, fixups: ['A', 'C']
88
+ # there will be extra stuff in result since fixups is overridden, so can't
89
+ # test strict equality.
90
+ assert_equal result['A'], 'Z' # fixups, myenv, env.bash
91
+ assert !result.include?('C') # fixups, not myenv, env.bash
92
+ assert_equal result['E'], 'F' # not fixups, myenv, env.bash
93
+ assert_equal result['G'], 'H' # not fixups, not myenv, env.bash
94
+ end
95
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: envbash
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aron Griffis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: codecov
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-assert_errors
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email: aron@scampersand.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".editorconfig"
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - envbash.gemspec
83
+ - lib/envbash.rb
84
+ - lib/envbash/load.rb
85
+ - lib/envbash/read.rb
86
+ - test/helper.rb
87
+ - test/test_load.rb
88
+ - test/test_read.rb
89
+ homepage: https://github.com/scampersand/envbash-ruby
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.5.2
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Source env.bash script to update environment
113
+ test_files:
114
+ - test/helper.rb
115
+ - test/test_load.rb
116
+ - test/test_read.rb