fig 0.1.81 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Changes +87 -0
  2. data/lib/fig.rb +1 -1
  3. data/lib/fig/command.rb +5 -0
  4. data/lib/fig/command/action/dump_package_definition_for_command_line.rb +62 -0
  5. data/lib/fig/command/action/dump_package_definition_parsed.rb +19 -2
  6. data/lib/fig/command/action/list_local.rb +9 -1
  7. data/lib/fig/command/action/list_remote.rb +9 -1
  8. data/lib/fig/command/action/role/list_variables_in_a_tree.rb +1 -1
  9. data/lib/fig/command/action/run_command_line.rb +1 -1
  10. data/lib/fig/command/action/run_command_statement.rb +4 -2
  11. data/lib/fig/command/options.rb +50 -18
  12. data/lib/fig/command/options/parser.rb +16 -15
  13. data/lib/fig/command/package_applier.rb +5 -3
  14. data/lib/fig/grammar/v0.rb +287 -289
  15. data/lib/fig/grammar/v0.treetop +66 -42
  16. data/lib/fig/grammar/v1.rb +629 -533
  17. data/lib/fig/grammar/v1.treetop +102 -39
  18. data/lib/fig/grammar_monkey_patches.rb +21 -0
  19. data/lib/fig/operating_system.rb +53 -36
  20. data/lib/fig/package_descriptor.rb +1 -12
  21. data/lib/fig/parser.rb +8 -33
  22. data/lib/fig/parser_package_build_state.rb +92 -31
  23. data/lib/fig/repository_package_publisher.rb +2 -2
  24. data/lib/fig/runtime_environment.rb +54 -120
  25. data/lib/fig/statement.rb +6 -6
  26. data/lib/fig/statement/asset.rb +1 -13
  27. data/lib/fig/statement/command.rb +47 -0
  28. data/lib/fig/statement/environment_variable.rb +64 -3
  29. data/lib/fig/statement/grammar_version.rb +4 -0
  30. data/lib/fig/statement/include.rb +4 -0
  31. data/lib/fig/statement/override.rb +4 -0
  32. data/lib/fig/statement/path.rb +40 -16
  33. data/lib/fig/statement/retrieve.rb +61 -5
  34. data/lib/fig/statement/set.rb +16 -19
  35. data/lib/fig/string_tokenizer.rb +63 -25
  36. data/lib/fig/tokenized_string.rb +31 -5
  37. data/lib/fig/tokenized_string/plain_segment.rb +32 -2
  38. data/lib/fig/tokenized_string/token.rb +12 -0
  39. data/lib/fig/unparser.rb +27 -12
  40. data/lib/fig/unparser/v0.rb +4 -5
  41. data/lib/fig/unparser/v1.rb +43 -6
  42. data/lib/fig/url.rb +13 -0
  43. metadata +44 -42
data/lib/fig/statement.rb CHANGED
@@ -8,8 +8,6 @@ module Fig; end
8
8
  class Fig::Statement
9
9
  ENVIRONMENT_VARIABLE_NAME_REGEX = %r< \A \w+ \z >x
10
10
 
11
- attr_reader :line, :column, :source_description
12
-
13
11
  def self.position_description(line, column, source_description)
14
12
  if not line or not column
15
13
  return '' if not source_description
@@ -26,6 +24,8 @@ class Fig::Statement
26
24
  return description
27
25
  end
28
26
 
27
+ attr_reader :line, :column, :source_description
28
+
29
29
  # This mess of getting these as a single array necessary is due to
30
30
  # limitations of the "*" array splat operator in ruby v1.8.
31
31
  def initialize(line_column, source_description)
@@ -39,7 +39,7 @@ class Fig::Statement
39
39
  # A name for this kind of Statement, usually a keyword for this statement as
40
40
  # it appears in package definition files.
41
41
  def statement_type()
42
- raise NotImplementedError
42
+ raise NotImplementedError.new self.class.name
43
43
  end
44
44
 
45
45
  # Block will receive a Statement.
@@ -48,19 +48,19 @@ class Fig::Statement
48
48
  end
49
49
 
50
50
  def unparse_as_version(unparser)
51
- raise NotImplementedError
51
+ raise NotImplementedError.new self.class.name
52
52
  end
53
53
 
54
54
  # Returns a two element array containing the version and an explanation of
55
55
  # why the version is necessary if the version is greater than 0.
56
56
  def minimum_grammar_for_emitting_input()
57
- raise NotImplementedError
57
+ raise NotImplementedError.new self.class.name
58
58
  end
59
59
 
60
60
  # Returns a two element array containing the version and an explanation of
61
61
  # why the version is necessary if the version is greater than 0.
62
62
  def minimum_grammar_for_publishing()
63
- raise NotImplementedError
63
+ raise NotImplementedError.new self.class.name
64
64
  end
65
65
 
66
66
  def urls()
@@ -1,6 +1,3 @@
1
- require 'cgi'
2
-
3
- require 'fig/parser'
4
1
  require 'fig/statement'
5
2
  require 'fig/string_tokenizer'
6
3
  require 'fig/url'
@@ -84,16 +81,7 @@ module Fig::Statement::Asset
84
81
 
85
82
  module ClassMethods
86
83
  def validate_and_process_escapes_in_location(location, &block)
87
- tokenizer = Fig::StringTokenizer.new
88
- tokenized_string = tokenizer.tokenize(location, &block)
89
- return if ! tokenized_string
90
-
91
- # "config" is a reasonable asset name, so we let that pass.
92
- if Fig::Parser.strict_keyword?(tokenized_string.to_expanded_string)
93
- yield 'is a keyword.'
94
- end
95
-
96
- return tokenized_string
84
+ return Fig::StringTokenizer.new.tokenize(location, &block)
97
85
  end
98
86
  end
99
87
  end
@@ -7,6 +7,15 @@ module Fig; end
7
7
  class Fig::Statement::Command < Fig::Statement
8
8
  attr_reader :command
9
9
 
10
+
11
+ def self.validate_and_process_escapes_in_argument(
12
+ command_line_argument, &block
13
+ )
14
+ tokenizer = Fig::StringTokenizer.new TOKENIZING_SUBEXPRESSION_MATCHER, '@'
15
+
16
+ return tokenizer.tokenize command_line_argument, &block
17
+ end
18
+
10
19
  def initialize(line_column, source_description, command)
11
20
  super(line_column, source_description)
12
21
 
@@ -21,7 +30,45 @@ class Fig::Statement::Command < Fig::Statement
21
30
  return unparser.command(self)
22
31
  end
23
32
 
33
+ def minimum_grammar_for_emitting_input()
34
+ return minimum_grammar()
35
+ end
36
+
24
37
  def minimum_grammar_for_publishing()
38
+ return minimum_grammar()
39
+ end
40
+
41
+ private
42
+
43
+ def minimum_grammar()
44
+ if command.size > 1
45
+ return [1, 'contains multiple components']
46
+ end
47
+
48
+ argument = command.first.to_escaped_string
49
+
50
+ # Can't have octothorpes anywhere in v0 due to comment stripping via
51
+ # regex.
52
+ if argument =~ /#/
53
+ return [1, 'contains a comment ("#") character']
54
+ end
55
+
56
+ if argument =~ /"/
57
+ return [1, %Q<contains a double quote>]
58
+ end
59
+
25
60
  return [0]
26
61
  end
62
+
63
+ TOKENIZING_SUBEXPRESSION_MATCHER = [
64
+ {
65
+ :pattern => %r< \@ [a-zA-Z0-9_.-]* >x,
66
+ :action =>
67
+ lambda {
68
+ |subexpression, error_block|
69
+
70
+ Fig::TokenizedString::Token.new :package_path, subexpression[1..-1]
71
+ }
72
+ }
73
+ ]
27
74
  end
@@ -1,9 +1,19 @@
1
+ require 'fig/statement'
2
+ require 'fig/string_tokenizer'
3
+ require 'fig/tokenized_string/token'
4
+
1
5
  module Fig; end
2
6
  class Fig::Statement; end
3
7
 
4
8
  # A statement that manipulates an environment variable.
5
9
  module Fig::Statement::EnvironmentVariable
6
- attr_reader :name, :value
10
+ attr_reader :name, :tokenized_value
11
+
12
+ def self.included(class_included_into)
13
+ class_included_into.extend(ClassMethods)
14
+
15
+ return
16
+ end
7
17
 
8
18
  def minimum_grammar_for_emitting_input()
9
19
  return minimum_grammar()
@@ -15,7 +25,8 @@ module Fig::Statement::EnvironmentVariable
15
25
 
16
26
  private
17
27
 
18
- def minimum_grammar()
28
+ def standard_minimum_grammar()
29
+ value = tokenized_value.to_escaped_string
19
30
  if value =~ /\s/
20
31
  return [1, 'contains whitespace']
21
32
  end
@@ -23,7 +34,7 @@ module Fig::Statement::EnvironmentVariable
23
34
  # Can't have octothorpes anywhere in v0 due to comment stripping via
24
35
  # regex.
25
36
  if value =~ /#/
26
- return [1, 'contains a "#" character']
37
+ return [1, 'contains a comment ("#") character']
27
38
  end
28
39
 
29
40
  if value =~ / ( ["'] ) /x
@@ -32,4 +43,54 @@ module Fig::Statement::EnvironmentVariable
32
43
 
33
44
  return [0]
34
45
  end
46
+
47
+ module ClassMethods
48
+ def seperate_name_and_value(combined, &error_block)
49
+ variable, raw_value = combined.split '=', 2
50
+ if variable !~ Fig::Statement::ENVIRONMENT_VARIABLE_NAME_REGEX
51
+ yield \
52
+ %Q<"#{variable}" does not consist solely of alphanumerics and underscores.>
53
+ return
54
+ end
55
+
56
+ return [variable, raw_value || '']
57
+ end
58
+
59
+ def tokenize_value(value, &error_block)
60
+ tokenizer = Fig::StringTokenizer.new TOKENIZING_SUBEXPRESSION_MATCHER, '@'
61
+ return tokenizer.tokenize value, &error_block
62
+ end
63
+
64
+ # TODO: Test coverage doesn't appear to be running this.
65
+ def base_v0_value_validation(variable, raw_value)
66
+ if raw_value =~ /\s/
67
+ yield %Q<The value of #{variable} (#{raw_value}) contains whitespace.>
68
+ return
69
+ end
70
+ if raw_value =~ /'/
71
+ yield %Q<The value of #{variable} (#{raw_value}) contains a single quote.>
72
+ return
73
+ end
74
+ if raw_value =~ /"/
75
+ yield %Q<The value of #{variable} (#{raw_value}) contains a double quote.>
76
+ return
77
+ end
78
+
79
+ return
80
+ end
81
+
82
+ private
83
+
84
+ TOKENIZING_SUBEXPRESSION_MATCHER = [
85
+ {
86
+ :pattern => %r<\@>,
87
+ :action =>
88
+ lambda {
89
+ |subexpression, error_block|
90
+
91
+ Fig::TokenizedString::Token.new :package_path, '@'
92
+ }
93
+ }
94
+ ]
95
+ end
35
96
  end
@@ -20,6 +20,10 @@ class Fig::Statement::GrammarVersion < Fig::Statement
20
20
  return unparser.grammar_version(self)
21
21
  end
22
22
 
23
+ def minimum_grammar_for_emitting_input()
24
+ return [version]
25
+ end
26
+
23
27
  def minimum_grammar_for_publishing()
24
28
  return [version]
25
29
  end
@@ -70,6 +70,10 @@ class Fig::Statement::Include < Fig::Statement
70
70
  return unparser.include(self)
71
71
  end
72
72
 
73
+ def minimum_grammar_for_emitting_input()
74
+ return [0]
75
+ end
76
+
73
77
  def minimum_grammar_for_publishing()
74
78
  return [0]
75
79
  end
@@ -41,6 +41,10 @@ class Fig::Statement::Override < Fig::Statement
41
41
  return unparser.override(self)
42
42
  end
43
43
 
44
+ def minimum_grammar_for_emitting_input()
45
+ return [0]
46
+ end
47
+
44
48
  def minimum_grammar_for_publishing()
45
49
  return [0]
46
50
  end
@@ -8,33 +8,43 @@ module Fig; end
8
8
  class Fig::Statement::Path < Fig::Statement
9
9
  include Fig::Statement::EnvironmentVariable
10
10
 
11
- # We block single-quotes right now in order to allow for using them for
12
- # quoting later.
13
- VALUE_REGEX = %r< \A [^;:'"<>|\s]+ \z >x
14
- ARGUMENT_DESCRIPTION =
15
- %q[The value must look like "NAME=VALUE". VALUE cannot contain any of ";:<>|", double quotes, or whitespace.]
16
-
17
11
  # Yields on error.
18
- def self.parse_name_value(combined)
19
- variable, value = combined.split('=')
12
+ def self.parse_name_value(combined, &error_block)
13
+ variable, raw_value = seperate_name_and_value combined, &error_block
14
+
15
+ tokenized_value = tokenize_value(raw_value, &error_block)
16
+
17
+ if tokenized_value.to_escaped_string.length < 1
18
+ yield %Q<The value of path variable #{variable} is empty.>
19
+ return
20
+ end
21
+
22
+ return [variable, tokenized_value]
23
+ end
24
+
25
+ def self.parse_v0_name_value(combined, &error_block)
26
+ variable, raw_value = seperate_name_and_value combined, &error_block
20
27
 
21
- if variable !~ ENVIRONMENT_VARIABLE_NAME_REGEX
22
- yield
28
+ if raw_value.length < 1
29
+ yield %Q<The value of path variable #{variable} is empty.>
30
+ return
23
31
  end
24
32
 
25
- value = '' if value.nil?
26
- if value !~ VALUE_REGEX
27
- yield
33
+ base_v0_value_validation(variable, raw_value, &error_block)
34
+
35
+ if raw_value =~ /([;:<>|])/
36
+ yield %Q<The value of path variable #{variable} (#{raw_value}) contains a "#{raw_value}" character.>
37
+ return
28
38
  end
29
39
 
30
- return [variable, value]
40
+ return [variable, tokenize_value(raw_value, &error_block)]
31
41
  end
32
42
 
33
- def initialize(line_column, source_description, name, value)
43
+ def initialize(line_column, source_description, name, tokenized_value)
34
44
  super(line_column, source_description)
35
45
 
36
46
  @name = name
37
- @value = value
47
+ @tokenized_value = tokenized_value
38
48
  end
39
49
 
40
50
  def statement_type()
@@ -48,4 +58,18 @@ class Fig::Statement::Path < Fig::Statement
48
58
  def unparse_as_version(unparser)
49
59
  return unparser.path(self)
50
60
  end
61
+
62
+ private
63
+
64
+ def minimum_grammar()
65
+ base_grammar_version = standard_minimum_grammar
66
+ return base_grammar_version if base_grammar_version[0] != 0
67
+
68
+ value = tokenized_value.to_escaped_string
69
+ if value =~ / ( [;:<>|] ) /x
70
+ return [1, %Q<contains a "#{$1}" character>]
71
+ end
72
+
73
+ return [0]
74
+ end
51
75
  end
@@ -7,14 +7,21 @@ module Fig; end
7
7
  # Specifies that files from a package should be copied into the current
8
8
  # directory when an environment variable has its value changed.
9
9
  class Fig::Statement::Retrieve < Fig::Statement
10
- attr_reader :var, :path
10
+ def self.tokenize_path(path, &error_block)
11
+ tokenizer = Fig::StringTokenizer.new TOKENIZING_SUBEXPRESSION_MATCHER, '\\['
12
+ return tokenizer.tokenize path, &error_block
13
+ end
14
+
15
+ attr_reader :variable
16
+ attr_reader :tokenized_path
11
17
 
12
- def initialize(line_column, source_description, var, path)
18
+ def initialize(line_column, source_description, variable, tokenized_path)
13
19
  super(line_column, source_description)
14
20
 
15
- @var = var
16
- @path = path
21
+ @variable = variable
22
+ @tokenized_path = tokenized_path
17
23
 
24
+ path = tokenized_path.to_escaped_string
18
25
  # Yeah, it's not cross-platform, but File doesn't have an #absolute? method
19
26
  # and this is better than nothing.
20
27
  if (
@@ -56,10 +63,59 @@ class Fig::Statement::Retrieve < Fig::Statement
56
63
  end
57
64
 
58
65
  def minimum_grammar_for_emitting_input()
59
- return [0]
66
+ return minimum_grammar()
60
67
  end
61
68
 
62
69
  def minimum_grammar_for_publishing()
70
+ return minimum_grammar()
71
+ end
72
+
73
+ private
74
+
75
+ def minimum_grammar()
76
+ path = tokenized_path.to_escaped_string
77
+ if path =~ /\s/
78
+ return [1, 'contains whitespace']
79
+ end
80
+
81
+ # Can't have octothorpes anywhere in v0 due to comment stripping via
82
+ # regex.
83
+ if path =~ /#/
84
+ return [1, 'contains a comment ("#") character']
85
+ end
86
+
87
+ if path =~ %r< ' >x
88
+ return [1, %Q<contains a single quote character>]
89
+ end
90
+
91
+ if path =~ %r< " >x
92
+ return [1, %Q<contains a double quote character>]
93
+ end
94
+
95
+ if path =~ %r< ( [^a-zA-Z0-9_/.\[\]-] ) >x
96
+ return [1, %Q<contains a "#{$1}" character>]
97
+ end
98
+
63
99
  return [0]
64
100
  end
101
+
102
+ TOKENIZING_SUBEXPRESSION_MATCHER = [
103
+ {
104
+ # Shortest sequence of characters that starts with an open square bracket
105
+ # and ends with either a close square bracket or end of string.
106
+ :pattern => %r< \[ [^\]]* \]? >x,
107
+ :action =>
108
+ lambda {
109
+ |subexpression, error_block|
110
+
111
+ if subexpression == '[package]'
112
+ return Fig::TokenizedString::Token.new :package_path, '[package]'
113
+ end
114
+
115
+ error_block.call \
116
+ %q<contains an unescaped "[" that is not followed by "ackage]".>
117
+ return
118
+ }
119
+ }
120
+ ]
65
121
  end
@@ -7,33 +7,24 @@ module Fig; end
7
7
  class Fig::Statement::Set < Fig::Statement
8
8
  include Fig::Statement::EnvironmentVariable
9
9
 
10
- # We block quotes right now in order to allow for using them for
11
- # quoting later.
12
- VALUE_REGEX = %r< \A [^\s\\'"]* \z >x
13
- ARGUMENT_DESCRIPTION =
14
- %q<The value must look like "NAME=VALUE"; VALUE cannot contain whitespace though it can be empty.>
15
-
16
10
  # Yields on error.
17
- def self.parse_name_value(combined)
18
- variable, value = combined.split('=')
19
-
20
- if variable !~ ENVIRONMENT_VARIABLE_NAME_REGEX
21
- yield
22
- end
11
+ def self.parse_name_value(combined, &error_block)
12
+ variable, raw_value = seperate_name_and_value combined, &error_block
23
13
 
24
- value = '' if value.nil?
25
- if value !~ VALUE_REGEX
26
- yield
27
- end
14
+ return [variable, tokenize_value(raw_value, &error_block)]
15
+ end
28
16
 
29
- return [variable, value]
17
+ def self.parse_v0_name_value(combined, &error_block)
18
+ variable, raw_value = seperate_name_and_value combined, &error_block
19
+ base_v0_value_validation(variable, raw_value, &error_block)
20
+ return [variable, tokenize_value(raw_value, &error_block)]
30
21
  end
31
22
 
32
- def initialize(line_column, source_description, name, value)
23
+ def initialize(line_column, source_description, name, tokenized_value)
33
24
  super(line_column, source_description)
34
25
 
35
26
  @name = name
36
- @value = value
27
+ @tokenized_value = tokenized_value
37
28
  end
38
29
 
39
30
  def statement_type()
@@ -47,4 +38,10 @@ class Fig::Statement::Set < Fig::Statement
47
38
  def unparse_as_version(unparser)
48
39
  return unparser.set(self)
49
40
  end
41
+
42
+ private
43
+
44
+ def minimum_grammar()
45
+ return standard_minimum_grammar
46
+ end
50
47
  end