module Senv

Constants

DEFAULT
ENCRYPTED_PATH_RE
LICENSE
SUMMARY
THREAD_SAFE
VERSION

Public Class Methods

binread(path, options = {}) click to toggle source
# File lib/senv.rb, line 336
def Senv.binread(path, options = {})
  data = IO.binread(path)

  encrypted =
    if options.has_key?('encrypted')
      options['encrypted']
    else
      Senv.is_encrypted?(path)
    end

  if encrypted
    data = 
      begin
        Blowfish.decrypt(Senv.key, data)
      rescue
        abort "could not decrypt `#{ path }` with key `#{ Senv.key }` from `#{ Senv.key_source }`"
      end
  end

  data
end
binwrite(path, data, options = {}) click to toggle source
# File lib/senv.rb, line 362
def Senv.binwrite(path, data, options = {})
  encrypted =
    if options.has_key?('encrypted')
      options['encrypted']
    else
      Senv.is_encrypted?(path)
    end

  if encrypted
    data = 
      begin
        Blowfish.encrypt(Senv.key, data)
      rescue
        abort "could not encrypt `#{ data.to_s.split("\n").first }...` with key `#{ Senv.key }` from `#{ Senv.key_source }`"
      end
  end

  FileUtils.mkdir_p(File.dirname(path))

  IO.binwrite(path, data)
end
capturing_environment_changes(&block) click to toggle source
# File lib/senv.rb, line 544
def Senv.capturing_environment_changes(&block)
  EnvChangeTracker.track(&block)
end
config_paths_for(env) click to toggle source
# File lib/senv.rb, line 162
def Senv.config_paths_for(env)
  glob = "**/#{ env }.{rb,enc.rb}"

  Senv.directory.glob(glob).sort_by do |path|
    ext = path.basename.extname.split('.')
    [path.basename.to_s.size, ext.size]
  end
end
debug(*args, &block) click to toggle source
# File lib/senv.rb, line 432
def Senv.debug(*args, &block)
  if args.empty? && block.nil?
    return Senv.debug?
  end

  return nil unless Senv.debug?

  lines = []

  args.each do |arg|
    case
      when arg.is_a?(String)
        lines << arg.strip
      else
        lines << arg.inspect.strip
    end
  end

  return nil if(lines.empty? && block.nil?)

  if lines
    lines.each do |line|
      STDERR.puts "# [SENV=#{ Senv.env }] : #{ line }"
    end
  end

  if block
    return block.call
  else
    true
  end
end
debug=(arg) click to toggle source
# File lib/senv.rb, line 469
def Senv.debug=(arg)
  if arg
    ENV['SENV_DEBUG'] = 'true'
  else
    ENV.delete('SENV_DEBUG')
  end
end
debug?() click to toggle source
# File lib/senv.rb, line 465
def Senv.debug?
  !!ENV['SENV_DEBUG']
end
default() click to toggle source
# File lib/senv.rb, line 37
def Senv.default
  DEFAULT
end
determine_root!() click to toggle source
# File lib/senv.rb, line 262
def Senv.determine_root!
  if ENV['SENV_ROOT']
    Senv.root = ENV['SENV_ROOT']
    return @root
  else
    Senv.search_path.each do |dirname|
      if test(?d, dirname)
        Senv.root = dirname
        return @root
      end
    end
  end

  msg = "[SENV] no `.senv` directory found via `#{ Senv.search_path.join(' | ') }`"
  Senv.error!(msg)
end
directory() click to toggle source
# File lib/senv.rb, line 279
def Senv.directory
  Senv.root.join('.senv')
end
env() click to toggle source
# File lib/senv.rb, line 50
def Senv.env
  ENV['SENV']
end
env=(env) click to toggle source
# File lib/senv.rb, line 54
def Senv.env=(env)
  if env
    ENV['SENV'] = env.to_s.strip
  else
    ENV.delete('SENV')
  end
end
environment() click to toggle source
# File lib/senv.rb, line 235
def Senv.environment
  @environment ||= {}
end
environment=(hash) click to toggle source
# File lib/senv.rb, line 239
def Senv.environment=(hash)
  @environment = hash
end
error!(*args, &block) click to toggle source
# File lib/senv.rb, line 45
def Senv.error!(*args, &block)
  raise Error.new(*args, &block)
end
expand_path(path) click to toggle source
# File lib/senv.rb, line 248
def Senv.expand_path(path)
  (realpath(path) rescue File.expand_path(path)).to_s
end
for_senv(senv) click to toggle source
# File lib/senv.rb, line 498
def Senv.for_senv(senv)
  senv = senv.to_s

  if Senv.senvs.has_key?(senv)
    return Senv.senvs[senv]
  end

  Senv.senvs[senv] = Senv.for_senv!(senv)
end
for_senv!(senv) click to toggle source
# File lib/senv.rb, line 482
def Senv.for_senv!(senv)
  senv = senv.to_s

  IO.popen('-', 'w+') do |io|
    child = io.nil?

    if child
      Senv.load(senv)
      puts Senv.environment.to_yaml
      exit
    else
      YAML.load(io.read)
    end
  end
end
get(senv, var) click to toggle source
# File lib/senv.rb, line 508
def Senv.get(senv, var)
  Senv.for_senv(senv)[var.to_s]
end
get!(senv, var) click to toggle source
# File lib/senv.rb, line 512
def Senv.get!(senv, var)
  Senv.for_senv!(senv)[var.to_s]
end
is_encrypted?(path) click to toggle source
# File lib/senv.rb, line 331
def Senv.is_encrypted?(path)
  path.to_s =~ ENCRYPTED_PATH_RE
end
key() click to toggle source
# File lib/senv.rb, line 303
def Senv.key
  if ENV['SENV_KEY']
    ENV['SENV_KEY']
  else
    if Senv.key_path.exist?
      Senv.key_path.binread.strip
    else
      msg = "Senv.key not found in : #{ Senv.key_path }"
      Senv.error!(msg)
    end
  end
end
key=(key) click to toggle source
# File lib/senv.rb, line 316
def Senv.key=(key)
  ENV['SENV_KEY'] = key.to_s.strip
end
key_path() click to toggle source
# File lib/senv.rb, line 299
def Senv.key_path
  Senv.directory.join('.key')
end
key_source() click to toggle source
# File lib/senv.rb, line 320
def Senv.key_source
  if ENV['SENV_KEY']
    "ENV['SENV_KEY']"
  else
    Senv.key_path rescue '(no key source)'
  end
end
license() click to toggle source
# File lib/senv.rb, line 27
def Senv.license
  LICENSE
end
load(*args) click to toggle source
# File lib/senv.rb, line 63
def Senv.load(*args)
  Senv.thread_safe do
  #
    env, options = Senv.parse_load_args(*args)

  #
    force = !!(options['force'] || options[:force])

  #
    a_parent_process_has_already_loaded_the_senv = (
      ENV['SENV'] == env &&
      ENV['SENV_LOADED'] &&
      ENV['SENV_ENVIRONMENT']
    )

    if(a_parent_process_has_already_loaded_the_senv && !force)
      Senv.env = env
      Senv.loaded = JSON.parse(ENV['SENV_LOADED'])
      Senv.environment = JSON.parse(ENV['SENV_ENVIRONMENT'])
      return env
    end

  #
    unless Senv.loading
      loading = Senv.loading

      begin
        Senv.loading = env

        Senv.loaded.clear
        Senv.environment.clear

        Senv.load_config_paths_for(env)

        Senv.env = env

        ENV['SENV'] = Senv.env
        ENV['SENV_LOADED'] = JSON.generate(Senv.loaded)
        ENV['SENV_ENVIRONMENT'] = JSON.generate(Senv.environment)

        return env
      ensure
        Senv.loading = loading
      end
    else
      a_config_file_imports_another_senv = (
        Senv.loading != env
      )

      if a_config_file_imports_another_senv
        Senv.load_config_paths_for(env)
        return env
      end

      a_config_file_imports_itself_recursively = (
        Senv.loading == env
      )

      if a_config_file_imports_itself_recursively
        :cowardly_refuse_to_infinitely_recurse
        return nil
      end
    end
  end
end
load!(*args) click to toggle source
# File lib/senv.rb, line 129
def Senv.load!(*args)
  env, options = Senv.parse_load_args(*args)
  options['force'] = options[:force] = true
  Senv.load(env, options)
end
load_config(path) click to toggle source
# File lib/senv.rb, line 398
def Senv.load_config(path)
#
  erb = Senv.binread(path)
  expanded = ERB.new(erb).result(::TOPLEVEL_BINDING)
  buf = expanded

#
  encoded = buf

  config =
    case
      when path =~ /yml|yaml/
        YAML.load(encoded)
      when path =~ /json/
        JSON.parse(encoded)
      else
        abort "unknown config format in #{ path }"
    end

#
  unless config && config.is_a?(Hash)
    abort "[SENV] failed to load #{ path }"
  end

#
  config.each do |key, val|
    ENV[key.to_s] = val.to_s
  end

#
  config
end
load_config_paths(*paths) click to toggle source
# File lib/senv.rb, line 171
def Senv.load_config_paths(*paths)
  libs    = []
  configs = []

  paths.each do |path|
    exts = path.extname.split('.')[1..-1]

    case
      when exts.include?('rb')
        libs << path
      else
        configs << path
    end
  end

  {
    libs => :load_lib,
    configs => :load_config,
  }.each do |list, loader|
    list.each do |path|
      path = path.to_s

      Senv.debug({'loading' => path})

      if Senv.loaded.has_key?(path)
        Senv.debug({'skipping' => path})
        next
      end

      Senv.loaded[path] = nil

      captured =
        Senv.capturing_environment_changes do
          Senv.send(loader, path)
        end

      changes = captured.changes

      Senv.debug({path => changes})

      Senv.loaded[path] = changes

      captured.apply(Senv.environment)
    end
  end
end
load_config_paths_for(env) click to toggle source
# File lib/senv.rb, line 157
def Senv.load_config_paths_for(env)
  paths = Senv.config_paths_for(env)
  Senv.load_config_paths(*paths)
end
load_lib(path) click to toggle source
# File lib/senv.rb, line 388
def Senv.load_lib(path)
#
  code = Senv.binread(path.to_s)
  binding = ::TOPLEVEL_BINDING
  filename = path.to_s

#
  Kernel.eval(code, binding, filename)
end
loaded() click to toggle source
# File lib/senv.rb, line 227
def Senv.loaded
  @loaded ||= {}
end
loaded=(hash) click to toggle source
# File lib/senv.rb, line 231
def Senv.loaded=(hash)
  @loaded = hash
end
loading() click to toggle source
# File lib/senv.rb, line 219
def Senv.loading
  @loading
end
loading=(env) click to toggle source
# File lib/senv.rb, line 223
def Senv.loading=(env)
  @loading = env.to_s.strip 
end
parse_load_args(*args) click to toggle source
# File lib/senv.rb, line 135
def Senv.parse_load_args(*args)
  env = Senv.env || Senv.default
  options = Hash.new

  case args.first
    when String, Symbol
      env = args.shift.to_s
  end

  case args.first
    when Hash
      options = args.shift
  end

  [env, options]
end
read(path, options = {}) click to toggle source
# File lib/senv.rb, line 358
def Senv.read(path, options = {})
  Senv.binread(path)
end
realpath(path) click to toggle source
# File lib/senv.rb, line 244
def Senv.realpath(path)
  Pathname.new(path.to_s).realpath
end
root() click to toggle source
# File lib/senv.rb, line 253
def Senv.root
  determine_root! unless @root
  @root
end
root=(root) click to toggle source
# File lib/senv.rb, line 258
def Senv.root=(root)
  @root = realpath(root)
end
script(*args, &block) click to toggle source
# File lib/senv/script.rb, line 525
def Senv.script(*args, &block)
  Senv::Script.run!(*args, &block)
end
search_path() click to toggle source
# File lib/senv.rb, line 283
def Senv.search_path
  search_path = []

  if ENV['SENV_PATH']
    ENV['SENV_PATH'].split(':').each do |path|
      search_path << Senv.expand_path(path).to_s
    end
  else
    Pathname.pwd.realpath.ascend do |path|
      search_path << path.to_s
    end
  end

  search_path
end
senvs() click to toggle source
# File lib/senv.rb, line 478
def Senv.senvs
  @senvs ||= Hash.new
end
thread_safe(&block) click to toggle source
# File lib/senv.rb, line 152
def Senv.thread_safe(&block)
  THREAD_SAFE.synchronize(&block)
end
version() click to toggle source
# File lib/senv.rb, line 20
def Senv.version
  VERSION
end
write(path, data, options = {}) click to toggle source
# File lib/senv.rb, line 384
def Senv.write(path, data, options = {})
  Senv.binwrite(path, data, options)
end