Module: QB::Util::Bundler
- Defined in:
- lib/qb/util/bundler.rb
Class Method Summary collapse
-
.bundled? ⇒ Boolean
Are we running inside
bundler exec
?. - .rebundle! ⇒ Object
- .unbundle!(&block) ⇒ Object
-
.with_clean_env(&block) ⇒ RESULT
Wrapper around Bundler.with_clean_env that copies the Bundler ENV vars to other keys, allowing that Bundler ENV to be re-instated later, specifically by child processes like Ansible module scripts that inherit the ENV.
Class Method Details
.bundled? ⇒ Boolean
Are we running inside bundler exec
?
10 11 12 |
# File 'lib/qb/util/bundler.rb', line 10 def self.bundled? defined? ::Bundler end |
.rebundle! ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/qb/util/bundler.rb', line 108 def self.rebundle! return if $qb_replaced_env_vars.nil? unless $qb_replaced_env_vars.empty? raise "Looks like you're already unbundled: #{ $qb_replaced_env_vars }" end ENV.each do |k, v| if k.start_with? 'QB_BUNDLER_ENV_' key = k.sub 'QB_BUNDLER_ENV_', '' $qb_replaced_env_vars[key] = [ENV[key], v] ENV[key] = v end end end |
.unbundle!(&block) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/qb/util/bundler.rb', line 87 def self.unbundle! &block if $qb_replaced_env_vars.nil? || $qb_replaced_env_vars.empty? if block return block.call else return end end $qb_replaced_env_vars.each do |key, (original, replacement)| ENV[key] = original end $qb_replaced_env_vars = {} if block block.call.tap { rebundle! } end end |
.with_clean_env(&block) ⇒ RESULT
Wrapper around with_clean_env that copies the Bundler ENV vars to other keys, allowing that Bundler ENV to be re-instated later, specifically by child processes like Ansible module scripts that inherit the ENV.
We execute Ansible commands in this context because any Ruby processes it
starts want the system environment, not the Bundler environment that QB
may be running in. In particular, Ansible's gem
module fails if the
Bundler ENV vars are still in place, which totally make sense.
Instead, we let programs that want to boot up the possibly separate
environment that QB is running in (so they can require it - again,
Ansible module scripts, specifically those using Ansible::Module)
can load //load/rebundle.rb
, which will restore the Bundler ENV vars
(and require 'bundler/setup'
).
We make the absolute path to //load/rebundle.rb
available in the "clean"
ENV as the QB_REBUNDLE_PATH
var, so child Ruby programs can drop a
single line at the top of the file:
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
and be set up to require QB files.
If QB is not running in Bundler (#bundled? returns false
) then
this method simply calls &block
and returns the value.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/qb/util/bundler.rb', line 48 def self.with_clean_env &block # If we're not running "bundled" then just call the block and return return block.call unless bundled? # copy the Bundler env vars into a hash dev_env = ENV.select {|k, v| k.start_with?("BUNDLE_") || [ 'GEM_HOME', 'GEM_PATH', 'MANPATH', 'RUBYOPT', 'RUBYLIB', ].include?(k) } qb_env = ENV.select { |k, v| k.start_with? 'QB_' } ::Bundler.with_clean_env do # Now that we're in a clean env, copy the Bundler env vars into # 'QB_BUNDLER_ENV_<NAME>' vars. dev_env.each { |k, v| ENV["QB_BUNDLER_ENV_#{ k }"] = v } # Set the path to the `//load/rebundle.rb` script in an ENV var. # # Child Ruby processes that want to load up the environment QB was run # in look for this and load it if they find it, restoring the Bundler / # Ruby Gems ENV vars, allowing them to `require 'qb'`, etc. # ENV['QB_REBUNDLE_PATH'] = (QB::ROOT / 'load' / 'rebundle.rb').to_s qb_env.each { |k, v| ENV[k] = v } # invoke the block block.call end # ::Bundler.with_clean_env end |