Module: QB::Util::Bundler

Defined in:
lib/qb/util/bundler.rb

Class Method Summary collapse

Class Method Details

.bundled?Boolean

Are we running inside bundler exec?

Returns:

  • (Boolean)


10
11
12
# File 'lib/qb/util/bundler.rb', line 10

def self.bundled?
  defined? ::Bundler
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.

Parameters:

  • &block (Proc<() => RESULT>)

    Block to execute in the "clean" env.

Returns:

  • (RESULT)

    Whatever &block returns when called.



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