fig 0.1.77 → 0.1.79

Sign up to get free protection for your applications and to get access to all the features.
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