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.
- data/Changes +87 -0
- data/lib/fig.rb +1 -1
- data/lib/fig/command.rb +5 -0
- data/lib/fig/command/action/dump_package_definition_for_command_line.rb +62 -0
- data/lib/fig/command/action/dump_package_definition_parsed.rb +19 -2
- data/lib/fig/command/action/list_local.rb +9 -1
- data/lib/fig/command/action/list_remote.rb +9 -1
- data/lib/fig/command/action/role/list_variables_in_a_tree.rb +1 -1
- data/lib/fig/command/action/run_command_line.rb +1 -1
- data/lib/fig/command/action/run_command_statement.rb +4 -2
- data/lib/fig/command/options.rb +50 -18
- data/lib/fig/command/options/parser.rb +16 -15
- data/lib/fig/command/package_applier.rb +5 -3
- data/lib/fig/grammar/v0.rb +287 -289
- data/lib/fig/grammar/v0.treetop +66 -42
- data/lib/fig/grammar/v1.rb +629 -533
- data/lib/fig/grammar/v1.treetop +102 -39
- data/lib/fig/grammar_monkey_patches.rb +21 -0
- data/lib/fig/operating_system.rb +53 -36
- data/lib/fig/package_descriptor.rb +1 -12
- data/lib/fig/parser.rb +8 -33
- data/lib/fig/parser_package_build_state.rb +92 -31
- data/lib/fig/repository_package_publisher.rb +2 -2
- data/lib/fig/runtime_environment.rb +54 -120
- data/lib/fig/statement.rb +6 -6
- data/lib/fig/statement/asset.rb +1 -13
- data/lib/fig/statement/command.rb +47 -0
- data/lib/fig/statement/environment_variable.rb +64 -3
- data/lib/fig/statement/grammar_version.rb +4 -0
- data/lib/fig/statement/include.rb +4 -0
- data/lib/fig/statement/override.rb +4 -0
- data/lib/fig/statement/path.rb +40 -16
- data/lib/fig/statement/retrieve.rb +61 -5
- data/lib/fig/statement/set.rb +16 -19
- data/lib/fig/string_tokenizer.rb +63 -25
- data/lib/fig/tokenized_string.rb +31 -5
- data/lib/fig/tokenized_string/plain_segment.rb +32 -2
- data/lib/fig/tokenized_string/token.rb +12 -0
- data/lib/fig/unparser.rb +27 -12
- data/lib/fig/unparser/v0.rb +4 -5
- data/lib/fig/unparser/v1.rb +43 -6
- data/lib/fig/url.rb +13 -0
- 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()
|
data/lib/fig/statement/asset.rb
CHANGED
@@ -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
|
-
|
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, :
|
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
|
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
|
data/lib/fig/statement/path.rb
CHANGED
@@ -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,
|
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
|
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
|
-
|
26
|
-
|
27
|
-
|
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,
|
40
|
+
return [variable, tokenize_value(raw_value, &error_block)]
|
31
41
|
end
|
32
42
|
|
33
|
-
def initialize(line_column, source_description, name,
|
43
|
+
def initialize(line_column, source_description, name, tokenized_value)
|
34
44
|
super(line_column, source_description)
|
35
45
|
|
36
46
|
@name = name
|
37
|
-
@
|
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
|
-
|
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,
|
18
|
+
def initialize(line_column, source_description, variable, tokenized_path)
|
13
19
|
super(line_column, source_description)
|
14
20
|
|
15
|
-
@
|
16
|
-
@
|
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
|
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
|
data/lib/fig/statement/set.rb
CHANGED
@@ -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,
|
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
|
-
|
25
|
-
|
26
|
-
yield
|
27
|
-
end
|
14
|
+
return [variable, tokenize_value(raw_value, &error_block)]
|
15
|
+
end
|
28
16
|
|
29
|
-
|
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,
|
23
|
+
def initialize(line_column, source_description, name, tokenized_value)
|
33
24
|
super(line_column, source_description)
|
34
25
|
|
35
26
|
@name = name
|
36
|
-
@
|
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
|