starenv 0.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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.md +25 -0
- data/README.md +31 -0
- data/Rakefile +18 -0
- data/bin/rake +12 -0
- data/lib/starenv/env_file.rb +85 -0
- data/lib/starenv/environment.rb +50 -0
- data/lib/starenv/file/node.rb +35 -0
- data/lib/starenv/file/parser.rb +29 -0
- data/lib/starenv/file/set.rb +23 -0
- data/lib/starenv/file/template.rb +34 -0
- data/lib/starenv/file.rb +133 -0
- data/lib/starenv/results.rb +49 -0
- data/lib/starenv/tasks.rb +112 -0
- data/lib/starenv/variable.rb +39 -0
- data/lib/starenv.rb +41 -0
- data/starenv.gemspec +27 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d259f537e28341d2ba00408a875e0267b7874cca
|
4
|
+
data.tar.gz: 8e1a771716fb1535fd133e01f26202a0d92f796d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e546387c1e7ac165fa2c6bc91509f8b8b27b30655553b22e82a65e90872b104b7ac0234ffa2df94cf4ea64b0c99333aa0a792afc4bfb9683f0b1537d1060bb8
|
7
|
+
data.tar.gz: 487ef54e34937b2671cff7c9f21feba0307bcbc371787f6ee80e5de782db4202becf7db029d706faf1365510759550f6c694c8cfedb092bd6221d539a9da3c92
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
> **Copyright (c) 2015 Chris Keele**
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
-----------
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
*
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
*
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Starenv
|
2
|
+
=======
|
3
|
+
|
4
|
+
> **Load and manage suites of environment variables.**
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
Synopsis
|
9
|
+
--------
|
10
|
+
|
11
|
+
One of the tenants of building [12-factor apps](http://12factor.net/) is loading your [configuration from the environment](http://12factor.net/config).
|
12
|
+
|
13
|
+
However, developing complicated applications, entirely configured from the environment, comes with some pitfalls:
|
14
|
+
|
15
|
+
1. *Environment variables aren't easy to manage*
|
16
|
+
|
17
|
+
1. *Environment variables aren't easy to reproduce*
|
18
|
+
|
19
|
+
1. *Environment variables aren't easy to reason about*
|
20
|
+
|
21
|
+
1. *Environment variables aren't easy to tweak*
|
22
|
+
|
23
|
+
Starenv was created to alleviate these problems.
|
24
|
+
|
25
|
+
1. *Starenv supports multiple, project-defined env files.*
|
26
|
+
|
27
|
+
1. *Starenv allows declaring dependencies files.*
|
28
|
+
|
29
|
+
1. *Starenv allows conditionally and contextually loading files.*
|
30
|
+
|
31
|
+
1. *Starenv comes with rake tasks for managing and documenting environment variables.*
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
desc 'Open a pry console preloaded with this library'
|
4
|
+
task console: 'console:pry'
|
5
|
+
|
6
|
+
namespace :console do
|
7
|
+
|
8
|
+
task :pry do
|
9
|
+
sh 'bundle exec pry -I lib -r starenv.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
task :irb do
|
13
|
+
sh 'bundle exec irb -I lib -r starenv.rb'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative 'lib/starenv/tasks'
|
data/bin/rake
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
6
|
+
|
7
|
+
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
8
|
+
|
9
|
+
load Gem.bin_path('rake', 'rake')
|
10
|
+
|
11
|
+
require 'rake'
|
12
|
+
Rake.application.run
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'starenv/results'
|
2
|
+
|
3
|
+
class EnvFile < Struct.new(:name, :dependencies, :pattern, :hook)
|
4
|
+
|
5
|
+
def load
|
6
|
+
(hook || default_hook).call self do
|
7
|
+
Dotenv.load(filename).tap do |results|
|
8
|
+
puts info results
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def filename
|
14
|
+
format pattern, name
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :to_s, :filename
|
18
|
+
|
19
|
+
def info(results)
|
20
|
+
longest = results.keys.group_by(&:size).max
|
21
|
+
length = longest.nil? ? 0 : longest.first
|
22
|
+
applied, ignored = results.partition do |key, value|
|
23
|
+
ENV[key] == value
|
24
|
+
end
|
25
|
+
[
|
26
|
+
Results.for(:applied).new(self, applied, length),
|
27
|
+
Results.for(:ignored).new(self, ignored, length),
|
28
|
+
].map(&:to_s).compact.push("\n").join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
@@default_hook = -> file, &loader { loader.call }
|
34
|
+
|
35
|
+
def default_hook
|
36
|
+
@@default_hook
|
37
|
+
end
|
38
|
+
|
39
|
+
module Utils
|
40
|
+
|
41
|
+
def without_leading_comments(file)
|
42
|
+
file.each_line.drop_while do |line|
|
43
|
+
comment? line
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def comment?(line)
|
48
|
+
line.start_with? '#'
|
49
|
+
end
|
50
|
+
|
51
|
+
def variable(line)
|
52
|
+
line.match(/^\s*?(?<name>\b.*\b)=(?<value>\b\S*\b)?\s*?$/)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class Template < self
|
58
|
+
|
59
|
+
include Utils
|
60
|
+
|
61
|
+
attr_reader :content
|
62
|
+
|
63
|
+
def initialize(name, pattern = Starenv.pattern, content = [])
|
64
|
+
@content = content
|
65
|
+
super name, [], pattern, nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse
|
69
|
+
File.open(filename) do |lines|
|
70
|
+
yield without_leading_comments lines
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def write
|
75
|
+
File.open(filename, 'w') do |file|
|
76
|
+
content.each do |line|
|
77
|
+
line = yield line
|
78
|
+
file.puts line if line
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Starenv
|
4
|
+
class Environment
|
5
|
+
|
6
|
+
attr_reader :variables, :applied, :ignored
|
7
|
+
|
8
|
+
def initialize(source = nil)
|
9
|
+
@source = source ? source : ENV
|
10
|
+
@variables, @applied, @ignored = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def [] key
|
14
|
+
@source[key].tap do |value|
|
15
|
+
@variables[key] ||= Variable.new(key, value) if value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def []= key, value
|
20
|
+
@source.store(key, value.to_s).tap do |value|
|
21
|
+
@variables[key] = Variable.new(key, value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def apply(hash)
|
26
|
+
self.tap do |env|
|
27
|
+
hash.each do |key, value|
|
28
|
+
self[key] ||= value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def respond_to_missing?(method)
|
34
|
+
@source.respond_to?(method) or super
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(method, *args)
|
38
|
+
if @source.respond_to? method
|
39
|
+
if block_given?
|
40
|
+
@source.send method, *args, &Proc.new
|
41
|
+
else
|
42
|
+
@source.send method, *args
|
43
|
+
end
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'starenv/file'
|
2
|
+
|
3
|
+
module Starenv
|
4
|
+
class File < ::File
|
5
|
+
class Node < Struct.new(:name, :dependencies, :hook)
|
6
|
+
|
7
|
+
attr_reader :environment
|
8
|
+
|
9
|
+
def initialize(name, dependencies = [], hook = nil)
|
10
|
+
super name, dependencies, hook
|
11
|
+
end
|
12
|
+
|
13
|
+
def load
|
14
|
+
tap do
|
15
|
+
unless loaded?
|
16
|
+
(hook || default_hook).call self do
|
17
|
+
File.parse(name).environment
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def loaded?
|
24
|
+
!!file
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def default_hook
|
30
|
+
@@default_hook ||= -> file, &loader { loader.call }
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'starenv/environment'
|
2
|
+
require 'starenv/variable'
|
3
|
+
|
4
|
+
module Starenv
|
5
|
+
class File < ::File
|
6
|
+
class Parser
|
7
|
+
|
8
|
+
attr_accessor :lines
|
9
|
+
|
10
|
+
def initialize(lines)
|
11
|
+
@lines = lines
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
Environment.new(
|
16
|
+
Hash[
|
17
|
+
lines.map(&:strip).select do |line|
|
18
|
+
line =~ Variable.line
|
19
|
+
end.compact.map do |line|
|
20
|
+
variable = Variable.from line
|
21
|
+
[ variable.name, variable ]
|
22
|
+
end
|
23
|
+
]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
|
3
|
+
require 'starenv/file/node'
|
4
|
+
|
5
|
+
module Starenv
|
6
|
+
class File < ::File
|
7
|
+
class Set < Hash
|
8
|
+
|
9
|
+
include TSort
|
10
|
+
|
11
|
+
alias_method :tsort_each_node, :each_key
|
12
|
+
|
13
|
+
def tsort_each_child(node)
|
14
|
+
fetch(node).dependencies.each(&Proc.new)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(name, dependencies, hook)
|
18
|
+
store name, Node.new(name, Array(dependencies).flatten, hook)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Starenv
|
2
|
+
class File < ::File
|
3
|
+
class Template < self
|
4
|
+
|
5
|
+
def initialize(name, mode = 'r+', *args)
|
6
|
+
super name, mode, *args
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :files
|
10
|
+
|
11
|
+
def header
|
12
|
+
%r{^#\sfile:\s(\w+).*?$}mi
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
tap do
|
17
|
+
unless parsed?
|
18
|
+
require 'pry'; binding.pry
|
19
|
+
@files = Hash[
|
20
|
+
read.split(header).drop(1).each_slice(2).map do |key, value|
|
21
|
+
[ key.to_sym, Parser.new(value.strip.lines).call ]
|
22
|
+
end
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parsed?
|
29
|
+
!!files
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/starenv/file.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
require 'starenv/file/parser'
|
5
|
+
|
6
|
+
module Starenv
|
7
|
+
class File < ::File
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def parse(name, *args)
|
12
|
+
open name, *args, &:parse
|
13
|
+
end
|
14
|
+
|
15
|
+
def touch(name, *args)
|
16
|
+
new(name, *args).touch(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :name, :filename, :environment
|
22
|
+
|
23
|
+
def initialize(name, mode = 'r', *args)
|
24
|
+
@name = name
|
25
|
+
@filename = Pathname.new Starenv.format @name
|
26
|
+
super @filename, mode, *args
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse
|
30
|
+
tap do |file|
|
31
|
+
unless parsed?
|
32
|
+
@environment = Parser.new(each_line).call
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parsed?
|
38
|
+
!!environment
|
39
|
+
end
|
40
|
+
|
41
|
+
def touch(*args)
|
42
|
+
tap do |file|
|
43
|
+
FileUtils.mkpath file.filename.dirname, *args
|
44
|
+
FileUtils.touch file.filename, *args
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# class EnvFile < Struct.new(:name, :dependencies, :pattern, :hook)
|
52
|
+
#
|
53
|
+
# def load
|
54
|
+
# (hook || default_hook).call self do
|
55
|
+
# Dotenv.load(filename).tap do |results|
|
56
|
+
# puts info results
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# def filename
|
62
|
+
# format pattern, name
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# alias_method :to_s, :filename
|
66
|
+
#
|
67
|
+
# def info(results)
|
68
|
+
# longest = results.keys.group_by(&:size).max
|
69
|
+
# length = longest.nil? ? 0 : longest.first
|
70
|
+
# applied, ignored = results.partition do |key, value|
|
71
|
+
# ENV[key] == value
|
72
|
+
# end
|
73
|
+
# [
|
74
|
+
# Results.for(:applied).new(self, applied, length),
|
75
|
+
# Results.for(:ignored).new(self, ignored, length),
|
76
|
+
# ].map(&:to_s).compact.push("\n").join("\n")
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# private
|
80
|
+
#
|
81
|
+
# @@default_hook = -> file, &loader { loader.call }
|
82
|
+
#
|
83
|
+
# def default_hook
|
84
|
+
# @@default_hook
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# module Utils
|
88
|
+
#
|
89
|
+
# def without_leading_comments(file)
|
90
|
+
# file.each_line.drop_while do |line|
|
91
|
+
# comment? line
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# def comment?(line)
|
96
|
+
# line.start_with? '#'
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# def variable(line)
|
100
|
+
# line.match(/^\s*?(?<name>\b.*\b)=(?<value>\b\S*\b)?\s*?$/)
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# class Template < self
|
106
|
+
#
|
107
|
+
# include Utils
|
108
|
+
#
|
109
|
+
# attr_reader :content
|
110
|
+
#
|
111
|
+
# def initialize(name, pattern = Starenv.pattern, content = [])
|
112
|
+
# @content = content
|
113
|
+
# super name, [], pattern, nil
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# def parse
|
117
|
+
# File.open(filename) do |lines|
|
118
|
+
# yield without_leading_comments lines
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# def write
|
123
|
+
# File.open(filename, 'w') do |file|
|
124
|
+
# content.each do |line|
|
125
|
+
# line = yield line
|
126
|
+
# file.puts line if line
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Results < Struct.new(:file, :variables, :name_length)
|
2
|
+
|
3
|
+
class << self
|
4
|
+
def for(type)
|
5
|
+
const_get type.to_s.capitalize
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def display
|
10
|
+
formatted(variables).unshift(header).join("\n") unless variables.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
display or ''
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def formatted(variables)
|
20
|
+
variables.map do |name, value|
|
21
|
+
format_variable name, value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Applied < self
|
26
|
+
|
27
|
+
def header
|
28
|
+
"Applied variables from #{file}:"
|
29
|
+
end
|
30
|
+
|
31
|
+
def format_variable(name, value)
|
32
|
+
format " %-#{name_length}s => %s", name, value
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class Ignored < self
|
38
|
+
|
39
|
+
def header
|
40
|
+
'Ignored already set variables:'
|
41
|
+
end
|
42
|
+
|
43
|
+
def format_variable(name, value)
|
44
|
+
format " %-#{name_length}s => %s\n %-#{length-1}s => %s", name, value, 'already', ENV[name]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rake' unless defined? Rake
|
2
|
+
|
3
|
+
require 'highline'
|
4
|
+
|
5
|
+
require 'starenv'
|
6
|
+
require 'starenv/file/template'
|
7
|
+
|
8
|
+
module Starenv
|
9
|
+
module Tasks
|
10
|
+
|
11
|
+
extend self
|
12
|
+
extend Rake::DSL
|
13
|
+
|
14
|
+
task starenv: 'starenv:load'
|
15
|
+
|
16
|
+
namespace :starenv do
|
17
|
+
|
18
|
+
task :require do
|
19
|
+
require 'starenv'
|
20
|
+
end
|
21
|
+
|
22
|
+
task load: :require do
|
23
|
+
Starenv.load
|
24
|
+
end
|
25
|
+
|
26
|
+
task dry_run: :require do
|
27
|
+
Starenv.load Hash.new
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
namespace :envs do
|
33
|
+
|
34
|
+
desc "Creates starenv files according to template file."
|
35
|
+
task :init, %i[template] => %i[starenv] do |t, args|
|
36
|
+
init_from args.with_defaults(template: :example)
|
37
|
+
end
|
38
|
+
#
|
39
|
+
# desc "Adds a new environment variable to starenv."
|
40
|
+
# task new: :starenv, %i[name value file] do |t, args|
|
41
|
+
# new_variable args.with_defaults(file: Starenv.files.tsort.last)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# desc "Sets a starenv variable."
|
45
|
+
# task set: :starenv, %i[name value file] do |t, args|
|
46
|
+
# set_variable args.with_defaults(file: Starenv.files.tsort.first)
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# desc "Shows the value of a starenv variable."
|
50
|
+
# task get: :starenv, %i[name file] do |t, args|
|
51
|
+
# get_variable args.with_defaults(file: Starenv.files.tsort.first)
|
52
|
+
# end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def init_from(template: :example, noop: false, verbose: true)
|
57
|
+
File::Template.touch(template, noop: noop, verbose: verbose).parse.files.each do |file, env|
|
58
|
+
require 'pry'; binding.pry
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# def init_from(template: :example, pattern: Starenv.pattern)
|
63
|
+
# EnvFile::Template.new(file, pattern).parse do |lines|
|
64
|
+
# chunk_into_files(lines).each do |file, lines|
|
65
|
+
# file = EnvFile::Template.new(file, pattern, lines)
|
66
|
+
# if not File.exists?(file.filename) or console.agree(console.color("Do you want to override your current #{file.filename}?", [:bold, :yellow]))
|
67
|
+
# console.say "Generating #{file.filename}..."
|
68
|
+
# file.write do |line|
|
69
|
+
# line.tap do |line|
|
70
|
+
# if variable = file.variable(line) and not variable[:value]
|
71
|
+
# line[-1] = console.ask("Enter a value for #{variable[:name]}:")
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
|
80
|
+
def new_variable(name:, value:, file: Starenv.files.tsort.last || :core)
|
81
|
+
file = EnvFile.new(file, [], pattern, nil)
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_variable(name, value:, file: Starenv.files.tsort.last || :core)
|
85
|
+
file = EnvFile.new(file, [], pattern, nil)
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_variable(name, value:, file: Starenv.files.tsort.last || :core)
|
89
|
+
file = EnvFile.new(file, [], pattern, nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def console(*args)
|
95
|
+
@@console ||= HighLine.new(*args)
|
96
|
+
end
|
97
|
+
|
98
|
+
def chunk_into_files(lines)
|
99
|
+
lines.reduce({initial: []}) do |files, line|
|
100
|
+
if file = line[/^#\s+?FILE:\s+?(?<file>\w+)/, :file]
|
101
|
+
previous = files[files.keys.last]
|
102
|
+
files[file] = []
|
103
|
+
files[file] << previous.pop if previous
|
104
|
+
files.delete(:initial)
|
105
|
+
end
|
106
|
+
files[files.keys.last] << line
|
107
|
+
files
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Starenv
|
2
|
+
class Variable < Struct.new(:name, :value, :default)
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def line
|
7
|
+
%r{
|
8
|
+
\A
|
9
|
+
(?:export\s+)? # optional export
|
10
|
+
([\w\.]+) # key
|
11
|
+
(?:\s*=\s*|:\s+?) # separator
|
12
|
+
( # optional value begin
|
13
|
+
'(?:\'|[^'])*' # single quoted value
|
14
|
+
| # or
|
15
|
+
"(?:\"|[^"])*" # double quoted value
|
16
|
+
| # or
|
17
|
+
[^#\n]+ # unquoted value
|
18
|
+
)? # value end
|
19
|
+
(?:\s*\#.*)? # optional comment
|
20
|
+
\z
|
21
|
+
}x
|
22
|
+
end
|
23
|
+
|
24
|
+
def from(input)
|
25
|
+
new *line.match(input).captures
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(name, value, default = nil)
|
31
|
+
super name, value, default
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
value.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/lib/starenv.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'starenv/file/set'
|
2
|
+
|
3
|
+
module Starenv
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def format(name)
|
8
|
+
Kernel.format pattern, name
|
9
|
+
end
|
10
|
+
|
11
|
+
def pattern
|
12
|
+
@@pattern ||= default_pattern
|
13
|
+
end
|
14
|
+
|
15
|
+
def pattern= string
|
16
|
+
@@pattern = string.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def files
|
20
|
+
@@env_files ||= File::Set.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def register(names, dependencies: [])
|
24
|
+
Array(names).flatten.each do |name|
|
25
|
+
files.add name, dependencies, block_given? ? Proc.new : nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def load(env = nil)
|
30
|
+
files.tsort.reduce(Environment.new(env)) do |environment, node|
|
31
|
+
environment.apply files[node].load.environment
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def default_pattern
|
38
|
+
'envs/%s.env'
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/starenv.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "starenv"
|
7
|
+
spec.version = '0.0.1'
|
8
|
+
spec.authors = ["Chris Keele"]
|
9
|
+
spec.email = ["dev@chriskeele.com"]
|
10
|
+
spec.summary = 'Load and manage suites of environment variables.'
|
11
|
+
spec.description = "Declare multiple '.env' files, set up dynamic load orders between them, and use rake tasks to keep them up to date and documented."
|
12
|
+
spec.homepage = "https://github.com/christhekeele/starenv"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.required_ruby_version = '~> 2.1'
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "rake"
|
23
|
+
spec.add_runtime_dependency "highline"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "> 1.3"
|
26
|
+
spec.add_development_dependency "pry"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: starenv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Keele
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
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: highline
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
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: Declare multiple '.env' files, set up dynamic load orders between them,
|
70
|
+
and use rake tasks to keep them up to date and documented.
|
71
|
+
email:
|
72
|
+
- dev@chriskeele.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.md
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/rake
|
83
|
+
- lib/starenv.rb
|
84
|
+
- lib/starenv/env_file.rb
|
85
|
+
- lib/starenv/environment.rb
|
86
|
+
- lib/starenv/file.rb
|
87
|
+
- lib/starenv/file/node.rb
|
88
|
+
- lib/starenv/file/parser.rb
|
89
|
+
- lib/starenv/file/set.rb
|
90
|
+
- lib/starenv/file/template.rb
|
91
|
+
- lib/starenv/results.rb
|
92
|
+
- lib/starenv/tasks.rb
|
93
|
+
- lib/starenv/variable.rb
|
94
|
+
- starenv.gemspec
|
95
|
+
homepage: https://github.com/christhekeele/starenv
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '2.1'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.2.2
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Load and manage suites of environment variables.
|
119
|
+
test_files: []
|