1 |
commit: 56affbecaa1e5faecdf5176a574aa97d098d486b |
2 |
Author: Michał Górny <mgorny <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri Feb 2 19:32:24 2018 +0000 |
4 |
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> |
5 |
CommitDate: Mon Feb 5 18:41:38 2018 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=56affbec |
7 |
|
8 |
rsync: Pre-indent the try-finally block for gemato key scope |
9 |
|
10 |
Reviewed-by: Zac Medico <zmedico <AT> gentoo.org> |
11 |
|
12 |
pym/portage/sync/modules/rsync/rsync.py | 467 ++++++++++++++++---------------- |
13 |
1 file changed, 235 insertions(+), 232 deletions(-) |
14 |
|
15 |
diff --git a/pym/portage/sync/modules/rsync/rsync.py b/pym/portage/sync/modules/rsync/rsync.py |
16 |
index e6e218868..5c0b53f9e 100644 |
17 |
--- a/pym/portage/sync/modules/rsync/rsync.py |
18 |
+++ b/pym/portage/sync/modules/rsync/rsync.py |
19 |
@@ -110,247 +110,250 @@ class RsyncSync(NewBase): |
20 |
level=logging.WARNING, noiselevel=-1) |
21 |
self.verify_jobs = None |
22 |
|
23 |
- # Real local timestamp file. |
24 |
- self.servertimestampfile = os.path.join( |
25 |
- self.repo.location, "metadata", "timestamp.chk") |
26 |
- |
27 |
- content = portage.util.grabfile(self.servertimestampfile) |
28 |
- timestamp = 0 |
29 |
- if content: |
30 |
- try: |
31 |
- timestamp = time.mktime(time.strptime(content[0], |
32 |
- TIMESTAMP_FORMAT)) |
33 |
- except (OverflowError, ValueError): |
34 |
- pass |
35 |
- del content |
36 |
- |
37 |
- try: |
38 |
- self.rsync_initial_timeout = \ |
39 |
- int(self.settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15")) |
40 |
- except ValueError: |
41 |
- self.rsync_initial_timeout = 15 |
42 |
- |
43 |
- try: |
44 |
- maxretries=int(self.settings["PORTAGE_RSYNC_RETRIES"]) |
45 |
- except SystemExit as e: |
46 |
- raise # Needed else can't exit |
47 |
- except: |
48 |
- maxretries = -1 #default number of retries |
49 |
- |
50 |
- if syncuri.startswith("file://"): |
51 |
- self.proto = "file" |
52 |
- dosyncuri = syncuri[7:] |
53 |
- unchanged, is_synced, exitcode, updatecache_flg = self._do_rsync( |
54 |
- dosyncuri, timestamp, opts) |
55 |
- self._process_exitcode(exitcode, dosyncuri, out, 1) |
56 |
- return (exitcode, updatecache_flg) |
57 |
- |
58 |
- retries=0 |
59 |
try: |
60 |
- self.proto, user_name, hostname, port = re.split( |
61 |
- r"(rsync|ssh)://([^:/]+@)?(\[[:\da-fA-F]*\]|[^:/]*)(:[0-9]+)?", |
62 |
- syncuri, maxsplit=4)[1:5] |
63 |
- except ValueError: |
64 |
- writemsg_level("!!! sync-uri is invalid: %s\n" % syncuri, |
65 |
- noiselevel=-1, level=logging.ERROR) |
66 |
- return (1, False) |
67 |
+ # Real local timestamp file. |
68 |
+ self.servertimestampfile = os.path.join( |
69 |
+ self.repo.location, "metadata", "timestamp.chk") |
70 |
|
71 |
- self.ssh_opts = self.settings.get("PORTAGE_SSH_OPTS") |
72 |
+ content = portage.util.grabfile(self.servertimestampfile) |
73 |
+ timestamp = 0 |
74 |
+ if content: |
75 |
+ try: |
76 |
+ timestamp = time.mktime(time.strptime(content[0], |
77 |
+ TIMESTAMP_FORMAT)) |
78 |
+ except (OverflowError, ValueError): |
79 |
+ pass |
80 |
+ del content |
81 |
|
82 |
- if port is None: |
83 |
- port="" |
84 |
- if user_name is None: |
85 |
- user_name="" |
86 |
- if re.match(r"^\[[:\da-fA-F]*\]$", hostname) is None: |
87 |
- getaddrinfo_host = hostname |
88 |
- else: |
89 |
- # getaddrinfo needs the brackets stripped |
90 |
- getaddrinfo_host = hostname[1:-1] |
91 |
- updatecache_flg = False |
92 |
- all_rsync_opts = set(self.rsync_opts) |
93 |
- all_rsync_opts.update(self.extra_rsync_opts) |
94 |
+ try: |
95 |
+ self.rsync_initial_timeout = \ |
96 |
+ int(self.settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15")) |
97 |
+ except ValueError: |
98 |
+ self.rsync_initial_timeout = 15 |
99 |
|
100 |
- family = socket.AF_UNSPEC |
101 |
- if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts: |
102 |
- family = socket.AF_INET |
103 |
- elif socket.has_ipv6 and \ |
104 |
- ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts): |
105 |
- family = socket.AF_INET6 |
106 |
+ try: |
107 |
+ maxretries=int(self.settings["PORTAGE_RSYNC_RETRIES"]) |
108 |
+ except SystemExit as e: |
109 |
+ raise # Needed else can't exit |
110 |
+ except: |
111 |
+ maxretries = -1 #default number of retries |
112 |
+ |
113 |
+ if syncuri.startswith("file://"): |
114 |
+ self.proto = "file" |
115 |
+ dosyncuri = syncuri[7:] |
116 |
+ unchanged, is_synced, exitcode, updatecache_flg = self._do_rsync( |
117 |
+ dosyncuri, timestamp, opts) |
118 |
+ self._process_exitcode(exitcode, dosyncuri, out, 1) |
119 |
+ return (exitcode, updatecache_flg) |
120 |
+ |
121 |
+ retries=0 |
122 |
+ try: |
123 |
+ self.proto, user_name, hostname, port = re.split( |
124 |
+ r"(rsync|ssh)://([^:/]+@)?(\[[:\da-fA-F]*\]|[^:/]*)(:[0-9]+)?", |
125 |
+ syncuri, maxsplit=4)[1:5] |
126 |
+ except ValueError: |
127 |
+ writemsg_level("!!! sync-uri is invalid: %s\n" % syncuri, |
128 |
+ noiselevel=-1, level=logging.ERROR) |
129 |
+ return (1, False) |
130 |
|
131 |
- addrinfos = None |
132 |
- uris = [] |
133 |
+ self.ssh_opts = self.settings.get("PORTAGE_SSH_OPTS") |
134 |
|
135 |
- try: |
136 |
- addrinfos = getaddrinfo_validate( |
137 |
- socket.getaddrinfo(getaddrinfo_host, None, |
138 |
- family, socket.SOCK_STREAM)) |
139 |
- except socket.error as e: |
140 |
- writemsg_level( |
141 |
- "!!! getaddrinfo failed for '%s': %s\n" |
142 |
- % (_unicode_decode(hostname), _unicode(e)), |
143 |
- noiselevel=-1, level=logging.ERROR) |
144 |
- |
145 |
- if addrinfos: |
146 |
- |
147 |
- AF_INET = socket.AF_INET |
148 |
- AF_INET6 = None |
149 |
- if socket.has_ipv6: |
150 |
- AF_INET6 = socket.AF_INET6 |
151 |
- |
152 |
- ips_v4 = [] |
153 |
- ips_v6 = [] |
154 |
- |
155 |
- for addrinfo in addrinfos: |
156 |
- if addrinfo[0] == AF_INET: |
157 |
- ips_v4.append("%s" % addrinfo[4][0]) |
158 |
- elif AF_INET6 is not None and addrinfo[0] == AF_INET6: |
159 |
- # IPv6 addresses need to be enclosed in square brackets |
160 |
- ips_v6.append("[%s]" % addrinfo[4][0]) |
161 |
- |
162 |
- random.shuffle(ips_v4) |
163 |
- random.shuffle(ips_v6) |
164 |
- |
165 |
- # Give priority to the address family that |
166 |
- # getaddrinfo() returned first. |
167 |
- if AF_INET6 is not None and addrinfos and \ |
168 |
- addrinfos[0][0] == AF_INET6: |
169 |
- ips = ips_v6 + ips_v4 |
170 |
- else: |
171 |
- ips = ips_v4 + ips_v6 |
172 |
- |
173 |
- for ip in ips: |
174 |
- uris.append(syncuri.replace( |
175 |
- "//" + user_name + hostname + port + "/", |
176 |
- "//" + user_name + ip + port + "/", 1)) |
177 |
- |
178 |
- if not uris: |
179 |
- # With some configurations we need to use the plain hostname |
180 |
- # rather than try to resolve the ip addresses (bug #340817). |
181 |
- uris.append(syncuri) |
182 |
- |
183 |
- # reverse, for use with pop() |
184 |
- uris.reverse() |
185 |
- uris_orig = uris[:] |
186 |
- |
187 |
- effective_maxretries = maxretries |
188 |
- if effective_maxretries < 0: |
189 |
- effective_maxretries = len(uris) - 1 |
190 |
- |
191 |
- local_state_unchanged = True |
192 |
- while (1): |
193 |
- if uris: |
194 |
- dosyncuri = uris.pop() |
195 |
- elif maxretries < 0 or retries > maxretries: |
196 |
- writemsg("!!! Exhausted addresses for %s\n" |
197 |
- % _unicode_decode(hostname), noiselevel=-1) |
198 |
- return (1, False) |
199 |
- else: |
200 |
- uris.extend(uris_orig) |
201 |
- dosyncuri = uris.pop() |
202 |
- |
203 |
- if (retries==0): |
204 |
- if "--ask" in opts: |
205 |
- uq = UserQuery(opts) |
206 |
- if uq.query("Do you want to sync your Portage tree " + \ |
207 |
- "with the mirror at\n" + blue(dosyncuri) + bold("?"), |
208 |
- enter_invalid) == "No": |
209 |
- print() |
210 |
- print("Quitting.") |
211 |
- print() |
212 |
- sys.exit(128 + signal.SIGINT) |
213 |
- self.logger(self.xterm_titles, |
214 |
- ">>> Starting rsync with " + dosyncuri) |
215 |
- if "--quiet" not in opts: |
216 |
- print(">>> Starting rsync with "+dosyncuri+"...") |
217 |
- else: |
218 |
- self.logger(self.xterm_titles, |
219 |
- ">>> Starting retry %d of %d with %s" % \ |
220 |
- (retries, effective_maxretries, dosyncuri)) |
221 |
- writemsg_stdout( |
222 |
- "\n\n>>> Starting retry %d of %d with %s\n" % \ |
223 |
- (retries, effective_maxretries, dosyncuri), noiselevel=-1) |
224 |
- |
225 |
- if dosyncuri.startswith('ssh://'): |
226 |
- dosyncuri = dosyncuri[6:].replace('/', ':/', 1) |
227 |
- |
228 |
- unchanged, is_synced, exitcode, updatecache_flg = self._do_rsync( |
229 |
- dosyncuri, timestamp, opts) |
230 |
- if not unchanged: |
231 |
- local_state_unchanged = False |
232 |
- if is_synced: |
233 |
- break |
234 |
- |
235 |
- retries=retries+1 |
236 |
- |
237 |
- if maxretries < 0 or retries <= maxretries: |
238 |
- print(">>> Retrying...") |
239 |
- else: |
240 |
- # over retries |
241 |
- # exit loop |
242 |
- exitcode = EXCEEDED_MAX_RETRIES |
243 |
- break |
244 |
- self._process_exitcode(exitcode, dosyncuri, out, maxretries) |
245 |
- |
246 |
- # if synced successfully, verify now |
247 |
- if exitcode == 0 and self.verify_metamanifest: |
248 |
- if gemato is None: |
249 |
- writemsg_level("!!! Unable to verify: gemato-11.0+ is required\n", |
250 |
- level=logging.ERROR, noiselevel=-1) |
251 |
- exitcode = 127 |
252 |
+ if port is None: |
253 |
+ port="" |
254 |
+ if user_name is None: |
255 |
+ user_name="" |
256 |
+ if re.match(r"^\[[:\da-fA-F]*\]$", hostname) is None: |
257 |
+ getaddrinfo_host = hostname |
258 |
else: |
259 |
- # Use isolated environment if key is specified, |
260 |
- # system environment otherwise |
261 |
- if self.repo.sync_openpgp_key_path is not None: |
262 |
- openpgp_env_cls = gemato.openpgp.OpenPGPEnvironment |
263 |
+ # getaddrinfo needs the brackets stripped |
264 |
+ getaddrinfo_host = hostname[1:-1] |
265 |
+ updatecache_flg = False |
266 |
+ all_rsync_opts = set(self.rsync_opts) |
267 |
+ all_rsync_opts.update(self.extra_rsync_opts) |
268 |
+ |
269 |
+ family = socket.AF_UNSPEC |
270 |
+ if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts: |
271 |
+ family = socket.AF_INET |
272 |
+ elif socket.has_ipv6 and \ |
273 |
+ ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts): |
274 |
+ family = socket.AF_INET6 |
275 |
+ |
276 |
+ addrinfos = None |
277 |
+ uris = [] |
278 |
+ |
279 |
+ try: |
280 |
+ addrinfos = getaddrinfo_validate( |
281 |
+ socket.getaddrinfo(getaddrinfo_host, None, |
282 |
+ family, socket.SOCK_STREAM)) |
283 |
+ except socket.error as e: |
284 |
+ writemsg_level( |
285 |
+ "!!! getaddrinfo failed for '%s': %s\n" |
286 |
+ % (_unicode_decode(hostname), _unicode(e)), |
287 |
+ noiselevel=-1, level=logging.ERROR) |
288 |
+ |
289 |
+ if addrinfos: |
290 |
+ |
291 |
+ AF_INET = socket.AF_INET |
292 |
+ AF_INET6 = None |
293 |
+ if socket.has_ipv6: |
294 |
+ AF_INET6 = socket.AF_INET6 |
295 |
+ |
296 |
+ ips_v4 = [] |
297 |
+ ips_v6 = [] |
298 |
+ |
299 |
+ for addrinfo in addrinfos: |
300 |
+ if addrinfo[0] == AF_INET: |
301 |
+ ips_v4.append("%s" % addrinfo[4][0]) |
302 |
+ elif AF_INET6 is not None and addrinfo[0] == AF_INET6: |
303 |
+ # IPv6 addresses need to be enclosed in square brackets |
304 |
+ ips_v6.append("[%s]" % addrinfo[4][0]) |
305 |
+ |
306 |
+ random.shuffle(ips_v4) |
307 |
+ random.shuffle(ips_v6) |
308 |
+ |
309 |
+ # Give priority to the address family that |
310 |
+ # getaddrinfo() returned first. |
311 |
+ if AF_INET6 is not None and addrinfos and \ |
312 |
+ addrinfos[0][0] == AF_INET6: |
313 |
+ ips = ips_v6 + ips_v4 |
314 |
+ else: |
315 |
+ ips = ips_v4 + ips_v6 |
316 |
+ |
317 |
+ for ip in ips: |
318 |
+ uris.append(syncuri.replace( |
319 |
+ "//" + user_name + hostname + port + "/", |
320 |
+ "//" + user_name + ip + port + "/", 1)) |
321 |
+ |
322 |
+ if not uris: |
323 |
+ # With some configurations we need to use the plain hostname |
324 |
+ # rather than try to resolve the ip addresses (bug #340817). |
325 |
+ uris.append(syncuri) |
326 |
+ |
327 |
+ # reverse, for use with pop() |
328 |
+ uris.reverse() |
329 |
+ uris_orig = uris[:] |
330 |
+ |
331 |
+ effective_maxretries = maxretries |
332 |
+ if effective_maxretries < 0: |
333 |
+ effective_maxretries = len(uris) - 1 |
334 |
+ |
335 |
+ local_state_unchanged = True |
336 |
+ while (1): |
337 |
+ if uris: |
338 |
+ dosyncuri = uris.pop() |
339 |
+ elif maxretries < 0 or retries > maxretries: |
340 |
+ writemsg("!!! Exhausted addresses for %s\n" |
341 |
+ % _unicode_decode(hostname), noiselevel=-1) |
342 |
+ return (1, False) |
343 |
+ else: |
344 |
+ uris.extend(uris_orig) |
345 |
+ dosyncuri = uris.pop() |
346 |
+ |
347 |
+ if (retries==0): |
348 |
+ if "--ask" in opts: |
349 |
+ uq = UserQuery(opts) |
350 |
+ if uq.query("Do you want to sync your Portage tree " + \ |
351 |
+ "with the mirror at\n" + blue(dosyncuri) + bold("?"), |
352 |
+ enter_invalid) == "No": |
353 |
+ print() |
354 |
+ print("Quitting.") |
355 |
+ print() |
356 |
+ sys.exit(128 + signal.SIGINT) |
357 |
+ self.logger(self.xterm_titles, |
358 |
+ ">>> Starting rsync with " + dosyncuri) |
359 |
+ if "--quiet" not in opts: |
360 |
+ print(">>> Starting rsync with "+dosyncuri+"...") |
361 |
+ else: |
362 |
+ self.logger(self.xterm_titles, |
363 |
+ ">>> Starting retry %d of %d with %s" % \ |
364 |
+ (retries, effective_maxretries, dosyncuri)) |
365 |
+ writemsg_stdout( |
366 |
+ "\n\n>>> Starting retry %d of %d with %s\n" % \ |
367 |
+ (retries, effective_maxretries, dosyncuri), noiselevel=-1) |
368 |
+ |
369 |
+ if dosyncuri.startswith('ssh://'): |
370 |
+ dosyncuri = dosyncuri[6:].replace('/', ':/', 1) |
371 |
+ |
372 |
+ unchanged, is_synced, exitcode, updatecache_flg = self._do_rsync( |
373 |
+ dosyncuri, timestamp, opts) |
374 |
+ if not unchanged: |
375 |
+ local_state_unchanged = False |
376 |
+ if is_synced: |
377 |
+ break |
378 |
+ |
379 |
+ retries=retries+1 |
380 |
+ |
381 |
+ if maxretries < 0 or retries <= maxretries: |
382 |
+ print(">>> Retrying...") |
383 |
else: |
384 |
- openpgp_env_cls = gemato.openpgp.OpenPGPSystemEnvironment |
385 |
+ # over retries |
386 |
+ # exit loop |
387 |
+ exitcode = EXCEEDED_MAX_RETRIES |
388 |
+ break |
389 |
+ self._process_exitcode(exitcode, dosyncuri, out, maxretries) |
390 |
+ |
391 |
+ # if synced successfully, verify now |
392 |
+ if exitcode == 0 and self.verify_metamanifest: |
393 |
+ if gemato is None: |
394 |
+ writemsg_level("!!! Unable to verify: gemato-11.0+ is required\n", |
395 |
+ level=logging.ERROR, noiselevel=-1) |
396 |
+ exitcode = 127 |
397 |
+ else: |
398 |
+ # Use isolated environment if key is specified, |
399 |
+ # system environment otherwise |
400 |
+ if self.repo.sync_openpgp_key_path is not None: |
401 |
+ openpgp_env_cls = gemato.openpgp.OpenPGPEnvironment |
402 |
+ else: |
403 |
+ openpgp_env_cls = gemato.openpgp.OpenPGPSystemEnvironment |
404 |
+ |
405 |
+ try: |
406 |
+ with openpgp_env_cls() as openpgp_env: |
407 |
+ if self.repo.sync_openpgp_key_path is not None: |
408 |
+ out.einfo('Using keys from %s' % (self.repo.sync_openpgp_key_path,)) |
409 |
+ with io.open(self.repo.sync_openpgp_key_path, 'rb') as f: |
410 |
+ openpgp_env.import_key(f) |
411 |
+ out.ebegin('Refreshing keys from keyserver') |
412 |
+ openpgp_env.refresh_keys() |
413 |
+ out.eend(0) |
414 |
+ |
415 |
+ # we always verify the Manifest signature, in case |
416 |
+ # we had to deal with key revocation case |
417 |
+ m = gemato.recursiveloader.ManifestRecursiveLoader( |
418 |
+ os.path.join(self.repo.location, 'Manifest'), |
419 |
+ verify_openpgp=True, |
420 |
+ openpgp_env=openpgp_env, |
421 |
+ max_jobs=self.verify_jobs) |
422 |
+ if not m.openpgp_signed: |
423 |
+ raise RuntimeError('OpenPGP signature not found on Manifest') |
424 |
+ |
425 |
+ ts = m.find_timestamp() |
426 |
+ if ts is None: |
427 |
+ raise RuntimeError('Timestamp not found in Manifest') |
428 |
+ |
429 |
+ out.einfo('Manifest timestamp: %s UTC' % (ts.ts,)) |
430 |
+ out.einfo('Valid OpenPGP signature found:') |
431 |
+ out.einfo('- primary key: %s' % ( |
432 |
+ m.openpgp_signature.primary_key_fingerprint)) |
433 |
+ out.einfo('- subkey: %s' % ( |
434 |
+ m.openpgp_signature.fingerprint)) |
435 |
+ out.einfo('- timestamp: %s UTC' % ( |
436 |
+ m.openpgp_signature.timestamp)) |
437 |
+ |
438 |
+ # if nothing has changed, skip the actual Manifest |
439 |
+ # verification |
440 |
+ if not local_state_unchanged: |
441 |
+ out.ebegin('Verifying %s' % (self.repo.location,)) |
442 |
+ m.assert_directory_verifies() |
443 |
+ out.eend(0) |
444 |
+ except GematoException as e: |
445 |
+ writemsg_level("!!! Manifest verification failed:\n%s\n" |
446 |
+ % (e,), |
447 |
+ level=logging.ERROR, noiselevel=-1) |
448 |
+ exitcode = 1 |
449 |
|
450 |
- try: |
451 |
- with openpgp_env_cls() as openpgp_env: |
452 |
- if self.repo.sync_openpgp_key_path is not None: |
453 |
- out.einfo('Using keys from %s' % (self.repo.sync_openpgp_key_path,)) |
454 |
- with io.open(self.repo.sync_openpgp_key_path, 'rb') as f: |
455 |
- openpgp_env.import_key(f) |
456 |
- out.ebegin('Refreshing keys from keyserver') |
457 |
- openpgp_env.refresh_keys() |
458 |
- out.eend(0) |
459 |
- |
460 |
- # we always verify the Manifest signature, in case |
461 |
- # we had to deal with key revocation case |
462 |
- m = gemato.recursiveloader.ManifestRecursiveLoader( |
463 |
- os.path.join(self.repo.location, 'Manifest'), |
464 |
- verify_openpgp=True, |
465 |
- openpgp_env=openpgp_env, |
466 |
- max_jobs=self.verify_jobs) |
467 |
- if not m.openpgp_signed: |
468 |
- raise RuntimeError('OpenPGP signature not found on Manifest') |
469 |
- |
470 |
- ts = m.find_timestamp() |
471 |
- if ts is None: |
472 |
- raise RuntimeError('Timestamp not found in Manifest') |
473 |
- |
474 |
- out.einfo('Manifest timestamp: %s UTC' % (ts.ts,)) |
475 |
- out.einfo('Valid OpenPGP signature found:') |
476 |
- out.einfo('- primary key: %s' % ( |
477 |
- m.openpgp_signature.primary_key_fingerprint)) |
478 |
- out.einfo('- subkey: %s' % ( |
479 |
- m.openpgp_signature.fingerprint)) |
480 |
- out.einfo('- timestamp: %s UTC' % ( |
481 |
- m.openpgp_signature.timestamp)) |
482 |
- |
483 |
- # if nothing has changed, skip the actual Manifest |
484 |
- # verification |
485 |
- if not local_state_unchanged: |
486 |
- out.ebegin('Verifying %s' % (self.repo.location,)) |
487 |
- m.assert_directory_verifies() |
488 |
- out.eend(0) |
489 |
- except GematoException as e: |
490 |
- writemsg_level("!!! Manifest verification failed:\n%s\n" |
491 |
- % (e,), |
492 |
- level=logging.ERROR, noiselevel=-1) |
493 |
- exitcode = 1 |
494 |
- |
495 |
- return (exitcode, updatecache_flg) |
496 |
+ return (exitcode, updatecache_flg) |
497 |
+ finally: |
498 |
+ pass |
499 |
|
500 |
|
501 |
def _process_exitcode(self, exitcode, syncuri, out, maxretries): |