fig 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +43 -0
- data/lib/fig.rb +1 -1
- data/lib/fig/command.rb +6 -5
- data/lib/fig/command/action/list_dependencies/graphviz.rb +42 -0
- data/lib/fig/command/action/list_dependencies/graphviz_all_configs.rb +42 -0
- data/lib/fig/command/action/list_variables/all_configs.rb +1 -1
- data/lib/fig/command/action/list_variables/graphviz.rb +22 -0
- data/lib/fig/command/action/list_variables/graphviz_all_configs.rb +22 -0
- data/lib/fig/command/action/role/list_as_graphviz.rb +80 -0
- data/lib/fig/command/action/role/list_dependencies_as_graphviz.rb +25 -0
- data/lib/fig/command/action/role/list_dependencies_in_a_tree.rb +1 -1
- data/lib/fig/command/action/role/list_variables_as_graphviz.rb +76 -0
- data/lib/fig/command/action/role/list_variables_in_a_tree.rb +1 -1
- data/lib/fig/command/action/role/list_walking_dependency_tree.rb +70 -39
- data/lib/fig/command/options.rb +44 -11
- data/lib/fig/command/options/parser.rb +7 -2
- data/lib/fig/figrc.rb +4 -6
- data/lib/fig/operating_system.rb +32 -336
- data/lib/fig/package_descriptor.rb +3 -2
- data/lib/fig/protocol.rb +47 -0
- data/lib/fig/protocol/file.rb +64 -0
- data/lib/fig/protocol/ftp.rb +162 -0
- data/lib/fig/protocol/http.rb +61 -0
- data/lib/fig/protocol/netrc_enabled.rb +42 -0
- data/lib/fig/protocol/sftp.rb +150 -0
- metadata +55 -44
- data/bin/fig-download +0 -23
data/lib/fig/command/options.rb
CHANGED
@@ -9,6 +9,8 @@ require 'fig/command/action/list_configs'
|
|
9
9
|
require 'fig/command/action/list_dependencies'
|
10
10
|
require 'fig/command/action/list_dependencies/all_configs'
|
11
11
|
require 'fig/command/action/list_dependencies/default'
|
12
|
+
require 'fig/command/action/list_dependencies/graphviz'
|
13
|
+
require 'fig/command/action/list_dependencies/graphviz_all_configs'
|
12
14
|
require 'fig/command/action/list_dependencies/tree'
|
13
15
|
require 'fig/command/action/list_dependencies/tree_all_configs'
|
14
16
|
require 'fig/command/action/list_local'
|
@@ -16,6 +18,8 @@ require 'fig/command/action/list_remote'
|
|
16
18
|
require 'fig/command/action/list_variables'
|
17
19
|
require 'fig/command/action/list_variables/all_configs'
|
18
20
|
require 'fig/command/action/list_variables/default'
|
21
|
+
require 'fig/command/action/list_variables/graphviz'
|
22
|
+
require 'fig/command/action/list_variables/graphviz_all_configs'
|
19
23
|
require 'fig/command/action/list_variables/tree'
|
20
24
|
require 'fig/command/action/list_variables/tree_all_configs'
|
21
25
|
require 'fig/command/action/options'
|
@@ -163,6 +167,10 @@ class Fig::Command::Options
|
|
163
167
|
return @list_tree
|
164
168
|
end
|
165
169
|
|
170
|
+
def graphviz?()
|
171
|
+
return @graphviz
|
172
|
+
end
|
173
|
+
|
166
174
|
def strip_shell_command(argv)
|
167
175
|
argv.each_with_index do |arg, i|
|
168
176
|
case arg
|
@@ -308,6 +316,13 @@ class Fig::Command::Options
|
|
308
316
|
@list_tree = true
|
309
317
|
end
|
310
318
|
|
319
|
+
@parser.on(
|
320
|
+
'--graphviz',
|
321
|
+
'for listings, output DOT (http://graphviz.org/content/dot-language)'
|
322
|
+
) do
|
323
|
+
@graphviz = true
|
324
|
+
end
|
325
|
+
|
311
326
|
@parser.on(
|
312
327
|
'--list-all-configs',
|
313
328
|
'for listings, follow all configurations of the base package'
|
@@ -523,7 +538,7 @@ class Fig::Command::Options
|
|
523
538
|
end
|
524
539
|
|
525
540
|
@parser.on(
|
526
|
-
'-l', '--login', 'login to
|
541
|
+
'-l', '--login', 'login to FTP repo as a non-anonymous user'
|
527
542
|
) do
|
528
543
|
@login = true
|
529
544
|
end
|
@@ -678,6 +693,12 @@ class Fig::Command::Options
|
|
678
693
|
raise Fig::Command::OptionError.new(
|
679
694
|
'Cannot use --suppress-all-includes/--suppress-cross-package-includes with --list-tree.'
|
680
695
|
)
|
696
|
+
elsif graphviz?
|
697
|
+
# Not conceptually incompatible, just not implemented (would need to
|
698
|
+
# handle in command/action/role/list_*)
|
699
|
+
raise Fig::Command::OptionError.new(
|
700
|
+
'Cannot use --suppress-all-includes/--suppress-cross-package-includes with --graphviz.'
|
701
|
+
)
|
681
702
|
elsif list_all_configs?
|
682
703
|
# Not conceptually incompatible, just not implemented (would need to
|
683
704
|
# handle in command/action/role/list_*)
|
@@ -696,17 +717,27 @@ class Fig::Command::Options
|
|
696
717
|
)
|
697
718
|
end
|
698
719
|
elsif list_tree?
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
)
|
703
|
-
end
|
720
|
+
validate_list_option '--list-tree'
|
721
|
+
elsif graphviz?
|
722
|
+
validate_list_option '--graphviz'
|
704
723
|
elsif list_all_configs?
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
724
|
+
validate_list_option '--list-all-configs'
|
725
|
+
end
|
726
|
+
|
727
|
+
if list_tree? && graphviz?
|
728
|
+
raise Fig::Command::OptionError.new(
|
729
|
+
'Cannot use --list-tree and --graphviz at the same time.'
|
730
|
+
)
|
731
|
+
end
|
732
|
+
|
733
|
+
return
|
734
|
+
end
|
735
|
+
|
736
|
+
def validate_list_option(option)
|
737
|
+
if ! @base_action.list_dependencies? && ! @base_action.list_variables?
|
738
|
+
raise Fig::Command::OptionError.new(
|
739
|
+
%Q<The #{option} option isn't useful without --list-dependencies/--list-variables.>
|
740
|
+
)
|
710
741
|
end
|
711
742
|
|
712
743
|
return
|
@@ -720,6 +751,8 @@ class Fig::Command::Options
|
|
720
751
|
sub_action_name = :Default
|
721
752
|
if list_tree?
|
722
753
|
sub_action_name = list_all_configs? ? :TreeAllConfigs : :Tree
|
754
|
+
elsif graphviz?
|
755
|
+
sub_action_name = list_all_configs? ? :GraphvizAllConfigs : :Graphviz
|
723
756
|
elsif list_all_configs?
|
724
757
|
sub_action_name = :AllConfigs
|
725
758
|
end
|
@@ -63,13 +63,18 @@ Querying:
|
|
63
63
|
|
64
64
|
fig {--list-local | --list-remote} [...]
|
65
65
|
fig {-g | --get} VARIABLE [DESCRIPTOR] [...]
|
66
|
-
fig --list-dependencies [
|
67
|
-
fig --list-variables [
|
66
|
+
fig --list-dependencies [...list options...] [DESCRIPTOR] [...]
|
67
|
+
fig --list-variables [...list options...] [DESCRIPTOR] [...]
|
68
68
|
fig --list-configs [DESCRIPTOR] [...]
|
69
69
|
fig --dump-package-definition-text [DESCRIPTOR] [...]
|
70
70
|
fig --dump-package-definition-parsed [DESCRIPTOR] [...]
|
71
71
|
fig --dump-package-definition-for-command-line [DESCRIPTOR] [...]
|
72
72
|
|
73
|
+
List options (represented as "[...list options...]" above):
|
74
|
+
|
75
|
+
[--list-tree | --graphviz]
|
76
|
+
[--list-all-configs]
|
77
|
+
|
73
78
|
Standard options (represented as "[...]" above):
|
74
79
|
|
75
80
|
[-u | --update | -m | --update-if-missing]
|
data/lib/fig/figrc.rb
CHANGED
@@ -17,7 +17,7 @@ class Fig::FigRC
|
|
17
17
|
def self.find(
|
18
18
|
override_path,
|
19
19
|
specified_repository_url,
|
20
|
-
|
20
|
+
operating_system,
|
21
21
|
fig_home,
|
22
22
|
disable_figrc = false
|
23
23
|
)
|
@@ -33,7 +33,7 @@ class Fig::FigRC
|
|
33
33
|
configuration.remote_repository_url = repository_url
|
34
34
|
|
35
35
|
handle_repository_configuration(
|
36
|
-
configuration, repository_url,
|
36
|
+
configuration, repository_url, operating_system, fig_home
|
37
37
|
)
|
38
38
|
|
39
39
|
return configuration
|
@@ -77,7 +77,7 @@ class Fig::FigRC
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def self.handle_repository_configuration(
|
80
|
-
configuration, repository_url,
|
80
|
+
configuration, repository_url, operating_system, fig_home
|
81
81
|
)
|
82
82
|
return if repository_url.nil?
|
83
83
|
|
@@ -85,11 +85,9 @@ class Fig::FigRC
|
|
85
85
|
repo_figrc_path =
|
86
86
|
File.expand_path(File.join(fig_home, REPOSITORY_CONFIGURATION))
|
87
87
|
|
88
|
-
os = Fig::OperatingSystem.new(login)
|
89
|
-
|
90
88
|
repo_config_exists = nil
|
91
89
|
begin
|
92
|
-
|
90
|
+
operating_system.download figrc_url, repo_figrc_path
|
93
91
|
repo_config_exists = true
|
94
92
|
rescue Fig::FileNotFoundError
|
95
93
|
repo_config_exists = false
|
data/lib/fig/operating_system.rb
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
require 'fileutils'
|
3
|
-
require 'find'
|
4
3
|
# Must specify absolute path of ::Archive when using
|
5
4
|
# this module to avoid conflicts with Fig::Statement::Archive
|
6
5
|
require 'libarchive_ruby'
|
7
|
-
require 'net/http'
|
8
|
-
require 'net/ssh'
|
9
|
-
require 'net/sftp'
|
10
|
-
require 'net/netrc'
|
11
6
|
require 'rbconfig'
|
12
|
-
require 'tempfile'
|
13
|
-
|
14
|
-
require 'highline/import'
|
15
7
|
|
16
8
|
require 'fig/at_exit'
|
17
9
|
require 'fig/environment_variables/case_insensitive'
|
18
10
|
require 'fig/environment_variables/case_sensitive'
|
19
|
-
require 'fig/file_not_found_error'
|
20
11
|
require 'fig/logging'
|
21
12
|
require 'fig/network_error'
|
13
|
+
require 'fig/protocol/file'
|
14
|
+
require 'fig/protocol/ftp'
|
15
|
+
require 'fig/protocol/http'
|
16
|
+
require 'fig/protocol/sftp'
|
22
17
|
require 'fig/repository_error'
|
23
18
|
require 'fig/url'
|
24
19
|
require 'fig/user_input_error'
|
@@ -64,33 +59,11 @@ class Fig::OperatingSystem
|
|
64
59
|
end
|
65
60
|
|
66
61
|
def initialize(login)
|
67
|
-
@
|
68
|
-
@
|
69
|
-
@
|
70
|
-
|
71
|
-
|
72
|
-
def get_username()
|
73
|
-
# #ask() comes from highline
|
74
|
-
@username ||= ask('Username: ') { |q| q.echo = true }
|
75
|
-
end
|
76
|
-
|
77
|
-
def get_password()
|
78
|
-
# #ask() comes from highline
|
79
|
-
@password ||= ask('Password: ') { |q| q.echo = false }
|
80
|
-
end
|
81
|
-
|
82
|
-
def ftp_login(ftp, host)
|
83
|
-
if @login
|
84
|
-
rc = Net::Netrc.locate(host)
|
85
|
-
if rc
|
86
|
-
@username = rc.login
|
87
|
-
@password = rc.password
|
88
|
-
end
|
89
|
-
ftp.login(get_username, get_password)
|
90
|
-
else
|
91
|
-
ftp.login()
|
92
|
-
end
|
93
|
-
ftp.passive = true
|
62
|
+
@protocols = {}
|
63
|
+
@protocols['file'] = Fig::Protocol::File.new
|
64
|
+
@protocols['ftp'] = Fig::Protocol::FTP.new login
|
65
|
+
@protocols['http'] = Fig::Protocol::HTTP.new
|
66
|
+
@protocols['sftp'] = Fig::Protocol::SFTP.new
|
94
67
|
end
|
95
68
|
|
96
69
|
def list(dir)
|
@@ -105,55 +78,11 @@ class Fig::OperatingSystem
|
|
105
78
|
File.open(path, 'wb') { |f| f.binmode; f << content }
|
106
79
|
end
|
107
80
|
|
108
|
-
def strip_paths_for_list(ls_output, packages, path)
|
109
|
-
if not ls_output.nil?
|
110
|
-
ls_output = ls_output.gsub(path + '/', '').gsub(path, '').split("\n")
|
111
|
-
ls_output.each do |line|
|
112
|
-
parts = line.gsub(/\\/, '/').sub(/^\.\//, '').sub(/:$/, '').chomp().split('/')
|
113
|
-
packages << parts.join('/') if parts.size == 2
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
81
|
def download_list(url)
|
119
82
|
begin
|
120
|
-
uri =
|
121
|
-
rescue
|
122
|
-
Fig::Logging.fatal %Q<Unable to parse url: "#{url}">
|
123
|
-
raise Fig::NetworkError.new
|
124
|
-
end
|
83
|
+
protocol, uri = decode_protocol url
|
125
84
|
|
126
|
-
|
127
|
-
case uri.scheme
|
128
|
-
when 'ftp'
|
129
|
-
ftp = Net::FTP.new(uri.host)
|
130
|
-
ftp_login(ftp, uri.host)
|
131
|
-
ftp.chdir(uri.path)
|
132
|
-
dirs = ftp.nlst
|
133
|
-
ftp.close
|
134
|
-
|
135
|
-
download_ftp_list(uri, dirs)
|
136
|
-
when 'ssh'
|
137
|
-
packages = []
|
138
|
-
Net::SSH.start(uri.host, uri.user) do |ssh|
|
139
|
-
ls = ssh.exec!("[ -d #{uri.path} ] && find #{uri.path}")
|
140
|
-
strip_paths_for_list(ls, packages, uri.path)
|
141
|
-
end
|
142
|
-
packages
|
143
|
-
when 'file'
|
144
|
-
packages = []
|
145
|
-
unescaped_path = CGI.unescape uri.path
|
146
|
-
return packages if ! File.exist?(unescaped_path)
|
147
|
-
|
148
|
-
ls = ''
|
149
|
-
Find.find(unescaped_path) { |file| ls << file.to_s; ls << "\n" }
|
150
|
-
|
151
|
-
strip_paths_for_list(ls, packages, unescaped_path)
|
152
|
-
return packages
|
153
|
-
else
|
154
|
-
Fig::Logging.fatal "Protocol not supported: #{url}"
|
155
|
-
raise Fig::NetworkError.new "Protocol not supported: #{url}"
|
156
|
-
end
|
85
|
+
return protocol.download_list uri
|
157
86
|
rescue SocketError => error
|
158
87
|
Fig::Logging.debug error.message
|
159
88
|
raise Fig::NetworkError.new "#{url}: #{error.message}"
|
@@ -163,150 +92,23 @@ class Fig::OperatingSystem
|
|
163
92
|
end
|
164
93
|
end
|
165
94
|
|
166
|
-
def download_ftp_list(uri, dirs)
|
167
|
-
# Run a bunch of these in parallel since they're slow as hell
|
168
|
-
num_threads = (ENV['FIG_FTP_THREADS'] || '16').to_i
|
169
|
-
threads = []
|
170
|
-
all_packages = []
|
171
|
-
(0..num_threads-1).each { |num| all_packages[num] = [] }
|
172
|
-
(0..num_threads-1).each do |num|
|
173
|
-
threads << Thread.new do
|
174
|
-
packages = all_packages[num]
|
175
|
-
ftp = Net::FTP.new(uri.host)
|
176
|
-
ftp_login(ftp, uri.host)
|
177
|
-
ftp.chdir(uri.path)
|
178
|
-
pos = num
|
179
|
-
while pos < dirs.length
|
180
|
-
pkg = dirs[pos]
|
181
|
-
begin
|
182
|
-
ftp.nlst(dirs[pos]).each do |ver|
|
183
|
-
packages << pkg + '/' + ver
|
184
|
-
end
|
185
|
-
rescue Net::FTPPermError
|
186
|
-
# Ignore this error because it's indicative of the FTP library
|
187
|
-
# encountering a file or directory that it does not have
|
188
|
-
# permission to open. Fig needs to be able to have secure
|
189
|
-
# repos/packages and there is no way easy way to deal with the
|
190
|
-
# permissions issues other than consuming these errors.
|
191
|
-
#
|
192
|
-
# Actually, with FTP, you can't tell the difference between a
|
193
|
-
# file not existing and not having permission to access it (which
|
194
|
-
# is probably a good thing).
|
195
|
-
end
|
196
|
-
pos += num_threads
|
197
|
-
end
|
198
|
-
ftp.close
|
199
|
-
end
|
200
|
-
end
|
201
|
-
threads.each { |thread| thread.join }
|
202
|
-
all_packages.flatten.sort
|
203
|
-
end
|
204
|
-
|
205
95
|
# Determine whether we need to update something. Returns nil to indicate
|
206
96
|
# "don't know".
|
207
97
|
def path_up_to_date?(url, path)
|
208
98
|
return false if ! File.exist? path
|
209
99
|
|
210
|
-
uri =
|
211
|
-
|
212
|
-
when 'ftp'
|
213
|
-
begin
|
214
|
-
ftp = Net::FTP.new(uri.host)
|
215
|
-
ftp_login(ftp, uri.host)
|
216
|
-
|
217
|
-
if ftp.mtime(uri.path) <= File.mtime(path)
|
218
|
-
return true
|
219
|
-
end
|
220
|
-
|
221
|
-
return false
|
222
|
-
rescue Net::FTPPermError => error
|
223
|
-
Fig::Logging.debug error.message
|
224
|
-
raise Fig::FileNotFoundError.new error.message, url
|
225
|
-
rescue SocketError => error
|
226
|
-
Fig::Logging.debug error.message
|
227
|
-
raise Fig::FileNotFoundError.new error.message, url
|
228
|
-
end
|
229
|
-
when 'http'
|
230
|
-
return nil # Not implemented
|
231
|
-
when 'ssh'
|
232
|
-
when 'file'
|
233
|
-
begin
|
234
|
-
unescaped_path = CGI.unescape uri.path
|
235
|
-
if File.mtime(unescaped_path) <= File.mtime(path)
|
236
|
-
return true
|
237
|
-
end
|
238
|
-
|
239
|
-
return false
|
240
|
-
rescue Errno::ENOENT => error
|
241
|
-
raise Fig::FileNotFoundError.new error.message, url
|
242
|
-
end
|
243
|
-
else
|
244
|
-
raise_unknown_protocol(url)
|
245
|
-
end
|
100
|
+
protocol, uri = decode_protocol url
|
101
|
+
return protocol.path_up_to_date? uri, path
|
246
102
|
end
|
247
103
|
|
248
104
|
# Returns whether the file was not downloaded because the file already
|
249
105
|
# exists and is already up-to-date.
|
250
106
|
def download(url, path)
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
ftp = Net::FTP.new(uri.host)
|
257
|
-
ftp_login(ftp, uri.host)
|
258
|
-
|
259
|
-
if File.exist?(path) && ftp.mtime(uri.path) <= File.mtime(path)
|
260
|
-
Fig::Logging.debug "#{path} is up to date."
|
261
|
-
return false
|
262
|
-
else
|
263
|
-
log_download(url, path)
|
264
|
-
ftp.getbinaryfile(uri.path, path, 256*1024)
|
265
|
-
return true
|
266
|
-
end
|
267
|
-
rescue Net::FTPPermError => error
|
268
|
-
Fig::Logging.debug error.message
|
269
|
-
raise Fig::FileNotFoundError.new error.message, url
|
270
|
-
rescue SocketError => error
|
271
|
-
Fig::Logging.debug error.message
|
272
|
-
raise Fig::FileNotFoundError.new error.message, url
|
273
|
-
rescue Errno::ETIMEDOUT => error
|
274
|
-
Fig::Logging.debug error.message
|
275
|
-
raise Fig::FileNotFoundError.new error.message, url
|
276
|
-
end
|
277
|
-
when 'http'
|
278
|
-
log_download(url, path)
|
279
|
-
File.open(path, 'wb') do |file|
|
280
|
-
file.binmode
|
281
|
-
|
282
|
-
begin
|
283
|
-
download_via_http_get(url, file)
|
284
|
-
rescue SystemCallError => error
|
285
|
-
Fig::Logging.debug error.message
|
286
|
-
raise Fig::FileNotFoundError.new error.message, url
|
287
|
-
rescue SocketError => error
|
288
|
-
Fig::Logging.debug error.message
|
289
|
-
raise Fig::FileNotFoundError.new error.message, url
|
290
|
-
end
|
291
|
-
end
|
292
|
-
when 'ssh'
|
293
|
-
# TODO need better way to do conditional download
|
294
|
-
timestamp = File.exist?(path) ? File.mtime(path).to_i : 0
|
295
|
-
# Requires that remote installation of fig be at the same location as the local machine.
|
296
|
-
command = `which fig-download`.strip + " #{timestamp} #{uri.path}"
|
297
|
-
log_download(url, path)
|
298
|
-
ssh_download(uri.user, uri.host, path, command)
|
299
|
-
when 'file'
|
300
|
-
begin
|
301
|
-
unescaped_path = CGI.unescape uri.path
|
302
|
-
FileUtils.cp(unescaped_path, path)
|
303
|
-
return true
|
304
|
-
rescue Errno::ENOENT => error
|
305
|
-
raise Fig::FileNotFoundError.new error.message, url
|
306
|
-
end
|
307
|
-
else
|
308
|
-
raise_unknown_protocol(url)
|
309
|
-
end
|
107
|
+
protocol, uri = decode_protocol url
|
108
|
+
|
109
|
+
FileUtils.mkdir_p(File.dirname path)
|
110
|
+
|
111
|
+
return protocol.download uri, path
|
310
112
|
end
|
311
113
|
|
312
114
|
# Returns the basename and full path to the download.
|
@@ -343,43 +145,12 @@ class Fig::OperatingSystem
|
|
343
145
|
|
344
146
|
def upload(local_file, remote_file)
|
345
147
|
Fig::Logging.debug "Uploading #{local_file} to #{remote_file}."
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
require 'net/ftp'
|
353
|
-
ftp_uri = Fig::URL.parse(ENV['FIG_REMOTE_URL'])
|
354
|
-
ftp_root_path = ftp_uri.path
|
355
|
-
ftp_root_dirs = ftp_uri.path.split('/')
|
356
|
-
remote_publish_path = uri.path[0, uri.path.rindex('/')]
|
357
|
-
remote_publish_dirs = remote_publish_path.split('/')
|
358
|
-
# Use array subtraction to deduce which project/version folder to upload
|
359
|
-
# to, i.e. [1,2,3] - [2,3,4] = [1]
|
360
|
-
remote_project_dirs = remote_publish_dirs - ftp_root_dirs
|
361
|
-
Net::FTP.open(uri.host) do |ftp|
|
362
|
-
ftp_login(ftp, uri.host)
|
363
|
-
# Assume that the FIG_REMOTE_URL path exists.
|
364
|
-
ftp.chdir(ftp_root_path)
|
365
|
-
remote_project_dirs.each do |dir|
|
366
|
-
# Can't automatically create parent directories, so do it manually.
|
367
|
-
if ftp.nlst().index(dir).nil?
|
368
|
-
ftp.mkdir(dir)
|
369
|
-
ftp.chdir(dir)
|
370
|
-
else
|
371
|
-
ftp.chdir(dir)
|
372
|
-
end
|
373
|
-
end
|
374
|
-
ftp.putbinaryfile(local_file)
|
375
|
-
end
|
376
|
-
when 'file'
|
377
|
-
unescaped_path = CGI.unescape uri.path
|
378
|
-
FileUtils.mkdir_p(File.dirname(unescaped_path))
|
379
|
-
FileUtils.cp(local_file, unescaped_path)
|
380
|
-
else
|
381
|
-
raise_unknown_protocol(uri)
|
382
|
-
end
|
148
|
+
|
149
|
+
|
150
|
+
protocol, uri = decode_protocol remote_file
|
151
|
+
protocol.upload local_file, uri
|
152
|
+
|
153
|
+
return
|
383
154
|
end
|
384
155
|
|
385
156
|
def delete_and_recreate_directory(dir)
|
@@ -397,7 +168,7 @@ class Fig::OperatingSystem
|
|
397
168
|
end
|
398
169
|
else
|
399
170
|
if ! File.exist?(target) || File.mtime(source) != File.mtime(target)
|
400
|
-
|
171
|
+
Fig::Logging.info "#{msg} #{target}" if msg
|
401
172
|
FileUtils.mkdir_p(File.dirname(target))
|
402
173
|
FileUtils.cp(source, target)
|
403
174
|
File.utime(File.atime(source), File.mtime(source), target)
|
@@ -409,10 +180,6 @@ class Fig::OperatingSystem
|
|
409
180
|
Dir.chdir(directory) { FileUtils.mv(from, to, :force => true) }
|
410
181
|
end
|
411
182
|
|
412
|
-
def log_info(msg)
|
413
|
-
Fig::Logging.info msg
|
414
|
-
end
|
415
|
-
|
416
183
|
# Expects files_to_archive as an Array of filenames.
|
417
184
|
def create_archive(archive_name, files_to_archive)
|
418
185
|
# TODO: Need to verify files_to_archive exists.
|
@@ -509,9 +276,13 @@ class Fig::OperatingSystem
|
|
509
276
|
|
510
277
|
private
|
511
278
|
|
512
|
-
|
513
|
-
|
514
|
-
|
279
|
+
def decode_protocol(url)
|
280
|
+
uri = Fig::URL.parse(url)
|
281
|
+
protocol = @protocols[uri.scheme]
|
282
|
+
raise_unknown_protocol(url) if protocol.nil?
|
283
|
+
|
284
|
+
return protocol, uri
|
285
|
+
end
|
515
286
|
|
516
287
|
def check_archive_entry_for_windows(entry, archive_path)
|
517
288
|
bad_type = nil
|
@@ -536,77 +307,6 @@ class Fig::OperatingSystem
|
|
536
307
|
return
|
537
308
|
end
|
538
309
|
|
539
|
-
# path = The local path the file should be downloaded to.
|
540
|
-
# command = The command to be run on the remote host.
|
541
|
-
def ssh_download(user, host, path, command)
|
542
|
-
return_code = nil
|
543
|
-
tempfile = Tempfile.new('tmp')
|
544
|
-
Net::SSH.start(host, user) do |ssh|
|
545
|
-
ssh.open_channel do |channel|
|
546
|
-
channel.exec(command)
|
547
|
-
channel.on_data() { |ch, data| tempfile << data }
|
548
|
-
channel.on_extended_data() { |ch, type, data| Fig::Logging.error "SSH Download ERROR: #{data}" }
|
549
|
-
channel.on_request('exit-status') { |ch, request|
|
550
|
-
return_code = request.read_long
|
551
|
-
}
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
|
-
tempfile.close()
|
556
|
-
|
557
|
-
case return_code
|
558
|
-
when NOT_MODIFIED
|
559
|
-
tempfile.delete
|
560
|
-
return false
|
561
|
-
when NOT_FOUND
|
562
|
-
tempfile.delete
|
563
|
-
raise Fig::FileNotFoundError.new 'Remote path not found', path
|
564
|
-
when SUCCESS
|
565
|
-
FileUtils.mv(tempfile.path, path)
|
566
|
-
return true
|
567
|
-
else
|
568
|
-
tempfile.delete
|
569
|
-
Fig::Logging.fatal "Unable to download file #{path}: #{return_code}"
|
570
|
-
raise Fig::NetworkError.new("Unable to download file #{path}: #{return_code}")
|
571
|
-
end
|
572
|
-
end
|
573
|
-
|
574
|
-
def ssh_upload(user, host, local_file, remote_file)
|
575
|
-
uri = Fig::URL.parse(remote_file)
|
576
|
-
dir = uri.path[0, uri.path.rindex('/')]
|
577
|
-
Net::SSH.start(host, user) do |ssh|
|
578
|
-
ssh.exec!("mkdir -p #{dir}")
|
579
|
-
end
|
580
|
-
Net::SFTP.start(host, user) do |sftp|
|
581
|
-
sftp.upload!(local_file, uri.path)
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
def download_via_http_get(uri_string, file, redirection_limit = 10)
|
586
|
-
if redirection_limit < 1
|
587
|
-
Fig::Logging.debug 'Too many HTTP redirects.'
|
588
|
-
raise Fig::FileNotFoundError.new 'Too many HTTP redirects.', uri_string
|
589
|
-
end
|
590
|
-
|
591
|
-
response = Net::HTTP.get_response(URI(uri_string))
|
592
|
-
|
593
|
-
case response
|
594
|
-
when Net::HTTPSuccess then
|
595
|
-
file.write(response.body)
|
596
|
-
when Net::HTTPRedirection then
|
597
|
-
location = response['location']
|
598
|
-
Fig::Logging.debug "Redirecting to #{location}."
|
599
|
-
download_via_http_get(location, file, redirection_limit - 1)
|
600
|
-
else
|
601
|
-
Fig::Logging.debug "Download failed: #{response.code} #{response.message}."
|
602
|
-
raise Fig::FileNotFoundError.new(
|
603
|
-
"Download failed: #{response.code} #{response.message}.", uri_string
|
604
|
-
)
|
605
|
-
end
|
606
|
-
|
607
|
-
return
|
608
|
-
end
|
609
|
-
|
610
310
|
def raise_unknown_protocol(url)
|
611
311
|
Fig::Logging.fatal %Q<Don't know how to handle the protocol in "#{url}".>
|
612
312
|
raise Fig::NetworkError.new(
|
@@ -615,8 +315,4 @@ class Fig::OperatingSystem
|
|
615
315
|
|
616
316
|
return
|
617
317
|
end
|
618
|
-
|
619
|
-
def log_download(url, path)
|
620
|
-
Fig::Logging.debug "Downloading #{url} to #{path}."
|
621
|
-
end
|
622
318
|
end
|