fig 0.1.81 → 0.2.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.
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