fig18 0.1.39 → 0.1.40
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 +41 -0
- data/LICENSE +2 -2
- data/README.md +154 -100
- data/VERSION +1 -0
- data/bin/fig +4 -182
- data/lib/fig/applicationconfiguration.rb +52 -0
- data/lib/fig/backtrace.rb +6 -6
- data/lib/fig/configfileerror.rb +15 -0
- data/lib/fig/environment.rb +46 -26
- data/lib/fig/figrc.rb +105 -0
- data/lib/fig/grammar.treetop +1 -1
- data/lib/fig/log4rconfigerror.rb +14 -0
- data/lib/fig/logging.rb +131 -0
- data/lib/fig/networkerror.rb +7 -0
- data/lib/fig/notfounderror.rb +4 -0
- data/lib/fig/options.rb +191 -54
- data/lib/fig/os.rb +73 -74
- data/lib/fig/package.rb +30 -30
- data/lib/fig/packageerror.rb +7 -0
- data/lib/fig/parser.rb +5 -8
- data/lib/fig/repository.rb +44 -28
- data/lib/fig/repositoryerror.rb +7 -0
- data/lib/fig/retriever.rb +26 -17
- data/lib/fig/urlaccesserror.rb +9 -0
- data/lib/fig/userinputerror.rb +4 -0
- data/lib/fig/windows.rb +3 -3
- data/lib/fig.rb +222 -0
- metadata +221 -47
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module Fig
|
3
|
+
class ApplicationConfiguration
|
4
|
+
def initialize(remote_repository_url)
|
5
|
+
@data = []
|
6
|
+
@remote_repository_url = remote_repository_url
|
7
|
+
clear_cached_data
|
8
|
+
end
|
9
|
+
|
10
|
+
def ensure_url_whitelist_initialized()
|
11
|
+
return if not @whitelist.nil?
|
12
|
+
whitelist = self['url_whitelist']
|
13
|
+
if whitelist.nil?
|
14
|
+
@whitelist = []
|
15
|
+
else
|
16
|
+
@whitelist = [@remote_repository_url, whitelist].flatten
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
@data.each do |dataset|
|
22
|
+
if dataset.has_key?(key)
|
23
|
+
return dataset[key]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def push_dataset(dataset)
|
30
|
+
@data.push(dataset)
|
31
|
+
end
|
32
|
+
|
33
|
+
def unshift_dataset(dataset)
|
34
|
+
@data.unshift(dataset)
|
35
|
+
end
|
36
|
+
|
37
|
+
# after push_dataset or unshift_dataset, call clear_cached, and lazy initialize as far as the list of things to exclude
|
38
|
+
|
39
|
+
def clear_cached_data()
|
40
|
+
@whitelist = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def url_access_allowed?(url)
|
44
|
+
ensure_url_whitelist_initialized
|
45
|
+
return true if @whitelist.empty?
|
46
|
+
@whitelist.each do |allowed_url|
|
47
|
+
return true if url.match(/\A#{Regexp.quote(allowed_url)}\b/)
|
48
|
+
end
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/fig/backtrace.rb
CHANGED
@@ -5,7 +5,7 @@ class Backtrace
|
|
5
5
|
@parent = parent
|
6
6
|
@package_name = package_name
|
7
7
|
@version_name = version_name
|
8
|
-
@config_name = config_name ||
|
8
|
+
@config_name = config_name || 'default'
|
9
9
|
@overrides = {}
|
10
10
|
end
|
11
11
|
|
@@ -13,15 +13,15 @@ class Backtrace
|
|
13
13
|
if @parent
|
14
14
|
@parent.collect(stack)
|
15
15
|
end
|
16
|
-
elem =
|
16
|
+
elem = ''
|
17
17
|
if @package_name
|
18
18
|
elem = @package_name
|
19
19
|
end
|
20
20
|
if @version_name
|
21
|
-
elem +=
|
21
|
+
elem += '/' + @version_name
|
22
22
|
end
|
23
23
|
if @config_name
|
24
|
-
elem +=
|
24
|
+
elem += ':' + @config_name
|
25
25
|
end
|
26
26
|
stack << elem
|
27
27
|
end
|
@@ -41,8 +41,8 @@ class Backtrace
|
|
41
41
|
collect(stack)
|
42
42
|
i=0
|
43
43
|
for elem in stack
|
44
|
-
indent=
|
45
|
-
i.times { indent +=
|
44
|
+
indent=''
|
45
|
+
i.times { indent += ' ' }
|
46
46
|
out.puts indent+elem
|
47
47
|
i += 1
|
48
48
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fig/userinputerror'
|
2
|
+
|
3
|
+
module Fig
|
4
|
+
# Could not determine some kind of information from a configuration file,
|
5
|
+
# whether .figrc, log4r, package.fig, etc.
|
6
|
+
class ConfigFileError < UserInputError
|
7
|
+
def initialize(message, file)
|
8
|
+
super(message)
|
9
|
+
|
10
|
+
@file = file
|
11
|
+
|
12
|
+
return
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/fig/environment.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
require 'fig/backtrace'
|
4
|
+
require 'fig/logging'
|
5
|
+
require 'fig/repositoryerror'
|
2
6
|
|
3
7
|
module Fig
|
4
|
-
|
5
|
-
#
|
6
|
-
# variables, and which packages have already been applied
|
8
|
+
# This class manages the program's state, including the value of all
|
9
|
+
# environment variables, and which packages have already been applied.
|
7
10
|
class Environment
|
8
|
-
DEFAULT_VERSION_NAME =
|
11
|
+
DEFAULT_VERSION_NAME = 'current'
|
9
12
|
|
10
13
|
def initialize(os, repository, variables, retriever)
|
11
14
|
@os = os
|
@@ -22,8 +25,8 @@ module Fig
|
|
22
25
|
@variables[name]
|
23
26
|
end
|
24
27
|
|
25
|
-
# Indicates that the values from a particular envrionment variable path
|
26
|
-
|
28
|
+
# Indicates that the values from a particular envrionment variable path
|
29
|
+
|
27
30
|
def add_retrieve(name, path)
|
28
31
|
@retrieve_vars[name] = path
|
29
32
|
end
|
@@ -31,8 +34,8 @@ module Fig
|
|
31
34
|
def register_package(package)
|
32
35
|
name = package.package_name
|
33
36
|
if @packages[name]
|
34
|
-
|
35
|
-
|
37
|
+
Fig::Logging.fatal %Q<There is already a package with the name "#{name}".>
|
38
|
+
raise RepositoryError.new
|
36
39
|
end
|
37
40
|
@packages[name] = package
|
38
41
|
end
|
@@ -41,7 +44,7 @@ module Fig
|
|
41
44
|
if (@applied_configs[package.package_name] ||= []).member?(config_name)
|
42
45
|
return
|
43
46
|
end
|
44
|
-
new_backtrace = backtrace
|
47
|
+
new_backtrace = backtrace
|
45
48
|
|
46
49
|
config = package[config_name]
|
47
50
|
config.statements.each { |stmt| apply_config_statement(package, stmt, new_backtrace) }
|
@@ -57,11 +60,11 @@ module Fig
|
|
57
60
|
def execute_config(base_package, package_name, config_name, version_name, args)
|
58
61
|
package = lookup_package(package_name || base_package.package_name, version_name, Backtrace.new(nil, package_name, version_name, config_name))
|
59
62
|
result = nil
|
60
|
-
commands = package[config_name ||
|
63
|
+
commands = package[config_name || 'default'].commands
|
61
64
|
with_environment do
|
62
|
-
#
|
65
|
+
# TODO nil check
|
63
66
|
commands.each do |command|
|
64
|
-
result = yield expand_arg("#{command.command} #{args.join(' ')}").gsub(
|
67
|
+
result = yield expand_arg("#{command.command} #{args.join(' ')}").gsub('@',package.directory).split(' ')
|
65
68
|
end
|
66
69
|
end
|
67
70
|
result
|
@@ -83,7 +86,7 @@ module Fig
|
|
83
86
|
end
|
84
87
|
|
85
88
|
def include_config(base_package, package_name, config_name, version_name, overrides, backtrace)
|
86
|
-
# Check to see if this include has been overridden
|
89
|
+
# Check to see if this include has been overridden.
|
87
90
|
if backtrace
|
88
91
|
override = backtrace.get_override(package_name || base_package.package_name)
|
89
92
|
if override
|
@@ -95,7 +98,7 @@ module Fig
|
|
95
98
|
new_backtrace.add_override(override.package_name, override.version_name)
|
96
99
|
end
|
97
100
|
package = lookup_package(package_name || base_package.package_name, version_name, new_backtrace)
|
98
|
-
apply_config(package, config_name ||
|
101
|
+
apply_config(package, config_name || 'default', new_backtrace)
|
99
102
|
end
|
100
103
|
|
101
104
|
def direct_retrieve(package_name, source_path, target_path)
|
@@ -104,7 +107,7 @@ module Fig
|
|
104
107
|
FileUtils.cp_r(File.join(package.directory, source_path, '.'), target_path)
|
105
108
|
end
|
106
109
|
|
107
|
-
private
|
110
|
+
private
|
108
111
|
|
109
112
|
def set_variable(base_package, name, value)
|
110
113
|
@variables[name] = expand_value(base_package, name, value)
|
@@ -146,10 +149,14 @@ module Fig
|
|
146
149
|
package.backtrace = backtrace
|
147
150
|
@packages[package_name] = package
|
148
151
|
elsif version_name && version_name != package.version_name
|
149
|
-
|
150
|
-
backtrace.dump(
|
151
|
-
package.backtrace.dump(
|
152
|
-
|
152
|
+
string_handle = StringIO.new
|
153
|
+
backtrace.dump(string_handle) if backtrace
|
154
|
+
package.backtrace.dump(string_handle) if package.backtrace
|
155
|
+
stacktrace = string_handle.to_s
|
156
|
+
Fig::Logging.fatal \
|
157
|
+
"Version mismatch: #{package_name}" \
|
158
|
+
+ stacktrace.empty? ? '' : "\n#{stacktrace}"
|
159
|
+
raise RepositoryError.new
|
153
160
|
end
|
154
161
|
package
|
155
162
|
end
|
@@ -159,18 +166,31 @@ module Fig
|
|
159
166
|
return value unless base_package && base_package.package_name
|
160
167
|
file = value.gsub(/\@/, base_package.directory)
|
161
168
|
if @retrieve_vars.member?(name)
|
162
|
-
# A '//' in the source file's path tells us to preserve path
|
163
|
-
# after the '//' when doing a retrieve.
|
169
|
+
# A '//' in the source file's path tells us to preserve path
|
170
|
+
# information after the '//' when doing a retrieve.
|
164
171
|
if file.split('//').size > 1
|
165
172
|
preserved_path = file.split('//').last
|
166
|
-
target = File.join(
|
173
|
+
target = File.join(
|
174
|
+
@retrieve_vars[name].gsub(
|
175
|
+
/\[package\]/,
|
176
|
+
base_package.package_name
|
177
|
+
),
|
178
|
+
preserved_path
|
179
|
+
)
|
167
180
|
else
|
168
|
-
target = File.join(
|
181
|
+
target = File.join(
|
182
|
+
@retrieve_vars[name].gsub(
|
183
|
+
/\[package\]/,
|
184
|
+
base_package.package_name
|
185
|
+
)
|
186
|
+
)
|
169
187
|
if not File.directory?(file)
|
170
188
|
target = File.join(target, File.basename(file))
|
171
189
|
end
|
172
190
|
end
|
173
|
-
@retriever.
|
191
|
+
@retriever.with_package_config(
|
192
|
+
base_package.package_name, base_package.version_name
|
193
|
+
) do
|
174
194
|
@retriever.retrieve(file, target)
|
175
195
|
end
|
176
196
|
file = target
|
@@ -182,8 +202,8 @@ module Fig
|
|
182
202
|
arg.gsub(/\@([a-zA-Z0-9\-\.]+)/) do |match|
|
183
203
|
package = @packages[$1]
|
184
204
|
if package.nil?
|
185
|
-
|
186
|
-
|
205
|
+
Fig::Logging.fatal "Package not found: #{$1}"
|
206
|
+
raise RepositoryError.new
|
187
207
|
end
|
188
208
|
package.directory
|
189
209
|
end
|
data/lib/fig/figrc.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'fig/applicationconfiguration'
|
4
|
+
require 'fig/configfileerror'
|
5
|
+
require 'fig/os'
|
6
|
+
|
7
|
+
REPOSITORY_CONFIGURATION = '_meta/figrc'
|
8
|
+
|
9
|
+
module Fig
|
10
|
+
class FigRC
|
11
|
+
def self.find(
|
12
|
+
override_path, repository_url, login, fig_home, disable_figrc = false
|
13
|
+
)
|
14
|
+
configuration = ApplicationConfiguration.new(repository_url)
|
15
|
+
|
16
|
+
handle_override_configuration(configuration, override_path)
|
17
|
+
handle_figrc(configuration) if not disable_figrc
|
18
|
+
handle_repository_configuration(
|
19
|
+
configuration, repository_url, login, fig_home
|
20
|
+
)
|
21
|
+
|
22
|
+
return configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def self.handle_override_configuration(configuration, override_path)
|
28
|
+
begin
|
29
|
+
if not override_path.nil?
|
30
|
+
configuration.push_dataset(
|
31
|
+
JSON.parse(File::open(override_path).read)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
rescue JSON::ParserError => exception
|
35
|
+
translate_parse_error(exception, override_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.handle_figrc(configuration)
|
42
|
+
user_figrc_path = File.expand_path('~/.figrc')
|
43
|
+
return if not File.exists? user_figrc_path
|
44
|
+
|
45
|
+
begin
|
46
|
+
configuration.push_dataset(
|
47
|
+
JSON.parse(File::open(user_figrc_path).read)
|
48
|
+
)
|
49
|
+
rescue JSON::ParserError => exception
|
50
|
+
translate_parse_error(exception, user_figrc_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.handle_repository_configuration(
|
57
|
+
configuration, repository_url, login, fig_home
|
58
|
+
)
|
59
|
+
return if repository_url.nil?
|
60
|
+
|
61
|
+
figrc_url = "#{repository_url}/#{REPOSITORY_CONFIGURATION}"
|
62
|
+
repo_figrc_path =
|
63
|
+
File.expand_path(File.join(fig_home, REPOSITORY_CONFIGURATION))
|
64
|
+
|
65
|
+
os = OS.new(login)
|
66
|
+
|
67
|
+
repo_config_exists = nil
|
68
|
+
begin
|
69
|
+
os.download( figrc_url, repo_figrc_path )
|
70
|
+
repo_config_exists = true
|
71
|
+
rescue NotFoundError => e
|
72
|
+
repo_config_exists = false
|
73
|
+
end
|
74
|
+
|
75
|
+
return configuration if not repo_config_exists
|
76
|
+
|
77
|
+
begin
|
78
|
+
configuration.push_dataset(
|
79
|
+
JSON.parse(File.open(repo_figrc_path).read)
|
80
|
+
)
|
81
|
+
rescue JSON::ParserError => exception
|
82
|
+
translate_parse_error(exception, figrc_url)
|
83
|
+
end
|
84
|
+
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.translate_parse_error(json_parse_error, config_file_path)
|
89
|
+
message = json_parse_error.message
|
90
|
+
message.chomp!
|
91
|
+
|
92
|
+
# JSON::ParserError tends to include final newline inside of single
|
93
|
+
# quotes, which makes error messages ugly.
|
94
|
+
message.sub!(/ \n+ ' \z /xm, %q<'>)
|
95
|
+
|
96
|
+
# Also, there's a useless source code line number in the message.
|
97
|
+
message.sub!(/ \A \d+ : \s+ /xm, %q<>)
|
98
|
+
|
99
|
+
raise ConfigFileError.new(
|
100
|
+
"Parse issue with #{config_file_path}: #{message}",
|
101
|
+
config_file_path
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/fig/grammar.treetop
CHANGED
@@ -107,7 +107,7 @@ grammar Fig
|
|
107
107
|
end
|
108
108
|
|
109
109
|
rule descriptor
|
110
|
-
((package:package_name ("/" version:version_name)? (":" config:config_name)? ws) /
|
110
|
+
((package:package_name ("/" version:version_name)? (":" config:config_name)? ws) /
|
111
111
|
(":" config:config_name ws)) {
|
112
112
|
def get_version
|
113
113
|
elements.each do |element|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'fig/userinputerror'
|
2
|
+
|
3
|
+
module Fig
|
4
|
+
class Log4rConfigError < UserInputError
|
5
|
+
def initialize(config_file, original_exception)
|
6
|
+
super(
|
7
|
+
%Q<Problem with #{config_file}: #{original_exception.message}>
|
8
|
+
)
|
9
|
+
|
10
|
+
@config_file = config_file
|
11
|
+
@original_exception = original_exception
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/fig/logging.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'log4r/configurator'
|
3
|
+
require 'log4r/yamlconfigurator'
|
4
|
+
|
5
|
+
require 'fig/configfileerror'
|
6
|
+
require 'fig/log4rconfigerror'
|
7
|
+
|
8
|
+
module Fig; end
|
9
|
+
|
10
|
+
module Fig::Logging
|
11
|
+
if not Log4r::Logger['initial']
|
12
|
+
@@logger = Log4r::Logger.new('initial')
|
13
|
+
end
|
14
|
+
|
15
|
+
STRING_TO_LEVEL_MAPPING = {
|
16
|
+
'off' => Log4r::OFF,
|
17
|
+
'fatal' => Log4r::FATAL,
|
18
|
+
'error' => Log4r::ERROR,
|
19
|
+
'warn' => Log4r::WARN,
|
20
|
+
'info' => Log4r::INFO,
|
21
|
+
'debug' => Log4r::DEBUG,
|
22
|
+
'all' => Log4r::ALL
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.initialize_pre_configuration(log_level = nil)
|
26
|
+
log_level ||= 'info'
|
27
|
+
|
28
|
+
assign_log_level(@@logger, log_level)
|
29
|
+
setup_default_outputter(@@logger)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.initialize_post_configuration(
|
33
|
+
config_file = nil,
|
34
|
+
log_level = nil,
|
35
|
+
suppress_default_configuration = false
|
36
|
+
)
|
37
|
+
if config_file
|
38
|
+
begin
|
39
|
+
case config_file
|
40
|
+
when / [.] xml \z /x
|
41
|
+
Log4r::Configurator.load_xml_file(config_file)
|
42
|
+
when / [.] ya?ml \z /x
|
43
|
+
Log4r::YamlConfigurator.load_yaml_file(config_file)
|
44
|
+
else
|
45
|
+
raise ConfigFileError, %Q<Don't know what format #{config_file} is in.>, config_file
|
46
|
+
end
|
47
|
+
|
48
|
+
if Log4r::Logger['fig'].nil?
|
49
|
+
$stderr.puts %q<A value was provided for --log-config but no "fig" logger was defined.>
|
50
|
+
end
|
51
|
+
rescue Log4r::ConfigError, ArgumentError => exception
|
52
|
+
raise Log4rConfigError.new(config_file, exception)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if Log4r::Logger['fig'].nil?
|
57
|
+
@@logger = Log4r::Logger.new('fig')
|
58
|
+
else
|
59
|
+
@@logger = Log4r::Logger['fig']
|
60
|
+
end
|
61
|
+
|
62
|
+
if not config_file and not suppress_default_configuration
|
63
|
+
assign_log_level(@@logger, 'info')
|
64
|
+
setup_default_outputter(@@logger)
|
65
|
+
end
|
66
|
+
|
67
|
+
assign_log_level(@@logger, log_level)
|
68
|
+
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.fatal(data = nil, propagated = nil)
|
73
|
+
@@logger.fatal data, propagated
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.fatal?()
|
77
|
+
return @@logger.fatal?
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.error(data = nil, propagated = nil)
|
81
|
+
@@logger.error data, propagated
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.error?()
|
85
|
+
return @@logger.error?
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.warn(data = nil, propagated = nil)
|
89
|
+
@@logger.warn data, propagated
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.warn?()
|
93
|
+
return @@logger.warn?
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.info(data = nil, propagated = nil)
|
97
|
+
@@logger.info data, propagated
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.info?()
|
101
|
+
return @@logger.info?
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.debug(data = nil, propagated = nil)
|
105
|
+
@@logger.debug data, propagated
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.debug?()
|
109
|
+
return @@logger.debug?
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def self.assign_log_level(logger, string_level)
|
115
|
+
return if string_level.nil?
|
116
|
+
|
117
|
+
level = STRING_TO_LEVEL_MAPPING[string_level.downcase]
|
118
|
+
logger.level = level
|
119
|
+
logger.outputters.each { | outputter | outputter.level = level }
|
120
|
+
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.setup_default_outputter(logger)
|
125
|
+
outputter = Log4r::Outputter.stdout
|
126
|
+
logger.add outputter
|
127
|
+
outputter.formatter = Log4r::PatternFormatter.new :pattern => '%M'
|
128
|
+
|
129
|
+
return
|
130
|
+
end
|
131
|
+
end
|