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