summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Pursehouse <dpursehouse@collab.net>2020-02-12 15:20:19 +0900
committerDavid Pursehouse <dpursehouse@collab.net>2020-02-12 06:36:40 +0000
commit819827a42ddb364f98c3a1a7eae2536dc54bc4cc (patch)
treefe6bdca5ff7e44d53595a6da76d2b56ea659eee1
parentabdf7500612f1d115863ba8f026ddbea1e5a1f28 (diff)
downloadgit-repo-819827a42ddb364f98c3a1a7eae2536dc54bc4cc.tar.gz
Fix blank line issues reported by flake8
- E301 expected 1 blank line - E302 expected 2 blank lines - E303 too many blank lines - E305 expected 2 blank lines after class or function definition - E306 expected 1 blank line before a nested definition Fixed automatically with autopep8: git ls-files | grep py$ | xargs autopep8 --in-place \ --select E301,E302,E303,E305,E306 Manually fix issues in project.py caused by misuse of block comments. Change-Id: Iee840fcaff48aae504ddac9c3e76d2acd484f6a9 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/254599 Reviewed-by: Mike Frysinger <vapier@google.com> Tested-by: David Pursehouse <dpursehouse@collab.net>
-rw-r--r--color.py1
-rw-r--r--command.py2
-rw-r--r--editor.py1
-rw-r--r--error.py19
-rw-r--r--event_log.py2
-rw-r--r--git_command.py14
-rw-r--r--git_config.py16
-rw-r--r--gitc_utils.py6
-rwxr-xr-xmain.py13
-rw-r--r--manifest_xml.py4
-rw-r--r--pager.py6
-rw-r--r--platform_utils.py4
-rw-r--r--progress.py1
-rw-r--r--project.py10
-rw-r--r--pyversion.py1
-rw-r--r--repo_trace.py3
-rw-r--r--subcmds/abandon.py2
-rw-r--r--subcmds/branches.py2
-rw-r--r--subcmds/checkout.py1
-rw-r--r--subcmds/cherry_pick.py1
-rw-r--r--subcmds/diff.py1
-rw-r--r--subcmds/diffmanifests.py2
-rw-r--r--subcmds/download.py1
-rw-r--r--subcmds/forall.py3
-rw-r--r--subcmds/gitc_delete.py1
-rw-r--r--subcmds/grep.py3
-rw-r--r--subcmds/help.py1
-rw-r--r--subcmds/info.py3
-rw-r--r--subcmds/init.py1
-rw-r--r--subcmds/list.py1
-rw-r--r--subcmds/manifest.py1
-rw-r--r--subcmds/prune.py1
-rw-r--r--subcmds/selfupdate.py1
-rw-r--r--subcmds/smartsync.py1
-rw-r--r--subcmds/stage.py3
-rw-r--r--subcmds/start.py1
-rw-r--r--subcmds/status.py1
-rw-r--r--subcmds/sync.py9
-rw-r--r--subcmds/upload.py4
-rw-r--r--subcmds/version.py1
-rw-r--r--tests/test_git_config.py4
-rw-r--r--tests/test_wrapper.py4
-rw-r--r--wrapper.py3
43 files changed, 148 insertions, 12 deletions
diff --git a/color.py b/color.py
index 5b3a282d..7df20223 100644
--- a/color.py
+++ b/color.py
@@ -84,6 +84,7 @@ def _Color(fg=None, bg=None, attr=None):
84 code = '' 84 code = ''
85 return code 85 return code
86 86
87
87DEFAULT = None 88DEFAULT = None
88 89
89 90
diff --git a/command.py b/command.py
index 4f6515e7..d4d86798 100644
--- a/command.py
+++ b/command.py
@@ -236,6 +236,7 @@ class InteractiveCommand(Command):
236 """Command which requires user interaction on the tty and 236 """Command which requires user interaction on the tty and
237 must not run within a pager, even if the user asks to. 237 must not run within a pager, even if the user asks to.
238 """ 238 """
239
239 def WantPager(self, _opt): 240 def WantPager(self, _opt):
240 return False 241 return False
241 242
@@ -244,6 +245,7 @@ class PagedCommand(Command):
244 """Command which defaults to output in a pager, as its 245 """Command which defaults to output in a pager, as its
245 display tends to be larger than one screen full. 246 display tends to be larger than one screen full.
246 """ 247 """
248
247 def WantPager(self, _opt): 249 def WantPager(self, _opt):
248 return True 250 return True
249 251
diff --git a/editor.py b/editor.py
index 6319ada5..4306836d 100644
--- a/editor.py
+++ b/editor.py
@@ -24,6 +24,7 @@ import tempfile
24from error import EditorError 24from error import EditorError
25import platform_utils 25import platform_utils
26 26
27
27class Editor(object): 28class Editor(object):
28 """Manages the user's preferred text editor.""" 29 """Manages the user's preferred text editor."""
29 30
diff --git a/error.py b/error.py
index f22a0e75..cfed8083 100644
--- a/error.py
+++ b/error.py
@@ -14,21 +14,26 @@
14# See the License for the specific language governing permissions and 14# See the License for the specific language governing permissions and
15# limitations under the License. 15# limitations under the License.
16 16
17
17class ManifestParseError(Exception): 18class ManifestParseError(Exception):
18 """Failed to parse the manifest file. 19 """Failed to parse the manifest file.
19 """ 20 """
20 21
22
21class ManifestInvalidRevisionError(Exception): 23class ManifestInvalidRevisionError(Exception):
22 """The revision value in a project is incorrect. 24 """The revision value in a project is incorrect.
23 """ 25 """
24 26
27
25class ManifestInvalidPathError(Exception): 28class ManifestInvalidPathError(Exception):
26 """A path used in <copyfile> or <linkfile> is incorrect. 29 """A path used in <copyfile> or <linkfile> is incorrect.
27 """ 30 """
28 31
32
29class NoManifestException(Exception): 33class NoManifestException(Exception):
30 """The required manifest does not exist. 34 """The required manifest does not exist.
31 """ 35 """
36
32 def __init__(self, path, reason): 37 def __init__(self, path, reason):
33 super(NoManifestException, self).__init__() 38 super(NoManifestException, self).__init__()
34 self.path = path 39 self.path = path
@@ -37,9 +42,11 @@ class NoManifestException(Exception):
37 def __str__(self): 42 def __str__(self):
38 return self.reason 43 return self.reason
39 44
45
40class EditorError(Exception): 46class EditorError(Exception):
41 """Unspecified error from the user's text editor. 47 """Unspecified error from the user's text editor.
42 """ 48 """
49
43 def __init__(self, reason): 50 def __init__(self, reason):
44 super(EditorError, self).__init__() 51 super(EditorError, self).__init__()
45 self.reason = reason 52 self.reason = reason
@@ -47,9 +54,11 @@ class EditorError(Exception):
47 def __str__(self): 54 def __str__(self):
48 return self.reason 55 return self.reason
49 56
57
50class GitError(Exception): 58class GitError(Exception):
51 """Unspecified internal error from git. 59 """Unspecified internal error from git.
52 """ 60 """
61
53 def __init__(self, command): 62 def __init__(self, command):
54 super(GitError, self).__init__() 63 super(GitError, self).__init__()
55 self.command = command 64 self.command = command
@@ -57,9 +66,11 @@ class GitError(Exception):
57 def __str__(self): 66 def __str__(self):
58 return self.command 67 return self.command
59 68
69
60class UploadError(Exception): 70class UploadError(Exception):
61 """A bundle upload to Gerrit did not succeed. 71 """A bundle upload to Gerrit did not succeed.
62 """ 72 """
73
63 def __init__(self, reason): 74 def __init__(self, reason):
64 super(UploadError, self).__init__() 75 super(UploadError, self).__init__()
65 self.reason = reason 76 self.reason = reason
@@ -67,9 +78,11 @@ class UploadError(Exception):
67 def __str__(self): 78 def __str__(self):
68 return self.reason 79 return self.reason
69 80
81
70class DownloadError(Exception): 82class DownloadError(Exception):
71 """Cannot download a repository. 83 """Cannot download a repository.
72 """ 84 """
85
73 def __init__(self, reason): 86 def __init__(self, reason):
74 super(DownloadError, self).__init__() 87 super(DownloadError, self).__init__()
75 self.reason = reason 88 self.reason = reason
@@ -77,9 +90,11 @@ class DownloadError(Exception):
77 def __str__(self): 90 def __str__(self):
78 return self.reason 91 return self.reason
79 92
93
80class NoSuchProjectError(Exception): 94class NoSuchProjectError(Exception):
81 """A specified project does not exist in the work tree. 95 """A specified project does not exist in the work tree.
82 """ 96 """
97
83 def __init__(self, name=None): 98 def __init__(self, name=None):
84 super(NoSuchProjectError, self).__init__() 99 super(NoSuchProjectError, self).__init__()
85 self.name = name 100 self.name = name
@@ -93,6 +108,7 @@ class NoSuchProjectError(Exception):
93class InvalidProjectGroupsError(Exception): 108class InvalidProjectGroupsError(Exception):
94 """A specified project is not suitable for the specified groups 109 """A specified project is not suitable for the specified groups
95 """ 110 """
111
96 def __init__(self, name=None): 112 def __init__(self, name=None):
97 super(InvalidProjectGroupsError, self).__init__() 113 super(InvalidProjectGroupsError, self).__init__()
98 self.name = name 114 self.name = name
@@ -102,15 +118,18 @@ class InvalidProjectGroupsError(Exception):
102 return 'in current directory' 118 return 'in current directory'
103 return self.name 119 return self.name
104 120
121
105class RepoChangedException(Exception): 122class RepoChangedException(Exception):
106 """Thrown if 'repo sync' results in repo updating its internal 123 """Thrown if 'repo sync' results in repo updating its internal
107 repo or manifest repositories. In this special case we must 124 repo or manifest repositories. In this special case we must
108 use exec to re-execute repo with the new code and manifest. 125 use exec to re-execute repo with the new code and manifest.
109 """ 126 """
127
110 def __init__(self, extra_args=None): 128 def __init__(self, extra_args=None):
111 super(RepoChangedException, self).__init__() 129 super(RepoChangedException, self).__init__()
112 self.extra_args = extra_args or [] 130 self.extra_args = extra_args or []
113 131
132
114class HookError(Exception): 133class HookError(Exception):
115 """Thrown if a 'repo-hook' could not be run. 134 """Thrown if a 'repo-hook' could not be run.
116 135
diff --git a/event_log.py b/event_log.py
index 45800a59..5dd9db66 100644
--- a/event_log.py
+++ b/event_log.py
@@ -23,6 +23,7 @@ TASK_COMMAND = 'command'
23TASK_SYNC_NETWORK = 'sync-network' 23TASK_SYNC_NETWORK = 'sync-network'
24TASK_SYNC_LOCAL = 'sync-local' 24TASK_SYNC_LOCAL = 'sync-local'
25 25
26
26class EventLog(object): 27class EventLog(object):
27 """Event log that records events that occurred during a repo invocation. 28 """Event log that records events that occurred during a repo invocation.
28 29
@@ -165,6 +166,7 @@ class EventLog(object):
165# An integer id that is unique across this invocation of the program. 166# An integer id that is unique across this invocation of the program.
166_EVENT_ID = multiprocessing.Value('i', 1) 167_EVENT_ID = multiprocessing.Value('i', 1)
167 168
169
168def _NextEventId(): 170def _NextEventId():
169 """Helper function for grabbing the next unique id. 171 """Helper function for grabbing the next unique id.
170 172
diff --git a/git_command.py b/git_command.py
index df39ec09..c7e94fd0 100644
--- a/git_command.py
+++ b/git_command.py
@@ -48,6 +48,7 @@ _ssh_proxy_path = None
48_ssh_sock_path = None 48_ssh_sock_path = None
49_ssh_clients = [] 49_ssh_clients = []
50 50
51
51def ssh_sock(create=True): 52def ssh_sock(create=True):
52 global _ssh_sock_path 53 global _ssh_sock_path
53 if _ssh_sock_path is None: 54 if _ssh_sock_path is None:
@@ -61,6 +62,7 @@ def ssh_sock(create=True):
61 'master-%r@%h:%p') 62 'master-%r@%h:%p')
62 return _ssh_sock_path 63 return _ssh_sock_path
63 64
65
64def _ssh_proxy(): 66def _ssh_proxy():
65 global _ssh_proxy_path 67 global _ssh_proxy_path
66 if _ssh_proxy_path is None: 68 if _ssh_proxy_path is None:
@@ -69,15 +71,18 @@ def _ssh_proxy():
69 'git_ssh') 71 'git_ssh')
70 return _ssh_proxy_path 72 return _ssh_proxy_path
71 73
74
72def _add_ssh_client(p): 75def _add_ssh_client(p):
73 _ssh_clients.append(p) 76 _ssh_clients.append(p)
74 77
78
75def _remove_ssh_client(p): 79def _remove_ssh_client(p):
76 try: 80 try:
77 _ssh_clients.remove(p) 81 _ssh_clients.remove(p)
78 except ValueError: 82 except ValueError:
79 pass 83 pass
80 84
85
81def terminate_ssh_clients(): 86def terminate_ssh_clients():
82 global _ssh_clients 87 global _ssh_clients
83 for p in _ssh_clients: 88 for p in _ssh_clients:
@@ -88,8 +93,10 @@ def terminate_ssh_clients():
88 pass 93 pass
89 _ssh_clients = [] 94 _ssh_clients = []
90 95
96
91_git_version = None 97_git_version = None
92 98
99
93class _GitCall(object): 100class _GitCall(object):
94 def version_tuple(self): 101 def version_tuple(self):
95 global _git_version 102 global _git_version
@@ -102,11 +109,14 @@ class _GitCall(object):
102 109
103 def __getattr__(self, name): 110 def __getattr__(self, name):
104 name = name.replace('_', '-') 111 name = name.replace('_', '-')
112
105 def fun(*cmdv): 113 def fun(*cmdv):
106 command = [name] 114 command = [name]
107 command.extend(cmdv) 115 command.extend(cmdv)
108 return GitCommand(None, command).Wait() == 0 116 return GitCommand(None, command).Wait() == 0
109 return fun 117 return fun
118
119
110git = _GitCall() 120git = _GitCall()
111 121
112 122
@@ -187,8 +197,10 @@ class UserAgent(object):
187 197
188 return self._git_ua 198 return self._git_ua
189 199
200
190user_agent = UserAgent() 201user_agent = UserAgent()
191 202
203
192def git_require(min_version, fail=False, msg=''): 204def git_require(min_version, fail=False, msg=''):
193 git_version = git.version_tuple() 205 git_version = git.version_tuple()
194 if min_version <= git_version: 206 if min_version <= git_version:
@@ -201,9 +213,11 @@ def git_require(min_version, fail=False, msg=''):
201 sys.exit(1) 213 sys.exit(1)
202 return False 214 return False
203 215
216
204def _setenv(env, name, value): 217def _setenv(env, name, value):
205 env[name] = value.encode() 218 env[name] = value.encode()
206 219
220
207class GitCommand(object): 221class GitCommand(object):
208 def __init__(self, 222 def __init__(self,
209 project, 223 project,
diff --git a/git_config.py b/git_config.py
index 13fbda24..5fb61d21 100644
--- a/git_config.py
+++ b/git_config.py
@@ -59,18 +59,23 @@ ID_RE = re.compile(r'^[0-9a-f]{40}$')
59 59
60REVIEW_CACHE = dict() 60REVIEW_CACHE = dict()
61 61
62
62def IsChange(rev): 63def IsChange(rev):
63 return rev.startswith(R_CHANGES) 64 return rev.startswith(R_CHANGES)
64 65
66
65def IsId(rev): 67def IsId(rev):
66 return ID_RE.match(rev) 68 return ID_RE.match(rev)
67 69
70
68def IsTag(rev): 71def IsTag(rev):
69 return rev.startswith(R_TAGS) 72 return rev.startswith(R_TAGS)
70 73
74
71def IsImmutable(rev): 75def IsImmutable(rev):
72 return IsChange(rev) or IsId(rev) or IsTag(rev) 76 return IsChange(rev) or IsId(rev) or IsTag(rev)
73 77
78
74def _key(name): 79def _key(name):
75 parts = name.split('.') 80 parts = name.split('.')
76 if len(parts) < 2: 81 if len(parts) < 2:
@@ -79,6 +84,7 @@ def _key(name):
79 parts[-1] = parts[-1].lower() 84 parts[-1] = parts[-1].lower()
80 return '.'.join(parts) 85 return '.'.join(parts)
81 86
87
82class GitConfig(object): 88class GitConfig(object):
83 _ForUser = None 89 _ForUser = None
84 90
@@ -392,6 +398,7 @@ _master_keys = set()
392_ssh_master = True 398_ssh_master = True
393_master_keys_lock = None 399_master_keys_lock = None
394 400
401
395def init_ssh(): 402def init_ssh():
396 """Should be called once at the start of repo to init ssh master handling. 403 """Should be called once at the start of repo to init ssh master handling.
397 404
@@ -401,6 +408,7 @@ def init_ssh():
401 assert _master_keys_lock is None, "Should only call init_ssh once" 408 assert _master_keys_lock is None, "Should only call init_ssh once"
402 _master_keys_lock = _threading.Lock() 409 _master_keys_lock = _threading.Lock()
403 410
411
404def _open_ssh(host, port=None): 412def _open_ssh(host, port=None):
405 global _ssh_master 413 global _ssh_master
406 414
@@ -479,6 +487,7 @@ def _open_ssh(host, port=None):
479 finally: 487 finally:
480 _master_keys_lock.release() 488 _master_keys_lock.release()
481 489
490
482def close_ssh(): 491def close_ssh():
483 global _master_keys_lock 492 global _master_keys_lock
484 493
@@ -503,15 +512,18 @@ def close_ssh():
503 # We're done with the lock, so we can delete it. 512 # We're done with the lock, so we can delete it.
504 _master_keys_lock = None 513 _master_keys_lock = None
505 514
515
506URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') 516URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
507URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/') 517URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/')
508 518
519
509def GetSchemeFromUrl(url): 520def GetSchemeFromUrl(url):
510 m = URI_ALL.match(url) 521 m = URI_ALL.match(url)
511 if m: 522 if m:
512 return m.group(1) 523 return m.group(1)
513 return None 524 return None
514 525
526
515@contextlib.contextmanager 527@contextlib.contextmanager
516def GetUrlCookieFile(url, quiet): 528def GetUrlCookieFile(url, quiet):
517 if url.startswith('persistent-'): 529 if url.startswith('persistent-'):
@@ -552,6 +564,7 @@ def GetUrlCookieFile(url, quiet):
552 cookiefile = os.path.expanduser(cookiefile) 564 cookiefile = os.path.expanduser(cookiefile)
553 yield cookiefile, None 565 yield cookiefile, None
554 566
567
555def _preconnect(url): 568def _preconnect(url):
556 m = URI_ALL.match(url) 569 m = URI_ALL.match(url)
557 if m: 570 if m:
@@ -572,9 +585,11 @@ def _preconnect(url):
572 585
573 return False 586 return False
574 587
588
575class Remote(object): 589class Remote(object):
576 """Configuration options related to a remote. 590 """Configuration options related to a remote.
577 """ 591 """
592
578 def __init__(self, config, name): 593 def __init__(self, config, name):
579 self._config = config 594 self._config = config
580 self.name = name 595 self.name = name
@@ -735,6 +750,7 @@ class Remote(object):
735class Branch(object): 750class Branch(object):
736 """Configuration options related to a single branch. 751 """Configuration options related to a single branch.
737 """ 752 """
753
738 def __init__(self, config, name): 754 def __init__(self, config, name):
739 self._config = config 755 self._config = config
740 self.name = name 756 self.name = name
diff --git a/gitc_utils.py b/gitc_utils.py
index 45920b07..11284e20 100644
--- a/gitc_utils.py
+++ b/gitc_utils.py
@@ -29,12 +29,15 @@ from error import ManifestParseError
29 29
30NUM_BATCH_RETRIEVE_REVISIONID = 32 30NUM_BATCH_RETRIEVE_REVISIONID = 32
31 31
32
32def get_gitc_manifest_dir(): 33def get_gitc_manifest_dir():
33 return wrapper.Wrapper().get_gitc_manifest_dir() 34 return wrapper.Wrapper().get_gitc_manifest_dir()
34 35
36
35def parse_clientdir(gitc_fs_path): 37def parse_clientdir(gitc_fs_path):
36 return wrapper.Wrapper().gitc_parse_clientdir(gitc_fs_path) 38 return wrapper.Wrapper().gitc_parse_clientdir(gitc_fs_path)
37 39
40
38def _set_project_revisions(projects): 41def _set_project_revisions(projects):
39 """Sets the revisionExpr for a list of projects. 42 """Sets the revisionExpr for a list of projects.
40 43
@@ -63,6 +66,7 @@ def _set_project_revisions(projects):
63 (proj.remote.url, proj.revisionExpr)) 66 (proj.remote.url, proj.revisionExpr))
64 proj.revisionExpr = revisionExpr 67 proj.revisionExpr = revisionExpr
65 68
69
66def _manifest_groups(manifest): 70def _manifest_groups(manifest):
67 """Returns the manifest group string that should be synced 71 """Returns the manifest group string that should be synced
68 72
@@ -77,6 +81,7 @@ def _manifest_groups(manifest):
77 groups = 'default,platform-' + platform.system().lower() 81 groups = 'default,platform-' + platform.system().lower()
78 return groups 82 return groups
79 83
84
80def generate_gitc_manifest(gitc_manifest, manifest, paths=None): 85def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
81 """Generate a manifest for shafsd to use for this GITC client. 86 """Generate a manifest for shafsd to use for this GITC client.
82 87
@@ -140,6 +145,7 @@ def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
140 # Save the manifest. 145 # Save the manifest.
141 save_manifest(manifest) 146 save_manifest(manifest)
142 147
148
143def save_manifest(manifest, client_dir=None): 149def save_manifest(manifest, client_dir=None):
144 """Save the manifest file in the client_dir. 150 """Save the manifest file in the client_dir.
145 151
diff --git a/main.py b/main.py
index 7724a765..d2a303ca 100755
--- a/main.py
+++ b/main.py
@@ -101,6 +101,7 @@ global_options.add_option('--event-log',
101 dest='event_log', action='store', 101 dest='event_log', action='store',
102 help='filename of event log to append timeline to') 102 help='filename of event log to append timeline to')
103 103
104
104class _Repo(object): 105class _Repo(object):
105 def __init__(self, repodir): 106 def __init__(self, repodir):
106 self.repodir = repodir 107 self.repodir = repodir
@@ -300,11 +301,13 @@ repo: error:
300 cp %s %s 301 cp %s %s
301""" % (exp_str, WrapperPath(), repo_path), file=sys.stderr) 302""" % (exp_str, WrapperPath(), repo_path), file=sys.stderr)
302 303
304
303def _CheckRepoDir(repo_dir): 305def _CheckRepoDir(repo_dir):
304 if not repo_dir: 306 if not repo_dir:
305 print('no --repo-dir argument', file=sys.stderr) 307 print('no --repo-dir argument', file=sys.stderr)
306 sys.exit(1) 308 sys.exit(1)
307 309
310
308def _PruneOptions(argv, opt): 311def _PruneOptions(argv, opt):
309 i = 0 312 i = 0
310 while i < len(argv): 313 while i < len(argv):
@@ -320,6 +323,7 @@ def _PruneOptions(argv, opt):
320 continue 323 continue
321 i += 1 324 i += 1
322 325
326
323class _UserAgentHandler(urllib.request.BaseHandler): 327class _UserAgentHandler(urllib.request.BaseHandler):
324 def http_request(self, req): 328 def http_request(self, req):
325 req.add_header('User-Agent', user_agent.repo) 329 req.add_header('User-Agent', user_agent.repo)
@@ -329,6 +333,7 @@ class _UserAgentHandler(urllib.request.BaseHandler):
329 req.add_header('User-Agent', user_agent.repo) 333 req.add_header('User-Agent', user_agent.repo)
330 return req 334 return req
331 335
336
332def _AddPasswordFromUserInput(handler, msg, req): 337def _AddPasswordFromUserInput(handler, msg, req):
333 # If repo could not find auth info from netrc, try to get it from user input 338 # If repo could not find auth info from netrc, try to get it from user input
334 url = req.get_full_url() 339 url = req.get_full_url()
@@ -342,6 +347,7 @@ def _AddPasswordFromUserInput(handler, msg, req):
342 return 347 return
343 handler.passwd.add_password(None, url, user, password) 348 handler.passwd.add_password(None, url, user, password)
344 349
350
345class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): 351class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
346 def http_error_401(self, req, fp, code, msg, headers): 352 def http_error_401(self, req, fp, code, msg, headers):
347 _AddPasswordFromUserInput(self, msg, req) 353 _AddPasswordFromUserInput(self, msg, req)
@@ -351,6 +357,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
351 def http_error_auth_reqed(self, authreq, host, req, headers): 357 def http_error_auth_reqed(self, authreq, host, req, headers):
352 try: 358 try:
353 old_add_header = req.add_header 359 old_add_header = req.add_header
360
354 def _add_header(name, val): 361 def _add_header(name, val):
355 val = val.replace('\n', '') 362 val = val.replace('\n', '')
356 old_add_header(name, val) 363 old_add_header(name, val)
@@ -365,6 +372,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
365 self.retried = 0 372 self.retried = 0
366 raise 373 raise
367 374
375
368class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): 376class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
369 def http_error_401(self, req, fp, code, msg, headers): 377 def http_error_401(self, req, fp, code, msg, headers):
370 _AddPasswordFromUserInput(self, msg, req) 378 _AddPasswordFromUserInput(self, msg, req)
@@ -374,6 +382,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
374 def http_error_auth_reqed(self, auth_header, host, req, headers): 382 def http_error_auth_reqed(self, auth_header, host, req, headers):
375 try: 383 try:
376 old_add_header = req.add_header 384 old_add_header = req.add_header
385
377 def _add_header(name, val): 386 def _add_header(name, val):
378 val = val.replace('\n', '') 387 val = val.replace('\n', '')
379 old_add_header(name, val) 388 old_add_header(name, val)
@@ -388,6 +397,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
388 self.retried = 0 397 self.retried = 0
389 raise 398 raise
390 399
400
391class _KerberosAuthHandler(urllib.request.BaseHandler): 401class _KerberosAuthHandler(urllib.request.BaseHandler):
392 def __init__(self): 402 def __init__(self):
393 self.retried = 0 403 self.retried = 0
@@ -468,6 +478,7 @@ class _KerberosAuthHandler(urllib.request.BaseHandler):
468 kerberos.authGSSClientClean(self.context) 478 kerberos.authGSSClientClean(self.context)
469 self.context = None 479 self.context = None
470 480
481
471def init_http(): 482def init_http():
472 handlers = [_UserAgentHandler()] 483 handlers = [_UserAgentHandler()]
473 484
@@ -495,6 +506,7 @@ def init_http():
495 handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) 506 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
496 urllib.request.install_opener(urllib.request.build_opener(*handlers)) 507 urllib.request.install_opener(urllib.request.build_opener(*handlers))
497 508
509
498def _Main(argv): 510def _Main(argv):
499 result = 0 511 result = 0
500 512
@@ -551,5 +563,6 @@ def _Main(argv):
551 TerminatePager() 563 TerminatePager()
552 sys.exit(result) 564 sys.exit(result)
553 565
566
554if __name__ == '__main__': 567if __name__ == '__main__':
555 _Main(sys.argv[1:]) 568 _Main(sys.argv[1:])
diff --git a/manifest_xml.py b/manifest_xml.py
index fd0e4f12..7f38d8c3 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -56,6 +56,7 @@ urllib.parse.uses_netloc.extend([
56 'sso', 56 'sso',
57 'rpc']) 57 'rpc'])
58 58
59
59class _Default(object): 60class _Default(object):
60 """Project defaults within the manifest.""" 61 """Project defaults within the manifest."""
61 62
@@ -74,6 +75,7 @@ class _Default(object):
74 def __ne__(self, other): 75 def __ne__(self, other):
75 return self.__dict__ != other.__dict__ 76 return self.__dict__ != other.__dict__
76 77
78
77class _XmlRemote(object): 79class _XmlRemote(object):
78 def __init__(self, 80 def __init__(self,
79 name, 81 name,
@@ -127,6 +129,7 @@ class _XmlRemote(object):
127 orig_name=self.name, 129 orig_name=self.name,
128 fetchUrl=self.fetchUrl) 130 fetchUrl=self.fetchUrl)
129 131
132
130class XmlManifest(object): 133class XmlManifest(object):
131 """manages the repo configuration file""" 134 """manages the repo configuration file"""
132 135
@@ -655,7 +658,6 @@ class XmlManifest(object):
655 if self._repo_hooks_project and (self._repo_hooks_project.name == name): 658 if self._repo_hooks_project and (self._repo_hooks_project.name == name):
656 self._repo_hooks_project = None 659 self._repo_hooks_project = None
657 660
658
659 def _AddMetaProjectMirror(self, m): 661 def _AddMetaProjectMirror(self, m):
660 name = None 662 name = None
661 m_url = m.GetRemote(m.remote.name).url 663 m_url = m.GetRemote(m.remote.name).url
diff --git a/pager.py b/pager.py
index 64090488..7ad25770 100644
--- a/pager.py
+++ b/pager.py
@@ -27,6 +27,7 @@ pager_process = None
27old_stdout = None 27old_stdout = None
28old_stderr = None 28old_stderr = None
29 29
30
30def RunPager(globalConfig): 31def RunPager(globalConfig):
31 if not os.isatty(0) or not os.isatty(1): 32 if not os.isatty(0) or not os.isatty(1):
32 return 33 return
@@ -39,6 +40,7 @@ def RunPager(globalConfig):
39 else: 40 else:
40 _ForkPager(pager) 41 _ForkPager(pager)
41 42
43
42def TerminatePager(): 44def TerminatePager():
43 global pager_process, old_stdout, old_stderr 45 global pager_process, old_stdout, old_stderr
44 if pager_process: 46 if pager_process:
@@ -52,6 +54,7 @@ def TerminatePager():
52 sys.stdout = old_stdout 54 sys.stdout = old_stdout
53 sys.stderr = old_stderr 55 sys.stderr = old_stderr
54 56
57
55def _PipePager(pager): 58def _PipePager(pager):
56 global pager_process, old_stdout, old_stderr 59 global pager_process, old_stdout, old_stderr
57 assert pager_process is None, "Only one active pager process at a time" 60 assert pager_process is None, "Only one active pager process at a time"
@@ -62,6 +65,7 @@ def _PipePager(pager):
62 sys.stdout = pager_process.stdin 65 sys.stdout = pager_process.stdin
63 sys.stderr = pager_process.stdin 66 sys.stderr = pager_process.stdin
64 67
68
65def _ForkPager(pager): 69def _ForkPager(pager):
66 global active 70 global active
67 # This process turns into the pager; a child it forks will 71 # This process turns into the pager; a child it forks will
@@ -88,6 +92,7 @@ def _ForkPager(pager):
88 print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) 92 print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
89 sys.exit(255) 93 sys.exit(255)
90 94
95
91def _SelectPager(globalConfig): 96def _SelectPager(globalConfig):
92 try: 97 try:
93 return os.environ['GIT_PAGER'] 98 return os.environ['GIT_PAGER']
@@ -105,6 +110,7 @@ def _SelectPager(globalConfig):
105 110
106 return 'less' 111 return 'less'
107 112
113
108def _BecomePager(pager): 114def _BecomePager(pager):
109 # Delaying execution of the pager until we have output 115 # Delaying execution of the pager until we have output
110 # ready works around a long-standing bug in popularly 116 # ready works around a long-standing bug in popularly
diff --git a/platform_utils.py b/platform_utils.py
index 06ef9b18..490ba208 100644
--- a/platform_utils.py
+++ b/platform_utils.py
@@ -92,6 +92,7 @@ class _FileDescriptorStreamsNonBlocking(FileDescriptorStreams):
92 """ 92 """
93 class Stream(object): 93 class Stream(object):
94 """ Encapsulates a file descriptor """ 94 """ Encapsulates a file descriptor """
95
95 def __init__(self, fd, dest, std_name): 96 def __init__(self, fd, dest, std_name):
96 self.fd = fd 97 self.fd = fd
97 self.dest = dest 98 self.dest = dest
@@ -125,6 +126,7 @@ class _FileDescriptorStreamsThreads(FileDescriptorStreams):
125 non blocking I/O. This implementation requires creating threads issuing 126 non blocking I/O. This implementation requires creating threads issuing
126 blocking read operations on file descriptors. 127 blocking read operations on file descriptors.
127 """ 128 """
129
128 def __init__(self): 130 def __init__(self):
129 super(_FileDescriptorStreamsThreads, self).__init__() 131 super(_FileDescriptorStreamsThreads, self).__init__()
130 # The queue is shared accross all threads so we can simulate the 132 # The queue is shared accross all threads so we can simulate the
@@ -144,12 +146,14 @@ class _FileDescriptorStreamsThreads(FileDescriptorStreams):
144 146
145 class QueueItem(object): 147 class QueueItem(object):
146 """ Item put in the shared queue """ 148 """ Item put in the shared queue """
149
147 def __init__(self, stream, data): 150 def __init__(self, stream, data):
148 self.stream = stream 151 self.stream = stream
149 self.data = data 152 self.data = data
150 153
151 class Stream(object): 154 class Stream(object):
152 """ Encapsulates a file descriptor """ 155 """ Encapsulates a file descriptor """
156
153 def __init__(self, fd, dest, std_name, queue): 157 def __init__(self, fd, dest, std_name, queue):
154 self.fd = fd 158 self.fd = fd
155 self.dest = dest 159 self.dest = dest
diff --git a/progress.py b/progress.py
index 8a643db2..ff627980 100644
--- a/progress.py
+++ b/progress.py
@@ -26,6 +26,7 @@ _NOT_TTY = not os.isatty(2)
26# column 0. 26# column 0.
27CSI_ERASE_LINE = '\x1b[2K' 27CSI_ERASE_LINE = '\x1b[2K'
28 28
29
29class Progress(object): 30class Progress(object):
30 def __init__(self, title, total=0, units='', print_newline=False, 31 def __init__(self, title, total=0, units='', print_newline=False,
31 always_print_percentage=False): 32 always_print_percentage=False):
diff --git a/project.py b/project.py
index 8c56af42..372421cf 100644
--- a/project.py
+++ b/project.py
@@ -85,6 +85,7 @@ def not_rev(r):
85def sq(r): 85def sq(r):
86 return "'" + r.replace("'", "'\''") + "'" 86 return "'" + r.replace("'", "'\''") + "'"
87 87
88
88_project_hook_list = None 89_project_hook_list = None
89 90
90 91
@@ -1256,9 +1257,7 @@ class Project(object):
1256 print(line[:-1]) 1257 print(line[:-1])
1257 return p.Wait() == 0 1258 return p.Wait() == 0
1258 1259
1259
1260# Publish / Upload ## 1260# Publish / Upload ##
1261
1262 def WasPublished(self, branch, all_refs=None): 1261 def WasPublished(self, branch, all_refs=None):
1263 """Was the branch published (uploaded) for code review? 1262 """Was the branch published (uploaded) for code review?
1264 If so, returns the SHA-1 hash of the last published 1263 If so, returns the SHA-1 hash of the last published
@@ -1410,9 +1409,7 @@ class Project(object):
1410 R_HEADS + branch.name, 1409 R_HEADS + branch.name,
1411 message=msg) 1410 message=msg)
1412 1411
1413
1414# Sync ## 1412# Sync ##
1415
1416 def _ExtractArchive(self, tarpath, path=None): 1413 def _ExtractArchive(self, tarpath, path=None):
1417 """Extract the given tar on its current location 1414 """Extract the given tar on its current location
1418 1415
@@ -1819,9 +1816,7 @@ class Project(object):
1819 patch_id, 1816 patch_id,
1820 self.bare_git.rev_parse('FETCH_HEAD')) 1817 self.bare_git.rev_parse('FETCH_HEAD'))
1821 1818
1822
1823# Branch Management ## 1819# Branch Management ##
1824
1825 def GetHeadPath(self): 1820 def GetHeadPath(self):
1826 """Return the full path to the HEAD ref.""" 1821 """Return the full path to the HEAD ref."""
1827 dotgit = os.path.join(self.worktree, '.git') 1822 dotgit = os.path.join(self.worktree, '.git')
@@ -2019,9 +2014,7 @@ class Project(object):
2019 kept.append(ReviewableBranch(self, branch, base)) 2014 kept.append(ReviewableBranch(self, branch, base))
2020 return kept 2015 return kept
2021 2016
2022
2023# Submodule Management ## 2017# Submodule Management ##
2024
2025 def GetRegisteredSubprojects(self): 2018 def GetRegisteredSubprojects(self):
2026 result = [] 2019 result = []
2027 2020
@@ -2172,7 +2165,6 @@ class Project(object):
2172 result.extend(subproject.GetDerivedSubprojects()) 2165 result.extend(subproject.GetDerivedSubprojects())
2173 return result 2166 return result
2174 2167
2175
2176# Direct Git Commands ## 2168# Direct Git Commands ##
2177 def _CheckForImmutableRevision(self): 2169 def _CheckForImmutableRevision(self):
2178 try: 2170 try:
diff --git a/pyversion.py b/pyversion.py
index f6082408..8dbf909b 100644
--- a/pyversion.py
+++ b/pyversion.py
@@ -16,5 +16,6 @@
16 16
17import sys 17import sys
18 18
19
19def is_python3(): 20def is_python3():
20 return sys.version_info[0] == 3 21 return sys.version_info[0] == 3
diff --git a/repo_trace.py b/repo_trace.py
index f5bc76d4..cd571f4c 100644
--- a/repo_trace.py
+++ b/repo_trace.py
@@ -28,13 +28,16 @@ REPO_TRACE = 'REPO_TRACE'
28 28
29_TRACE = os.environ.get(REPO_TRACE) == '1' 29_TRACE = os.environ.get(REPO_TRACE) == '1'
30 30
31
31def IsTrace(): 32def IsTrace():
32 return _TRACE 33 return _TRACE
33 34
35
34def SetTrace(): 36def SetTrace():
35 global _TRACE 37 global _TRACE
36 _TRACE = True 38 _TRACE = True
37 39
40
38def Trace(fmt, *args): 41def Trace(fmt, *args):
39 if IsTrace(): 42 if IsTrace():
40 print(fmt % args, file=sys.stderr) 43 print(fmt % args, file=sys.stderr)
diff --git a/subcmds/abandon.py b/subcmds/abandon.py
index 9a645c0a..f3478129 100644
--- a/subcmds/abandon.py
+++ b/subcmds/abandon.py
@@ -21,6 +21,7 @@ from collections import defaultdict
21from git_command import git 21from git_command import git
22from progress import Progress 22from progress import Progress
23 23
24
24class Abandon(Command): 25class Abandon(Command):
25 common = True 26 common = True
26 helpSummary = "Permanently abandon a development branch" 27 helpSummary = "Permanently abandon a development branch"
@@ -32,6 +33,7 @@ deleting it (and all its history) from your local repository.
32 33
33It is equivalent to "git branch -D <branchname>". 34It is equivalent to "git branch -D <branchname>".
34""" 35"""
36
35 def _Options(self, p): 37 def _Options(self, p):
36 p.add_option('--all', 38 p.add_option('--all',
37 dest='all', action='store_true', 39 dest='all', action='store_true',
diff --git a/subcmds/branches.py b/subcmds/branches.py
index b4894ec8..9709f7f0 100644
--- a/subcmds/branches.py
+++ b/subcmds/branches.py
@@ -19,6 +19,7 @@ import sys
19from color import Coloring 19from color import Coloring
20from command import Command 20from command import Command
21 21
22
22class BranchColoring(Coloring): 23class BranchColoring(Coloring):
23 def __init__(self, config): 24 def __init__(self, config):
24 Coloring.__init__(self, config, 'branch') 25 Coloring.__init__(self, config, 'branch')
@@ -26,6 +27,7 @@ class BranchColoring(Coloring):
26 self.local = self.printer('local') 27 self.local = self.printer('local')
27 self.notinproject = self.printer('notinproject', fg='red') 28 self.notinproject = self.printer('notinproject', fg='red')
28 29
30
29class BranchInfo(object): 31class BranchInfo(object):
30 def __init__(self, name): 32 def __init__(self, name):
31 self.name = name 33 self.name = name
diff --git a/subcmds/checkout.py b/subcmds/checkout.py
index c8a09a8e..efa31d26 100644
--- a/subcmds/checkout.py
+++ b/subcmds/checkout.py
@@ -19,6 +19,7 @@ import sys
19from command import Command 19from command import Command
20from progress import Progress 20from progress import Progress
21 21
22
22class Checkout(Command): 23class Checkout(Command):
23 common = True 24 common = True
24 helpSummary = "Checkout a branch for development" 25 helpSummary = "Checkout a branch for development"
diff --git a/subcmds/cherry_pick.py b/subcmds/cherry_pick.py
index 8d81be33..3ad82109 100644
--- a/subcmds/cherry_pick.py
+++ b/subcmds/cherry_pick.py
@@ -22,6 +22,7 @@ from git_command import GitCommand
22 22
23CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$') 23CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$')
24 24
25
25class CherryPick(Command): 26class CherryPick(Command):
26 common = True 27 common = True
27 helpSummary = "Cherry-pick a change." 28 helpSummary = "Cherry-pick a change."
diff --git a/subcmds/diff.py b/subcmds/diff.py
index fa41e70e..406baa28 100644
--- a/subcmds/diff.py
+++ b/subcmds/diff.py
@@ -16,6 +16,7 @@
16 16
17from command import PagedCommand 17from command import PagedCommand
18 18
19
19class Diff(PagedCommand): 20class Diff(PagedCommand):
20 common = True 21 common = True
21 helpSummary = "Show changes between commit and working tree" 22 helpSummary = "Show changes between commit and working tree"
diff --git a/subcmds/diffmanifests.py b/subcmds/diffmanifests.py
index 9bdb5e14..77f99df2 100644
--- a/subcmds/diffmanifests.py
+++ b/subcmds/diffmanifests.py
@@ -18,10 +18,12 @@ from color import Coloring
18from command import PagedCommand 18from command import PagedCommand
19from manifest_xml import XmlManifest 19from manifest_xml import XmlManifest
20 20
21
21class _Coloring(Coloring): 22class _Coloring(Coloring):
22 def __init__(self, config): 23 def __init__(self, config):
23 Coloring.__init__(self, config, "status") 24 Coloring.__init__(self, config, "status")
24 25
26
25class Diffmanifests(PagedCommand): 27class Diffmanifests(PagedCommand):
26 """ A command to see logs in projects represented by manifests 28 """ A command to see logs in projects represented by manifests
27 29
diff --git a/subcmds/download.py b/subcmds/download.py
index fbd302aa..87d0ce04 100644
--- a/subcmds/download.py
+++ b/subcmds/download.py
@@ -23,6 +23,7 @@ from error import GitError
23 23
24CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$') 24CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$')
25 25
26
26class Download(Command): 27class Download(Command):
27 common = True 28 common = True
28 helpSummary = "Download and checkout a change" 29 helpSummary = "Download and checkout a change"
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 5d2be91f..dbf26f0b 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -277,6 +277,7 @@ without iterating through the remaining projects.
277 return 277 return
278 yield [mirror, opt, cmd, shell, cnt, config, project] 278 yield [mirror, opt, cmd, shell, cnt, config, project]
279 279
280
280class WorkerKeyboardInterrupt(Exception): 281class WorkerKeyboardInterrupt(Exception):
281 """ Keyboard interrupt exception for worker processes. """ 282 """ Keyboard interrupt exception for worker processes. """
282 pass 283 pass
@@ -285,6 +286,7 @@ class WorkerKeyboardInterrupt(Exception):
285def InitWorker(): 286def InitWorker():
286 signal.signal(signal.SIGINT, signal.SIG_IGN) 287 signal.signal(signal.SIGINT, signal.SIG_IGN)
287 288
289
288def DoWorkWrapper(args): 290def DoWorkWrapper(args):
289 """ A wrapper around the DoWork() method. 291 """ A wrapper around the DoWork() method.
290 292
@@ -303,6 +305,7 @@ def DoWorkWrapper(args):
303 305
304def DoWork(project, mirror, opt, cmd, shell, cnt, config): 306def DoWork(project, mirror, opt, cmd, shell, cnt, config):
305 env = os.environ.copy() 307 env = os.environ.copy()
308
306 def setenv(name, val): 309 def setenv(name, val):
307 if val is None: 310 if val is None:
308 val = '' 311 val = ''
diff --git a/subcmds/gitc_delete.py b/subcmds/gitc_delete.py
index e5214b8e..1011276f 100644
--- a/subcmds/gitc_delete.py
+++ b/subcmds/gitc_delete.py
@@ -24,6 +24,7 @@ from pyversion import is_python3
24if not is_python3(): 24if not is_python3():
25 input = raw_input 25 input = raw_input
26 26
27
27class GitcDelete(Command, GitcClientCommand): 28class GitcDelete(Command, GitcClientCommand):
28 common = True 29 common = True
29 visible_everywhere = False 30 visible_everywhere = False
diff --git a/subcmds/grep.py b/subcmds/grep.py
index 4dd85d57..13069286 100644
--- a/subcmds/grep.py
+++ b/subcmds/grep.py
@@ -23,12 +23,14 @@ from command import PagedCommand
23from error import GitError 23from error import GitError
24from git_command import git_require, GitCommand 24from git_command import git_require, GitCommand
25 25
26
26class GrepColoring(Coloring): 27class GrepColoring(Coloring):
27 def __init__(self, config): 28 def __init__(self, config):
28 Coloring.__init__(self, config, 'grep') 29 Coloring.__init__(self, config, 'grep')
29 self.project = self.printer('project', attr='bold') 30 self.project = self.printer('project', attr='bold')
30 self.fail = self.printer('fail', fg='red') 31 self.fail = self.printer('fail', fg='red')
31 32
33
32class Grep(PagedCommand): 34class Grep(PagedCommand):
33 common = True 35 common = True
34 helpSummary = "Print lines matching a pattern" 36 helpSummary = "Print lines matching a pattern"
@@ -156,7 +158,6 @@ contain a line that matches both expressions:
156 action='callback', callback=carry, 158 action='callback', callback=carry,
157 help='Show only file names not containing matching lines') 159 help='Show only file names not containing matching lines')
158 160
159
160 def Execute(self, opt, args): 161 def Execute(self, opt, args):
161 out = GrepColoring(self.manifest.manifestProject.config) 162 out = GrepColoring(self.manifest.manifestProject.config)
162 163
diff --git a/subcmds/help.py b/subcmds/help.py
index 93b9a86d..36b3a7ae 100644
--- a/subcmds/help.py
+++ b/subcmds/help.py
@@ -23,6 +23,7 @@ from color import Coloring
23from command import PagedCommand, MirrorSafeCommand, GitcAvailableCommand, GitcClientCommand 23from command import PagedCommand, MirrorSafeCommand, GitcAvailableCommand, GitcClientCommand
24import gitc_utils 24import gitc_utils
25 25
26
26class Help(PagedCommand, MirrorSafeCommand): 27class Help(PagedCommand, MirrorSafeCommand):
27 common = False 28 common = False
28 helpSummary = "Display detailed help on a command" 29 helpSummary = "Display detailed help on a command"
diff --git a/subcmds/info.py b/subcmds/info.py
index 96fa6a4c..76f5d1d6 100644
--- a/subcmds/info.py
+++ b/subcmds/info.py
@@ -18,10 +18,12 @@ from command import PagedCommand
18from color import Coloring 18from color import Coloring
19from git_refs import R_M 19from git_refs import R_M
20 20
21
21class _Coloring(Coloring): 22class _Coloring(Coloring):
22 def __init__(self, config): 23 def __init__(self, config):
23 Coloring.__init__(self, config, "status") 24 Coloring.__init__(self, config, "status")
24 25
26
25class Info(PagedCommand): 27class Info(PagedCommand):
26 common = True 28 common = True
27 helpSummary = "Get info on the manifest branch, current branch or unmerged branches" 29 helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
@@ -41,7 +43,6 @@ class Info(PagedCommand):
41 dest="local", action="store_true", 43 dest="local", action="store_true",
42 help="Disable all remote operations") 44 help="Disable all remote operations")
43 45
44
45 def Execute(self, opt, args): 46 def Execute(self, opt, args):
46 self.out = _Coloring(self.manifest.globalConfig) 47 self.out = _Coloring(self.manifest.globalConfig)
47 self.heading = self.out.printer('heading', attr='bold') 48 self.heading = self.out.printer('heading', attr='bold')
diff --git a/subcmds/init.py b/subcmds/init.py
index 7181b86f..dde97286 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -37,6 +37,7 @@ from git_config import GitConfig
37from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD 37from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD
38import platform_utils 38import platform_utils
39 39
40
40class Init(InteractiveCommand, MirrorSafeCommand): 41class Init(InteractiveCommand, MirrorSafeCommand):
41 common = True 42 common = True
42 helpSummary = "Initialize repo in the current directory" 43 helpSummary = "Initialize repo in the current directory"
diff --git a/subcmds/list.py b/subcmds/list.py
index 1cd971ef..13cae5ff 100644
--- a/subcmds/list.py
+++ b/subcmds/list.py
@@ -18,6 +18,7 @@ from __future__ import print_function
18 18
19from command import Command, MirrorSafeCommand 19from command import Command, MirrorSafeCommand
20 20
21
21class List(Command, MirrorSafeCommand): 22class List(Command, MirrorSafeCommand):
22 common = True 23 common = True
23 helpSummary = "List projects and their associated directories" 24 helpSummary = "List projects and their associated directories"
diff --git a/subcmds/manifest.py b/subcmds/manifest.py
index 6bb01045..072c9ff7 100644
--- a/subcmds/manifest.py
+++ b/subcmds/manifest.py
@@ -20,6 +20,7 @@ import sys
20 20
21from command import PagedCommand 21from command import PagedCommand
22 22
23
23class Manifest(PagedCommand): 24class Manifest(PagedCommand):
24 common = False 25 common = False
25 helpSummary = "Manifest inspection utility" 26 helpSummary = "Manifest inspection utility"
diff --git a/subcmds/prune.py b/subcmds/prune.py
index ff2fba1d..e90ff213 100644
--- a/subcmds/prune.py
+++ b/subcmds/prune.py
@@ -18,6 +18,7 @@ from __future__ import print_function
18from color import Coloring 18from color import Coloring
19from command import PagedCommand 19from command import PagedCommand
20 20
21
21class Prune(PagedCommand): 22class Prune(PagedCommand):
22 common = True 23 common = True
23 helpSummary = "Prune (delete) already merged topics" 24 helpSummary = "Prune (delete) already merged topics"
diff --git a/subcmds/selfupdate.py b/subcmds/selfupdate.py
index b157e2f1..4817a862 100644
--- a/subcmds/selfupdate.py
+++ b/subcmds/selfupdate.py
@@ -22,6 +22,7 @@ from command import Command, MirrorSafeCommand
22from subcmds.sync import _PostRepoUpgrade 22from subcmds.sync import _PostRepoUpgrade
23from subcmds.sync import _PostRepoFetch 23from subcmds.sync import _PostRepoFetch
24 24
25
25class Selfupdate(Command, MirrorSafeCommand): 26class Selfupdate(Command, MirrorSafeCommand):
26 common = False 27 common = False
27 helpSummary = "Update repo to the latest version" 28 helpSummary = "Update repo to the latest version"
diff --git a/subcmds/smartsync.py b/subcmds/smartsync.py
index 675b9834..6037e5a3 100644
--- a/subcmds/smartsync.py
+++ b/subcmds/smartsync.py
@@ -16,6 +16,7 @@
16 16
17from subcmds.sync import Sync 17from subcmds.sync import Sync
18 18
19
19class Smartsync(Sync): 20class Smartsync(Sync):
20 common = True 21 common = True
21 helpSummary = "Update working tree to the latest known good revision" 22 helpSummary = "Update working tree to the latest known good revision"
diff --git a/subcmds/stage.py b/subcmds/stage.py
index aeb49513..4dce5ce5 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -21,6 +21,7 @@ from color import Coloring
21from command import InteractiveCommand 21from command import InteractiveCommand
22from git_command import GitCommand 22from git_command import GitCommand
23 23
24
24class _ProjectList(Coloring): 25class _ProjectList(Coloring):
25 def __init__(self, gc): 26 def __init__(self, gc):
26 Coloring.__init__(self, gc, 'interactive') 27 Coloring.__init__(self, gc, 'interactive')
@@ -28,6 +29,7 @@ class _ProjectList(Coloring):
28 self.header = self.printer('header', attr='bold') 29 self.header = self.printer('header', attr='bold')
29 self.help = self.printer('help', fg='red', attr='bold') 30 self.help = self.printer('help', fg='red', attr='bold')
30 31
32
31class Stage(InteractiveCommand): 33class Stage(InteractiveCommand):
32 common = True 34 common = True
33 helpSummary = "Stage file(s) for commit" 35 helpSummary = "Stage file(s) for commit"
@@ -105,6 +107,7 @@ The '%prog' command stages files to prepare the next commit.
105 continue 107 continue
106 print('Bye.') 108 print('Bye.')
107 109
110
108def _AddI(project): 111def _AddI(project):
109 p = GitCommand(project, ['add', '--interactive'], bare=False) 112 p = GitCommand(project, ['add', '--interactive'], bare=False)
110 p.Wait() 113 p.Wait()
diff --git a/subcmds/start.py b/subcmds/start.py
index f98f790a..adc6d293 100644
--- a/subcmds/start.py
+++ b/subcmds/start.py
@@ -25,6 +25,7 @@ import gitc_utils
25from progress import Progress 25from progress import Progress
26from project import SyncBuffer 26from project import SyncBuffer
27 27
28
28class Start(Command): 29class Start(Command):
29 common = True 30 common = True
30 helpSummary = "Start a new branch for development" 31 helpSummary = "Start a new branch for development"
diff --git a/subcmds/status.py b/subcmds/status.py
index a04ba922..b594bd89 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -31,6 +31,7 @@ import os
31from color import Coloring 31from color import Coloring
32import platform_utils 32import platform_utils
33 33
34
34class Status(PagedCommand): 35class Status(PagedCommand):
35 common = True 36 common = True
36 helpSummary = "Show the working tree status" 37 helpSummary = "Show the working tree status"
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 1ea102c0..c433ce6f 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -53,6 +53,7 @@ except ImportError:
53 53
54try: 54try:
55 import resource 55 import resource
56
56 def _rlimit_nofile(): 57 def _rlimit_nofile():
57 return resource.getrlimit(resource.RLIMIT_NOFILE) 58 return resource.getrlimit(resource.RLIMIT_NOFILE)
58except ImportError: 59except ImportError:
@@ -81,13 +82,16 @@ from manifest_xml import GitcManifest
81 82
82_ONE_DAY_S = 24 * 60 * 60 83_ONE_DAY_S = 24 * 60 * 60
83 84
85
84class _FetchError(Exception): 86class _FetchError(Exception):
85 """Internal error thrown in _FetchHelper() when we don't want stack trace.""" 87 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
86 pass 88 pass
87 89
90
88class _CheckoutError(Exception): 91class _CheckoutError(Exception):
89 """Internal error thrown in _CheckoutOne() when we don't want stack trace.""" 92 """Internal error thrown in _CheckoutOne() when we don't want stack trace."""
90 93
94
91class Sync(Command, MirrorSafeCommand): 95class Sync(Command, MirrorSafeCommand):
92 jobs = 1 96 jobs = 1
93 common = True 97 common = True
@@ -1044,6 +1048,7 @@ later is required to fix a server side protocol bug.
1044 file=sys.stderr) 1048 file=sys.stderr)
1045 sys.exit(1) 1049 sys.exit(1)
1046 1050
1051
1047def _PostRepoUpgrade(manifest, quiet=False): 1052def _PostRepoUpgrade(manifest, quiet=False):
1048 wrapper = Wrapper() 1053 wrapper = Wrapper()
1049 if wrapper.NeedSetupGnuPG(): 1054 if wrapper.NeedSetupGnuPG():
@@ -1052,6 +1057,7 @@ def _PostRepoUpgrade(manifest, quiet=False):
1052 if project.Exists: 1057 if project.Exists:
1053 project.PostRepoUpgrade() 1058 project.PostRepoUpgrade()
1054 1059
1060
1055def _PostRepoFetch(rp, no_repo_verify=False, verbose=False): 1061def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
1056 if rp.HasChanges: 1062 if rp.HasChanges:
1057 print('info: A new version of repo is available', file=sys.stderr) 1063 print('info: A new version of repo is available', file=sys.stderr)
@@ -1070,6 +1076,7 @@ def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
1070 print('repo version %s is current' % rp.work_git.describe(HEAD), 1076 print('repo version %s is current' % rp.work_git.describe(HEAD),
1071 file=sys.stderr) 1077 file=sys.stderr)
1072 1078
1079
1073def _VerifyTag(project): 1080def _VerifyTag(project):
1074 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg') 1081 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
1075 if not os.path.exists(gpg_dir): 1082 if not os.path.exists(gpg_dir):
@@ -1174,6 +1181,8 @@ class _FetchTimes(object):
1174# and supporting persistent-http[s]. It cannot change hosts from 1181# and supporting persistent-http[s]. It cannot change hosts from
1175# request to request like the normal transport, the real url 1182# request to request like the normal transport, the real url
1176# is passed during initialization. 1183# is passed during initialization.
1184
1185
1177class PersistentTransport(xmlrpc.client.Transport): 1186class PersistentTransport(xmlrpc.client.Transport):
1178 def __init__(self, orig_host): 1187 def __init__(self, orig_host):
1179 self.orig_host = orig_host 1188 self.orig_host = orig_host
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 180496fc..bc373b3e 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -33,6 +33,7 @@ else:
33 33
34UNUSUAL_COMMIT_THRESHOLD = 5 34UNUSUAL_COMMIT_THRESHOLD = 5
35 35
36
36def _ConfirmManyUploads(multiple_branches=False): 37def _ConfirmManyUploads(multiple_branches=False):
37 if multiple_branches: 38 if multiple_branches:
38 print('ATTENTION: One or more branches has an unusually high number ' 39 print('ATTENTION: One or more branches has an unusually high number '
@@ -44,17 +45,20 @@ def _ConfirmManyUploads(multiple_branches=False):
44 answer = input("If you are sure you intend to do this, type 'yes': ").strip() 45 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
45 return answer == "yes" 46 return answer == "yes"
46 47
48
47def _die(fmt, *args): 49def _die(fmt, *args):
48 msg = fmt % args 50 msg = fmt % args
49 print('error: %s' % msg, file=sys.stderr) 51 print('error: %s' % msg, file=sys.stderr)
50 sys.exit(1) 52 sys.exit(1)
51 53
54
52def _SplitEmails(values): 55def _SplitEmails(values):
53 result = [] 56 result = []
54 for value in values: 57 for value in values:
55 result.extend([s.strip() for s in value.split(',')]) 58 result.extend([s.strip() for s in value.split(',')])
56 return result 59 return result
57 60
61
58class Upload(InteractiveCommand): 62class Upload(InteractiveCommand):
59 common = True 63 common = True
60 helpSummary = "Upload changes for code review" 64 helpSummary = "Upload changes for code review"
diff --git a/subcmds/version.py b/subcmds/version.py
index 761172b7..92316549 100644
--- a/subcmds/version.py
+++ b/subcmds/version.py
@@ -20,6 +20,7 @@ from command import Command, MirrorSafeCommand
20from git_command import git, RepoSourceVersion, user_agent 20from git_command import git, RepoSourceVersion, user_agent
21from git_refs import HEAD 21from git_refs import HEAD
22 22
23
23class Version(Command, MirrorSafeCommand): 24class Version(Command, MirrorSafeCommand):
24 wrapper_version = None 25 wrapper_version = None
25 wrapper_path = None 26 wrapper_path = None
diff --git a/tests/test_git_config.py b/tests/test_git_config.py
index b735f27f..6aa6b381 100644
--- a/tests/test_git_config.py
+++ b/tests/test_git_config.py
@@ -23,14 +23,17 @@ import unittest
23 23
24import git_config 24import git_config
25 25
26
26def fixture(*paths): 27def fixture(*paths):
27 """Return a path relative to test/fixtures. 28 """Return a path relative to test/fixtures.
28 """ 29 """
29 return os.path.join(os.path.dirname(__file__), 'fixtures', *paths) 30 return os.path.join(os.path.dirname(__file__), 'fixtures', *paths)
30 31
32
31class GitConfigUnitTest(unittest.TestCase): 33class GitConfigUnitTest(unittest.TestCase):
32 """Tests the GitConfig class. 34 """Tests the GitConfig class.
33 """ 35 """
36
34 def setUp(self): 37 def setUp(self):
35 """Create a GitConfig object using the test.gitconfig fixture. 38 """Create a GitConfig object using the test.gitconfig fixture.
36 """ 39 """
@@ -68,5 +71,6 @@ class GitConfigUnitTest(unittest.TestCase):
68 val = config.GetString('empty') 71 val = config.GetString('empty')
69 self.assertEqual(val, None) 72 self.assertEqual(val, None)
70 73
74
71if __name__ == '__main__': 75if __name__ == '__main__':
72 unittest.main() 76 unittest.main()
diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py
index 8ef8d48d..38def512 100644
--- a/tests/test_wrapper.py
+++ b/tests/test_wrapper.py
@@ -23,14 +23,17 @@ import unittest
23 23
24import wrapper 24import wrapper
25 25
26
26def fixture(*paths): 27def fixture(*paths):
27 """Return a path relative to tests/fixtures. 28 """Return a path relative to tests/fixtures.
28 """ 29 """
29 return os.path.join(os.path.dirname(__file__), 'fixtures', *paths) 30 return os.path.join(os.path.dirname(__file__), 'fixtures', *paths)
30 31
32
31class RepoWrapperUnitTest(unittest.TestCase): 33class RepoWrapperUnitTest(unittest.TestCase):
32 """Tests helper functions in the repo wrapper 34 """Tests helper functions in the repo wrapper
33 """ 35 """
36
34 def setUp(self): 37 def setUp(self):
35 """Load the wrapper module every time 38 """Load the wrapper module every time
36 """ 39 """
@@ -76,5 +79,6 @@ class RepoWrapperUnitTest(unittest.TestCase):
76 self.assertEqual(self.wrapper.gitc_parse_clientdir('/gitc/manifest-rw/'), None) 79 self.assertEqual(self.wrapper.gitc_parse_clientdir('/gitc/manifest-rw/'), None)
77 self.assertEqual(self.wrapper.gitc_parse_clientdir('/test/usr/local/google/gitc/'), None) 80 self.assertEqual(self.wrapper.gitc_parse_clientdir('/test/usr/local/google/gitc/'), None)
78 81
82
79if __name__ == '__main__': 83if __name__ == '__main__':
80 unittest.main() 84 unittest.main()
diff --git a/wrapper.py b/wrapper.py
index 0ce32508..81302985 100644
--- a/wrapper.py
+++ b/wrapper.py
@@ -27,7 +27,10 @@ import os
27def WrapperPath(): 27def WrapperPath():
28 return os.path.join(os.path.dirname(__file__), 'repo') 28 return os.path.join(os.path.dirname(__file__), 'repo')
29 29
30
30_wrapper_module = None 31_wrapper_module = None
32
33
31def Wrapper(): 34def Wrapper():
32 global _wrapper_module 35 global _wrapper_module
33 if not _wrapper_module: 36 if not _wrapper_module: