fig 0.1.77 → 0.1.79
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 +58 -1
- data/bin/fig +1 -1
- data/lib/fig.rb +1 -1
- data/lib/fig/command.rb +3 -3
- data/lib/fig/command/action/dump_package_definition_parsed.rb +5 -4
- data/lib/fig/command/action/list_variables/all_configs.rb +2 -5
- data/lib/fig/command/action/publish_local.rb +1 -1
- data/lib/fig/command/action/role/list_variables_in_a_tree.rb +2 -5
- data/lib/fig/command/action/run_command_line.rb +10 -3
- data/lib/fig/command/action/run_command_statement.rb +1 -1
- data/lib/fig/command/options.rb +8 -7
- data/lib/fig/command/options/parser.rb +1 -1
- data/lib/fig/environment_variables/case_insensitive.rb +1 -1
- data/lib/fig/environment_variables/case_sensitive.rb +1 -1
- data/lib/fig/figrc.rb +10 -10
- data/lib/fig/{not_found_error.rb → file_not_found_error.rb} +1 -1
- data/lib/fig/grammar/v0.rb +174 -173
- data/lib/fig/grammar/v0.treetop +27 -21
- data/lib/fig/grammar/v1.rb +477 -171
- data/lib/fig/grammar/v1.treetop +34 -22
- data/lib/fig/operating_system.rb +139 -60
- data/lib/fig/package.rb +8 -4
- data/lib/fig/package_definition_text_assembler.rb +31 -23
- data/lib/fig/parser.rb +3 -5
- data/lib/fig/parser_package_build_state.rb +15 -14
- data/lib/fig/repository.rb +41 -28
- data/lib/fig/repository_package_publisher.rb +20 -25
- data/lib/fig/runtime_environment.rb +136 -87
- data/lib/fig/statement.rb +15 -116
- data/lib/fig/statement/archive.rb +6 -4
- data/lib/fig/statement/asset.rb +50 -35
- data/lib/fig/statement/command.rb +6 -2
- data/lib/fig/statement/configuration.rb +10 -2
- data/lib/fig/statement/environment_variable.rb +35 -0
- data/lib/fig/statement/grammar_version.rb +6 -2
- data/lib/fig/statement/include.rb +6 -2
- data/lib/fig/statement/override.rb +6 -2
- data/lib/fig/statement/path.rb +7 -8
- data/lib/fig/statement/resource.rb +7 -3
- data/lib/fig/statement/retrieve.rb +10 -2
- data/lib/fig/statement/set.rb +7 -8
- data/lib/fig/string_tokenizer.rb +195 -0
- data/lib/fig/tokenized_string.rb +22 -0
- data/lib/fig/tokenized_string/plain_segment.rb +24 -0
- data/lib/fig/tokenized_string/token.rb +18 -0
- data/lib/fig/unparser.rb +84 -1
- data/lib/fig/unparser/v0.rb +4 -0
- data/lib/fig/unparser/v1.rb +7 -7
- data/lib/fig/url.rb +12 -1
- data/lib/fig/{url_access_error.rb → url_access_disallowed_error.rb} +2 -2
- metadata +129 -128
- data/lib/fig/grammar/v0_asset_location.rb +0 -162
- data/lib/fig/grammar/v0_ish.rb +0 -1356
- data/lib/fig/grammar/v1_asset_location.rb +0 -162
- data/lib/fig/grammar/v2.rb +0 -1478
data/lib/fig/grammar/v1.treetop
CHANGED
@@ -45,29 +45,29 @@ module Fig
|
|
45
45
|
end
|
46
46
|
|
47
47
|
rule archive
|
48
|
-
statement_start:'archive' ws_or_comment+
|
48
|
+
statement_start:'archive' ws_or_comment+ location:asset_location {
|
49
49
|
def to_package_statement(build_state)
|
50
50
|
return build_state.new_asset_statement(
|
51
|
-
Statement::Archive, statement_start,
|
51
|
+
Statement::Archive, statement_start, location
|
52
52
|
)
|
53
53
|
end
|
54
54
|
}
|
55
55
|
end
|
56
56
|
|
57
57
|
rule resource
|
58
|
-
statement_start:'resource' ws_or_comment+
|
58
|
+
statement_start:'resource' ws_or_comment+ location:asset_location {
|
59
59
|
def to_package_statement(build_state)
|
60
60
|
return build_state.new_asset_statement(
|
61
|
-
Statement::Resource, statement_start,
|
61
|
+
Statement::Resource, statement_start, location
|
62
62
|
)
|
63
63
|
end
|
64
64
|
}
|
65
65
|
end
|
66
66
|
|
67
|
-
rule
|
68
|
-
'"' [^"]* '"' /
|
69
|
-
"'" [^']* "'" /
|
70
|
-
[
|
67
|
+
rule asset_location
|
68
|
+
'"' ( [^"\\] / '\\' . )* '"' /
|
69
|
+
"'" ( [^'\\] / '\\' . )* "'" /
|
70
|
+
[^\s#]+
|
71
71
|
end
|
72
72
|
|
73
73
|
rule retrieve
|
@@ -79,6 +79,8 @@ module Fig
|
|
79
79
|
end
|
80
80
|
|
81
81
|
rule retrieve_path
|
82
|
+
# TODO: this should match asset location rules, but handling of
|
83
|
+
# "[package]" substitution is going to be interesting.
|
82
84
|
[a-zA-Z0-9_/.\[\]-]+
|
83
85
|
end
|
84
86
|
|
@@ -130,44 +132,54 @@ module Fig
|
|
130
132
|
}
|
131
133
|
end
|
132
134
|
|
133
|
-
rule
|
134
|
-
|
135
|
+
rule environment_variable_name
|
136
|
+
[a-zA-Z0-9_]+
|
137
|
+
end
|
138
|
+
|
139
|
+
rule set
|
140
|
+
statement_start:'set' ws_or_comment+ environment_variable_name_value {
|
135
141
|
def to_config_statement(build_state)
|
136
142
|
return build_state.new_environment_variable_statement(
|
137
|
-
Statement::
|
143
|
+
Statement::Set, statement_start, environment_variable_name_value
|
138
144
|
)
|
139
145
|
end
|
140
146
|
}
|
141
147
|
end
|
142
148
|
|
143
|
-
rule
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
rule set
|
148
|
-
statement_start:'set' ws_or_comment+ name_value:[\S]+ {
|
149
|
+
rule path
|
150
|
+
statement_start:('add' / 'append' / 'path') ws_or_comment+ environment_variable_name_value {
|
149
151
|
def to_config_statement(build_state)
|
150
152
|
return build_state.new_environment_variable_statement(
|
151
|
-
Statement::
|
153
|
+
Statement::Path, statement_start, environment_variable_name_value
|
152
154
|
)
|
153
155
|
end
|
154
156
|
}
|
155
157
|
end
|
156
158
|
|
159
|
+
rule environment_variable_name_value
|
160
|
+
# Should result in somewhat reasonable handling by Treetop when
|
161
|
+
# encountering mis-quoted constructs.
|
162
|
+
[^\s#\\"]* '"' ( [^"\\] / '\\' . )* '"' /
|
163
|
+
[^\s#\\']* "'" ( [^'\\] / '\\' . )* "'" /
|
164
|
+
[^\s#]+
|
165
|
+
end
|
166
|
+
|
157
167
|
rule command
|
158
|
-
statement_start:'command' ws_or_comment+
|
168
|
+
statement_start:'command' ws_or_comment+ command_line {
|
159
169
|
def to_config_statement(build_state)
|
160
|
-
return build_state.new_command_statement(
|
170
|
+
return build_state.new_command_statement(
|
171
|
+
statement_start, command_line
|
172
|
+
)
|
161
173
|
end
|
162
174
|
}
|
163
175
|
end
|
164
176
|
|
165
|
-
rule
|
177
|
+
rule command_line
|
166
178
|
'"' value:[^"]* '"'
|
167
179
|
end
|
168
180
|
|
169
181
|
rule descriptor_string
|
170
|
-
[
|
182
|
+
[^\s#]+
|
171
183
|
end
|
172
184
|
end
|
173
185
|
end
|
data/lib/fig/operating_system.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'cgi'
|
1
2
|
require 'fileutils'
|
2
3
|
require 'find'
|
3
4
|
# Must specify absolute path of ::Archive when using
|
@@ -16,15 +17,54 @@ require 'highline/import'
|
|
16
17
|
require 'fig/at_exit'
|
17
18
|
require 'fig/environment_variables/case_insensitive'
|
18
19
|
require 'fig/environment_variables/case_sensitive'
|
20
|
+
require 'fig/file_not_found_error'
|
19
21
|
require 'fig/logging'
|
20
22
|
require 'fig/network_error'
|
21
|
-
require 'fig/not_found_error'
|
22
23
|
|
23
24
|
module Fig; end
|
24
25
|
|
25
26
|
# Does things requiring real O/S interaction, primarilly taking care of file
|
26
27
|
# transfers and running external commands.
|
27
28
|
class Fig::OperatingSystem
|
29
|
+
WINDOWS_FILE_NAME_ILLEGAL_CHARACTERS = %w[ \\ / : * ? " < > | ]
|
30
|
+
UNIX_FILE_NAME_ILLEGAL_CHARACTERS = %w[ / ]
|
31
|
+
|
32
|
+
def self.windows?
|
33
|
+
RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.java?
|
37
|
+
RUBY_PLATFORM == 'java'
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.unix?
|
41
|
+
!windows?
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.file_name_illegal_characters()
|
45
|
+
if Fig::OperatingSystem.windows?
|
46
|
+
return WINDOWS_FILE_NAME_ILLEGAL_CHARACTERS
|
47
|
+
end
|
48
|
+
|
49
|
+
return UNIX_FILE_NAME_ILLEGAL_CHARACTERS
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.wrap_variable_name_with_shell_expansion(variable_name)
|
53
|
+
if Fig::OperatingSystem.windows?
|
54
|
+
return "%#{variable_name}%"
|
55
|
+
else
|
56
|
+
return "$#{variable_name}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.get_environment_variables(initial_values = nil)
|
61
|
+
if Fig::OperatingSystem.windows?
|
62
|
+
return Fig::EnvironmentVariables::CaseInsensitive.new(initial_values)
|
63
|
+
end
|
64
|
+
|
65
|
+
return Fig::EnvironmentVariables::CaseSensitive.new(initial_values)
|
66
|
+
end
|
67
|
+
|
28
68
|
def initialize(login)
|
29
69
|
@login = login
|
30
70
|
@username = ENV['FIG_USERNAME']
|
@@ -67,10 +107,6 @@ class Fig::OperatingSystem
|
|
67
107
|
File.open(path, 'wb') { |f| f.binmode; f << content }
|
68
108
|
end
|
69
109
|
|
70
|
-
SUCCESS = 0
|
71
|
-
NOT_MODIFIED = 3
|
72
|
-
NOT_FOUND = 4
|
73
|
-
|
74
110
|
def strip_paths_for_list(ls_output, packages, path)
|
75
111
|
if not ls_output.nil?
|
76
112
|
ls_output = ls_output.gsub(path + '/', '').gsub(path, '').split("\n")
|
@@ -106,12 +142,13 @@ class Fig::OperatingSystem
|
|
106
142
|
packages
|
107
143
|
when 'file'
|
108
144
|
packages = []
|
109
|
-
|
145
|
+
unescaped_path = CGI.unescape uri.path
|
146
|
+
return packages if ! File.exist?(unescaped_path)
|
110
147
|
|
111
148
|
ls = ''
|
112
|
-
Find.find(
|
149
|
+
Find.find(unescaped_path) { |file| ls << file.to_s; ls << "\n" }
|
113
150
|
|
114
|
-
strip_paths_for_list(ls, packages,
|
151
|
+
strip_paths_for_list(ls, packages, unescaped_path)
|
115
152
|
return packages
|
116
153
|
else
|
117
154
|
Fig::Logging.fatal "Protocol not supported: #{url}"
|
@@ -158,6 +195,49 @@ class Fig::OperatingSystem
|
|
158
195
|
all_packages.flatten.sort
|
159
196
|
end
|
160
197
|
|
198
|
+
# Determine whether we need to update something. Returns nil to indicate
|
199
|
+
# "don't know".
|
200
|
+
def path_up_to_date?(url, path)
|
201
|
+
return false if ! File.exist? path
|
202
|
+
|
203
|
+
uri = URI.parse(url)
|
204
|
+
case uri.scheme
|
205
|
+
when 'ftp'
|
206
|
+
begin
|
207
|
+
ftp = Net::FTP.new(uri.host)
|
208
|
+
ftp_login(ftp, uri.host)
|
209
|
+
|
210
|
+
if ftp.mtime(uri.path) <= File.mtime(path)
|
211
|
+
return true
|
212
|
+
end
|
213
|
+
|
214
|
+
return false
|
215
|
+
rescue Net::FTPPermError => error
|
216
|
+
Fig::Logging.debug error.message
|
217
|
+
raise Fig::FileNotFoundError.new error.message, url
|
218
|
+
rescue SocketError => error
|
219
|
+
Fig::Logging.debug error.message
|
220
|
+
raise Fig::FileNotFoundError.new error.message, url
|
221
|
+
end
|
222
|
+
when 'http'
|
223
|
+
return nil # Not implemented
|
224
|
+
when 'ssh'
|
225
|
+
when 'file'
|
226
|
+
begin
|
227
|
+
unescaped_path = CGI.unescape uri.path
|
228
|
+
if File.mtime(unescaped_path) <= File.mtime(path)
|
229
|
+
return true
|
230
|
+
end
|
231
|
+
|
232
|
+
return false
|
233
|
+
rescue Errno::ENOENT => error
|
234
|
+
raise Fig::FileNotFoundError.new error.message, url
|
235
|
+
end
|
236
|
+
else
|
237
|
+
raise_unknown_protocol(url)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
161
241
|
# Returns whether the file was not downloaded because the file already
|
162
242
|
# exists and is already up-to-date.
|
163
243
|
def download(url, path)
|
@@ -179,10 +259,10 @@ class Fig::OperatingSystem
|
|
179
259
|
end
|
180
260
|
rescue Net::FTPPermError => error
|
181
261
|
Fig::Logging.debug error.message
|
182
|
-
raise Fig::
|
262
|
+
raise Fig::FileNotFoundError.new error.message, url
|
183
263
|
rescue SocketError => error
|
184
264
|
Fig::Logging.debug error.message
|
185
|
-
raise Fig::
|
265
|
+
raise Fig::FileNotFoundError.new error.message, url
|
186
266
|
end
|
187
267
|
when 'http'
|
188
268
|
log_download(url, path)
|
@@ -193,29 +273,29 @@ class Fig::OperatingSystem
|
|
193
273
|
download_via_http_get(url, file)
|
194
274
|
rescue SystemCallError => error
|
195
275
|
Fig::Logging.debug error.message
|
196
|
-
raise Fig::
|
276
|
+
raise Fig::FileNotFoundError.new error.message, url
|
197
277
|
rescue SocketError => error
|
198
278
|
Fig::Logging.debug error.message
|
199
|
-
raise Fig::
|
279
|
+
raise Fig::FileNotFoundError.new error.message, url
|
200
280
|
end
|
201
281
|
end
|
202
282
|
when 'ssh'
|
203
283
|
# TODO need better way to do conditional download
|
204
284
|
timestamp = File.exist?(path) ? File.mtime(path).to_i : 0
|
205
285
|
# Requires that remote installation of fig be at the same location as the local machine.
|
206
|
-
|
286
|
+
command = `which fig-download`.strip + " #{timestamp} #{uri.path}"
|
207
287
|
log_download(url, path)
|
208
|
-
ssh_download(uri.user, uri.host, path,
|
288
|
+
ssh_download(uri.user, uri.host, path, command)
|
209
289
|
when 'file'
|
210
290
|
begin
|
211
|
-
|
291
|
+
unescaped_path = CGI.unescape uri.path
|
292
|
+
FileUtils.cp(unescaped_path, path)
|
212
293
|
return true
|
213
294
|
rescue Errno::ENOENT => error
|
214
|
-
raise Fig::
|
295
|
+
raise Fig::FileNotFoundError.new error.message, url
|
215
296
|
end
|
216
297
|
else
|
217
|
-
|
218
|
-
raise Fig::NetworkError.new("Unknown protocol: #{url}")
|
298
|
+
raise_unknown_protocol(url)
|
219
299
|
end
|
220
300
|
end
|
221
301
|
|
@@ -223,7 +303,7 @@ class Fig::OperatingSystem
|
|
223
303
|
def download_resource(url, download_directory)
|
224
304
|
FileUtils.mkdir_p(download_directory)
|
225
305
|
|
226
|
-
basename = URI.parse(url).path.split('/').last
|
306
|
+
basename = CGI.unescape URI.parse(url).path.split('/').last
|
227
307
|
path = File.join(download_directory, basename)
|
228
308
|
|
229
309
|
download(url, path)
|
@@ -234,7 +314,7 @@ class Fig::OperatingSystem
|
|
234
314
|
def download_and_unpack_archive(url, download_directory)
|
235
315
|
basename, path = download_resource(url, download_directory)
|
236
316
|
|
237
|
-
case
|
317
|
+
case path
|
238
318
|
when /\.tar\.gz$/
|
239
319
|
unpack_archive(download_directory, path)
|
240
320
|
when /\.tgz$/
|
@@ -265,8 +345,8 @@ class Fig::OperatingSystem
|
|
265
345
|
ftp_root_dirs = ftp_uri.path.split('/')
|
266
346
|
remote_publish_path = uri.path[0, uri.path.rindex('/')]
|
267
347
|
remote_publish_dirs = remote_publish_path.split('/')
|
268
|
-
# Use array subtraction to deduce which project/version folder to upload
|
269
|
-
# i.e. [1,2,3] - [2,3,4] = [1]
|
348
|
+
# Use array subtraction to deduce which project/version folder to upload
|
349
|
+
# to, i.e. [1,2,3] - [2,3,4] = [1]
|
270
350
|
remote_project_dirs = remote_publish_dirs - ftp_root_dirs
|
271
351
|
Net::FTP.open(uri.host) do |ftp|
|
272
352
|
ftp_login(ftp, uri.host)
|
@@ -284,11 +364,11 @@ class Fig::OperatingSystem
|
|
284
364
|
ftp.putbinaryfile(local_file)
|
285
365
|
end
|
286
366
|
when 'file'
|
287
|
-
|
288
|
-
FileUtils.
|
367
|
+
unescaped_path = CGI.unescape uri.path
|
368
|
+
FileUtils.mkdir_p(File.dirname(unescaped_path))
|
369
|
+
FileUtils.cp(local_file, unescaped_path)
|
289
370
|
else
|
290
|
-
|
291
|
-
raise Fig::NetworkError.new("Unknown protocol: #{uri}")
|
371
|
+
raise_unknown_protocol(uri)
|
292
372
|
end
|
293
373
|
end
|
294
374
|
|
@@ -370,58 +450,48 @@ class Fig::OperatingSystem
|
|
370
450
|
end
|
371
451
|
end
|
372
452
|
|
373
|
-
def
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
end
|
380
|
-
|
381
|
-
def self.unix?
|
382
|
-
!windows?
|
453
|
+
def shell_exec(command)
|
454
|
+
if Fig::OperatingSystem.windows?
|
455
|
+
plain_exec( [ ENV['ComSpec'], '/c', command.join(' ') ] )
|
456
|
+
else
|
457
|
+
plain_exec( [ ENV['SHELL'], '-c', command.join(' ') ] )
|
458
|
+
end
|
383
459
|
end
|
384
460
|
|
385
|
-
def
|
461
|
+
def plain_exec(command)
|
386
462
|
# Kernel#exec won't run Kernel#at_exit handlers.
|
387
463
|
Fig::AtExit.execute()
|
388
464
|
if ENV['FIG_COVERAGE']
|
389
465
|
SimpleCov.at_exit.call
|
390
466
|
end
|
391
467
|
|
392
|
-
|
393
|
-
Kernel.exec(ENV['ComSpec'], '/c', cmd.join(' '))
|
394
|
-
else
|
395
|
-
Kernel.exec(ENV['SHELL'], '-c', cmd.join(' '))
|
396
|
-
end
|
468
|
+
Kernel.exec(*command)
|
397
469
|
end
|
398
470
|
|
399
|
-
|
400
|
-
|
401
|
-
|
471
|
+
# *sigh* Apparently Ruby < v1.9.3 does some wacko thing with single argument
|
472
|
+
# exec that causes it to not invoke the shell, so we've got this mess.
|
473
|
+
def plain_or_shell_exec(command)
|
474
|
+
if command.size > 1
|
475
|
+
plain_exec(command)
|
402
476
|
else
|
403
|
-
|
477
|
+
shell_exec(command)
|
404
478
|
end
|
405
479
|
end
|
406
480
|
|
407
|
-
def self.get_environment_variables(initial_values = nil)
|
408
|
-
if Fig::OperatingSystem.windows?
|
409
|
-
return Fig::EnvironmentVariables::CaseInsensitive.new(initial_values)
|
410
|
-
end
|
411
|
-
|
412
|
-
return Fig::EnvironmentVariables::CaseSensitive.new(initial_values)
|
413
|
-
end
|
414
|
-
|
415
481
|
private
|
416
482
|
|
483
|
+
SUCCESS = 0
|
484
|
+
NOT_MODIFIED = 3
|
485
|
+
NOT_FOUND = 4
|
486
|
+
|
417
487
|
# path = The local path the file should be downloaded to.
|
418
|
-
#
|
419
|
-
def ssh_download(user, host, path,
|
488
|
+
# command = The command to be run on the remote host.
|
489
|
+
def ssh_download(user, host, path, command)
|
420
490
|
return_code = nil
|
421
491
|
tempfile = Tempfile.new('tmp')
|
422
492
|
Net::SSH.start(host, user) do |ssh|
|
423
493
|
ssh.open_channel do |channel|
|
424
|
-
channel.exec(
|
494
|
+
channel.exec(command)
|
425
495
|
channel.on_data() { |ch, data| tempfile << data }
|
426
496
|
channel.on_extended_data() { |ch, type, data| Fig::Logging.error "SSH Download ERROR: #{data}" }
|
427
497
|
channel.on_request('exit-status') { |ch, request|
|
@@ -438,7 +508,7 @@ class Fig::OperatingSystem
|
|
438
508
|
return false
|
439
509
|
when NOT_FOUND
|
440
510
|
tempfile.delete
|
441
|
-
raise Fig::
|
511
|
+
raise Fig::FileNotFoundError.new 'Remote path not found', path
|
442
512
|
when SUCCESS
|
443
513
|
FileUtils.mv(tempfile.path, path)
|
444
514
|
return true
|
@@ -463,7 +533,7 @@ class Fig::OperatingSystem
|
|
463
533
|
def download_via_http_get(uri_string, file, redirection_limit = 10)
|
464
534
|
if redirection_limit < 1
|
465
535
|
Fig::Logging.debug 'Too many HTTP redirects.'
|
466
|
-
raise Fig::
|
536
|
+
raise Fig::FileNotFoundError.new 'Too many HTTP redirects.', uri_string
|
467
537
|
end
|
468
538
|
|
469
539
|
response = Net::HTTP.get_response(URI(uri_string))
|
@@ -477,7 +547,7 @@ class Fig::OperatingSystem
|
|
477
547
|
download_via_http_get(location, file, limit - 1)
|
478
548
|
else
|
479
549
|
Fig::Logging.debug "Download failed: #{response.code} #{response.message}."
|
480
|
-
raise Fig::
|
550
|
+
raise Fig::FileNotFoundError.new(
|
481
551
|
"Download failed: #{response.code} #{response.message}.", uri_string
|
482
552
|
)
|
483
553
|
end
|
@@ -485,6 +555,15 @@ class Fig::OperatingSystem
|
|
485
555
|
return
|
486
556
|
end
|
487
557
|
|
558
|
+
def raise_unknown_protocol(url)
|
559
|
+
Fig::Logging.fatal %Q<Don't know how to handle the protocol in "#{url}".>
|
560
|
+
raise Fig::NetworkError.new(
|
561
|
+
%Q<Don't know how to handle the protocol in "#{url}".>
|
562
|
+
)
|
563
|
+
|
564
|
+
return
|
565
|
+
end
|
566
|
+
|
488
567
|
def log_download(url, path)
|
489
568
|
Fig::Logging.debug "Downloading #{url} to #{path}."
|
490
569
|
end
|