Module: Senv
- Defined in:
- lib/senv.rb,
lib/senv/script.rb
Defined Under Namespace
Modules: Blowfish
Classes: EnvChangeTracker, Error, Script
Constant Summary
collapse
- VERSION =
'0.4.3'.freeze
- LICENSE =
'MIT'.freeze
- SUMMARY =
''
- DEFAULT =
'development'.freeze
- THREAD_SAFE =
::Monitor.new
- ENCRYPTED_PATH_RE =
Regexp.union(/\.enc(rypted)$/, /\.enc(rypted)?\./)
Class Method Summary
collapse
-
.binread(path, options = {}) ⇒ Object
-
.binwrite(path, data, options = {}) ⇒ Object
-
.capturing_environment_changes(&block) ⇒ Object
-
.config_paths_for(env) ⇒ Object
-
.debug(*args, &block) ⇒ Object
-
.debug=(arg) ⇒ Object
-
.debug? ⇒ Boolean
-
.default ⇒ Object
-
.determine_root! ⇒ Object
-
.directory ⇒ Object
-
.env ⇒ Object
-
.env=(env) ⇒ Object
-
.environment ⇒ Object
-
.environment=(hash) ⇒ Object
-
.error!(*args, &block) ⇒ Object
-
.expand_path(path) ⇒ Object
-
.for_senv(senv) ⇒ Object
-
.for_senv!(senv) ⇒ Object
-
.get(senv, var) ⇒ Object
-
.get!(senv, var) ⇒ Object
-
.is_encrypted?(path) ⇒ Boolean
-
.key ⇒ Object
-
.key=(key) ⇒ Object
-
.key_path ⇒ Object
-
.key_source ⇒ Object
-
.license ⇒ Object
-
.load(*args) ⇒ Object
-
.load!(*args) ⇒ Object
-
.load_config(path) ⇒ Object
-
.load_config_paths(*paths) ⇒ Object
-
.load_config_paths_for(env) ⇒ Object
-
.load_lib(path) ⇒ Object
-
.loaded ⇒ Object
-
.loaded=(hash) ⇒ Object
-
.loading ⇒ Object
-
.loading=(env) ⇒ Object
-
.parse_load_args(*args) ⇒ Object
-
.read(path, options = {}) ⇒ Object
-
.realpath(path) ⇒ Object
-
.root ⇒ Object
-
.root=(root) ⇒ Object
-
.script(*args, &block) ⇒ Object
-
.search_path ⇒ Object
-
.senvs ⇒ Object
-
.thread_safe(&block) ⇒ Object
-
.version ⇒ Object
-
.write(path, data, options = {}) ⇒ Object
Class Method Details
.binread(path, options = {}) ⇒ Object
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
|
# 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 = {}) ⇒ Object
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
# 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) ⇒ Object
.config_paths_for(env) ⇒ Object
162
163
164
165
166
167
168
169
|
# 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) ⇒ Object
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
|
# 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) ⇒ Object
469
470
471
472
473
474
475
|
# File 'lib/senv.rb', line 469
def Senv.debug=(arg)
if arg
ENV['SENV_DEBUG'] = 'true'
else
ENV.delete('SENV_DEBUG')
end
end
|
.debug? ⇒ Boolean
465
466
467
|
# File 'lib/senv.rb', line 465
def Senv.debug?
!!ENV['SENV_DEBUG']
end
|
.default ⇒ Object
37
38
39
|
# File 'lib/senv.rb', line 37
def Senv.default
DEFAULT
end
|
.determine_root! ⇒ Object
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
# 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 ⇒ Object
279
280
281
|
# File 'lib/senv.rb', line 279
def Senv.directory
Senv.root.join('.senv')
end
|
.env ⇒ Object
50
51
52
|
# File 'lib/senv.rb', line 50
def Senv.env
ENV['SENV']
end
|
.env=(env) ⇒ Object
54
55
56
57
58
59
60
|
# 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 ⇒ Object
235
236
237
|
# File 'lib/senv.rb', line 235
def Senv.environment
@environment ||= {}
end
|
.environment=(hash) ⇒ Object
239
240
241
|
# File 'lib/senv.rb', line 239
def Senv.environment=(hash)
@environment = hash
end
|
.error!(*args, &block) ⇒ Object
45
46
47
|
# File 'lib/senv.rb', line 45
def Senv.error!(*args, &block)
raise Error.new(*args, &block)
end
|
.expand_path(path) ⇒ Object
248
249
250
|
# File 'lib/senv.rb', line 248
def Senv.expand_path(path)
(realpath(path) rescue File.expand_path(path)).to_s
end
|
.for_senv!(senv) ⇒ Object
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
|
# 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) ⇒ Object
508
509
510
|
# File 'lib/senv.rb', line 508
def Senv.get(senv, var)
Senv.for_senv(senv)[var.to_s]
end
|
.get!(senv, var) ⇒ Object
512
513
514
|
# File 'lib/senv.rb', line 512
def Senv.get!(senv, var)
Senv.for_senv!(senv)[var.to_s]
end
|
.is_encrypted?(path) ⇒ Boolean
331
332
333
|
# File 'lib/senv.rb', line 331
def Senv.is_encrypted?(path)
path.to_s =~ ENCRYPTED_PATH_RE
end
|
.key ⇒ Object
303
304
305
306
307
308
309
310
311
312
313
314
|
# 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) ⇒ Object
316
317
318
|
# File 'lib/senv.rb', line 316
def Senv.key=(key)
ENV['SENV_KEY'] = key.to_s.strip
end
|
.key_path ⇒ Object
299
300
301
|
# File 'lib/senv.rb', line 299
def Senv.key_path
Senv.directory.join('.key')
end
|
.key_source ⇒ Object
320
321
322
323
324
325
326
|
# 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 ⇒ Object
27
28
29
|
# File 'lib/senv.rb', line 27
def Senv.license
LICENSE
end
|
.load(*args) ⇒ Object
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# 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) ⇒ Object
129
130
131
132
133
|
# 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) ⇒ Object
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
|
# 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) ⇒ Object
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
# 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) ⇒ Object
.load_lib(path) ⇒ Object
388
389
390
391
392
393
394
395
396
|
# 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 ⇒ Object
227
228
229
|
# File 'lib/senv.rb', line 227
def Senv.loaded
@loaded ||= {}
end
|
.loaded=(hash) ⇒ Object
231
232
233
|
# File 'lib/senv.rb', line 231
def Senv.loaded=(hash)
@loaded = hash
end
|
.loading ⇒ Object
219
220
221
|
# File 'lib/senv.rb', line 219
def Senv.loading
@loading
end
|
.loading=(env) ⇒ Object
223
224
225
|
# File 'lib/senv.rb', line 223
def Senv.loading=(env)
@loading = env.to_s.strip
end
|
.parse_load_args(*args) ⇒ Object
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
# 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 = {}) ⇒ Object
358
359
360
|
# File 'lib/senv.rb', line 358
def Senv.read(path, options = {})
Senv.binread(path)
end
|
.realpath(path) ⇒ Object
244
245
246
|
# File 'lib/senv.rb', line 244
def Senv.realpath(path)
Pathname.new(path.to_s).realpath
end
|
.root ⇒ Object
253
254
255
256
|
# File 'lib/senv.rb', line 253
def Senv.root
determine_root! unless @root
@root
end
|
.root=(root) ⇒ Object
258
259
260
|
# File 'lib/senv.rb', line 258
def Senv.root=(root)
@root = realpath(root)
end
|
.script(*args, &block) ⇒ Object
525
526
527
|
# File 'lib/senv/script.rb', line 525
def Senv.script(*args, &block)
Senv::Script.run!(*args, &block)
end
|
.search_path ⇒ Object
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
|
# 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 ⇒ Object
478
479
480
|
# File 'lib/senv.rb', line 478
def Senv.senvs
@senvs ||= Hash.new
end
|
.thread_safe(&block) ⇒ Object
152
153
154
|
# File 'lib/senv.rb', line 152
def Senv.thread_safe(&block)
THREAD_SAFE.synchronize(&block)
end
|
.version ⇒ Object
20
21
22
|
# File 'lib/senv.rb', line 20
def Senv.version
VERSION
end
|
.write(path, data, options = {}) ⇒ Object
384
385
386
|
# File 'lib/senv.rb', line 384
def Senv.write(path, data, options = {})
Senv.binwrite(path, data, options)
end
|