nugrant 2.0.0.dev2 → 2.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/.gitignore +2 -1
- data/.travis.yml +2 -2
- data/CHANGELOG.md +148 -3
- data/Gemfile +8 -20
- data/README.md +266 -72
- data/Rakefile +1 -0
- data/lib/nugrant.rb +14 -6
- data/lib/nugrant/bag.rb +116 -62
- data/lib/nugrant/helper/bag.rb +19 -19
- data/lib/nugrant/helper/env/exporter.rb +208 -0
- data/lib/nugrant/helper/env/namer.rb +47 -0
- data/lib/nugrant/helper/parameters.rb +12 -0
- data/lib/nugrant/helper/stack.rb +86 -0
- data/lib/nugrant/mixin/parameters.rb +98 -0
- data/lib/nugrant/parameters.rb +14 -68
- data/lib/nugrant/vagrant/errors.rb +27 -0
- data/lib/nugrant/vagrant/v2/command/env.rb +101 -0
- data/lib/nugrant/vagrant/v2/command/helper.rb +30 -0
- data/lib/nugrant/vagrant/v2/command/parameters.rb +16 -4
- data/lib/nugrant/vagrant/v2/command/restricted_keys.rb +60 -0
- data/lib/nugrant/vagrant/v2/command/root.rb +12 -2
- data/lib/nugrant/vagrant/v2/config/user.rb +9 -21
- data/lib/nugrant/vagrant/v2/plugin.rb +0 -1
- data/lib/nugrant/version.rb +1 -1
- data/locales/en.yml +13 -0
- data/nugrant.gemspec +3 -7
- data/test/lib/nugrant/helper/env/test_exporter.rb +238 -0
- data/test/lib/nugrant/helper/test_bag.rb +16 -0
- data/test/lib/nugrant/helper/test_parameters.rb +17 -0
- data/test/lib/nugrant/helper/test_stack.rb +152 -0
- data/test/lib/nugrant/test_bag.rb +132 -22
- data/test/lib/nugrant/test_config.rb +95 -92
- data/test/lib/nugrant/test_parameters.rb +232 -177
- data/test/lib/test_helper.rb +3 -0
- data/test/resources/json/params_user_nil_values.json +9 -0
- data/test/resources/vagrantfiles/v2.defaults_mixed_string_symbols +18 -0
- data/test/resources/vagrantfiles/v2.defaults_null_values_in_vagrantuser +23 -0
- data/test/resources/vagrantfiles/v2.defaults_using_string +18 -0
- data/test/resources/vagrantfiles/v2.defaults_using_symbol +18 -0
- data/test/resources/{Vagrantfile.v2.empty → vagrantfiles/v2.empty} +0 -2
- data/test/resources/{Vagrantfile.v2.fake → vagrantfiles/v2.fake} +4 -3
- data/test/resources/vagrantfiles/v2.missing_parameter +3 -0
- data/test/resources/{Vagrantfile.v2.real → vagrantfiles/v2.real} +0 -2
- data/test/resources/yaml/params_user_nil_values.yml +5 -0
- metadata +55 -88
- data/lib/nugrant/vagrant/v1/command/parameters.rb +0 -134
- data/lib/nugrant/vagrant/v1/command/root.rb +0 -81
- data/lib/nugrant/vagrant/v1/config/user.rb +0 -37
- data/lib/nugrant/vagrant/v1/plugin.rb +0 -6
- data/lib/vagrant_init.rb +0 -2
- data/test/resources/Vagrantfile.v1.empty +0 -2
- data/test/resources/Vagrantfile.v1.fake +0 -10
- data/test/resources/Vagrantfile.v1.real +0 -19
@@ -0,0 +1,47 @@
|
|
1
|
+
module Nugrant
|
2
|
+
module Helper
|
3
|
+
module Env
|
4
|
+
##
|
5
|
+
# A namer is a lambda taking as argument an array of segments
|
6
|
+
# that should return a string representation of those segments.
|
7
|
+
# How the segments are transformed to a string is up to the
|
8
|
+
# namer. By using various namer, we can change how a bag key
|
9
|
+
# is transformed into and environment variable name. This is
|
10
|
+
# like the strategy pattern.
|
11
|
+
#
|
12
|
+
module Namer
|
13
|
+
|
14
|
+
##
|
15
|
+
# Returns the default namer, which join segments together
|
16
|
+
# using a character and upcase the result.
|
17
|
+
#
|
18
|
+
# @param `char` The character used to join segments together, default to `"_"`.
|
19
|
+
#
|
20
|
+
# @return A lambda that will simply joins segment using the `char` argument
|
21
|
+
# and upcase the result.
|
22
|
+
#
|
23
|
+
def self.default(char = "_")
|
24
|
+
lambda do |segments|
|
25
|
+
segments.join(char).upcase()
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns the prefix namer, which add a prefix to segments
|
31
|
+
# and delegate its work to another namer.
|
32
|
+
#
|
33
|
+
# @param prefix The prefix to add to segments.
|
34
|
+
# @param delegate_namer A namer that will be used to transform the prefixed segments.
|
35
|
+
#
|
36
|
+
# @return A lambda that will simply add prefix to segments and will call
|
37
|
+
# the delegate_namer with those new segments.
|
38
|
+
#
|
39
|
+
def self.prefix(prefix, delegate_namer)
|
40
|
+
lambda do |segments|
|
41
|
+
delegate_namer.call([prefix] + segments)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Nugrant
|
2
|
+
module Helper
|
3
|
+
class Stack
|
4
|
+
@@DEFAULT_MATCHER = /^(.+):([0-9]+)/
|
5
|
+
|
6
|
+
def self.fetch_error_region(stack, options = {})
|
7
|
+
entry = find_entry(stack, options)
|
8
|
+
location = extract_error_location(entry, options)
|
9
|
+
|
10
|
+
return (options[:unknown] || "Unknown") if not location[:file] and not location[:line]
|
11
|
+
return location[:file] if not location[:line]
|
12
|
+
|
13
|
+
fetch_error_region_from_location(location, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.fetch_error_region_from_location(location, options = {})
|
17
|
+
prefix = options[:prefix] || " "
|
18
|
+
width = options[:width] || 4
|
19
|
+
file = File.new(location[:file], "r")
|
20
|
+
line = location[:line]
|
21
|
+
|
22
|
+
index = 0
|
23
|
+
|
24
|
+
lines = []
|
25
|
+
while (line_string = file.gets())
|
26
|
+
index += 1
|
27
|
+
next if (line - index).abs > width
|
28
|
+
|
29
|
+
line_prefix = "#{prefix}#{index}:"
|
30
|
+
line_prefix += (line == index ? ">> " : " ")
|
31
|
+
|
32
|
+
lines << "#{line_prefix}#{line_string}"
|
33
|
+
end
|
34
|
+
|
35
|
+
lines.join().chomp()
|
36
|
+
rescue
|
37
|
+
return (options[:unknown] || "Unknown") if not location[:file] and not location[:line]
|
38
|
+
return location[:file] if not location[:line]
|
39
|
+
|
40
|
+
"#{location[:file]}:#{location[:line]}"
|
41
|
+
ensure
|
42
|
+
file.close() if file
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Search a stack list (as simple string array) for the first
|
47
|
+
# entry that match the +:matcher+.
|
48
|
+
#
|
49
|
+
def self.find_entry(stack, options = {})
|
50
|
+
matcher = options[:matcher] || @@DEFAULT_MATCHER
|
51
|
+
|
52
|
+
stack.find do |entry|
|
53
|
+
entry =~ matcher
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Extract error location information from a stack entry using the
|
59
|
+
# matcher received in arguments.
|
60
|
+
#
|
61
|
+
# The usual stack entry format is:
|
62
|
+
# > /home/users/joe/work/lib/ruby.rb:4:Error message
|
63
|
+
#
|
64
|
+
# This function will extract the file and line information from
|
65
|
+
# the stack entry using the matcher. The matcher is expected to
|
66
|
+
# have two groups, the first for the file and the second for
|
67
|
+
# line.
|
68
|
+
#
|
69
|
+
# The results is returned in form of a hash with two keys, +:file+
|
70
|
+
# for the file information and +:line+ for the line information.
|
71
|
+
#
|
72
|
+
# If the matcher matched zero group, return +{:file => nil, :line => nil}+.
|
73
|
+
# If the matcher matched one group, return +{:file => file, :line => nil}+.
|
74
|
+
# If the matcher matched two groups, return +{:file => file, :line => line}+.
|
75
|
+
#
|
76
|
+
def self.extract_error_location(entry, options = {})
|
77
|
+
matcher = options[:matcher] || @@DEFAULT_MATCHER
|
78
|
+
|
79
|
+
result = matcher.match(entry)
|
80
|
+
captures = result ? result.captures : []
|
81
|
+
|
82
|
+
{:file => captures[0], :line => captures[1] ? captures[1].to_i() : nil}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Nugrant
|
2
|
+
module Mixin
|
3
|
+
##
|
4
|
+
# Mixin module so it's possible to share parameters
|
5
|
+
# logic between default Parameters class and Vagrant
|
6
|
+
# implementation.
|
7
|
+
#
|
8
|
+
# This method delegates method missing to the overall
|
9
|
+
# bag instance. This means that even if the class
|
10
|
+
# including this module doesn't inherit Bag directly,
|
11
|
+
# it act exactly like one.
|
12
|
+
#
|
13
|
+
# To initialize the mixin module correctly, you must call
|
14
|
+
# the compute_bags! method at least once to initialize
|
15
|
+
# all variables. You should make this call in including
|
16
|
+
# class' constructor directly.
|
17
|
+
#
|
18
|
+
module Parameters
|
19
|
+
def method_missing(method, *args, &block)
|
20
|
+
case
|
21
|
+
when @__all.class.method_defined?(method)
|
22
|
+
@__all.send(method, *args, &block)
|
23
|
+
else
|
24
|
+
@__all[method]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def defaults()
|
29
|
+
@__defaults
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Set the new default values for the
|
34
|
+
# various parameters contain by this instance.
|
35
|
+
# This will call __compute_all() to recompute
|
36
|
+
# correct precedences.
|
37
|
+
#
|
38
|
+
# =| Attributes
|
39
|
+
# * +elements+ - The new default elements
|
40
|
+
#
|
41
|
+
def defaults=(elements)
|
42
|
+
@__defaults = Bag.new(elements, @__options)
|
43
|
+
|
44
|
+
# When defaults change, we need to recompute parameters hierarchy
|
45
|
+
compute_all!(@__options)
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Compute all parameters bags (current, user, system, default and all).
|
50
|
+
#
|
51
|
+
# =| Arguments
|
52
|
+
# * `config`
|
53
|
+
# The configuration object used to determine where to find the various
|
54
|
+
# bag source data. This can be either directly a `Nugrant::Config`
|
55
|
+
# object or a hash that will be pass to `Nugrant::Config` constructor.
|
56
|
+
#
|
57
|
+
# * `options`
|
58
|
+
# An options hash where some customization option can be passed.
|
59
|
+
# Defaults to an empty hash, see options for specific option default
|
60
|
+
# values.
|
61
|
+
#
|
62
|
+
# =| Options
|
63
|
+
# * `:defaults`
|
64
|
+
# A hash that is used as the initial data for the defaults bag. Defaults
|
65
|
+
# to an empty hash.
|
66
|
+
#
|
67
|
+
# * `:key_error`
|
68
|
+
# This option is passed to Bag.new constructor in it's options hash. See
|
69
|
+
# Bag.new for details on this options.
|
70
|
+
#
|
71
|
+
def compute_bags!(config, options = {})
|
72
|
+
config = config.kind_of?(Nugrant::Config) ? config : Nugrant::Config.new(config)
|
73
|
+
|
74
|
+
@__options = options
|
75
|
+
|
76
|
+
@__current = Helper::Bag.read(config.current_path, config.params_format, options)
|
77
|
+
@__user = Helper::Bag.read(config.user_path, config.params_format, options)
|
78
|
+
@__system = Helper::Bag.read(config.system_path, config.params_format, options)
|
79
|
+
@__defaults = Bag.new(options[:defaults] || {}, options)
|
80
|
+
|
81
|
+
compute_all!(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Recompute the correct precedences by merging the various
|
86
|
+
# bag in the right order and return the result as a Nugrant::Bag
|
87
|
+
# object.
|
88
|
+
#
|
89
|
+
def compute_all!(options = {})
|
90
|
+
@__all = Bag.new({}, options)
|
91
|
+
@__all.merge!(@__defaults)
|
92
|
+
@__all.merge!(@__system)
|
93
|
+
@__all.merge!(@__user)
|
94
|
+
@__all.merge!(@__current)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/nugrant/parameters.rb
CHANGED
@@ -1,87 +1,33 @@
|
|
1
1
|
require 'nugrant/bag'
|
2
2
|
require 'nugrant/config'
|
3
3
|
require 'nugrant/helper/bag'
|
4
|
+
require 'nugrant/mixin/parameters'
|
4
5
|
|
5
6
|
module Nugrant
|
6
7
|
class Parameters
|
7
|
-
attr_reader :__current, :__user, :__system, :__defaults, :__all
|
8
|
-
|
9
8
|
##
|
10
9
|
# Create a new parameters object which holds completed
|
11
10
|
# merged values. The following precedence is used to decide
|
12
11
|
# which location has precedence over which location:
|
13
12
|
#
|
14
13
|
# (Highest) ------------------ (Lowest)
|
15
|
-
#
|
14
|
+
# project < user < system < defaults
|
16
15
|
#
|
17
|
-
# =|
|
18
|
-
# *
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
16
|
+
# =| Arguments
|
17
|
+
# * `config`
|
18
|
+
# A hash that will be passed to Nugrant::Config.new() or
|
19
|
+
# a Nugrant::Config instance directly.
|
20
|
+
# See Nugrant::Config constructor for options that you can use.
|
22
21
|
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@__user = Helper::Bag.read(@__config.user_path, @__config.params_format)
|
28
|
-
@__system = Helper::Bag.read(@__config.system_path, @__config.params_format)
|
29
|
-
@__defaults = Bag.new(options[:defaults] || {})
|
30
|
-
|
31
|
-
__compute_all()
|
32
|
-
end
|
33
|
-
|
34
|
-
def [](key)
|
35
|
-
return @__all[key]
|
36
|
-
end
|
37
|
-
|
38
|
-
def method_missing(method, *args, &block)
|
39
|
-
return @__all[method]
|
40
|
-
end
|
41
|
-
|
42
|
-
def empty?()
|
43
|
-
@__all.empty?()
|
44
|
-
end
|
45
|
-
|
46
|
-
def has?(key)
|
47
|
-
return @__all.has?(key)
|
48
|
-
end
|
49
|
-
|
50
|
-
def each(&block)
|
51
|
-
@__all.each(&block)
|
52
|
-
end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Set the new default values for the
|
56
|
-
# various parameters contain by this instance.
|
57
|
-
# This will call __compute_all() to recompute
|
58
|
-
# correct precedences.
|
59
|
-
#
|
60
|
-
# =| Attributes
|
61
|
-
# * +elements+ - The new default elements
|
22
|
+
# * `options`
|
23
|
+
# An options hash that is passed to Mixin::Parameters.compute_bags! method.
|
24
|
+
# See Mixin::Parameters.compute_bags! for details on the various options
|
25
|
+
# available.
|
62
26
|
#
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
# When defaults change, we need to recompute parameters hierarchy
|
67
|
-
__compute_all()
|
27
|
+
def initialize(config, options = {})
|
28
|
+
compute_bags!(config, options)
|
68
29
|
end
|
69
30
|
|
70
|
-
|
71
|
-
# Recompute the correct precedences by merging the various
|
72
|
-
# bag in the right order and return the result as a Nugrant::Bag
|
73
|
-
# object.
|
74
|
-
#
|
75
|
-
def __compute_all()
|
76
|
-
@__all = Bag.new()
|
77
|
-
@__all.__merge!(@__defaults)
|
78
|
-
@__all.__merge!(@__system)
|
79
|
-
@__all.__merge!(@__user)
|
80
|
-
@__all.__merge!(@__current)
|
81
|
-
end
|
82
|
-
|
83
|
-
def __to_hash()
|
84
|
-
@__all.__to_hash()
|
85
|
-
end
|
31
|
+
include Mixin::Parameters
|
86
32
|
end
|
87
33
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'vagrant/errors'
|
2
|
+
|
3
|
+
require 'nugrant/helper/stack'
|
4
|
+
|
5
|
+
module Nugrant
|
6
|
+
module Vagrant
|
7
|
+
module Errors
|
8
|
+
class NugrantVagrantError < ::Vagrant::Errors::VagrantError
|
9
|
+
error_namespace("nugrant.vagrant.errors")
|
10
|
+
end
|
11
|
+
|
12
|
+
class ParameterNotFoundError < NugrantVagrantError
|
13
|
+
error_key(:parameter_not_found)
|
14
|
+
|
15
|
+
def initialize(options = nil, *args)
|
16
|
+
super({:context => compute_context()}.merge(options || {}), *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def compute_context()
|
20
|
+
Helper::Stack.fetch_error_region(caller(), {
|
21
|
+
:matcher => /(.+Vagrantfile):([0-9]+)/
|
22
|
+
})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'nugrant'
|
2
|
+
require 'nugrant/helper/env/exporter'
|
3
|
+
require 'nugrant/parameters'
|
4
|
+
|
5
|
+
EnvExporter = Nugrant::Helper::Env::Exporter
|
6
|
+
|
7
|
+
module Nugrant
|
8
|
+
module Vagrant
|
9
|
+
module V2
|
10
|
+
module Command
|
11
|
+
class Env < ::Vagrant.plugin("2", :command)
|
12
|
+
def initialize(arguments, environment)
|
13
|
+
super(arguments, environment)
|
14
|
+
|
15
|
+
@unset = false
|
16
|
+
@format = :terminal
|
17
|
+
@show_help = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_parser()
|
21
|
+
return OptionParser.new do |parser|
|
22
|
+
parser.banner = "Usage: vagrant user env [<options>]"
|
23
|
+
parser.separator ""
|
24
|
+
|
25
|
+
parser.separator "Outputs the commands that should be executed to export\n" +
|
26
|
+
"the various parameter as environment variables. By default,\n" +
|
27
|
+
"existing ones are overridden. The --format argument can be used\n" +
|
28
|
+
"to choose in which format the variables should be displayed.\n" +
|
29
|
+
"Changing the format will also change where they are displayed.\n"
|
30
|
+
parser.separator ""
|
31
|
+
|
32
|
+
parser.separator "Available formats:"
|
33
|
+
parser.separator " autoenv => Write commands to a file named `.env` in the current directory.\n" +
|
34
|
+
" See https://github.com/kennethreitz/autoenv for more info."
|
35
|
+
parser.separator " terminal => Display commands to terminal so they can be sourced."
|
36
|
+
parser.separator " script => Write commands to a bash script named `nugrant2env.sh` so it can be sourced."
|
37
|
+
parser.separator ""
|
38
|
+
|
39
|
+
parser.separator "Available options:"
|
40
|
+
parser.separator ""
|
41
|
+
|
42
|
+
parser.on("-u", "--[no-]unset", "Generates commands needed to unset environment variables, default false") do |unset|
|
43
|
+
@unset = unset
|
44
|
+
end
|
45
|
+
|
46
|
+
parser.on("-f", "--format FORMAT", "Determines in what format variables are output, default to terminal") do |format|
|
47
|
+
@format = format.to_sym()
|
48
|
+
end
|
49
|
+
|
50
|
+
parser.on("-h", "--help", "Print this help") do
|
51
|
+
@show_help = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def error(message, parser)
|
57
|
+
@env.ui.info("ERROR: #{message}", :prefix => false)
|
58
|
+
@env.ui.info("", :prefix => false)
|
59
|
+
|
60
|
+
help(parser)
|
61
|
+
|
62
|
+
return 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def help(parser)
|
66
|
+
@env.ui.info(parser.help, :prefix => false)
|
67
|
+
end
|
68
|
+
|
69
|
+
def execute
|
70
|
+
parser = create_parser()
|
71
|
+
arguments = parse_options(parser)
|
72
|
+
|
73
|
+
return error("Invalid format value '#{@format}'", parser) if not EnvExporter.valid?(@format)
|
74
|
+
return help(parser) if @show_help
|
75
|
+
|
76
|
+
@logger.debug("Nugrant 'Env'")
|
77
|
+
with_target_vms(arguments) do |vm|
|
78
|
+
config = vm.config.user
|
79
|
+
parameters = config ? config : Nugrant::Parameters.new()
|
80
|
+
bag = parameters.__all
|
81
|
+
|
82
|
+
options = {:type => @unset ? :unset : :export}
|
83
|
+
|
84
|
+
case
|
85
|
+
when @format == :script
|
86
|
+
EnvExporter.script_exporter(bag, options)
|
87
|
+
when @format == :autoenv
|
88
|
+
EnvExporter.autoenv_exporter(bag, options)
|
89
|
+
when @format == :terminal
|
90
|
+
EnvExporter.terminal_exporter(bag, options)
|
91
|
+
end
|
92
|
+
|
93
|
+
# No need to execute for the other VMs
|
94
|
+
return 0
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|