fig 0.1.77 → 0.1.79

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.
Files changed (55) hide show
  1. data/Changes +58 -1
  2. data/bin/fig +1 -1
  3. data/lib/fig.rb +1 -1
  4. data/lib/fig/command.rb +3 -3
  5. data/lib/fig/command/action/dump_package_definition_parsed.rb +5 -4
  6. data/lib/fig/command/action/list_variables/all_configs.rb +2 -5
  7. data/lib/fig/command/action/publish_local.rb +1 -1
  8. data/lib/fig/command/action/role/list_variables_in_a_tree.rb +2 -5
  9. data/lib/fig/command/action/run_command_line.rb +10 -3
  10. data/lib/fig/command/action/run_command_statement.rb +1 -1
  11. data/lib/fig/command/options.rb +8 -7
  12. data/lib/fig/command/options/parser.rb +1 -1
  13. data/lib/fig/environment_variables/case_insensitive.rb +1 -1
  14. data/lib/fig/environment_variables/case_sensitive.rb +1 -1
  15. data/lib/fig/figrc.rb +10 -10
  16. data/lib/fig/{not_found_error.rb → file_not_found_error.rb} +1 -1
  17. data/lib/fig/grammar/v0.rb +174 -173
  18. data/lib/fig/grammar/v0.treetop +27 -21
  19. data/lib/fig/grammar/v1.rb +477 -171
  20. data/lib/fig/grammar/v1.treetop +34 -22
  21. data/lib/fig/operating_system.rb +139 -60
  22. data/lib/fig/package.rb +8 -4
  23. data/lib/fig/package_definition_text_assembler.rb +31 -23
  24. data/lib/fig/parser.rb +3 -5
  25. data/lib/fig/parser_package_build_state.rb +15 -14
  26. data/lib/fig/repository.rb +41 -28
  27. data/lib/fig/repository_package_publisher.rb +20 -25
  28. data/lib/fig/runtime_environment.rb +136 -87
  29. data/lib/fig/statement.rb +15 -116
  30. data/lib/fig/statement/archive.rb +6 -4
  31. data/lib/fig/statement/asset.rb +50 -35
  32. data/lib/fig/statement/command.rb +6 -2
  33. data/lib/fig/statement/configuration.rb +10 -2
  34. data/lib/fig/statement/environment_variable.rb +35 -0
  35. data/lib/fig/statement/grammar_version.rb +6 -2
  36. data/lib/fig/statement/include.rb +6 -2
  37. data/lib/fig/statement/override.rb +6 -2
  38. data/lib/fig/statement/path.rb +7 -8
  39. data/lib/fig/statement/resource.rb +7 -3
  40. data/lib/fig/statement/retrieve.rb +10 -2
  41. data/lib/fig/statement/set.rb +7 -8
  42. data/lib/fig/string_tokenizer.rb +195 -0
  43. data/lib/fig/tokenized_string.rb +22 -0
  44. data/lib/fig/tokenized_string/plain_segment.rb +24 -0
  45. data/lib/fig/tokenized_string/token.rb +18 -0
  46. data/lib/fig/unparser.rb +84 -1
  47. data/lib/fig/unparser/v0.rb +4 -0
  48. data/lib/fig/unparser/v1.rb +7 -7
  49. data/lib/fig/url.rb +12 -1
  50. data/lib/fig/{url_access_error.rb → url_access_disallowed_error.rb} +2 -2
  51. metadata +129 -128
  52. data/lib/fig/grammar/v0_asset_location.rb +0 -162
  53. data/lib/fig/grammar/v0_ish.rb +0 -1356
  54. data/lib/fig/grammar/v1_asset_location.rb +0 -162
  55. data/lib/fig/grammar/v2.rb +0 -1478
@@ -11,15 +11,19 @@ class Fig::Statement; end
11
11
  class Fig::Statement::Resource < Fig::Statement
12
12
  include Fig::Statement::Asset
13
13
 
14
- def initialize(line_column, source_description, url, glob_if_not_url)
14
+ def initialize(line_column, source_description, location, glob_if_not_url)
15
15
  super(line_column, source_description)
16
16
 
17
- @url = url
17
+ @location = location
18
18
  @glob_if_not_url = glob_if_not_url
19
19
  end
20
20
 
21
+ def statement_type()
22
+ return 'resource'
23
+ end
24
+
21
25
  def asset_name()
22
- if Fig::URL.is_url?(url())
26
+ if Fig::URL.is_url?(location())
23
27
  return standard_asset_name()
24
28
  end
25
29
 
@@ -27,6 +27,10 @@ class Fig::Statement::Retrieve < Fig::Statement
27
27
  end
28
28
  end
29
29
 
30
+ def statement_type()
31
+ return 'retrieve'
32
+ end
33
+
30
34
  def loaded_but_not_referenced?()
31
35
  return added_to_environment? && ! referenced?
32
36
  end
@@ -51,7 +55,11 @@ class Fig::Statement::Retrieve < Fig::Statement
51
55
  return unparser.retrieve(self)
52
56
  end
53
57
 
54
- def minimum_grammar_version_required()
55
- return 0
58
+ def minimum_grammar_for_emitting_input()
59
+ return [0]
60
+ end
61
+
62
+ def minimum_grammar_for_publishing()
63
+ return [0]
56
64
  end
57
65
  end
@@ -1,9 +1,12 @@
1
1
  require 'fig/statement'
2
+ require 'fig/statement/environment_variable'
2
3
 
3
4
  module Fig; end
4
5
 
5
6
  # A statement that sets the value of an environment variable.
6
7
  class Fig::Statement::Set < Fig::Statement
8
+ include Fig::Statement::EnvironmentVariable
9
+
7
10
  # We block quotes right now in order to allow for using them for
8
11
  # quoting later.
9
12
  VALUE_REGEX = %r< \A [^\s\\'"]* \z >x
@@ -26,8 +29,6 @@ class Fig::Statement::Set < Fig::Statement
26
29
  return [variable, value]
27
30
  end
28
31
 
29
- attr_reader :name, :value
30
-
31
32
  def initialize(line_column, source_description, name, value)
32
33
  super(line_column, source_description)
33
34
 
@@ -35,6 +36,10 @@ class Fig::Statement::Set < Fig::Statement
35
36
  @value = value
36
37
  end
37
38
 
39
+ def statement_type()
40
+ return 'set'
41
+ end
42
+
38
43
  def is_environment_variable?()
39
44
  return true
40
45
  end
@@ -42,10 +47,4 @@ class Fig::Statement::Set < Fig::Statement
42
47
  def unparse_as_version(unparser)
43
48
  return unparser.set(self)
44
49
  end
45
-
46
- def minimum_grammar_version_required()
47
- # TODO: fix this once going through
48
- # Statement.strip_quotes_and_process_escapes()
49
- return 0
50
- end
51
50
  end
@@ -0,0 +1,195 @@
1
+ require 'fig/tokenized_string'
2
+ require 'fig/tokenized_string/plain_segment'
3
+
4
+ module Fig; end
5
+
6
+ class Fig::StringTokenizer
7
+ def initialize(subexpression_matchers = DEFAULT_SUBEXPRESSION_MATCHER)
8
+ @subexpression_matchers = subexpression_matchers
9
+
10
+ return
11
+ end
12
+
13
+ # Takes a block that is invoked when there is an error. Block receives a
14
+ # single parameter of an error message that is the end of a statement
15
+ # describing the problem, with no leading space character. For example,
16
+ # given «'foo», the block will receive a message like 'has unbalanced single
17
+ # quotes.'.
18
+ #
19
+ # Returns the TokenizedString; if there was a parse error, then the return
20
+ # value will be nil (and the block will have been invoked).
21
+ def tokenize(string, &error_block)
22
+ @string = string.clone
23
+ @error_block = error_block
24
+ @single_quoted = nil
25
+ @segments = []
26
+
27
+ strip_quotes_and_process_escapes
28
+
29
+ return if @segments.empty?
30
+
31
+ return Fig::TokenizedString.new(@segments, @single_quoted)
32
+ end
33
+
34
+ private
35
+
36
+ DEFAULT_SUBEXPRESSION_MATCHER = [
37
+ { :pattern => %r<\@>, :action => lambda {|character| character} }
38
+ ]
39
+
40
+ def strip_quotes_and_process_escapes()
41
+ if @string.length == 0
42
+ @single_quoted = false
43
+ @segments << Fig::TokenizedString::PlainSegment.new('')
44
+
45
+ return
46
+ end
47
+
48
+ @single_quoted = strip_single_quotes_and_process_escapes
49
+ return if @single_quoted.nil?
50
+ if @single_quoted
51
+ @segments << Fig::TokenizedString::PlainSegment.new(@string.clone)
52
+
53
+ return
54
+ end
55
+
56
+ strip_double_quotes_and_process_escapes
57
+
58
+ return
59
+ end
60
+
61
+ def strip_single_quotes_and_process_escapes()
62
+ return false if @string[0..0] != %q<'> && @string[-1..-1] != %q<'>
63
+ return false if @string =~ %r< \A (?: \\{2} )* \\ ' \z >x # «\'» is legal
64
+
65
+ if (
66
+ @string.length == 1 ||
67
+ @string[0..0] != %q<'> ||
68
+ @string[-1..-1] != %q<'> ||
69
+ @string =~ %r< [^\\] (?: \\{2} )* \\ ' \z >x
70
+ )
71
+ @error_block.call 'has unbalanced single quotes.'
72
+ return
73
+ end
74
+
75
+ if @string =~ %r< [^\\] (?: \\{2} )*? \\ ([^\\']) >x
76
+ @error_block.call(
77
+ "contains a bad escape sequence (\\#{$1}) inside single quotes."
78
+ )
79
+ return
80
+ end
81
+
82
+ @string.sub!( %r< \A ' (.*) ' \z >xm, '\1')
83
+
84
+ return true
85
+ end
86
+
87
+ def strip_double_quotes_and_process_escapes()
88
+ return if ! check_and_strip_double_quotes
89
+
90
+ if @string == %q<\\'>
91
+ @segments << Fig::TokenizedString::PlainSegment.new(%q<'>)
92
+
93
+ return
94
+ end
95
+
96
+ generate_segments
97
+
98
+ return
99
+ end
100
+
101
+ def check_and_strip_double_quotes()
102
+ # We accept any unquoted single character at this point. Later validation
103
+ # will catch bad characters.
104
+ return true if @string =~ %r< \A \\ . \z >xm
105
+
106
+ if @string[0..0] == %q<">
107
+ if @string.length == 1 || @string[-1..-1] != %q<">
108
+ @error_block.call 'has unbalanced double quotes.'
109
+ return
110
+ end
111
+ if @string =~ %r< [^\\] (?: \\{2} )*? \\ " \z >xm
112
+ @error_block.call \
113
+ 'has unbalanced double quotes; the trailing double quote is escaped.'
114
+ return
115
+ end
116
+
117
+ @string.sub!( %r< \A " (.*) " \z >xm, '\1' )
118
+ elsif @string =~ %r< (?: \A | [^\\] ) (?: \\{2} )* " \z >xm
119
+ @error_block.call \
120
+ %q<has unbalanced double quotes; it ends in a double quote when it didn't start with one.>
121
+ return
122
+ end
123
+
124
+ return true
125
+ end
126
+
127
+ def generate_segments()
128
+ plain_string = nil
129
+
130
+ while ! @string.empty?
131
+ if @string =~ %r< \A (\\+) ([^\\] .*)? \z >xm
132
+ slashes, remainder = $1, $2
133
+ if slashes.length % 2 == 1
134
+ if remainder.nil?
135
+ @error_block.call 'ends in an incomplete escape.'
136
+ return
137
+ end
138
+ if subexpression_match(remainder) || remainder[0..0] == %q<">
139
+ plain_string ||= ''
140
+ plain_string << slashes
141
+ plain_string << remainder[0..0]
142
+ @string = remainder[1..-1] || ''
143
+ else
144
+ @error_block.call "contains a bad escape sequence (\\#{$1})."
145
+ return
146
+ end
147
+ else
148
+ plain_string ||= ''
149
+ plain_string << slashes
150
+ @string = remainder
151
+ end
152
+ else
153
+ replacement, remainder = subexpression_match @string
154
+ if replacement
155
+ if replacement.is_a? String
156
+ plain_string << replacement
157
+ else
158
+ @segments << Fig::TokenizedString::PlainSegment.new(plain_string)
159
+ plain_string = nil
160
+ end
161
+ @string = remainder
162
+ elsif @string =~ %r< \A (["']) >xm # Fix single quotes in quoted strings
163
+ quote_name = $1 == %q<'> ? 'single' : 'double'
164
+ @error_block.call "contains an unescaped #{quote_name} quote."
165
+ return
166
+ else
167
+ plain_string ||= ''
168
+ plain_string << @string[0..0]
169
+ @string = @string[1..-1] || ''
170
+ end
171
+ end
172
+ end
173
+
174
+ if plain_string
175
+ @segments << Fig::TokenizedString::PlainSegment.new(plain_string)
176
+ end
177
+
178
+ return
179
+ end
180
+
181
+ def subexpression_match(sub_string)
182
+ @subexpression_matchers.each do
183
+ |matcher|
184
+
185
+ pattern = matcher[:pattern]
186
+ if sub_string =~ %r< \A ( #{pattern} ) >x
187
+ subexpression, remainder = $1, $'
188
+ replacement = matcher[:action].call subexpression
189
+ return [replacement, remainder]
190
+ end
191
+ end
192
+
193
+ return
194
+ end
195
+ end
@@ -0,0 +1,22 @@
1
+ module Fig; end
2
+
3
+ class Fig::TokenizedString
4
+ def initialize(segments, single_quoted)
5
+ @segments = segments
6
+ @single_quoted = single_quoted
7
+
8
+ return
9
+ end
10
+
11
+ def single_quoted?()
12
+ return @single_quoted
13
+ end
14
+
15
+ def to_expanded_string()
16
+ return ( @segments.collect {|segment| segment.to_expanded_string} ).join ''
17
+ end
18
+
19
+ def to_escaped_string()
20
+ return ( @segments.collect {|segment| segment.to_escaped_string} ).join ''
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ module Fig; end
2
+ class Fig::TokenizedString; end
3
+
4
+ class Fig::TokenizedString::PlainSegment
5
+ attr_reader :raw_value
6
+
7
+ def initialize(raw_value)
8
+ @raw_value = raw_value
9
+
10
+ return
11
+ end
12
+
13
+ def type
14
+ return :plain_segment
15
+ end
16
+
17
+ def to_expanded_string()
18
+ return @raw_value.gsub(%r< \\ (.) >xm, '\1')
19
+ end
20
+
21
+ def to_escaped_string()
22
+ return @raw_value
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module Fig; end
2
+ class Fig::TokenizedString; end
3
+
4
+ class Fig::TokenizedString::Token
5
+ attr_reader :type
6
+ attr_reader :raw_value
7
+
8
+ def initialize(type, raw_value)
9
+ @type = type
10
+ @raw_value = raw_value
11
+
12
+ return
13
+ end
14
+
15
+ def to_escaped_string()
16
+ return raw_value
17
+ end
18
+ end
@@ -1,7 +1,86 @@
1
1
  module Fig; end
2
2
 
3
3
  module Fig::Unparser
4
+ # Determine the class of Unparser necessary for a set of Statements; the
5
+ # parameter can be a single statement or multiple. Returns both the class
6
+ # and a list of explanations of why the class was picked.
7
+ def self.class_for_statements(
8
+ statements, emit_as_input_or_to_be_published_values
9
+ )
10
+ # Note: we very specifically do not require the files containing the
11
+ # Unparser classes in order to avoid circular dependencies.
12
+ statements = [statements].flatten
13
+
14
+ versions =
15
+ self.gather_versions statements, emit_as_input_or_to_be_published_values
16
+ version = (versions.map {|version_info| version_info[0]}).max || 0
17
+ explanations = (versions.collect {|v| v[1]}).reject {|e| e.nil?}
18
+
19
+ case version
20
+ when 0
21
+ return Fig::Unparser::V0, explanations
22
+ end
23
+
24
+ # TODO: Until v1 grammar handling is done, ensure we don't emit anything
25
+ # old fig versions cannot handle.
26
+ if ! ENV['FIG_ALLOW_NON_V0_GRAMMAR']
27
+ raise 'Reached a point where something could not be represented by the v0 grammar. Bailing out.'
28
+ end
29
+
30
+ return Fig::Unparser::V1, explanations
31
+ end
32
+
33
+ def self.determine_version_and_unparse(
34
+ statements, emit_as_input_or_to_be_published_values
35
+ )
36
+ unparser_class, explanations = self.class_for_statements(
37
+ statements, emit_as_input_or_to_be_published_values
38
+ )
39
+ unparser = unparser_class.new emit_as_input_or_to_be_published_values
40
+
41
+ return (unparser.unparse [statements].flatten), explanations
42
+ end
43
+
44
+ private
45
+
46
+ def self.gather_versions(statements, emit_as_input_or_to_be_published_values)
47
+ if emit_as_input_or_to_be_published_values == :emit_as_input
48
+ return statements.map {
49
+ |statement|
50
+
51
+ self.expand_version_and_explanation(
52
+ statement, statement.minimum_grammar_for_emitting_input
53
+ )
54
+ }
55
+ end
56
+
57
+ return statements.map {
58
+ |statement|
59
+
60
+ self.expand_version_and_explanation(
61
+ statement, statement.minimum_grammar_for_publishing
62
+ )
63
+ }
64
+ end
65
+
66
+ def self.expand_version_and_explanation(statement, version_info)
67
+ version, explanation = *version_info
68
+ if explanation.nil?
69
+ return [version]
70
+ end
71
+
72
+ return [
73
+ version,
74
+ "Grammar v#{version} is required because the #{statement.statement_type} statement#{statement.position_string} #{explanation}."
75
+ ]
76
+ end
77
+
78
+
79
+ public
80
+
4
81
  def unparse(statements)
82
+ # It's double dispatch time!
83
+
5
84
  @text = ''
6
85
  @indent_level = @initial_indent_level
7
86
 
@@ -101,6 +180,10 @@ module Fig::Unparser
101
180
  return
102
181
  end
103
182
 
183
+ def grammar_description
184
+ raise NotImplementedError
185
+ end
186
+
104
187
  private
105
188
 
106
189
  def asset(keyword, statement)
@@ -109,7 +192,7 @@ module Fig::Unparser
109
192
 
110
193
  def asset_path(statement)
111
194
  if @emit_as_input_or_to_be_published_values == :emit_as_input
112
- return statement.url
195
+ return statement.location
113
196
  end
114
197
 
115
198
  return statement.asset_name