fig 1.0.0 → 1.1.0
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 +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
|