summaryrefslogtreecommitdiffstats
path: root/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'main.py')
-rwxr-xr-xmain.py302
1 files changed, 206 insertions, 96 deletions
diff --git a/main.py b/main.py
index 16db144f..2050cabb 100755
--- a/main.py
+++ b/main.py
@@ -1,5 +1,4 @@
1#!/usr/bin/env python 1#!/usr/bin/env python3
2# -*- coding:utf-8 -*-
3# 2#
4# Copyright (C) 2008 The Android Open Source Project 3# Copyright (C) 2008 The Android Open Source Project
5# 4#
@@ -21,23 +20,15 @@ People shouldn't run this directly; instead, they should use the `repo` wrapper
21which takes care of execing this entry point. 20which takes care of execing this entry point.
22""" 21"""
23 22
24from __future__ import print_function
25import getpass 23import getpass
26import netrc 24import netrc
27import optparse 25import optparse
28import os 26import os
27import shlex
29import sys 28import sys
30import textwrap 29import textwrap
31import time 30import time
32 31import urllib.request
33from pyversion import is_python3
34if is_python3():
35 import urllib.request
36else:
37 import imp
38 import urllib2
39 urllib = imp.new_module('urllib')
40 urllib.request = urllib2
41 32
42try: 33try:
43 import kerberos 34 import kerberos
@@ -47,8 +38,9 @@ except ImportError:
47from color import SetDefaultColoring 38from color import SetDefaultColoring
48import event_log 39import event_log
49from repo_trace import SetTrace 40from repo_trace import SetTrace
50from git_command import git, GitCommand, user_agent 41from git_command import user_agent
51from git_config import init_ssh, close_ssh 42from git_config import RepoConfig
43from git_trace2_event_log import EventLog
52from command import InteractiveCommand 44from command import InteractiveCommand
53from command import MirrorSafeCommand 45from command import MirrorSafeCommand
54from command import GitcAvailableCommand, GitcClientCommand 46from command import GitcAvailableCommand, GitcClientCommand
@@ -62,25 +54,54 @@ from error import NoManifestException
62from error import NoSuchProjectError 54from error import NoSuchProjectError
63from error import RepoChangedException 55from error import RepoChangedException
64import gitc_utils 56import gitc_utils
65from manifest_xml import GitcManifest, XmlManifest 57from manifest_xml import GitcClient, RepoClient
66from pager import RunPager, TerminatePager 58from pager import RunPager, TerminatePager
67from wrapper import WrapperPath, Wrapper 59from wrapper import WrapperPath, Wrapper
68 60
69from subcmds import all_commands 61from subcmds import all_commands
70 62
71if not is_python3(): 63
72 input = raw_input 64# NB: These do not need to be kept in sync with the repo launcher script.
65# These may be much newer as it allows the repo launcher to roll between
66# different repo releases while source versions might require a newer python.
67#
68# The soft version is when we start warning users that the version is old and
69# we'll be dropping support for it. We'll refuse to work with versions older
70# than the hard version.
71#
72# python-3.6 is in Ubuntu Bionic.
73MIN_PYTHON_VERSION_SOFT = (3, 6)
74MIN_PYTHON_VERSION_HARD = (3, 6)
75
76if sys.version_info.major < 3:
77 print('repo: error: Python 2 is no longer supported; '
78 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION_SOFT),
79 file=sys.stderr)
80 sys.exit(1)
81else:
82 if sys.version_info < MIN_PYTHON_VERSION_HARD:
83 print('repo: error: Python 3 version is too old; '
84 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION_SOFT),
85 file=sys.stderr)
86 sys.exit(1)
87 elif sys.version_info < MIN_PYTHON_VERSION_SOFT:
88 print('repo: warning: your Python 3 version is no longer supported; '
89 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION_SOFT),
90 file=sys.stderr)
91
73 92
74global_options = optparse.OptionParser( 93global_options = optparse.OptionParser(
75 usage='repo [-p|--paginate|--no-pager] COMMAND [ARGS]', 94 usage='repo [-p|--paginate|--no-pager] COMMAND [ARGS]',
76 add_help_option=False) 95 add_help_option=False)
77global_options.add_option('-h', '--help', action='store_true', 96global_options.add_option('-h', '--help', action='store_true',
78 help='show this help message and exit') 97 help='show this help message and exit')
98global_options.add_option('--help-all', action='store_true',
99 help='show this help message with all subcommands and exit')
79global_options.add_option('-p', '--paginate', 100global_options.add_option('-p', '--paginate',
80 dest='pager', action='store_true', 101 dest='pager', action='store_true',
81 help='display command output in the pager') 102 help='display command output in the pager')
82global_options.add_option('--no-pager', 103global_options.add_option('--no-pager',
83 dest='no_pager', action='store_true', 104 dest='pager', action='store_false',
84 help='disable the pager') 105 help='disable the pager')
85global_options.add_option('--color', 106global_options.add_option('--color',
86 choices=('auto', 'always', 'never'), default=None, 107 choices=('auto', 'always', 'never'), default=None,
@@ -97,76 +118,125 @@ global_options.add_option('--time',
97global_options.add_option('--version', 118global_options.add_option('--version',
98 dest='show_version', action='store_true', 119 dest='show_version', action='store_true',
99 help='display this version of repo') 120 help='display this version of repo')
121global_options.add_option('--show-toplevel',
122 action='store_true',
123 help='display the path of the top-level directory of '
124 'the repo client checkout')
100global_options.add_option('--event-log', 125global_options.add_option('--event-log',
101 dest='event_log', action='store', 126 dest='event_log', action='store',
102 help='filename of event log to append timeline to') 127 help='filename of event log to append timeline to')
128global_options.add_option('--git-trace2-event-log', action='store',
129 help='directory to write git trace2 event log to')
130
103 131
104class _Repo(object): 132class _Repo(object):
105 def __init__(self, repodir): 133 def __init__(self, repodir):
106 self.repodir = repodir 134 self.repodir = repodir
107 self.commands = all_commands 135 self.commands = all_commands
108 # add 'branch' as an alias for 'branches' 136
109 all_commands['branch'] = all_commands['branches'] 137 def _PrintHelp(self, short: bool = False, all_commands: bool = False):
138 """Show --help screen."""
139 global_options.print_help()
140 print()
141 if short:
142 commands = ' '.join(sorted(self.commands))
143 wrapped_commands = textwrap.wrap(commands, width=77)
144 print('Available commands:\n %s' % ('\n '.join(wrapped_commands),))
145 print('\nRun `repo help <command>` for command-specific details.')
146 print('Bug reports:', Wrapper().BUG_URL)
147 else:
148 cmd = self.commands['help']()
149 if all_commands:
150 cmd.PrintAllCommandsBody()
151 else:
152 cmd.PrintCommonCommandsBody()
110 153
111 def _ParseArgs(self, argv): 154 def _ParseArgs(self, argv):
112 """Parse the main `repo` command line options.""" 155 """Parse the main `repo` command line options."""
113 name = None 156 for i, arg in enumerate(argv):
114 glob = [] 157 if not arg.startswith('-'):
115 158 name = arg
116 for i in range(len(argv)): 159 glob = argv[:i]
117 if not argv[i].startswith('-'):
118 name = argv[i]
119 if i > 0:
120 glob = argv[:i]
121 argv = argv[i + 1:] 160 argv = argv[i + 1:]
122 break 161 break
123 if not name: 162 else:
163 name = None
124 glob = argv 164 glob = argv
125 name = 'help'
126 argv = [] 165 argv = []
127 gopts, _gargs = global_options.parse_args(glob) 166 gopts, _gargs = global_options.parse_args(glob)
128 167
129 if gopts.help: 168 if name:
130 global_options.print_help() 169 name, alias_args = self._ExpandAlias(name)
131 commands = ' '.join(sorted(self.commands)) 170 argv = alias_args + argv
132 wrapped_commands = textwrap.wrap(commands, width=77)
133 print('\nAvailable commands:\n %s' % ('\n '.join(wrapped_commands),))
134 print('\nRun `repo help <command>` for command-specific details.')
135 global_options.exit()
136 171
137 return (name, gopts, argv) 172 return (name, gopts, argv)
138 173
174 def _ExpandAlias(self, name):
175 """Look up user registered aliases."""
176 # We don't resolve aliases for existing subcommands. This matches git.
177 if name in self.commands:
178 return name, []
179
180 key = 'alias.%s' % (name,)
181 alias = RepoConfig.ForRepository(self.repodir).GetString(key)
182 if alias is None:
183 alias = RepoConfig.ForUser().GetString(key)
184 if alias is None:
185 return name, []
186
187 args = alias.strip().split(' ', 1)
188 name = args[0]
189 if len(args) == 2:
190 args = shlex.split(args[1])
191 else:
192 args = []
193 return name, args
194
139 def _Run(self, name, gopts, argv): 195 def _Run(self, name, gopts, argv):
140 """Execute the requested subcommand.""" 196 """Execute the requested subcommand."""
141 result = 0 197 result = 0
142 198
143 if gopts.trace: 199 if gopts.trace:
144 SetTrace() 200 SetTrace()
145 if gopts.show_version: 201
146 if name == 'help': 202 # Handle options that terminate quickly first.
147 name = 'version' 203 if gopts.help or gopts.help_all:
148 else: 204 self._PrintHelp(short=False, all_commands=gopts.help_all)
149 print('fatal: invalid usage of --version', file=sys.stderr) 205 return 0
150 return 1 206 elif gopts.show_version:
207 # Always allow global --version regardless of subcommand validity.
208 name = 'version'
209 elif gopts.show_toplevel:
210 print(os.path.dirname(self.repodir))
211 return 0
212 elif not name:
213 # No subcommand specified, so show the help/subcommand.
214 self._PrintHelp(short=True)
215 return 1
151 216
152 SetDefaultColoring(gopts.color) 217 SetDefaultColoring(gopts.color)
153 218
219 git_trace2_event_log = EventLog()
220 repo_client = RepoClient(self.repodir)
221 gitc_manifest = None
222 gitc_client_name = gitc_utils.parse_clientdir(os.getcwd())
223 if gitc_client_name:
224 gitc_manifest = GitcClient(self.repodir, gitc_client_name)
225 repo_client.isGitcClient = True
226
154 try: 227 try:
155 cmd = self.commands[name] 228 cmd = self.commands[name](
229 repodir=self.repodir,
230 client=repo_client,
231 manifest=repo_client.manifest,
232 gitc_manifest=gitc_manifest,
233 git_event_log=git_trace2_event_log)
156 except KeyError: 234 except KeyError:
157 print("repo: '%s' is not a repo command. See 'repo help'." % name, 235 print("repo: '%s' is not a repo command. See 'repo help'." % name,
158 file=sys.stderr) 236 file=sys.stderr)
159 return 1 237 return 1
160 238
161 cmd.repodir = self.repodir 239 Editor.globalConfig = cmd.client.globalConfig
162 cmd.manifest = XmlManifest(cmd.repodir)
163 cmd.gitc_manifest = None
164 gitc_client_name = gitc_utils.parse_clientdir(os.getcwd())
165 if gitc_client_name:
166 cmd.gitc_manifest = GitcManifest(cmd.repodir, gitc_client_name)
167 cmd.manifest.isGitcClient = True
168
169 Editor.globalConfig = cmd.manifest.globalConfig
170 240
171 if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror: 241 if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror:
172 print("fatal: '%s' requires a working directory" % name, 242 print("fatal: '%s' requires a working directory" % name,
@@ -188,13 +258,13 @@ class _Repo(object):
188 copts = cmd.ReadEnvironmentOptions(copts) 258 copts = cmd.ReadEnvironmentOptions(copts)
189 except NoManifestException as e: 259 except NoManifestException as e:
190 print('error: in `%s`: %s' % (' '.join([name] + argv), str(e)), 260 print('error: in `%s`: %s' % (' '.join([name] + argv), str(e)),
191 file=sys.stderr) 261 file=sys.stderr)
192 print('error: manifest missing or unreadable -- please run init', 262 print('error: manifest missing or unreadable -- please run init',
193 file=sys.stderr) 263 file=sys.stderr)
194 return 1 264 return 1
195 265
196 if not gopts.no_pager and not isinstance(cmd, InteractiveCommand): 266 if gopts.pager is not False and not isinstance(cmd, InteractiveCommand):
197 config = cmd.manifest.globalConfig 267 config = cmd.client.globalConfig
198 if gopts.pager: 268 if gopts.pager:
199 use_pager = True 269 use_pager = True
200 else: 270 else:
@@ -207,13 +277,17 @@ class _Repo(object):
207 start = time.time() 277 start = time.time()
208 cmd_event = cmd.event_log.Add(name, event_log.TASK_COMMAND, start) 278 cmd_event = cmd.event_log.Add(name, event_log.TASK_COMMAND, start)
209 cmd.event_log.SetParent(cmd_event) 279 cmd.event_log.SetParent(cmd_event)
280 git_trace2_event_log.StartEvent()
281 git_trace2_event_log.CommandEvent(name='repo', subcommands=[name])
282
210 try: 283 try:
284 cmd.CommonValidateOptions(copts, cargs)
211 cmd.ValidateOptions(copts, cargs) 285 cmd.ValidateOptions(copts, cargs)
212 result = cmd.Execute(copts, cargs) 286 result = cmd.Execute(copts, cargs)
213 except (DownloadError, ManifestInvalidRevisionError, 287 except (DownloadError, ManifestInvalidRevisionError,
214 NoManifestException) as e: 288 NoManifestException) as e:
215 print('error: in `%s`: %s' % (' '.join([name] + argv), str(e)), 289 print('error: in `%s`: %s' % (' '.join([name] + argv), str(e)),
216 file=sys.stderr) 290 file=sys.stderr)
217 if isinstance(e, NoManifestException): 291 if isinstance(e, NoManifestException):
218 print('error: manifest missing or unreadable -- please run init', 292 print('error: manifest missing or unreadable -- please run init',
219 file=sys.stderr) 293 file=sys.stderr)
@@ -228,7 +302,8 @@ class _Repo(object):
228 if e.name: 302 if e.name:
229 print('error: project group must be enabled for project %s' % e.name, file=sys.stderr) 303 print('error: project group must be enabled for project %s' % e.name, file=sys.stderr)
230 else: 304 else:
231 print('error: project group must be enabled for the project in the current directory', file=sys.stderr) 305 print('error: project group must be enabled for the project in the current directory',
306 file=sys.stderr)
232 result = 1 307 result = 1
233 except SystemExit as e: 308 except SystemExit as e:
234 if e.code: 309 if e.code:
@@ -248,49 +323,78 @@ class _Repo(object):
248 323
249 cmd.event_log.FinishEvent(cmd_event, finish, 324 cmd.event_log.FinishEvent(cmd_event, finish,
250 result is None or result == 0) 325 result is None or result == 0)
326 git_trace2_event_log.DefParamRepoEvents(
327 cmd.manifest.manifestProject.config.DumpConfigDict())
328 git_trace2_event_log.ExitEvent(result)
329
251 if gopts.event_log: 330 if gopts.event_log:
252 cmd.event_log.Write(os.path.abspath( 331 cmd.event_log.Write(os.path.abspath(
253 os.path.expanduser(gopts.event_log))) 332 os.path.expanduser(gopts.event_log)))
254 333
334 git_trace2_event_log.Write(gopts.git_trace2_event_log)
255 return result 335 return result
256 336
257 337
258def _CheckWrapperVersion(ver, repo_path): 338def _CheckWrapperVersion(ver_str, repo_path):
339 """Verify the repo launcher is new enough for this checkout.
340
341 Args:
342 ver_str: The version string passed from the repo launcher when it ran us.
343 repo_path: The path to the repo launcher that loaded us.
344 """
345 # Refuse to work with really old wrapper versions. We don't test these,
346 # so might as well require a somewhat recent sane version.
347 # v1.15 of the repo launcher was released in ~Mar 2012.
348 MIN_REPO_VERSION = (1, 15)
349 min_str = '.'.join(str(x) for x in MIN_REPO_VERSION)
350
259 if not repo_path: 351 if not repo_path:
260 repo_path = '~/bin/repo' 352 repo_path = '~/bin/repo'
261 353
262 if not ver: 354 if not ver_str:
263 print('no --wrapper-version argument', file=sys.stderr) 355 print('no --wrapper-version argument', file=sys.stderr)
264 sys.exit(1) 356 sys.exit(1)
265 357
358 # Pull out the version of the repo launcher we know about to compare.
266 exp = Wrapper().VERSION 359 exp = Wrapper().VERSION
267 ver = tuple(map(int, ver.split('.'))) 360 ver = tuple(map(int, ver_str.split('.')))
268 if len(ver) == 1:
269 ver = (0, ver[0])
270 361
271 exp_str = '.'.join(map(str, exp)) 362 exp_str = '.'.join(map(str, exp))
272 if exp[0] > ver[0] or ver < (0, 4): 363 if ver < MIN_REPO_VERSION:
273 print(""" 364 print("""
274!!! A new repo command (%5s) is available. !!! 365repo: error:
275!!! You must upgrade before you can continue: !!! 366!!! Your version of repo %s is too old.
367!!! We need at least version %s.
368!!! A new version of repo (%s) is available.
369!!! You must upgrade before you can continue:
276 370
277 cp %s %s 371 cp %s %s
278""" % (exp_str, WrapperPath(), repo_path), file=sys.stderr) 372""" % (ver_str, min_str, exp_str, WrapperPath(), repo_path), file=sys.stderr)
279 sys.exit(1) 373 sys.exit(1)
280 374
281 if exp > ver: 375 if exp > ver:
282 print(""" 376 print('\n... A new version of repo (%s) is available.' % (exp_str,),
283... A new repo command (%5s) is available. 377 file=sys.stderr)
378 if os.access(repo_path, os.W_OK):
379 print("""\
284... You should upgrade soon: 380... You should upgrade soon:
285
286 cp %s %s 381 cp %s %s
287""" % (exp_str, WrapperPath(), repo_path), file=sys.stderr) 382""" % (WrapperPath(), repo_path), file=sys.stderr)
383 else:
384 print("""\
385... New version is available at: %s
386... The launcher is run from: %s
387!!! The launcher is not writable. Please talk to your sysadmin or distro
388!!! to get an update installed.
389""" % (WrapperPath(), repo_path), file=sys.stderr)
390
288 391
289def _CheckRepoDir(repo_dir): 392def _CheckRepoDir(repo_dir):
290 if not repo_dir: 393 if not repo_dir:
291 print('no --repo-dir argument', file=sys.stderr) 394 print('no --repo-dir argument', file=sys.stderr)
292 sys.exit(1) 395 sys.exit(1)
293 396
397
294def _PruneOptions(argv, opt): 398def _PruneOptions(argv, opt):
295 i = 0 399 i = 0
296 while i < len(argv): 400 while i < len(argv):
@@ -306,6 +410,7 @@ def _PruneOptions(argv, opt):
306 continue 410 continue
307 i += 1 411 i += 1
308 412
413
309class _UserAgentHandler(urllib.request.BaseHandler): 414class _UserAgentHandler(urllib.request.BaseHandler):
310 def http_request(self, req): 415 def http_request(self, req):
311 req.add_header('User-Agent', user_agent.repo) 416 req.add_header('User-Agent', user_agent.repo)
@@ -315,6 +420,7 @@ class _UserAgentHandler(urllib.request.BaseHandler):
315 req.add_header('User-Agent', user_agent.repo) 420 req.add_header('User-Agent', user_agent.repo)
316 return req 421 return req
317 422
423
318def _AddPasswordFromUserInput(handler, msg, req): 424def _AddPasswordFromUserInput(handler, msg, req):
319 # If repo could not find auth info from netrc, try to get it from user input 425 # If repo could not find auth info from netrc, try to get it from user input
320 url = req.get_full_url() 426 url = req.get_full_url()
@@ -328,22 +434,24 @@ def _AddPasswordFromUserInput(handler, msg, req):
328 return 434 return
329 handler.passwd.add_password(None, url, user, password) 435 handler.passwd.add_password(None, url, user, password)
330 436
437
331class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): 438class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
332 def http_error_401(self, req, fp, code, msg, headers): 439 def http_error_401(self, req, fp, code, msg, headers):
333 _AddPasswordFromUserInput(self, msg, req) 440 _AddPasswordFromUserInput(self, msg, req)
334 return urllib.request.HTTPBasicAuthHandler.http_error_401( 441 return urllib.request.HTTPBasicAuthHandler.http_error_401(
335 self, req, fp, code, msg, headers) 442 self, req, fp, code, msg, headers)
336 443
337 def http_error_auth_reqed(self, authreq, host, req, headers): 444 def http_error_auth_reqed(self, authreq, host, req, headers):
338 try: 445 try:
339 old_add_header = req.add_header 446 old_add_header = req.add_header
447
340 def _add_header(name, val): 448 def _add_header(name, val):
341 val = val.replace('\n', '') 449 val = val.replace('\n', '')
342 old_add_header(name, val) 450 old_add_header(name, val)
343 req.add_header = _add_header 451 req.add_header = _add_header
344 return urllib.request.AbstractBasicAuthHandler.http_error_auth_reqed( 452 return urllib.request.AbstractBasicAuthHandler.http_error_auth_reqed(
345 self, authreq, host, req, headers) 453 self, authreq, host, req, headers)
346 except: 454 except Exception:
347 reset = getattr(self, 'reset_retry_count', None) 455 reset = getattr(self, 'reset_retry_count', None)
348 if reset is not None: 456 if reset is not None:
349 reset() 457 reset()
@@ -351,22 +459,24 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
351 self.retried = 0 459 self.retried = 0
352 raise 460 raise
353 461
462
354class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): 463class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
355 def http_error_401(self, req, fp, code, msg, headers): 464 def http_error_401(self, req, fp, code, msg, headers):
356 _AddPasswordFromUserInput(self, msg, req) 465 _AddPasswordFromUserInput(self, msg, req)
357 return urllib.request.HTTPDigestAuthHandler.http_error_401( 466 return urllib.request.HTTPDigestAuthHandler.http_error_401(
358 self, req, fp, code, msg, headers) 467 self, req, fp, code, msg, headers)
359 468
360 def http_error_auth_reqed(self, auth_header, host, req, headers): 469 def http_error_auth_reqed(self, auth_header, host, req, headers):
361 try: 470 try:
362 old_add_header = req.add_header 471 old_add_header = req.add_header
472
363 def _add_header(name, val): 473 def _add_header(name, val):
364 val = val.replace('\n', '') 474 val = val.replace('\n', '')
365 old_add_header(name, val) 475 old_add_header(name, val)
366 req.add_header = _add_header 476 req.add_header = _add_header
367 return urllib.request.AbstractDigestAuthHandler.http_error_auth_reqed( 477 return urllib.request.AbstractDigestAuthHandler.http_error_auth_reqed(
368 self, auth_header, host, req, headers) 478 self, auth_header, host, req, headers)
369 except: 479 except Exception:
370 reset = getattr(self, 'reset_retry_count', None) 480 reset = getattr(self, 'reset_retry_count', None)
371 if reset is not None: 481 if reset is not None:
372 reset() 482 reset()
@@ -374,6 +484,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
374 self.retried = 0 484 self.retried = 0
375 raise 485 raise
376 486
487
377class _KerberosAuthHandler(urllib.request.BaseHandler): 488class _KerberosAuthHandler(urllib.request.BaseHandler):
378 def __init__(self): 489 def __init__(self):
379 self.retried = 0 490 self.retried = 0
@@ -392,7 +503,7 @@ class _KerberosAuthHandler(urllib.request.BaseHandler):
392 503
393 if self.retried > 3: 504 if self.retried > 3:
394 raise urllib.request.HTTPError(req.get_full_url(), 401, 505 raise urllib.request.HTTPError(req.get_full_url(), 401,
395 "Negotiate auth failed", headers, None) 506 "Negotiate auth failed", headers, None)
396 else: 507 else:
397 self.retried += 1 508 self.retried += 1
398 509
@@ -408,7 +519,7 @@ class _KerberosAuthHandler(urllib.request.BaseHandler):
408 return response 519 return response
409 except kerberos.GSSError: 520 except kerberos.GSSError:
410 return None 521 return None
411 except: 522 except Exception:
412 self.reset_retry_count() 523 self.reset_retry_count()
413 raise 524 raise
414 finally: 525 finally:
@@ -454,6 +565,7 @@ class _KerberosAuthHandler(urllib.request.BaseHandler):
454 kerberos.authGSSClientClean(self.context) 565 kerberos.authGSSClientClean(self.context)
455 self.context = None 566 self.context = None
456 567
568
457def init_http(): 569def init_http():
458 handlers = [_UserAgentHandler()] 570 handlers = [_UserAgentHandler()]
459 571
@@ -462,7 +574,7 @@ def init_http():
462 n = netrc.netrc() 574 n = netrc.netrc()
463 for host in n.hosts: 575 for host in n.hosts:
464 p = n.hosts[host] 576 p = n.hosts[host]
465 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2]) 577 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
466 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2]) 578 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
467 except netrc.NetrcParseError: 579 except netrc.NetrcParseError:
468 pass 580 pass
@@ -481,6 +593,7 @@ def init_http():
481 handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) 593 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
482 urllib.request.install_opener(urllib.request.build_opener(*handlers)) 594 urllib.request.install_opener(urllib.request.build_opener(*handlers))
483 595
596
484def _Main(argv): 597def _Main(argv):
485 result = 0 598 result = 0
486 599
@@ -502,20 +615,16 @@ def _Main(argv):
502 615
503 repo = _Repo(opt.repodir) 616 repo = _Repo(opt.repodir)
504 try: 617 try:
505 try: 618 init_http()
506 init_ssh() 619 name, gopts, argv = repo._ParseArgs(argv)
507 init_http() 620 run = lambda: repo._Run(name, gopts, argv) or 0
508 name, gopts, argv = repo._ParseArgs(argv) 621 if gopts.trace_python:
509 run = lambda: repo._Run(name, gopts, argv) or 0 622 import trace
510 if gopts.trace_python: 623 tracer = trace.Trace(count=False, trace=True, timing=True,
511 import trace 624 ignoredirs=set(sys.path[1:]))
512 tracer = trace.Trace(count=False, trace=True, timing=True, 625 result = tracer.runfunc(run)
513 ignoredirs=set(sys.path[1:])) 626 else:
514 result = tracer.runfunc(run) 627 result = run()
515 else:
516 result = run()
517 finally:
518 close_ssh()
519 except KeyboardInterrupt: 628 except KeyboardInterrupt:
520 print('aborted by user', file=sys.stderr) 629 print('aborted by user', file=sys.stderr)
521 result = 1 630 result = 1
@@ -528,7 +637,7 @@ def _Main(argv):
528 argv = list(sys.argv) 637 argv = list(sys.argv)
529 argv.extend(rce.extra_args) 638 argv.extend(rce.extra_args)
530 try: 639 try:
531 os.execv(__file__, argv) 640 os.execv(sys.executable, [__file__] + argv)
532 except OSError as e: 641 except OSError as e:
533 print('fatal: cannot restart repo after upgrade', file=sys.stderr) 642 print('fatal: cannot restart repo after upgrade', file=sys.stderr)
534 print('fatal: %s' % e, file=sys.stderr) 643 print('fatal: %s' % e, file=sys.stderr)
@@ -537,5 +646,6 @@ def _Main(argv):
537 TerminatePager() 646 TerminatePager()
538 sys.exit(result) 647 sys.exit(result)
539 648
649
540if __name__ == '__main__': 650if __name__ == '__main__':
541 _Main(sys.argv[1:]) 651 _Main(sys.argv[1:])