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): code = '' return code + DEFAULT = None 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): """Command which requires user interaction on the tty and must not run within a pager, even if the user asks to. """ + def WantPager(self, _opt): return False @@ -244,6 +245,7 @@ class PagedCommand(Command): """Command which defaults to output in a pager, as its display tends to be larger than one screen full. """ + def WantPager(self, _opt): return True diff --git a/editor.py b/editor.py index 6319ada5..4306836d 100644 --- a/editor.py +++ b/editor.py @@ -24,6 +24,7 @@ import tempfile from error import EditorError import platform_utils + class Editor(object): """Manages the user's preferred text editor.""" diff --git a/error.py b/error.py index f22a0e75..cfed8083 100644 --- a/error.py +++ b/error.py @@ -14,21 +14,26 @@ # See the License for the specific language governing permissions and # limitations under the License. + class ManifestParseError(Exception): """Failed to parse the manifest file. """ + class ManifestInvalidRevisionError(Exception): """The revision value in a project is incorrect. """ + class ManifestInvalidPathError(Exception): """A path used in or is incorrect. """ + class NoManifestException(Exception): """The required manifest does not exist. """ + def __init__(self, path, reason): super(NoManifestException, self).__init__() self.path = path @@ -37,9 +42,11 @@ class NoManifestException(Exception): def __str__(self): return self.reason + class EditorError(Exception): """Unspecified error from the user's text editor. """ + def __init__(self, reason): super(EditorError, self).__init__() self.reason = reason @@ -47,9 +54,11 @@ class EditorError(Exception): def __str__(self): return self.reason + class GitError(Exception): """Unspecified internal error from git. """ + def __init__(self, command): super(GitError, self).__init__() self.command = command @@ -57,9 +66,11 @@ class GitError(Exception): def __str__(self): return self.command + class UploadError(Exception): """A bundle upload to Gerrit did not succeed. """ + def __init__(self, reason): super(UploadError, self).__init__() self.reason = reason @@ -67,9 +78,11 @@ class UploadError(Exception): def __str__(self): return self.reason + class DownloadError(Exception): """Cannot download a repository. """ + def __init__(self, reason): super(DownloadError, self).__init__() self.reason = reason @@ -77,9 +90,11 @@ class DownloadError(Exception): def __str__(self): return self.reason + class NoSuchProjectError(Exception): """A specified project does not exist in the work tree. """ + def __init__(self, name=None): super(NoSuchProjectError, self).__init__() self.name = name @@ -93,6 +108,7 @@ class NoSuchProjectError(Exception): class InvalidProjectGroupsError(Exception): """A specified project is not suitable for the specified groups """ + def __init__(self, name=None): super(InvalidProjectGroupsError, self).__init__() self.name = name @@ -102,15 +118,18 @@ class InvalidProjectGroupsError(Exception): return 'in current directory' return self.name + class RepoChangedException(Exception): """Thrown if 'repo sync' results in repo updating its internal repo or manifest repositories. In this special case we must use exec to re-execute repo with the new code and manifest. """ + def __init__(self, extra_args=None): super(RepoChangedException, self).__init__() self.extra_args = extra_args or [] + class HookError(Exception): """Thrown if a 'repo-hook' could not be run. 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' TASK_SYNC_NETWORK = 'sync-network' TASK_SYNC_LOCAL = 'sync-local' + class EventLog(object): """Event log that records events that occurred during a repo invocation. @@ -165,6 +166,7 @@ class EventLog(object): # An integer id that is unique across this invocation of the program. _EVENT_ID = multiprocessing.Value('i', 1) + def _NextEventId(): """Helper function for grabbing the next unique id. 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 _ssh_sock_path = None _ssh_clients = [] + def ssh_sock(create=True): global _ssh_sock_path if _ssh_sock_path is None: @@ -61,6 +62,7 @@ def ssh_sock(create=True): 'master-%r@%h:%p') return _ssh_sock_path + def _ssh_proxy(): global _ssh_proxy_path if _ssh_proxy_path is None: @@ -69,15 +71,18 @@ def _ssh_proxy(): 'git_ssh') return _ssh_proxy_path + def _add_ssh_client(p): _ssh_clients.append(p) + def _remove_ssh_client(p): try: _ssh_clients.remove(p) except ValueError: pass + def terminate_ssh_clients(): global _ssh_clients for p in _ssh_clients: @@ -88,8 +93,10 @@ def terminate_ssh_clients(): pass _ssh_clients = [] + _git_version = None + class _GitCall(object): def version_tuple(self): global _git_version @@ -102,11 +109,14 @@ class _GitCall(object): def __getattr__(self, name): name = name.replace('_', '-') + def fun(*cmdv): command = [name] command.extend(cmdv) return GitCommand(None, command).Wait() == 0 return fun + + git = _GitCall() @@ -187,8 +197,10 @@ class UserAgent(object): return self._git_ua + user_agent = UserAgent() + def git_require(min_version, fail=False, msg=''): git_version = git.version_tuple() if min_version <= git_version: @@ -201,9 +213,11 @@ def git_require(min_version, fail=False, msg=''): sys.exit(1) return False + def _setenv(env, name, value): env[name] = value.encode() + class GitCommand(object): def __init__(self, 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}$') REVIEW_CACHE = dict() + def IsChange(rev): return rev.startswith(R_CHANGES) + def IsId(rev): return ID_RE.match(rev) + def IsTag(rev): return rev.startswith(R_TAGS) + def IsImmutable(rev): return IsChange(rev) or IsId(rev) or IsTag(rev) + def _key(name): parts = name.split('.') if len(parts) < 2: @@ -79,6 +84,7 @@ def _key(name): parts[-1] = parts[-1].lower() return '.'.join(parts) + class GitConfig(object): _ForUser = None @@ -392,6 +398,7 @@ _master_keys = set() _ssh_master = True _master_keys_lock = None + def init_ssh(): """Should be called once at the start of repo to init ssh master handling. @@ -401,6 +408,7 @@ def init_ssh(): assert _master_keys_lock is None, "Should only call init_ssh once" _master_keys_lock = _threading.Lock() + def _open_ssh(host, port=None): global _ssh_master @@ -479,6 +487,7 @@ def _open_ssh(host, port=None): finally: _master_keys_lock.release() + def close_ssh(): global _master_keys_lock @@ -503,15 +512,18 @@ def close_ssh(): # We're done with the lock, so we can delete it. _master_keys_lock = None + URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/') + def GetSchemeFromUrl(url): m = URI_ALL.match(url) if m: return m.group(1) return None + @contextlib.contextmanager def GetUrlCookieFile(url, quiet): if url.startswith('persistent-'): @@ -552,6 +564,7 @@ def GetUrlCookieFile(url, quiet): cookiefile = os.path.expanduser(cookiefile) yield cookiefile, None + def _preconnect(url): m = URI_ALL.match(url) if m: @@ -572,9 +585,11 @@ def _preconnect(url): return False + class Remote(object): """Configuration options related to a remote. """ + def __init__(self, config, name): self._config = config self.name = name @@ -735,6 +750,7 @@ class Remote(object): class Branch(object): """Configuration options related to a single branch. """ + def __init__(self, config, name): self._config = config 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 NUM_BATCH_RETRIEVE_REVISIONID = 32 + def get_gitc_manifest_dir(): return wrapper.Wrapper().get_gitc_manifest_dir() + def parse_clientdir(gitc_fs_path): return wrapper.Wrapper().gitc_parse_clientdir(gitc_fs_path) + def _set_project_revisions(projects): """Sets the revisionExpr for a list of projects. @@ -63,6 +66,7 @@ def _set_project_revisions(projects): (proj.remote.url, proj.revisionExpr)) proj.revisionExpr = revisionExpr + def _manifest_groups(manifest): """Returns the manifest group string that should be synced @@ -77,6 +81,7 @@ def _manifest_groups(manifest): groups = 'default,platform-' + platform.system().lower() return groups + def generate_gitc_manifest(gitc_manifest, manifest, paths=None): """Generate a manifest for shafsd to use for this GITC client. @@ -140,6 +145,7 @@ def generate_gitc_manifest(gitc_manifest, manifest, paths=None): # Save the manifest. save_manifest(manifest) + def save_manifest(manifest, client_dir=None): """Save the manifest file in the client_dir. 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', dest='event_log', action='store', help='filename of event log to append timeline to') + class _Repo(object): def __init__(self, repodir): self.repodir = repodir @@ -300,11 +301,13 @@ repo: error: cp %s %s """ % (exp_str, WrapperPath(), repo_path), file=sys.stderr) + def _CheckRepoDir(repo_dir): if not repo_dir: print('no --repo-dir argument', file=sys.stderr) sys.exit(1) + def _PruneOptions(argv, opt): i = 0 while i < len(argv): @@ -320,6 +323,7 @@ def _PruneOptions(argv, opt): continue i += 1 + class _UserAgentHandler(urllib.request.BaseHandler): def http_request(self, req): req.add_header('User-Agent', user_agent.repo) @@ -329,6 +333,7 @@ class _UserAgentHandler(urllib.request.BaseHandler): req.add_header('User-Agent', user_agent.repo) return req + def _AddPasswordFromUserInput(handler, msg, req): # If repo could not find auth info from netrc, try to get it from user input url = req.get_full_url() @@ -342,6 +347,7 @@ def _AddPasswordFromUserInput(handler, msg, req): return handler.passwd.add_password(None, url, user, password) + class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): def http_error_401(self, req, fp, code, msg, headers): _AddPasswordFromUserInput(self, msg, req) @@ -351,6 +357,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): def http_error_auth_reqed(self, authreq, host, req, headers): try: old_add_header = req.add_header + def _add_header(name, val): val = val.replace('\n', '') old_add_header(name, val) @@ -365,6 +372,7 @@ class _BasicAuthHandler(urllib.request.HTTPBasicAuthHandler): self.retried = 0 raise + class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): def http_error_401(self, req, fp, code, msg, headers): _AddPasswordFromUserInput(self, msg, req) @@ -374,6 +382,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): def http_error_auth_reqed(self, auth_header, host, req, headers): try: old_add_header = req.add_header + def _add_header(name, val): val = val.replace('\n', '') old_add_header(name, val) @@ -388,6 +397,7 @@ class _DigestAuthHandler(urllib.request.HTTPDigestAuthHandler): self.retried = 0 raise + class _KerberosAuthHandler(urllib.request.BaseHandler): def __init__(self): self.retried = 0 @@ -468,6 +478,7 @@ class _KerberosAuthHandler(urllib.request.BaseHandler): kerberos.authGSSClientClean(self.context) self.context = None + def init_http(): handlers = [_UserAgentHandler()] @@ -495,6 +506,7 @@ def init_http(): handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) urllib.request.install_opener(urllib.request.build_opener(*handlers)) + def _Main(argv): result = 0 @@ -551,5 +563,6 @@ def _Main(argv): TerminatePager() sys.exit(result) + if __name__ == '__main__': _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([ 'sso', 'rpc']) + class _Default(object): """Project defaults within the manifest.""" @@ -74,6 +75,7 @@ class _Default(object): def __ne__(self, other): return self.__dict__ != other.__dict__ + class _XmlRemote(object): def __init__(self, name, @@ -127,6 +129,7 @@ class _XmlRemote(object): orig_name=self.name, fetchUrl=self.fetchUrl) + class XmlManifest(object): """manages the repo configuration file""" @@ -655,7 +658,6 @@ class XmlManifest(object): if self._repo_hooks_project and (self._repo_hooks_project.name == name): self._repo_hooks_project = None - def _AddMetaProjectMirror(self, m): name = None 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 old_stdout = None old_stderr = None + def RunPager(globalConfig): if not os.isatty(0) or not os.isatty(1): return @@ -39,6 +40,7 @@ def RunPager(globalConfig): else: _ForkPager(pager) + def TerminatePager(): global pager_process, old_stdout, old_stderr if pager_process: @@ -52,6 +54,7 @@ def TerminatePager(): sys.stdout = old_stdout sys.stderr = old_stderr + def _PipePager(pager): global pager_process, old_stdout, old_stderr assert pager_process is None, "Only one active pager process at a time" @@ -62,6 +65,7 @@ def _PipePager(pager): sys.stdout = pager_process.stdin sys.stderr = pager_process.stdin + def _ForkPager(pager): global active # This process turns into the pager; a child it forks will @@ -88,6 +92,7 @@ def _ForkPager(pager): print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) sys.exit(255) + def _SelectPager(globalConfig): try: return os.environ['GIT_PAGER'] @@ -105,6 +110,7 @@ def _SelectPager(globalConfig): return 'less' + def _BecomePager(pager): # Delaying execution of the pager until we have output # 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): """ class Stream(object): """ Encapsulates a file descriptor """ + def __init__(self, fd, dest, std_name): self.fd = fd self.dest = dest @@ -125,6 +126,7 @@ class _FileDescriptorStreamsThreads(FileDescriptorStreams): non blocking I/O. This implementation requires creating threads issuing blocking read operations on file descriptors. """ + def __init__(self): super(_FileDescriptorStreamsThreads, self).__init__() # The queue is shared accross all threads so we can simulate the @@ -144,12 +146,14 @@ class _FileDescriptorStreamsThreads(FileDescriptorStreams): class QueueItem(object): """ Item put in the shared queue """ + def __init__(self, stream, data): self.stream = stream self.data = data class Stream(object): """ Encapsulates a file descriptor """ + def __init__(self, fd, dest, std_name, queue): self.fd = fd 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) # column 0. CSI_ERASE_LINE = '\x1b[2K' + class Progress(object): def __init__(self, title, total=0, units='', print_newline=False, 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): def sq(r): return "'" + r.replace("'", "'\''") + "'" + _project_hook_list = None @@ -1256,9 +1257,7 @@ class Project(object): print(line[:-1]) return p.Wait() == 0 - # Publish / Upload ## - def WasPublished(self, branch, all_refs=None): """Was the branch published (uploaded) for code review? If so, returns the SHA-1 hash of the last published @@ -1410,9 +1409,7 @@ class Project(object): R_HEADS + branch.name, message=msg) - # Sync ## - def _ExtractArchive(self, tarpath, path=None): """Extract the given tar on its current location @@ -1819,9 +1816,7 @@ class Project(object): patch_id, self.bare_git.rev_parse('FETCH_HEAD')) - # Branch Management ## - def GetHeadPath(self): """Return the full path to the HEAD ref.""" dotgit = os.path.join(self.worktree, '.git') @@ -2019,9 +2014,7 @@ class Project(object): kept.append(ReviewableBranch(self, branch, base)) return kept - # Submodule Management ## - def GetRegisteredSubprojects(self): result = [] @@ -2172,7 +2165,6 @@ class Project(object): result.extend(subproject.GetDerivedSubprojects()) return result - # Direct Git Commands ## def _CheckForImmutableRevision(self): try: diff --git a/pyversion.py b/pyversion.py index f6082408..8dbf909b 100644 --- a/pyversion.py +++ b/pyversion.py @@ -16,5 +16,6 @@ import sys + def is_python3(): 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' _TRACE = os.environ.get(REPO_TRACE) == '1' + def IsTrace(): return _TRACE + def SetTrace(): global _TRACE _TRACE = True + def Trace(fmt, *args): if IsTrace(): 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 from git_command import git from progress import Progress + class Abandon(Command): common = True helpSummary = "Permanently abandon a development branch" @@ -32,6 +33,7 @@ deleting it (and all its history) from your local repository. It is equivalent to "git branch -D ". """ + def _Options(self, p): p.add_option('--all', 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 from color import Coloring from command import Command + class BranchColoring(Coloring): def __init__(self, config): Coloring.__init__(self, config, 'branch') @@ -26,6 +27,7 @@ class BranchColoring(Coloring): self.local = self.printer('local') self.notinproject = self.printer('notinproject', fg='red') + class BranchInfo(object): def __init__(self, name): 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 from command import Command from progress import Progress + class Checkout(Command): common = True 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 CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$') + class CherryPick(Command): common = True 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 @@ from command import PagedCommand + class Diff(PagedCommand): common = True 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 from command import PagedCommand from manifest_xml import XmlManifest + class _Coloring(Coloring): def __init__(self, config): Coloring.__init__(self, config, "status") + class Diffmanifests(PagedCommand): """ A command to see logs in projects represented by manifests 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 CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$') + class Download(Command): common = True 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. return yield [mirror, opt, cmd, shell, cnt, config, project] + class WorkerKeyboardInterrupt(Exception): """ Keyboard interrupt exception for worker processes. """ pass @@ -285,6 +286,7 @@ class WorkerKeyboardInterrupt(Exception): def InitWorker(): signal.signal(signal.SIGINT, signal.SIG_IGN) + def DoWorkWrapper(args): """ A wrapper around the DoWork() method. @@ -303,6 +305,7 @@ def DoWorkWrapper(args): def DoWork(project, mirror, opt, cmd, shell, cnt, config): env = os.environ.copy() + def setenv(name, val): if val is None: 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 if not is_python3(): input = raw_input + class GitcDelete(Command, GitcClientCommand): common = True 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 from error import GitError from git_command import git_require, GitCommand + class GrepColoring(Coloring): def __init__(self, config): Coloring.__init__(self, config, 'grep') self.project = self.printer('project', attr='bold') self.fail = self.printer('fail', fg='red') + class Grep(PagedCommand): common = True helpSummary = "Print lines matching a pattern" @@ -156,7 +158,6 @@ contain a line that matches both expressions: action='callback', callback=carry, help='Show only file names not containing matching lines') - def Execute(self, opt, args): out = GrepColoring(self.manifest.manifestProject.config) 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 from command import PagedCommand, MirrorSafeCommand, GitcAvailableCommand, GitcClientCommand import gitc_utils + class Help(PagedCommand, MirrorSafeCommand): common = False 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 from color import Coloring from git_refs import R_M + class _Coloring(Coloring): def __init__(self, config): Coloring.__init__(self, config, "status") + class Info(PagedCommand): common = True helpSummary = "Get info on the manifest branch, current branch or unmerged branches" @@ -41,7 +43,6 @@ class Info(PagedCommand): dest="local", action="store_true", help="Disable all remote operations") - def Execute(self, opt, args): self.out = _Coloring(self.manifest.globalConfig) 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 from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD import platform_utils + class Init(InteractiveCommand, MirrorSafeCommand): common = True 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 from command import Command, MirrorSafeCommand + class List(Command, MirrorSafeCommand): common = True 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 from command import PagedCommand + class Manifest(PagedCommand): common = False 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 from color import Coloring from command import PagedCommand + class Prune(PagedCommand): common = True 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 from subcmds.sync import _PostRepoUpgrade from subcmds.sync import _PostRepoFetch + class Selfupdate(Command, MirrorSafeCommand): common = False 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 @@ from subcmds.sync import Sync + class Smartsync(Sync): common = True 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 from command import InteractiveCommand from git_command import GitCommand + class _ProjectList(Coloring): def __init__(self, gc): Coloring.__init__(self, gc, 'interactive') @@ -28,6 +29,7 @@ class _ProjectList(Coloring): self.header = self.printer('header', attr='bold') self.help = self.printer('help', fg='red', attr='bold') + class Stage(InteractiveCommand): common = True helpSummary = "Stage file(s) for commit" @@ -105,6 +107,7 @@ The '%prog' command stages files to prepare the next commit. continue print('Bye.') + def _AddI(project): p = GitCommand(project, ['add', '--interactive'], bare=False) 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 from progress import Progress from project import SyncBuffer + class Start(Command): common = True 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 from color import Coloring import platform_utils + class Status(PagedCommand): common = True 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: try: import resource + def _rlimit_nofile(): return resource.getrlimit(resource.RLIMIT_NOFILE) except ImportError: @@ -81,13 +82,16 @@ from manifest_xml import GitcManifest _ONE_DAY_S = 24 * 60 * 60 + class _FetchError(Exception): """Internal error thrown in _FetchHelper() when we don't want stack trace.""" pass + class _CheckoutError(Exception): """Internal error thrown in _CheckoutOne() when we don't want stack trace.""" + class Sync(Command, MirrorSafeCommand): jobs = 1 common = True @@ -1044,6 +1048,7 @@ later is required to fix a server side protocol bug. file=sys.stderr) sys.exit(1) + def _PostRepoUpgrade(manifest, quiet=False): wrapper = Wrapper() if wrapper.NeedSetupGnuPG(): @@ -1052,6 +1057,7 @@ def _PostRepoUpgrade(manifest, quiet=False): if project.Exists: project.PostRepoUpgrade() + def _PostRepoFetch(rp, no_repo_verify=False, verbose=False): if rp.HasChanges: 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): print('repo version %s is current' % rp.work_git.describe(HEAD), file=sys.stderr) + def _VerifyTag(project): gpg_dir = os.path.expanduser('~/.repoconfig/gnupg') if not os.path.exists(gpg_dir): @@ -1174,6 +1181,8 @@ class _FetchTimes(object): # and supporting persistent-http[s]. It cannot change hosts from # request to request like the normal transport, the real url # is passed during initialization. + + class PersistentTransport(xmlrpc.client.Transport): def __init__(self, orig_host): 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: UNUSUAL_COMMIT_THRESHOLD = 5 + def _ConfirmManyUploads(multiple_branches=False): if multiple_branches: print('ATTENTION: One or more branches has an unusually high number ' @@ -44,17 +45,20 @@ def _ConfirmManyUploads(multiple_branches=False): answer = input("If you are sure you intend to do this, type 'yes': ").strip() return answer == "yes" + def _die(fmt, *args): msg = fmt % args print('error: %s' % msg, file=sys.stderr) sys.exit(1) + def _SplitEmails(values): result = [] for value in values: result.extend([s.strip() for s in value.split(',')]) return result + class Upload(InteractiveCommand): common = True 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 from git_command import git, RepoSourceVersion, user_agent from git_refs import HEAD + class Version(Command, MirrorSafeCommand): wrapper_version = None 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 import git_config + def fixture(*paths): """Return a path relative to test/fixtures. """ return os.path.join(os.path.dirname(__file__), 'fixtures', *paths) + class GitConfigUnitTest(unittest.TestCase): """Tests the GitConfig class. """ + def setUp(self): """Create a GitConfig object using the test.gitconfig fixture. """ @@ -68,5 +71,6 @@ class GitConfigUnitTest(unittest.TestCase): val = config.GetString('empty') self.assertEqual(val, None) + if __name__ == '__main__': 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 import wrapper + def fixture(*paths): """Return a path relative to tests/fixtures. """ return os.path.join(os.path.dirname(__file__), 'fixtures', *paths) + class RepoWrapperUnitTest(unittest.TestCase): """Tests helper functions in the repo wrapper """ + def setUp(self): """Load the wrapper module every time """ @@ -76,5 +79,6 @@ class RepoWrapperUnitTest(unittest.TestCase): self.assertEqual(self.wrapper.gitc_parse_clientdir('/gitc/manifest-rw/'), None) self.assertEqual(self.wrapper.gitc_parse_clientdir('/test/usr/local/google/gitc/'), None) + if __name__ == '__main__': 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 def WrapperPath(): return os.path.join(os.path.dirname(__file__), 'repo') + _wrapper_module = None + + def Wrapper(): global _wrapper_module if not _wrapper_module: