| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package urpm::download; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
2
|
|
|
2
|
|
8084
|
use strict; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
165
|
|
|
5
|
2
|
|
|
2
|
|
713
|
use urpm::msg; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
use urpm::util qw(cat_ basename dirname file_size max member output_safe reduce_pathname); |
|
7
|
|
|
|
|
|
|
use bytes (); |
|
8
|
|
|
|
|
|
|
use Cwd; |
|
9
|
|
|
|
|
|
|
use Exporter; |
|
10
|
|
|
|
|
|
|
# perl_checker: require urpm |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# help perl_checker: |
|
13
|
|
|
|
|
|
|
sub getcwd { goto &Cwd::getcwd } |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @ISA = 'Exporter'; |
|
16
|
|
|
|
|
|
|
our @EXPORT = qw(get_proxy |
|
17
|
|
|
|
|
|
|
propagate_sync_callback |
|
18
|
|
|
|
|
|
|
sync_file sync_rsync sync_ssh |
|
19
|
|
|
|
|
|
|
set_proxy_config dump_proxy_config |
|
20
|
|
|
|
|
|
|
); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#- proxy config file. |
|
23
|
|
|
|
|
|
|
our $PROXY_CFG = '/etc/urpmi/proxy.cfg'; |
|
24
|
|
|
|
|
|
|
my $proxy_config; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#- Timeout for curl connection and wget operations |
|
27
|
|
|
|
|
|
|
our $CONNECT_TIMEOUT = 60; #- (in seconds) |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 NAME |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
urpm::download - download routines for the urpm* tools |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=over |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=cut |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub ftp_http_downloaders() { qw(curl wget prozilla aria2) } |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub available_ftp_http_downloaders() { |
|
46
|
|
|
|
|
|
|
my %binaries = ( |
|
47
|
|
|
|
|
|
|
curl => 'curl', |
|
48
|
|
|
|
|
|
|
wget => 'wget', |
|
49
|
|
|
|
|
|
|
prozilla => 'proz', |
|
50
|
|
|
|
|
|
|
aria2 => 'aria2c', |
|
51
|
|
|
|
|
|
|
); |
|
52
|
|
|
|
|
|
|
grep { -x "/usr/bin/$binaries{$_}" || -x "/bin/$binaries{$_}" } ftp_http_downloaders(); |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub metalink_downloaders() { qw(aria2) } |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub available_metalink_downloaders() { |
|
58
|
|
|
|
|
|
|
my %binaries = ( |
|
59
|
|
|
|
|
|
|
aria2 => 'aria2c', |
|
60
|
|
|
|
|
|
|
); |
|
61
|
|
|
|
|
|
|
grep { -x "/usr/bin/$binaries{$_}" || -x "/bin/$binaries{$_}" } metalink_downloaders(); |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub use_metalink { |
|
65
|
|
|
|
|
|
|
my ($urpm, $medium) = @_; |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
$medium->{allow_metalink} //= do { |
|
68
|
|
|
|
|
|
|
my $use_metalink = 1; |
|
69
|
|
|
|
|
|
|
preferred_downloader($urpm, $medium, \$use_metalink); |
|
70
|
|
|
|
|
|
|
$use_metalink; |
|
71
|
|
|
|
|
|
|
}; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
my %warned; |
|
75
|
|
|
|
|
|
|
sub preferred_downloader { |
|
76
|
|
|
|
|
|
|
my ($urpm, $medium, $use_metalink) = @_; |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my @available = urpm::download::available_ftp_http_downloaders(); |
|
79
|
|
|
|
|
|
|
my @metalink_downloaders = urpm::download::available_metalink_downloaders(); |
|
80
|
|
|
|
|
|
|
my $metalink_disabled = !$$use_metalink && $medium->{disable_metalink}; |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
if ($$use_metalink && !$metalink_disabled) { |
|
83
|
|
|
|
|
|
|
#- If metalink is used, only aria2 is available as other downloaders doesn't support metalink |
|
84
|
|
|
|
|
|
|
unshift @available, @metalink_downloaders; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
#- first downloader of @available is the default one |
|
88
|
|
|
|
|
|
|
my $preferred = $available[0]; |
|
89
|
|
|
|
|
|
|
my $requested_downloader = requested_ftp_http_downloader($urpm, $medium); |
|
90
|
|
|
|
|
|
|
if ($requested_downloader) { |
|
91
|
|
|
|
|
|
|
if (member($requested_downloader, @available)) { |
|
92
|
|
|
|
|
|
|
#- use user default downloader if provided and available |
|
93
|
|
|
|
|
|
|
$preferred = $requested_downloader; |
|
94
|
|
|
|
|
|
|
} elsif ($warned{webfetch_not_available}++ == 0) { |
|
95
|
|
|
|
|
|
|
$urpm->{log}(N("%s is not available, falling back on %s", $requested_downloader, $preferred)); |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
if ($$use_metalink && !member($preferred, @metalink_downloaders)) { |
|
100
|
|
|
|
|
|
|
$warned{not_using_metalink}++ or |
|
101
|
|
|
|
|
|
|
$urpm->{log}($requested_downloader eq $preferred ? |
|
102
|
|
|
|
|
|
|
"not using metalink since requested downloader does not handle it" : |
|
103
|
|
|
|
|
|
|
"not using metalink since no downloaders handling metalink are available"); |
|
104
|
|
|
|
|
|
|
$$use_metalink = 0; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
$preferred; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub parse_http_proxy { |
|
110
|
|
|
|
|
|
|
$_[0] =~ m!^(?:http://)?([^:/]+(:\d+)?)/*$!; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
#- parses proxy.cfg (private) |
|
114
|
|
|
|
|
|
|
sub load_proxy_config () { |
|
115
|
|
|
|
|
|
|
return if defined $proxy_config; |
|
116
|
|
|
|
|
|
|
$proxy_config = {}; |
|
117
|
|
|
|
|
|
|
foreach (cat_($PROXY_CFG)) { |
|
118
|
|
|
|
|
|
|
chomp; s/#.*$//; s/^\s*//; s/\s*$//; |
|
119
|
|
|
|
|
|
|
if (/^(?:(.*):\s*)?(ftp_proxy|http_proxy)\s*=\s*(.*)$/) { |
|
120
|
|
|
|
|
|
|
$proxy_config->{$1 || ''}{$2} = $3; |
|
121
|
|
|
|
|
|
|
next; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
if (/^(?:(.*):\s*)?proxy_user\s*=\s*([^:]*)(?::(.*))?$/) { |
|
124
|
|
|
|
|
|
|
$proxy_config->{$1 || ''}{user} = $2; |
|
125
|
|
|
|
|
|
|
$proxy_config->{$1 || ''}{pwd} = $3 if defined $3; |
|
126
|
|
|
|
|
|
|
next; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
if (/^(?:(.*):\s*)?proxy_user_ask/) { |
|
129
|
|
|
|
|
|
|
$proxy_config->{$1 || ''}{ask} = 1; |
|
130
|
|
|
|
|
|
|
next; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#- writes proxy.cfg |
|
136
|
|
|
|
|
|
|
sub dump_proxy_config () { |
|
137
|
|
|
|
|
|
|
$proxy_config or return 0; #- hasn't been read yet |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
my $has_password; |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
open my $f, '>', $PROXY_CFG or return 0; |
|
142
|
|
|
|
|
|
|
foreach ('', sort grep { !/^(|cmd_line)$/ } keys %$proxy_config) { |
|
143
|
|
|
|
|
|
|
my $m = $_ eq '' ? '' : "$_:"; |
|
144
|
|
|
|
|
|
|
my $p = $proxy_config->{$_}; |
|
145
|
|
|
|
|
|
|
foreach (qw(http_proxy ftp_proxy)) { |
|
146
|
|
|
|
|
|
|
if (defined $p->{$_} && $p->{$_} ne '') { |
|
147
|
|
|
|
|
|
|
print $f "$m$_=$p->{$_}\n"; |
|
148
|
|
|
|
|
|
|
$has_password ||= hide_password($p->{$_}) ne $p->{$_}; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
if ($p->{ask}) { |
|
152
|
|
|
|
|
|
|
print $f "${m}proxy_user_ask\n"; |
|
153
|
|
|
|
|
|
|
} elsif (defined $p->{user} && $p->{user} ne '') { |
|
154
|
|
|
|
|
|
|
print $f "${m}proxy_user=$p->{user}:$p->{pwd}\n"; |
|
155
|
|
|
|
|
|
|
$has_password ||= $p->{pwd}; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
close $f; |
|
159
|
|
|
|
|
|
|
chmod 0600, $PROXY_CFG if $has_password; |
|
160
|
|
|
|
|
|
|
return 1; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
#- deletes the proxy configuration for the specified media |
|
164
|
|
|
|
|
|
|
sub remove_proxy_media { |
|
165
|
|
|
|
|
|
|
defined $proxy_config and delete $proxy_config->{$_[0] || ''}; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub get_proxy_ { |
|
169
|
|
|
|
|
|
|
my ($urpm) = @_; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
-e $PROXY_CFG && !-r $PROXY_CFG and $urpm->{error}(N("can not read proxy settings (not enough rights to read %s)", $PROXY_CFG)); |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
get_proxy($urpm); |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=item get_proxy($media) |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Reads and loads the proxy.cfg file ; |
|
179
|
|
|
|
|
|
|
Returns the global proxy settings (without arguments) or the |
|
180
|
|
|
|
|
|
|
proxy settings for the specified media (with a media name as argument) |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=cut |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub get_proxy (;$) { |
|
185
|
|
|
|
|
|
|
my ($o_media) = @_; $o_media ||= ''; |
|
186
|
|
|
|
|
|
|
load_proxy_config(); |
|
187
|
|
|
|
|
|
|
my $p = $proxy_config->{cmd_line} |
|
188
|
|
|
|
|
|
|
|| $proxy_config->{$o_media} |
|
189
|
|
|
|
|
|
|
|| $proxy_config->{''} |
|
190
|
|
|
|
|
|
|
|| { |
|
191
|
|
|
|
|
|
|
http_proxy => undef, |
|
192
|
|
|
|
|
|
|
ftp_proxy => undef, |
|
193
|
|
|
|
|
|
|
user => undef, |
|
194
|
|
|
|
|
|
|
pwd => undef, |
|
195
|
|
|
|
|
|
|
}; |
|
196
|
|
|
|
|
|
|
if ($p->{ask} && ($p->{http_proxy} || $p->{ftp_proxy}) && !$p->{user}) { |
|
197
|
|
|
|
|
|
|
our $PROMPT_PROXY; |
|
198
|
|
|
|
|
|
|
unless (defined $PROMPT_PROXY) { |
|
199
|
|
|
|
|
|
|
require urpm::prompt; |
|
200
|
|
|
|
|
|
|
$PROMPT_PROXY = new urpm::prompt( |
|
201
|
|
|
|
|
|
|
N("Please enter your credentials for accessing proxy\n"), |
|
202
|
|
|
|
|
|
|
[ N("User name:"), N("Password:") ], |
|
203
|
|
|
|
|
|
|
undef, |
|
204
|
|
|
|
|
|
|
[ 0, 1 ], |
|
205
|
|
|
|
|
|
|
); |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
($p->{user}, $p->{pwd}) = $PROMPT_PROXY->prompt; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
$p; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
#- copies the settings for proxies from the command line to media named $media |
|
213
|
|
|
|
|
|
|
#- and writes the proxy.cfg file (used when adding new media) |
|
214
|
|
|
|
|
|
|
sub copy_cmd_line_proxy { |
|
215
|
|
|
|
|
|
|
my ($media) = @_; |
|
216
|
|
|
|
|
|
|
return unless $media; |
|
217
|
|
|
|
|
|
|
load_proxy_config(); |
|
218
|
|
|
|
|
|
|
if (defined $proxy_config->{cmd_line}) { |
|
219
|
|
|
|
|
|
|
$proxy_config->{$media} = $proxy_config->{cmd_line}; |
|
220
|
|
|
|
|
|
|
dump_proxy_config(); |
|
221
|
|
|
|
|
|
|
} else { |
|
222
|
|
|
|
|
|
|
#- use default if available |
|
223
|
|
|
|
|
|
|
$proxy_config->{$media} = $proxy_config->{''}; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item set_cmdline_proxy(%h) |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
Overrides the config file proxy settings with values passed via command-line |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub set_cmdline_proxy { |
|
234
|
|
|
|
|
|
|
my (%h) = @_; |
|
235
|
|
|
|
|
|
|
load_proxy_config(); |
|
236
|
|
|
|
|
|
|
$proxy_config->{cmd_line} ||= { |
|
237
|
|
|
|
|
|
|
http_proxy => undef, |
|
238
|
|
|
|
|
|
|
ftp_proxy => undef, |
|
239
|
|
|
|
|
|
|
user => undef, |
|
240
|
|
|
|
|
|
|
pwd => undef, |
|
241
|
|
|
|
|
|
|
}; |
|
242
|
|
|
|
|
|
|
$proxy_config->{cmd_line}{$_} = $h{$_} foreach keys %h; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item set_proxy_config($key, $value, $o_media) |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Changes permanently the proxy settings |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=cut |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub set_proxy_config { |
|
252
|
|
|
|
|
|
|
my ($key, $value, $o_media) = @_; |
|
253
|
|
|
|
|
|
|
$proxy_config->{$o_media || ''}{$key} = $value; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
#- set up the environment for proxy usage for the appropriate tool. |
|
257
|
|
|
|
|
|
|
#- returns an array of command-line arguments for wget or curl. |
|
258
|
|
|
|
|
|
|
sub set_proxy { |
|
259
|
|
|
|
|
|
|
my ($proxy) = @_; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my $p = $proxy->{proxy}; |
|
262
|
|
|
|
|
|
|
defined $p->{http_proxy} || defined $p->{ftp_proxy} or return; |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
my @res; |
|
265
|
|
|
|
|
|
|
if ($proxy->{type} =~ /\bwget\b/) { |
|
266
|
|
|
|
|
|
|
if (defined $p->{http_proxy}) { |
|
267
|
|
|
|
|
|
|
$ENV{http_proxy} = $p->{http_proxy} =~ /^http:/ |
|
268
|
|
|
|
|
|
|
? $p->{http_proxy} : "http://$p->{http_proxy}"; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
$ENV{ftp_proxy} = $p->{ftp_proxy} if defined $p->{ftp_proxy}; |
|
271
|
|
|
|
|
|
|
@res = ("--proxy-user=$p->{user}", "--proxy-passwd=$p->{pwd}") |
|
272
|
|
|
|
|
|
|
if defined $p->{user} && defined $p->{pwd}; |
|
273
|
|
|
|
|
|
|
} elsif ($proxy->{type} =~ /\bcurl\b/) { |
|
274
|
|
|
|
|
|
|
push @res, ('-x', $p->{http_proxy}) if defined $p->{http_proxy}; |
|
275
|
|
|
|
|
|
|
push @res, ('-x', $p->{ftp_proxy}) if defined $p->{ftp_proxy}; |
|
276
|
|
|
|
|
|
|
push @res, ('-U', "$p->{user}:$p->{pwd}") |
|
277
|
|
|
|
|
|
|
if defined $p->{user} && defined $p->{pwd}; |
|
278
|
|
|
|
|
|
|
push @res, '-H', 'Pragma:' if @res; |
|
279
|
|
|
|
|
|
|
} elsif ($proxy->{type} =~ /\baria2\b/) { |
|
280
|
|
|
|
|
|
|
if (my ($http_proxy) = $p->{http_proxy} && parse_http_proxy($p->{http_proxy})) { |
|
281
|
|
|
|
|
|
|
my $allproxy = $p->{user}; |
|
282
|
|
|
|
|
|
|
$allproxy .= ":" . $p->{pwd} if $p->{pwd}; |
|
283
|
|
|
|
|
|
|
$allproxy .= "@" if $p->{user}; |
|
284
|
|
|
|
|
|
|
$allproxy .= $http_proxy; |
|
285
|
|
|
|
|
|
|
@res = ("--all-proxy=http://$allproxy"); |
|
286
|
|
|
|
|
|
|
} |
|
287
|
|
|
|
|
|
|
} else { |
|
288
|
|
|
|
|
|
|
die N("Unknown webfetch `%s' !!!\n", $proxy->{type}); |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
@res; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub _error_msg { |
|
294
|
|
|
|
|
|
|
my ($name) = @_; |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
my $msg = $? & 127 ? N("%s failed: exited with signal %d", $name, $? & 127) : |
|
297
|
|
|
|
|
|
|
N("%s failed: exited with %d", $name, $? >> 8); |
|
298
|
|
|
|
|
|
|
"$msg\n"; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub _error { |
|
302
|
|
|
|
|
|
|
my ($name) = @_; |
|
303
|
|
|
|
|
|
|
die _error_msg($name); |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub hide_password { |
|
307
|
|
|
|
|
|
|
my ($url) = @_; |
|
308
|
|
|
|
|
|
|
$url =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed... |
|
309
|
|
|
|
|
|
|
$url; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub propagate_sync_callback { |
|
313
|
|
|
|
|
|
|
my $options = shift; |
|
314
|
|
|
|
|
|
|
if (ref($options) && $options->{callback}) { |
|
315
|
|
|
|
|
|
|
my $mode = shift; |
|
316
|
|
|
|
|
|
|
if ($mode =~ /^(?:start|progress|end)$/) { |
|
317
|
|
|
|
|
|
|
my $file = shift; |
|
318
|
|
|
|
|
|
|
return $options->{callback}($mode, hide_password($file), @_); |
|
319
|
|
|
|
|
|
|
} else { |
|
320
|
|
|
|
|
|
|
return $options->{callback}($mode, @_); |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub sync_file { |
|
326
|
|
|
|
|
|
|
my $options = shift; |
|
327
|
|
|
|
|
|
|
foreach (@_) { |
|
328
|
|
|
|
|
|
|
propagate_sync_callback($options, 'start', $_); |
|
329
|
|
|
|
|
|
|
require urpm::util; |
|
330
|
|
|
|
|
|
|
urpm::util::copy($_, ref($options) ? $options->{dir} : $options) |
|
331
|
|
|
|
|
|
|
or die N("copy failed"); |
|
332
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $_); |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub sync_wget { |
|
337
|
|
|
|
|
|
|
-x "/usr/bin/wget" or die N("wget is missing\n"); |
|
338
|
|
|
|
|
|
|
my $options = shift; |
|
339
|
|
|
|
|
|
|
$options = { dir => $options } if !ref $options; |
|
340
|
|
|
|
|
|
|
#- force download to be done in cachedir to avoid polluting cwd. |
|
341
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
342
|
|
|
|
|
|
|
chdir $options->{dir}; |
|
343
|
|
|
|
|
|
|
my ($buf, $total, $file) = ('', undef, undef); |
|
344
|
|
|
|
|
|
|
my $wget_command = join(" ", map { "'$_'" } |
|
345
|
|
|
|
|
|
|
#- construction of the wget command-line |
|
346
|
|
|
|
|
|
|
"/usr/bin/wget", |
|
347
|
|
|
|
|
|
|
($options->{'limit-rate'} ? "--limit-rate=$options->{'limit-rate'}" : @{[]}), |
|
348
|
|
|
|
|
|
|
($options->{resume} ? "--continue" : "--force-clobber"), |
|
349
|
|
|
|
|
|
|
($options->{proxy} ? set_proxy({ type => "wget", proxy => $options->{proxy} }) : @{[]}), |
|
350
|
|
|
|
|
|
|
($options->{retry} ? ('-t', $options->{retry}) : @{[]}), |
|
351
|
|
|
|
|
|
|
($options->{callback} ? ("--progress=bar:force", "-o", "-") : |
|
352
|
|
|
|
|
|
|
$options->{quiet} ? "-q" : @{[]}), |
|
353
|
|
|
|
|
|
|
"--retr-symlinks", |
|
354
|
|
|
|
|
|
|
($options->{"no-certificate-check"} ? "--no-check-certificate" : @{[]}), |
|
355
|
|
|
|
|
|
|
"--timeout=$CONNECT_TIMEOUT", |
|
356
|
|
|
|
|
|
|
(defined $options->{'wget-options'} ? split /\s+/, $options->{'wget-options'} : @{[]}), |
|
357
|
|
|
|
|
|
|
'-P', $options->{dir}, |
|
358
|
|
|
|
|
|
|
@_ |
|
359
|
|
|
|
|
|
|
) . " |"; |
|
360
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($wget_command); |
|
361
|
|
|
|
|
|
|
local $ENV{LC_ALL} = 'C'; |
|
362
|
|
|
|
|
|
|
my $wget_pid = open(my $wget, $wget_command); |
|
363
|
|
|
|
|
|
|
local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). |
|
364
|
|
|
|
|
|
|
local $_; |
|
365
|
|
|
|
|
|
|
while (<$wget>) { |
|
366
|
|
|
|
|
|
|
$buf .= $_; |
|
367
|
|
|
|
|
|
|
if ($_ eq "\r" || $_ eq "\n") { |
|
368
|
|
|
|
|
|
|
if ($options->{callback}) { |
|
369
|
|
|
|
|
|
|
if ($buf =~ /^--(\d\d\d\d-\d\d-\d\d )?\d\d:\d\d:\d\d--\s+(\S.*)\n/ms) { |
|
370
|
|
|
|
|
|
|
my $file_ = $2; |
|
371
|
|
|
|
|
|
|
if ($file && $file ne $file_) { |
|
372
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $file); |
|
373
|
|
|
|
|
|
|
undef $file; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
! defined $file and propagate_sync_callback($options, 'start', $file = $file_); |
|
376
|
|
|
|
|
|
|
} elsif (defined $file && ! defined $total && ($buf =~ /==>\s+RETR/ || $buf =~ /200 OK$/)) { |
|
377
|
|
|
|
|
|
|
$total = ''; |
|
378
|
|
|
|
|
|
|
} elsif ($buf =~ /^Length:\s*(\d\S*)/) { |
|
379
|
|
|
|
|
|
|
$total = $1; |
|
380
|
|
|
|
|
|
|
} elsif (defined $total && $buf =~ m!^\s*(\d+)%.*\s+(\S+/s)\s+((ETA|eta)\s+(.*?)\s*)?[\r\n]$!ms) { |
|
381
|
|
|
|
|
|
|
my ($percent, $speed, $eta) = ($1, $2, $5); |
|
382
|
|
|
|
|
|
|
if (propagate_sync_callback($options, 'progress', $file, $percent, $total, $eta, $speed) eq 'canceled') { |
|
383
|
|
|
|
|
|
|
kill 15, $wget_pid; |
|
384
|
|
|
|
|
|
|
close $wget; |
|
385
|
|
|
|
|
|
|
return; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
if ($_ eq "\n") { |
|
388
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $file); |
|
389
|
|
|
|
|
|
|
($total, $file) = (undef, undef); |
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
} else { |
|
393
|
|
|
|
|
|
|
$options->{quiet} or print STDERR $buf; |
|
394
|
|
|
|
|
|
|
} |
|
395
|
|
|
|
|
|
|
$buf = ''; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
$file and propagate_sync_callback($options, 'end', $file); |
|
399
|
|
|
|
|
|
|
chdir $cwd; |
|
400
|
|
|
|
|
|
|
close $wget or _error('wget'); |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub sync_curl { |
|
404
|
|
|
|
|
|
|
-x "/usr/bin/curl" or die N("curl is missing\n"); |
|
405
|
|
|
|
|
|
|
my $options = shift; |
|
406
|
|
|
|
|
|
|
$options = { dir => $options } if !ref $options; |
|
407
|
|
|
|
|
|
|
if (defined $options->{'limit-rate'} && $options->{'limit-rate'} =~ /\d$/) { |
|
408
|
|
|
|
|
|
|
#- use bytes by default |
|
409
|
|
|
|
|
|
|
$options->{'limit-rate'} .= 'B'; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
#- force download to be done in cachedir to avoid polluting cwd, |
|
412
|
|
|
|
|
|
|
#- however for curl, this is mandatory. |
|
413
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
414
|
|
|
|
|
|
|
chdir($options->{dir}); |
|
415
|
|
|
|
|
|
|
my (@ftp_files, @other_files); |
|
416
|
|
|
|
|
|
|
foreach (@_) { |
|
417
|
|
|
|
|
|
|
my ($proto, $nick, $rest) = m,^(http|ftp)://([^:/]+):(.*),,; |
|
418
|
|
|
|
|
|
|
if ($nick) { #- escape @ in user names |
|
419
|
|
|
|
|
|
|
$nick =~ s/@/%40/; |
|
420
|
|
|
|
|
|
|
$_ = "$proto://$nick:$rest"; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
if (m|^ftp://.*/([^/]*)$| && file_size($1) > 8192) { #- manage time stamp for large file only |
|
423
|
|
|
|
|
|
|
push @ftp_files, $_; |
|
424
|
|
|
|
|
|
|
} else { |
|
425
|
|
|
|
|
|
|
push @other_files, $_; |
|
426
|
|
|
|
|
|
|
} |
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
if (@ftp_files) { |
|
429
|
|
|
|
|
|
|
my ($cur_ftp_file, %ftp_files_info); |
|
430
|
|
|
|
|
|
|
local $_; |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
eval { require Date::Manip }; |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
#- prepare to get back size and time stamp of each file. |
|
435
|
|
|
|
|
|
|
my $cmd = join(" ", map { "'$_'" } "/usr/bin/curl", |
|
436
|
|
|
|
|
|
|
"-q", # don't read .curlrc; some toggle options might interfer |
|
437
|
|
|
|
|
|
|
($options->{'limit-rate'} ? ("--limit-rate", $options->{'limit-rate'}) : @{[]}), |
|
438
|
|
|
|
|
|
|
($options->{proxy} ? set_proxy({ type => "curl", proxy => $options->{proxy} }) : @{[]}), |
|
439
|
|
|
|
|
|
|
($options->{retry} ? ('--retry', $options->{retry}) : @{[]}), |
|
440
|
|
|
|
|
|
|
"--stderr", "-", # redirect everything to stdout |
|
441
|
|
|
|
|
|
|
"--disable-epsv", |
|
442
|
|
|
|
|
|
|
"--connect-timeout", $CONNECT_TIMEOUT, |
|
443
|
|
|
|
|
|
|
"-s", "-I", |
|
444
|
|
|
|
|
|
|
"--anyauth", |
|
445
|
|
|
|
|
|
|
(defined $options->{'curl-options'} ? split /\s+/, $options->{'curl-options'} : @{[]}), |
|
446
|
|
|
|
|
|
|
@ftp_files); |
|
447
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($cmd); |
|
448
|
|
|
|
|
|
|
open my $curl, "$cmd |"; |
|
449
|
|
|
|
|
|
|
while (<$curl>) { |
|
450
|
|
|
|
|
|
|
if (/Content-Length:\s*(\d+)/) { |
|
451
|
|
|
|
|
|
|
!$cur_ftp_file || exists($ftp_files_info{$cur_ftp_file}{size}) |
|
452
|
|
|
|
|
|
|
and $cur_ftp_file = shift @ftp_files; |
|
453
|
|
|
|
|
|
|
$ftp_files_info{$cur_ftp_file}{size} = $1; |
|
454
|
|
|
|
|
|
|
} |
|
455
|
|
|
|
|
|
|
if (/Last-Modified:\s*(.*)/) { |
|
456
|
|
|
|
|
|
|
!$cur_ftp_file || exists($ftp_files_info{$cur_ftp_file}{time}) |
|
457
|
|
|
|
|
|
|
and $cur_ftp_file = shift @ftp_files; |
|
458
|
|
|
|
|
|
|
eval { |
|
459
|
|
|
|
|
|
|
$ftp_files_info{$cur_ftp_file}{time} = Date::Manip::ParseDate($1); |
|
460
|
|
|
|
|
|
|
}; |
|
461
|
|
|
|
|
|
|
} |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
close $curl or _error('curl'); |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
#- now analyse size and time stamp according to what already exists here. |
|
466
|
|
|
|
|
|
|
if (@ftp_files) { |
|
467
|
|
|
|
|
|
|
#- re-insert back shifted element of ftp_files, because curl output above |
|
468
|
|
|
|
|
|
|
#- has not been parsed correctly, so in doubt download them all. |
|
469
|
|
|
|
|
|
|
push @ftp_files, keys %ftp_files_info; |
|
470
|
|
|
|
|
|
|
} else { |
|
471
|
|
|
|
|
|
|
#- for that, it should be clear ftp_files is empty... |
|
472
|
|
|
|
|
|
|
#- elsewhere, the above work was useless. |
|
473
|
|
|
|
|
|
|
foreach (keys %ftp_files_info) { |
|
474
|
|
|
|
|
|
|
my ($lfile) = m|/([^/]*)$| or next; #- strange if we can't parse it correctly. |
|
475
|
|
|
|
|
|
|
my $ltime = eval { Date::Manip::ParseDate(scalar gmtime((stat $1)[9])) }; |
|
476
|
|
|
|
|
|
|
$ltime && -s $lfile == $ftp_files_info{$_}{size} && $ftp_files_info{$_}{time} eq $ltime |
|
477
|
|
|
|
|
|
|
or push @ftp_files, $_; |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
} |
|
481
|
|
|
|
|
|
|
# Indicates whether this option is available in our curl |
|
482
|
|
|
|
|
|
|
our $location_trusted; |
|
483
|
|
|
|
|
|
|
if (!defined $location_trusted) { |
|
484
|
|
|
|
|
|
|
$location_trusted = `/usr/bin/curl -h` =~ /location-trusted/ ? 1 : 0; |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
#- http files (and other files) are correctly managed by curl wrt conditional download. |
|
487
|
|
|
|
|
|
|
#- options for ftp files, -R (-O )* |
|
488
|
|
|
|
|
|
|
#- options for http files, -R (-O )* |
|
489
|
|
|
|
|
|
|
my $result; |
|
490
|
|
|
|
|
|
|
if (my @all_files = ( |
|
491
|
|
|
|
|
|
|
(map { ("-O", $_) } @ftp_files), |
|
492
|
|
|
|
|
|
|
(map { m|/| ? ("-O", $_) : @{[]} } @other_files))) |
|
493
|
|
|
|
|
|
|
{ |
|
494
|
|
|
|
|
|
|
my @l = (@ftp_files, @other_files); |
|
495
|
|
|
|
|
|
|
my $cmd = join(" ", map { "'$_'" } "/usr/bin/curl", |
|
496
|
|
|
|
|
|
|
"-q", # don't read .curlrc; some toggle options might interfer |
|
497
|
|
|
|
|
|
|
($options->{'limit-rate'} ? ("--limit-rate", $options->{'limit-rate'}) : @{[]}), |
|
498
|
|
|
|
|
|
|
($options->{resume} ? ("--continue-at", "-") : @{[]}), |
|
499
|
|
|
|
|
|
|
($options->{proxy} ? set_proxy({ type => "curl", proxy => $options->{proxy} }) : @{[]}), |
|
500
|
|
|
|
|
|
|
($options->{retry} ? ('--retry', $options->{retry}) : @{[]}), |
|
501
|
|
|
|
|
|
|
($options->{quiet} ? "-s" : @{[]}), |
|
502
|
|
|
|
|
|
|
($options->{"no-certificate-check"} ? "-k" : @{[]}), |
|
503
|
|
|
|
|
|
|
$location_trusted ? "--location-trusted" : @{[]}, |
|
504
|
|
|
|
|
|
|
"-R", |
|
505
|
|
|
|
|
|
|
"-f", |
|
506
|
|
|
|
|
|
|
"--disable-epsv", |
|
507
|
|
|
|
|
|
|
"--connect-timeout", $CONNECT_TIMEOUT, |
|
508
|
|
|
|
|
|
|
"--anyauth", |
|
509
|
|
|
|
|
|
|
(defined $options->{'curl-options'} ? split /\s+/, $options->{'curl-options'} : @{[]}), |
|
510
|
|
|
|
|
|
|
"--stderr", "-", # redirect everything to stdout |
|
511
|
|
|
|
|
|
|
@all_files); |
|
512
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($cmd); |
|
513
|
|
|
|
|
|
|
$result = _curl_action($cmd, $options, @l); |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
chdir $cwd; |
|
516
|
|
|
|
|
|
|
$result; |
|
517
|
|
|
|
|
|
|
} |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub _curl_action { |
|
520
|
|
|
|
|
|
|
my ($cmd, $options, @l) = @_; |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
my ($buf, $file); $buf = ''; |
|
523
|
|
|
|
|
|
|
my $curl_pid = open(my $curl, "$cmd |"); |
|
524
|
|
|
|
|
|
|
local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). |
|
525
|
|
|
|
|
|
|
local $_; |
|
526
|
|
|
|
|
|
|
while (<$curl>) { |
|
527
|
|
|
|
|
|
|
$buf .= $_; |
|
528
|
|
|
|
|
|
|
if ($_ eq "\r" || $_ eq "\n") { |
|
529
|
|
|
|
|
|
|
if ($options->{callback}) { |
|
530
|
|
|
|
|
|
|
unless (defined $file) { |
|
531
|
|
|
|
|
|
|
$file = shift @l; |
|
532
|
|
|
|
|
|
|
propagate_sync_callback($options, 'start', $file); |
|
533
|
|
|
|
|
|
|
} |
|
534
|
|
|
|
|
|
|
if (my ($percent, $total, $eta, $speed) = $buf =~ /^\s*(\d+)\s+(\S+)[^\r\n]*\s+(\S+)\s+(\S+)\s*[\r\n]$/ms) { |
|
535
|
|
|
|
|
|
|
$speed =~ s/^-//; |
|
536
|
|
|
|
|
|
|
if (propagate_sync_callback($options, 'progress', $file, $percent, $total, $eta, $speed) eq 'canceled') { |
|
537
|
|
|
|
|
|
|
kill 15, $curl_pid; |
|
538
|
|
|
|
|
|
|
close $curl; |
|
539
|
|
|
|
|
|
|
die N("curl failed: download canceled\n"); |
|
540
|
|
|
|
|
|
|
} |
|
541
|
|
|
|
|
|
|
#- this checks that download has actually started |
|
542
|
|
|
|
|
|
|
if ($_ eq "\n" |
|
543
|
|
|
|
|
|
|
&& !($speed == 0 && $percent == 100 && index($eta, '--') >= 0) #- work around bug 13685 |
|
544
|
|
|
|
|
|
|
) { |
|
545
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $file); |
|
546
|
|
|
|
|
|
|
$file = undef; |
|
547
|
|
|
|
|
|
|
} |
|
548
|
|
|
|
|
|
|
} elsif ($buf =~ /^curl:/) { #- likely to be an error reported by curl |
|
549
|
|
|
|
|
|
|
local $/ = "\n"; |
|
550
|
|
|
|
|
|
|
chomp $buf; |
|
551
|
|
|
|
|
|
|
propagate_sync_callback($options, 'error', $file, $buf); |
|
552
|
|
|
|
|
|
|
} |
|
553
|
|
|
|
|
|
|
} else { |
|
554
|
|
|
|
|
|
|
$options->{quiet} or print STDERR $buf; |
|
555
|
|
|
|
|
|
|
} |
|
556
|
|
|
|
|
|
|
$buf = ''; |
|
557
|
|
|
|
|
|
|
} |
|
558
|
|
|
|
|
|
|
} |
|
559
|
|
|
|
|
|
|
close $curl or _error('curl'); |
|
560
|
|
|
|
|
|
|
} |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub _calc_limit_rate { |
|
563
|
|
|
|
|
|
|
my $limit_rate = $_[0]; |
|
564
|
|
|
|
|
|
|
for ($limit_rate) { |
|
565
|
|
|
|
|
|
|
/^(\d+)$/ and $limit_rate = int $1/1024, last; |
|
566
|
|
|
|
|
|
|
/^(\d+)[kK]$/ and $limit_rate = $1, last; |
|
567
|
|
|
|
|
|
|
/^(\d+)[mM]$/ and $limit_rate = 1024*$1, last; |
|
568
|
|
|
|
|
|
|
/^(\d+)[gG]$/ and $limit_rate = 1024*1024*$1, last; |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
$limit_rate; |
|
571
|
|
|
|
|
|
|
} |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
sub sync_rsync { |
|
574
|
|
|
|
|
|
|
-x "/usr/bin/rsync" or die N("rsync is missing\n"); |
|
575
|
|
|
|
|
|
|
my $options = shift; |
|
576
|
|
|
|
|
|
|
$options = { dir => $options } if !ref $options; |
|
577
|
|
|
|
|
|
|
#- force download to be done in cachedir to avoid polluting cwd. |
|
578
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
579
|
|
|
|
|
|
|
chdir($options->{dir}); |
|
580
|
|
|
|
|
|
|
my $limit_rate = _calc_limit_rate($options->{'limit-rate'}); |
|
581
|
|
|
|
|
|
|
foreach (@_) { |
|
582
|
|
|
|
|
|
|
my $count = 10; #- retry count on error (if file exists). |
|
583
|
|
|
|
|
|
|
my $basename = basename($_); |
|
584
|
|
|
|
|
|
|
my $file = m!^rsync://([^/]*::.*)! ? $1 : $_; |
|
585
|
|
|
|
|
|
|
propagate_sync_callback($options, 'start', $file); |
|
586
|
|
|
|
|
|
|
do { |
|
587
|
|
|
|
|
|
|
local $_; |
|
588
|
|
|
|
|
|
|
my $buf = ''; |
|
589
|
|
|
|
|
|
|
my $cmd = join(" ", "/usr/bin/rsync", |
|
590
|
|
|
|
|
|
|
($limit_rate ? "--bwlimit=$limit_rate" : @{[]}), |
|
591
|
|
|
|
|
|
|
($options->{quiet} ? qw(-q) : qw(--progress -v --no-human-readable)), |
|
592
|
|
|
|
|
|
|
($options->{compress} ? qw(-z) : @{[]}), |
|
593
|
|
|
|
|
|
|
($options->{ssh} ? qq(-e $options->{ssh}) : |
|
594
|
|
|
|
|
|
|
("--timeout=$CONNECT_TIMEOUT", |
|
595
|
|
|
|
|
|
|
"--contimeout=$CONNECT_TIMEOUT")), |
|
596
|
|
|
|
|
|
|
qw(--partial --no-whole-file --no-motd --copy-links), |
|
597
|
|
|
|
|
|
|
(defined $options->{'rsync-options'} ? split /\s+/, $options->{'rsync-options'} : @{[]}), |
|
598
|
|
|
|
|
|
|
"'$file' '$options->{dir}' 2>&1"); |
|
599
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($cmd); |
|
600
|
|
|
|
|
|
|
open(my $rsync, "$cmd |"); |
|
601
|
|
|
|
|
|
|
local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). |
|
602
|
|
|
|
|
|
|
local $_; |
|
603
|
|
|
|
|
|
|
while (<$rsync>) { |
|
604
|
|
|
|
|
|
|
$buf .= $_; |
|
605
|
|
|
|
|
|
|
if ($_ eq "\r" || $_ eq "\n") { |
|
606
|
|
|
|
|
|
|
if ($options->{callback}) { |
|
607
|
|
|
|
|
|
|
if (my ($percent, $speed) = $buf =~ /^\s*\d+\s+(\d+)%\s+(\S+)\s+/) { |
|
608
|
|
|
|
|
|
|
propagate_sync_callback($options, 'progress', $file, $percent, undef, undef, $speed); |
|
609
|
|
|
|
|
|
|
} else { |
|
610
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($buf); |
|
611
|
|
|
|
|
|
|
} |
|
612
|
|
|
|
|
|
|
} else { |
|
613
|
|
|
|
|
|
|
$options->{quiet} or print STDERR $buf; |
|
614
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($buf); |
|
615
|
|
|
|
|
|
|
} |
|
616
|
|
|
|
|
|
|
$buf = ''; |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
} |
|
619
|
|
|
|
|
|
|
close $rsync; |
|
620
|
|
|
|
|
|
|
} while ($? != 0 && --$count > 0 && -e $options->{dir} . "/$basename"); |
|
621
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $file); |
|
622
|
|
|
|
|
|
|
} |
|
623
|
|
|
|
|
|
|
chdir $cwd; |
|
624
|
|
|
|
|
|
|
$? == 0 or _error('rsync'); |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
our $SSH_PATH; |
|
628
|
|
|
|
|
|
|
sub _init_ssh_path() { |
|
629
|
|
|
|
|
|
|
foreach (qw(/usr/bin/ssh /bin/ssh)) { |
|
630
|
|
|
|
|
|
|
-x $_ and $SSH_PATH = $_; |
|
631
|
|
|
|
|
|
|
next; |
|
632
|
|
|
|
|
|
|
} |
|
633
|
|
|
|
|
|
|
} |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
#- Don't generate a tmp dir name, so when we restart urpmi, the old ssh |
|
636
|
|
|
|
|
|
|
#- connection can be reused |
|
637
|
|
|
|
|
|
|
our $SSH_CONTROL_DIR = $ENV{TMP} || $ENV{TMPDIR} || '/tmp'; |
|
638
|
|
|
|
|
|
|
our $SSH_CONTROL_OPTION; |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
sub sync_ssh { |
|
641
|
|
|
|
|
|
|
$SSH_PATH or _init_ssh_path(); |
|
642
|
|
|
|
|
|
|
$SSH_PATH or die N("ssh is missing\n"); |
|
643
|
|
|
|
|
|
|
my $options = shift; |
|
644
|
|
|
|
|
|
|
$options = { dir => $options } if !ref $options; |
|
645
|
|
|
|
|
|
|
unless ($options->{'rsync-options'} =~ /(?:-e|--rsh)\b/) { |
|
646
|
|
|
|
|
|
|
my ($server, $user) = ('', getpwuid($<)); |
|
647
|
|
|
|
|
|
|
$_[0] =~ /((?:\w|\.)*):/ and $server = $1; |
|
648
|
|
|
|
|
|
|
$_[0] =~ /((?:\w|-)*)@/ and $user = $1; |
|
649
|
|
|
|
|
|
|
$SSH_CONTROL_OPTION = "-o 'ControlPath $SSH_CONTROL_DIR/ssh-urpmi-$$-%h_%p_%r' -o 'ControlMaster auto'"; |
|
650
|
|
|
|
|
|
|
if (start_ssh_master($server, $user)) { |
|
651
|
|
|
|
|
|
|
$options->{ssh} = qq("$SSH_PATH $SSH_CONTROL_OPTION"); |
|
652
|
|
|
|
|
|
|
} else { |
|
653
|
|
|
|
|
|
|
#- can't start master, use single connection |
|
654
|
|
|
|
|
|
|
$options->{ssh} = $SSH_PATH; |
|
655
|
|
|
|
|
|
|
} |
|
656
|
|
|
|
|
|
|
} |
|
657
|
|
|
|
|
|
|
sync_rsync($options, @_); |
|
658
|
|
|
|
|
|
|
} |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
sub sync_prozilla { |
|
661
|
|
|
|
|
|
|
-x "/usr/bin/proz" or die N("prozilla is missing\n"); |
|
662
|
|
|
|
|
|
|
my $options = shift; |
|
663
|
|
|
|
|
|
|
$options = { dir => $options } if !ref $options; |
|
664
|
|
|
|
|
|
|
#- force download to be done in cachedir to avoid polluting cwd. |
|
665
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
666
|
|
|
|
|
|
|
chdir $options->{dir}; |
|
667
|
|
|
|
|
|
|
my $proz_command = join(" ", map { "'$_'" } |
|
668
|
|
|
|
|
|
|
"/usr/bin/proz", |
|
669
|
|
|
|
|
|
|
"--no-curses", |
|
670
|
|
|
|
|
|
|
(defined $options->{'prozilla-options'} ? split /\s+/, $options->{'prozilla-options'} : @{[]}), |
|
671
|
|
|
|
|
|
|
@_ |
|
672
|
|
|
|
|
|
|
); |
|
673
|
|
|
|
|
|
|
my $ret = system($proz_command); |
|
674
|
|
|
|
|
|
|
chdir $cwd; |
|
675
|
|
|
|
|
|
|
if ($ret) { |
|
676
|
|
|
|
|
|
|
if ($? == -1) { |
|
677
|
|
|
|
|
|
|
die N("Couldn't execute prozilla\n"); |
|
678
|
|
|
|
|
|
|
} else { |
|
679
|
|
|
|
|
|
|
_error('prozilla'); |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
} |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
sub sync_aria2 { |
|
685
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_files, $options) = @_; |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
-x "/usr/bin/aria2c" or die N("aria2 is missing\n"); |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
#- force download to be done in cachedir to avoid polluting cwd. |
|
690
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
691
|
|
|
|
|
|
|
chdir $options->{dir}; |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
my $stat_file = ($< ? $ENV{HOME} : '/root') . '/.aria2-adaptive-stats'; |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
my $aria2c_command = join(" ", map { "'$_'" } |
|
696
|
|
|
|
|
|
|
"/usr/bin/aria2c", $options->{debug} ? ('--log', "$options->{dir}/.aria2.log") : @{[]}, |
|
697
|
|
|
|
|
|
|
'--auto-file-renaming=false', |
|
698
|
|
|
|
|
|
|
'--ftp-pasv', |
|
699
|
|
|
|
|
|
|
'--summary-interval=1', |
|
700
|
|
|
|
|
|
|
'--follow-metalink=mem', |
|
701
|
|
|
|
|
|
|
$medium->{mirrorlist} ? ( |
|
702
|
|
|
|
|
|
|
'--metalink-enable-unique-protocol=true', # do not try to connect to the same server using the same protocol |
|
703
|
|
|
|
|
|
|
'--metalink-preferred-protocol=http', # try http as first protocol as they're stateless and |
|
704
|
|
|
|
|
|
|
# will put less strain on ie. the ftp servers which connections |
|
705
|
|
|
|
|
|
|
# are statefull for, causing unhappy mirror admins complaining |
|
706
|
|
|
|
|
|
|
# about increase of connections, increasing resource usage. |
|
707
|
|
|
|
|
|
|
'--max-tries=5', # nb: not using $options->{retry} |
|
708
|
|
|
|
|
|
|
'--lowest-speed-limit=20K', "--timeout", 3, |
|
709
|
|
|
|
|
|
|
'--split=3', # maximum number of servers to use for one download |
|
710
|
|
|
|
|
|
|
'--uri-selector=adaptive', "--server-stat-if=$stat_file", "--server-stat-of=$stat_file", |
|
711
|
|
|
|
|
|
|
$options->{is_versioned} ? @{[]} : '--max-file-not-found=9', # number of not found errors on different servers before aborting file download |
|
712
|
|
|
|
|
|
|
'--connect-timeout=6', # $CONNECT_TIMEOUT, |
|
713
|
|
|
|
|
|
|
) : @{[]}, |
|
714
|
|
|
|
|
|
|
'-Z', '-j1', |
|
715
|
|
|
|
|
|
|
($options->{'limit-rate'} ? "--max-download-limit=" . $options->{'limit-rate'} : @{[]}), |
|
716
|
|
|
|
|
|
|
($options->{resume} ? "--continue" : "--allow-overwrite=true"), |
|
717
|
|
|
|
|
|
|
($options->{proxy} ? set_proxy({ type => "aria2", proxy => $options->{proxy} }) : @{[]}), |
|
718
|
|
|
|
|
|
|
($options->{"no-certificate-check"} ? "--check-certificate=false" : @{[]}), |
|
719
|
|
|
|
|
|
|
(defined $options->{'aria2-options'} ? split /\s+/, $options->{'aria2-options'} : @{[]}), |
|
720
|
|
|
|
|
|
|
_create_metalink_($urpm, $medium, $rel_files, $options)); |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}($aria2c_command); |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
local $ENV{LC_ALL} = 'C'; |
|
725
|
|
|
|
|
|
|
my $aria2_pid = open(my $aria2, "$aria2c_command |"); |
|
726
|
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
_parse_aria2_output($options, $aria2, $aria2_pid, $medium, $rel_files); |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
chdir $cwd; |
|
730
|
|
|
|
|
|
|
if (!close $aria2) { |
|
731
|
|
|
|
|
|
|
my $raw_msg = _error_msg('aria2'); |
|
732
|
|
|
|
|
|
|
my $want_retry; |
|
733
|
|
|
|
|
|
|
if (!$options->{is_retry} & $options->{is_versioned}) { |
|
734
|
|
|
|
|
|
|
$want_retry = 1; |
|
735
|
|
|
|
|
|
|
} else { |
|
736
|
|
|
|
|
|
|
my $msg = N("Failed to download %s", $rel_files->[0]); |
|
737
|
|
|
|
|
|
|
$want_retry = $options->{ask_retry} && $options->{ask_retry}($raw_msg, $msg); |
|
738
|
|
|
|
|
|
|
} |
|
739
|
|
|
|
|
|
|
if ($want_retry) { |
|
740
|
|
|
|
|
|
|
$options->{is_retry}++; |
|
741
|
|
|
|
|
|
|
$options->{debug} and $options->{debug}("retrying ($options->{is_retry})"); |
|
742
|
|
|
|
|
|
|
goto &sync_aria2; |
|
743
|
|
|
|
|
|
|
} |
|
744
|
|
|
|
|
|
|
die $raw_msg; |
|
745
|
|
|
|
|
|
|
} |
|
746
|
|
|
|
|
|
|
} |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
sub _parse_aria2_output { |
|
749
|
|
|
|
|
|
|
my ($options, $aria2, $aria2_pid, $medium, $rel_files) = @_; |
|
750
|
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
my ($buf, $_total, $file) = ('', undef, undef); |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). |
|
754
|
|
|
|
|
|
|
local $_; |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
while (<$aria2>) { |
|
757
|
|
|
|
|
|
|
if ($_ eq "\r" || $_ eq "\n") { |
|
758
|
|
|
|
|
|
|
$options->{debug}("aria2c: $buf") if $options->{debug}; |
|
759
|
|
|
|
|
|
|
if ($options->{callback}) { |
|
760
|
|
|
|
|
|
|
if (!defined($file) && @$rel_files) { |
|
761
|
|
|
|
|
|
|
$file = $medium->{mirrorlist} ? |
|
762
|
|
|
|
|
|
|
$medium->{mirrorlist} . ': ' . $medium->{'with-dir'} . "/$rel_files->[0]" : |
|
763
|
|
|
|
|
|
|
"$medium->{url}/$rel_files->[0]"; |
|
764
|
|
|
|
|
|
|
propagate_sync_callback($options, 'start', $file) |
|
765
|
|
|
|
|
|
|
if !$options->{is_retry}; |
|
766
|
|
|
|
|
|
|
} |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
# aria2c 1.16 and beyond: |
|
769
|
|
|
|
|
|
|
# parses aria2c: [#2c8dae 496KiB/830KiB(59%) CN:1 DL:84KiB ETA:3s] |
|
770
|
|
|
|
|
|
|
# |
|
771
|
|
|
|
|
|
|
# using multiline mode and comments for better readability: |
|
772
|
|
|
|
|
|
|
# |
|
773
|
|
|
|
|
|
|
if ($buf =~ m! |
|
774
|
|
|
|
|
|
|
^\[\#[\dA-Fa-f]+ # match #2c8dae |
|
775
|
|
|
|
|
|
|
\s+ |
|
776
|
|
|
|
|
|
|
([\d\.]+\w*) # Match 496KiB |
|
777
|
|
|
|
|
|
|
/ |
|
778
|
|
|
|
|
|
|
([\d\.]+\w*) # Match 830KiB |
|
779
|
|
|
|
|
|
|
\s* \( (\d+) % \) # Match (59%) |
|
780
|
|
|
|
|
|
|
\s+ |
|
781
|
|
|
|
|
|
|
CN:(\S+) # Match CN:1 |
|
782
|
|
|
|
|
|
|
\s+ |
|
783
|
|
|
|
|
|
|
DL:(\S+) # Match DL:84KiB |
|
784
|
|
|
|
|
|
|
\s+ |
|
785
|
|
|
|
|
|
|
ETA:(\w+) |
|
786
|
|
|
|
|
|
|
\]$ |
|
787
|
|
|
|
|
|
|
!msx |
|
788
|
|
|
|
|
|
|
) |
|
789
|
|
|
|
|
|
|
{ |
|
790
|
|
|
|
|
|
|
my ($total, $percent, $speed, $eta) = ($2, $3, $5, $6); |
|
791
|
|
|
|
|
|
|
#- $1 = current downloaded size, $4 = connections |
|
792
|
|
|
|
|
|
|
if (propagate_sync_callback($options, 'progress', $file, $percent, $total, $eta, $speed) eq 'canceled') { |
|
793
|
|
|
|
|
|
|
kill 15, $aria2_pid; |
|
794
|
|
|
|
|
|
|
close $aria2; |
|
795
|
|
|
|
|
|
|
return; |
|
796
|
|
|
|
|
|
|
} |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
if ($buf =~ m!Download\scomplete:\s/!) { |
|
799
|
|
|
|
|
|
|
propagate_sync_callback($options, 'end', $file); |
|
800
|
|
|
|
|
|
|
shift @$rel_files; |
|
801
|
|
|
|
|
|
|
delete $options->{is_retry}; |
|
802
|
|
|
|
|
|
|
$file = undef; |
|
803
|
|
|
|
|
|
|
} elsif ($buf =~ /ERR\|(.*)/) { |
|
804
|
|
|
|
|
|
|
propagate_sync_callback($options, 'error', $file, $1); |
|
805
|
|
|
|
|
|
|
} |
|
806
|
|
|
|
|
|
|
} else { |
|
807
|
|
|
|
|
|
|
$options->{quiet} or print STDERR "$buf\n"; |
|
808
|
|
|
|
|
|
|
} |
|
809
|
|
|
|
|
|
|
$buf = ''; |
|
810
|
|
|
|
|
|
|
} else { |
|
811
|
|
|
|
|
|
|
$buf .= $_; |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
} |
|
814
|
|
|
|
|
|
|
} |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
sub start_ssh_master { |
|
817
|
|
|
|
|
|
|
my ($server, $user) = @_; |
|
818
|
|
|
|
|
|
|
$server or return 0; |
|
819
|
|
|
|
|
|
|
if (!check_ssh_master($server, $user)) { |
|
820
|
|
|
|
|
|
|
system(qq($SSH_PATH -f -N $SSH_CONTROL_OPTION -M $user\@$server)); |
|
821
|
|
|
|
|
|
|
return ! $?; |
|
822
|
|
|
|
|
|
|
} |
|
823
|
|
|
|
|
|
|
return 1; |
|
824
|
|
|
|
|
|
|
} |
|
825
|
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub check_ssh_master { |
|
827
|
|
|
|
|
|
|
my ($server, $user) = @_; |
|
828
|
|
|
|
|
|
|
system(qq($SSH_PATH -q -f -N $SSH_CONTROL_OPTION $user\@$server -O check)); |
|
829
|
|
|
|
|
|
|
return ! $?; |
|
830
|
|
|
|
|
|
|
} |
|
831
|
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
END { |
|
833
|
|
|
|
|
|
|
#- remove ssh persistent connections |
|
834
|
|
|
|
|
|
|
foreach my $socket (glob "$SSH_CONTROL_DIR/ssh-urpmi-$$-*") { |
|
835
|
|
|
|
|
|
|
my ($server, $login) = $socket =~ /ssh-urpmi-\d+-([^_]+)_\d+_(.*)$/ or next; |
|
836
|
|
|
|
|
|
|
system($SSH_PATH, '-q', '-f', '-N', '-o', "ControlPath $socket", '-O', 'exit', "$login\@$server"); |
|
837
|
|
|
|
|
|
|
} |
|
838
|
|
|
|
|
|
|
} |
|
839
|
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
#- get the width of the terminal |
|
841
|
|
|
|
|
|
|
my $wchar = 79; |
|
842
|
|
|
|
|
|
|
if (-t *STDOUT) { |
|
843
|
|
|
|
|
|
|
eval { |
|
844
|
|
|
|
|
|
|
require Term::ReadKey; |
|
845
|
|
|
|
|
|
|
($wchar) = Term::ReadKey::GetTerminalSize(); |
|
846
|
|
|
|
|
|
|
--$wchar; |
|
847
|
|
|
|
|
|
|
}; |
|
848
|
|
|
|
|
|
|
} |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
sub progress_text { |
|
851
|
|
|
|
|
|
|
my ($mode, $percent, $total, $eta, $speed) = @_; |
|
852
|
|
|
|
|
|
|
$mode eq 'progress' ? |
|
853
|
|
|
|
|
|
|
(defined $total && defined $eta ? |
|
854
|
|
|
|
|
|
|
N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed) : |
|
855
|
|
|
|
|
|
|
N(" %s%% completed, speed = %s", $percent, $speed)) : ''; |
|
856
|
|
|
|
|
|
|
} |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=item sync_logger($mode, $file, $percent, $_total, $_eta, $_speed) |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
Default logger (callback) suitable for sync operation on STDERR only. |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=cut |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
sub sync_logger { |
|
865
|
|
|
|
|
|
|
my ($mode, $file, $percent, $total, $eta, $speed) = @_; |
|
866
|
|
|
|
|
|
|
if ($mode eq 'start') { |
|
867
|
|
|
|
|
|
|
print STDERR " $file\n"; |
|
868
|
|
|
|
|
|
|
} elsif ($mode eq 'progress') { |
|
869
|
|
|
|
|
|
|
my $text = progress_text($mode, $percent, $total, $eta, $speed); |
|
870
|
|
|
|
|
|
|
if (length($text) > $wchar) { $text = substr($text, 0, $wchar) } |
|
871
|
|
|
|
|
|
|
if (bytes::length($text) < $wchar) { |
|
872
|
|
|
|
|
|
|
# clearing more than needed in case the terminal is not handling utf8 and we have a utf8 string |
|
873
|
|
|
|
|
|
|
print STDERR $text, " " x ($wchar - bytes::length($text)), "\r"; |
|
874
|
|
|
|
|
|
|
} else { |
|
875
|
|
|
|
|
|
|
# clearing all the line first since we can't really know the "length" of the string |
|
876
|
|
|
|
|
|
|
print STDERR " " x $wchar, "\r", $text, "\r"; |
|
877
|
|
|
|
|
|
|
} |
|
878
|
|
|
|
|
|
|
} elsif ($mode eq 'end') { |
|
879
|
|
|
|
|
|
|
print STDERR " " x $wchar, "\r"; |
|
880
|
|
|
|
|
|
|
} elsif ($mode eq 'error') { |
|
881
|
|
|
|
|
|
|
#- error is 3rd argument, saved in $percent |
|
882
|
|
|
|
|
|
|
print STDERR N("...retrieving failed: %s", $percent), "\n"; |
|
883
|
|
|
|
|
|
|
} |
|
884
|
|
|
|
|
|
|
} |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=item requested_ftp_http_downloader($urpm, $medium) |
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
Return the downloader program to use (whether it pas provided on the |
|
889
|
|
|
|
|
|
|
command line or in the config file). |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=cut |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
sub requested_ftp_http_downloader { |
|
894
|
|
|
|
|
|
|
my ($urpm, $medium) = @_; |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
$urpm->{options}{downloader} || #- cmd-line switch |
|
897
|
|
|
|
|
|
|
$medium && $medium->{downloader} || |
|
898
|
|
|
|
|
|
|
$urpm->{global_config}{downloader} || ""; |
|
899
|
|
|
|
|
|
|
} |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
sub parse_url_with_login { |
|
902
|
|
|
|
|
|
|
my ($url) = @_; |
|
903
|
|
|
|
|
|
|
$url =~ m!([^:]*)://([^/:]*)(:([^/:\@]*))?\@([^/]*)(.*)! && $1 ne 'ssh' && |
|
904
|
|
|
|
|
|
|
{ proto => $1, login => $2, password => $4, machine => $5, dir => $6 }; |
|
905
|
|
|
|
|
|
|
} |
|
906
|
|
|
|
|
|
|
sub url_obscuring_password { |
|
907
|
|
|
|
|
|
|
my ($url) = @_; |
|
908
|
|
|
|
|
|
|
my $u = parse_url_with_login($url); |
|
909
|
|
|
|
|
|
|
if ($u && $u->{password}) { |
|
910
|
|
|
|
|
|
|
sprintf('%s://xxx:xxx@%s%s', $u->{proto}, $u->{machine}, $u->{dir}); |
|
911
|
|
|
|
|
|
|
} else { |
|
912
|
|
|
|
|
|
|
$url; |
|
913
|
|
|
|
|
|
|
} |
|
914
|
|
|
|
|
|
|
} |
|
915
|
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
#- $medium can be undef |
|
917
|
|
|
|
|
|
|
sub _all_options { |
|
918
|
|
|
|
|
|
|
my ($urpm, $medium, $options) = @_; |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
my %all_options = ( |
|
921
|
|
|
|
|
|
|
dir => "$urpm->{cachedir}/partial", |
|
922
|
|
|
|
|
|
|
proxy => get_proxy_($urpm), |
|
923
|
|
|
|
|
|
|
metalink => $medium->{mirrorlist}, |
|
924
|
|
|
|
|
|
|
$medium->{"disable-certificate-check"} ? "no-certificate-check" : @{[]}, |
|
925
|
|
|
|
|
|
|
$urpm->{debug} ? (debug => $urpm->{debug}) : @{[]}, |
|
926
|
|
|
|
|
|
|
%$options, |
|
927
|
|
|
|
|
|
|
); |
|
928
|
|
|
|
|
|
|
foreach my $cpt (qw(compress limit-rate retry wget-options curl-options rsync-options prozilla-options aria2-options metalink)) { |
|
929
|
|
|
|
|
|
|
$all_options{$cpt} = $urpm->{options}{$cpt} if defined $urpm->{options}{$cpt}; |
|
930
|
|
|
|
|
|
|
} |
|
931
|
|
|
|
|
|
|
\%all_options; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
sub sync_rel { |
|
935
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_files, %options) = @_; |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
my @files = map { reduce_pathname("$medium->{url}/$_") } @$rel_files; |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
my $files_text = join(' ', (use_metalink($urpm, $medium) ? ($medium->{mirrorlist}, $medium->{'with-dir'}) : url_obscuring_password($medium->{url})), @$rel_files); |
|
940
|
|
|
|
|
|
|
$urpm->{debug} and $urpm->{debug}(N("retrieving %s", $files_text)); |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
my $all_options = _all_options($urpm, $medium, \%options); |
|
943
|
|
|
|
|
|
|
my @result_files = map { $all_options->{dir} . '/' . basename($_) } @$rel_files; |
|
944
|
|
|
|
|
|
|
unlink @result_files if $all_options->{preclean}; |
|
945
|
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
(my $cwd) = getcwd() =~ /(.*)/; |
|
947
|
|
|
|
|
|
|
eval { _sync_webfetch_raw($urpm, $medium, $rel_files, \@files, $all_options) }; |
|
948
|
|
|
|
|
|
|
my $err = $@; |
|
949
|
|
|
|
|
|
|
chdir $cwd; |
|
950
|
|
|
|
|
|
|
if (!$err) { |
|
951
|
|
|
|
|
|
|
$urpm->{log}(N("retrieved %s", $files_text)); |
|
952
|
|
|
|
|
|
|
\@result_files; |
|
953
|
|
|
|
|
|
|
} else { |
|
954
|
|
|
|
|
|
|
$urpm->{log}("error: $err"); |
|
955
|
|
|
|
|
|
|
# don't leave partial download |
|
956
|
|
|
|
|
|
|
unlink @result_files; |
|
957
|
|
|
|
|
|
|
undef; |
|
958
|
|
|
|
|
|
|
} |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
sub sync_rel_one { |
|
962
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_file, %options) = @_; |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
my $files = sync_rel($urpm, $medium, [$rel_file], %options) or return; |
|
965
|
|
|
|
|
|
|
$files->[0]; |
|
966
|
|
|
|
|
|
|
} |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=item sync_url($urpm, $url, %options) |
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
Retrieve a file from the network and return the local cached file path. |
|
971
|
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
=cut |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
sub sync_url { |
|
975
|
|
|
|
|
|
|
my ($urpm, $url, %options) = @_; |
|
976
|
|
|
|
|
|
|
sync_rel_one($urpm, { url => dirname($url), disable_metalink => $options{disable_metalink} }, basename($url), %options); |
|
977
|
|
|
|
|
|
|
} |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
sub sync_rel_to { |
|
980
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_file, $dest_file, %options) = @_; |
|
981
|
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
my $files = sync_rel($urpm, $medium, [$rel_file], %options) or return undef; |
|
983
|
|
|
|
|
|
|
my $result_file = $files->[0]; |
|
984
|
|
|
|
|
|
|
$result_file ne $dest_file or rename($result_file, $dest_file) or return; |
|
985
|
|
|
|
|
|
|
$result_file; |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
=item get_content($urpm, $url, %o_options) |
|
989
|
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
Retrieve a file and return its content. |
|
991
|
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
=cut |
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
sub get_content { |
|
995
|
|
|
|
|
|
|
my ($urpm, $url, %o_options) = @_; |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
my $file = sync_url($urpm, $url, %o_options, quiet => 1, preclean => 1) or return; |
|
998
|
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
my @l = cat_($file); |
|
1000
|
|
|
|
|
|
|
unlink $file; |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
wantarray() ? @l : join('', @l); |
|
1003
|
|
|
|
|
|
|
} |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
#- syncing algorithms. |
|
1007
|
|
|
|
|
|
|
#- |
|
1008
|
|
|
|
|
|
|
#- nb: $files is constructed from $rel_files using $medium |
|
1009
|
|
|
|
|
|
|
sub _sync_webfetch_raw { |
|
1010
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_files, $files, $options) = @_; |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
#- currently ftp and http protocols are managed by curl or wget, |
|
1013
|
|
|
|
|
|
|
#- ssh and rsync protocols are managed by rsync *AND* ssh. |
|
1014
|
|
|
|
|
|
|
my $proto = urpm::protocol_from_url($medium->{url}) or die N("unknown protocol defined for %s", $medium->{url}); |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
if ($proto eq 'file') { |
|
1017
|
|
|
|
|
|
|
my @l = map { urpm::file_from_local_url($_) } @$files; |
|
1018
|
|
|
|
|
|
|
eval { sync_file($options, @l) }; |
|
1019
|
|
|
|
|
|
|
$urpm->{fatal}(10, $@) if $@; |
|
1020
|
|
|
|
|
|
|
} elsif ($proto eq 'rsync') { |
|
1021
|
|
|
|
|
|
|
sync_rsync($options, @$files); |
|
1022
|
|
|
|
|
|
|
} elsif (member($proto, 'ftp', 'http', 'https') || $options->{metalink}) { |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
my $preferred = preferred_downloader($urpm, $medium, \$options->{metalink}); |
|
1025
|
|
|
|
|
|
|
if ($preferred eq 'aria2') { |
|
1026
|
|
|
|
|
|
|
sync_aria2($urpm, $medium, $rel_files, $options); |
|
1027
|
|
|
|
|
|
|
} else { |
|
1028
|
|
|
|
|
|
|
my $sync = $urpm::download::{"sync_$preferred"} or die N("no webfetch found, supported webfetch are: %s\n", join(", ", urpm::download::ftp_http_downloaders())); |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
my @l = @$files; |
|
1031
|
|
|
|
|
|
|
while (@l) { |
|
1032
|
|
|
|
|
|
|
my $half_MAX_ARG = 131072 / 2; |
|
1033
|
|
|
|
|
|
|
# restrict the number of elements so that it fits on cmdline of curl/wget/proz/aria2c |
|
1034
|
|
|
|
|
|
|
my $n = 0; |
|
1035
|
|
|
|
|
|
|
for (my $len = 0; $n < @l && $len < $half_MAX_ARG; $len += length($l[$n++])) {} |
|
1036
|
|
|
|
|
|
|
$sync->($options, splice(@l, 0, $n)); |
|
1037
|
|
|
|
|
|
|
} |
|
1038
|
|
|
|
|
|
|
} |
|
1039
|
|
|
|
|
|
|
} elsif ($proto eq 'ssh') { |
|
1040
|
|
|
|
|
|
|
my @ssh_files = map { m!^ssh://([^/]*)(.*)! ? "$1:$2" : @{[]} } @$files; |
|
1041
|
|
|
|
|
|
|
sync_ssh($options, @ssh_files); |
|
1042
|
|
|
|
|
|
|
} else { |
|
1043
|
|
|
|
|
|
|
die N("unable to handle protocol: %s", $proto); |
|
1044
|
|
|
|
|
|
|
} |
|
1045
|
|
|
|
|
|
|
} |
|
1046
|
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
sub _take_n_elem { |
|
1048
|
|
|
|
|
|
|
my ($n, @l) = @_; |
|
1049
|
|
|
|
|
|
|
@l < $n ? @l : @l[0 .. $n-1]; |
|
1050
|
|
|
|
|
|
|
} |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
sub _create_one_metalink_line { |
|
1053
|
|
|
|
|
|
|
my ($medium, $mirror, $rel_file, $counter) = @_; |
|
1054
|
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
my $type = urpm::protocol_from_url($mirror->{url}); |
|
1056
|
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
# If more than 100 mirrors, give all the remaining mirrors a priority of 0 |
|
1058
|
|
|
|
|
|
|
my $preference = max(0, 100 - $counter); |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
my @options = (qq(type="$type"), qq(preference="$preference")); |
|
1061
|
|
|
|
|
|
|
# Not supported in metalinks |
|
1062
|
|
|
|
|
|
|
#if (@$list[$i]->{bw}) { |
|
1063
|
|
|
|
|
|
|
# push @options, 'bandwidth="' . @$list[$i]->{bw} . '"'; |
|
1064
|
|
|
|
|
|
|
# } |
|
1065
|
|
|
|
|
|
|
# Supported in metalinks, but no longer used in mirror list..? |
|
1066
|
|
|
|
|
|
|
if ($mirror->{connections}) { |
|
1067
|
|
|
|
|
|
|
push @options, qq(maxconnections="$mirror->{connections}"); |
|
1068
|
|
|
|
|
|
|
} |
|
1069
|
|
|
|
|
|
|
push @options, 'location="' . lc($mirror->{zone}) . '"'; |
|
1070
|
|
|
|
|
|
|
my $base = urpm::mirrors::_add__with_dir($mirror->{url}, $medium->{'with-dir'}); |
|
1071
|
|
|
|
|
|
|
sprintf('%s/%s', join(' ', @options), $base, $rel_file); |
|
1072
|
|
|
|
|
|
|
} |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
sub _create_metalink_ { |
|
1075
|
|
|
|
|
|
|
my ($urpm, $medium, $rel_files, $options) = @_; |
|
1076
|
|
|
|
|
|
|
# Don't create a metalink when downloading mirror list |
|
1077
|
|
|
|
|
|
|
$medium or return; |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
# only use the 8 best mirrors, then we let aria2 choose |
|
1080
|
|
|
|
|
|
|
require urpm::mirrors; |
|
1081
|
|
|
|
|
|
|
my @mirrors = $medium->{mirrorlist} ? (map { |
|
1082
|
|
|
|
|
|
|
# aria2 doesn't handle rsync |
|
1083
|
|
|
|
|
|
|
my @l = grep { urpm::protocol_from_url($_->{url}) ne 'rsync' } @$_; |
|
1084
|
|
|
|
|
|
|
_take_n_elem(8, @l); |
|
1085
|
|
|
|
|
|
|
} urpm::mirrors::list_urls($urpm, $medium, '')) : { url => $medium->{url} }; |
|
1086
|
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
my $metalinkfile = "$urpm->{cachedir}/$options->{media}.metalink"; |
|
1088
|
|
|
|
|
|
|
# Even if not required by metalink spec, this line is needed at top of |
|
1089
|
|
|
|
|
|
|
# metalink file, otherwise aria2 won't be able to autodetect it.. |
|
1090
|
|
|
|
|
|
|
my @metalink = ( |
|
1091
|
|
|
|
|
|
|
'', |
|
1092
|
|
|
|
|
|
|
'', |
|
1093
|
|
|
|
|
|
|
'', |
|
1094
|
|
|
|
|
|
|
); |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
foreach my $rel_file (@$rel_files) { |
|
1097
|
|
|
|
|
|
|
my $i = 0; |
|
1098
|
|
|
|
|
|
|
my @lines = map { |
|
1099
|
|
|
|
|
|
|
$i++; |
|
1100
|
|
|
|
|
|
|
_create_one_metalink_line($medium, $_, $rel_file, $i); |
|
1101
|
|
|
|
|
|
|
} @mirrors; |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
push @metalink, map { "\t$_" } |
|
1104
|
|
|
|
|
|
|
sprintf('', basename($rel_file)), |
|
1105
|
|
|
|
|
|
|
(map { "\t$_" } @lines), |
|
1106
|
|
|
|
|
|
|
''; |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
|
|
|
|
|
|
push @metalink, '', ''; |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
output_safe($metalinkfile, join('', map { "$_\n" } @metalink)); |
|
1111
|
|
|
|
|
|
|
$metalinkfile; |
|
1112
|
|
|
|
|
|
|
} |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
1; |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
=back |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA |
|
1122
|
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
Copyright (C) 2005-2010 Mandriva SA |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
=cut |