From ce47c7f86237480d4301e56da724f5b6ade0a5fb Mon Sep 17 00:00:00 2001 From: Brian Evans Date: Thu, 11 Jan 2018 12:37:47 -0500 Subject: [PATCH] Add mercurial sync support --- pym/portage/const.py | 1 + pym/portage/sync/modules/mercurial/__init__.py | 39 +++++++ pym/portage/sync/modules/mercurial/mercurial.py | 136 ++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 pym/portage/sync/modules/mercurial/__init__.py create mode 100644 pym/portage/sync/modules/mercurial/mercurial.py diff --git a/pym/portage/const.py b/pym/portage/const.py index ec877b841..4900c84eb 100644 --- a/pym/portage/const.py +++ b/pym/portage/const.py @@ -83,6 +83,7 @@ LIBC_PACKAGE_ATOM = "virtual/libc" OS_HEADERS_PACKAGE_ATOM = "virtual/os-headers" CVS_PACKAGE_ATOM = "dev-vcs/cvs" GIT_PACKAGE_ATOM = "dev-vcs/git" +HG_PACKAGE_ATOM = "dev-vcs/mercurial" RSYNC_PACKAGE_ATOM = "net-misc/rsync" INCREMENTALS = ( diff --git a/pym/portage/sync/modules/mercurial/__init__.py b/pym/portage/sync/modules/mercurial/__init__.py new file mode 100644 index 000000000..0769434f1 --- /dev/null +++ b/pym/portage/sync/modules/mercurial/__init__.py @@ -0,0 +1,39 @@ +# Copyright 2014-2018 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +doc = """Mercurial plug-in module for portage. +Performs a hg pull on repositories.""" +__doc__ = doc[:] + +from portage.localization import _ +from portage.sync.config_checks import CheckSyncConfig +from portage.util import writemsg_level + +module_spec = { + 'name': 'mercurial', + 'description': doc, + 'provides':{ + 'mercurial-module': { + 'name': "mercurial", + 'sourcefile': "mercurial", + 'class': "MercurialSync", + 'description': doc, + 'functions': ['sync', 'new', 'exists', 'retrieve_head'], + 'func_desc': { + 'sync': 'Performs a hg pull on the repository', + 'new': 'Creates the new repository at the specified location', + 'exists': 'Returns a boolean of whether the specified dir ' + + 'exists and is a valid Mercurial repository', + 'retrieve_head': 'Returns the head commit hash', + }, + 'validate_config': CheckSyncConfig, + 'module_specific_options': ( + 'sync-mercurial-clone-env', + 'sync-mercurial-clone-extra-opts', + 'sync-mercurial-env', + 'sync-mercurial-pull-env', + 'sync-mercurial-pull-extra-opts', + ), + } + } +} diff --git a/pym/portage/sync/modules/mercurial/mercurial.py b/pym/portage/sync/modules/mercurial/mercurial.py new file mode 100644 index 000000000..9b7ae4985 --- /dev/null +++ b/pym/portage/sync/modules/mercurial/mercurial.py @@ -0,0 +1,136 @@ +# Copyright 2005-2018 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import logging +import subprocess + +import portage +from portage import os +from portage.util import writemsg_level, shlex_split +from portage.output import create_color_func +good = create_color_func("GOOD") +bad = create_color_func("BAD") +warn = create_color_func("WARN") +from portage.sync.syncbase import NewBase + + +class MercurialSync(NewBase): + '''Mercurial sync class''' + + short_desc = "Perform sync operations on mercurial based repositories" + + @staticmethod + def name(): + return "MercurialSync" + + + def __init__(self): + NewBase.__init__(self, "hg", portage.const.HG_PACKAGE_ATOM) + + + def exists(self, **kwargs): + '''Tests whether the repo actually exists''' + return os.path.exists(os.path.join(self.repo.location, '.hg')) + + + def new(self, **kwargs): + '''Do the initial clone of the repository''' + if kwargs: + self._kwargs(kwargs) + try: + if not os.path.exists(self.repo.location): + os.makedirs(self.repo.location) + self.logger(self.xterm_titles, + 'Created new directory %s' % self.repo.location) + except IOError: + return (1, False) + + sync_uri = self.repo.sync_uri + if sync_uri.startswith("file://"): + sync_uri = sync_uri[7:] + + hg_cmd_opts = "" + if self.repo.module_specific_options.get('sync-mercurial-env'): + shlexed_env = shlex_split(self.repo.module_specific_options['sync-mercurial-env']) + env = dict((k, v) for k, _, v in (assignment.partition('=') for assignment in shlexed_env) if k) + self.spawn_kwargs['env'].update(env) + + if self.repo.module_specific_options.get('sync-mercurial-clone-env'): + shlexed_env = shlex_split(self.repo.module_specific_options['sync-mercurial-clone-env']) + clone_env = dict((k, v) for k, _, v in (assignment.partition('=') for assignment in shlexed_env) if k) + self.spawn_kwargs['env'].update(clone_env) + + if self.settings.get("PORTAGE_QUIET") == "1": + hg_cmd_opts += " --quiet" + if self.repo.module_specific_options.get('sync-mercurial-clone-extra-opts'): + hg_cmd_opts += " %s" % self.repo.module_specific_options['sync-mercurial-clone-extra-opts'] + hg_cmd = "%s clone%s %s ." % (self.bin_command, hg_cmd_opts, + portage._shell_quote(sync_uri)) + writemsg_level(hg_cmd + "\n") + + exitcode = portage.process.spawn_bash("cd %s ; exec %s" % ( + portage._shell_quote(self.repo.location), hg_cmd), + **self.spawn_kwargs) + if exitcode != os.EX_OK: + msg = "!!! hg clone error in %s" % self.repo.location + self.logger(self.xterm_titles, msg) + writemsg_level(msg + "\n", level=logging.ERROR, noiselevel=-1) + return (exitcode, False) + return (os.EX_OK, True) + + + def update(self): + ''' Update existing mercurial repository, and ignore the syncuri. We are + going to trust the user and assume that the user is in the branch + that he/she wants updated. We'll let the user manage branches with + hg directly. + ''' + + hg_cmd_opts = "" + if self.repo.module_specific_options.get('sync-mercurial-env'): + shlexed_env = shlex_split(self.repo.module_specific_options['sync-mercurial-env']) + env = dict((k, v) for k, _, v in (assignment.partition('=') for assignment in shlexed_env) if k) + self.spawn_kwargs['env'].update(env) + + if self.repo.module_specific_options.get('sync-mercurial-pull-env'): + shlexed_env = shlex_split(self.repo.module_specific_options['sync-mercurial-pull-env']) + pull_env = dict((k, v) for k, _, v in (assignment.partition('=') for assignment in shlexed_env) if k) + self.spawn_kwargs['env'].update(pull_env) + + if self.settings.get("PORTAGE_QUIET") == "1": + hg_cmd_opts += " --quiet" + if self.repo.module_specific_options.get('sync-mercurial-pull-extra-opts'): + hg_cmd_opts += " %s" % self.repo.module_specific_options['sync-mercurial-pull-extra-opts'] + hg_cmd = "%s pull -u%s" % (self.bin_command, hg_cmd_opts) + writemsg_level(hg_cmd + "\n") + + rev_cmd = [self.bin_command, "id", "--id", "--rev", "tip"] + previous_rev = subprocess.check_output(rev_cmd, + cwd=portage._unicode_encode(self.repo.location)) + + exitcode = portage.process.spawn_bash("cd %s ; exec %s" % ( + portage._shell_quote(self.repo.location), hg_cmd), + **self.spawn_kwargs) + if exitcode != os.EX_OK: + msg = "!!! hg pull error in %s" % self.repo.location + self.logger(self.xterm_titles, msg) + writemsg_level(msg + "\n", level=logging.ERROR, noiselevel=-1) + return (exitcode, False) + + current_rev = subprocess.check_output(rev_cmd, + cwd=portage._unicode_encode(self.repo.location)) + + return (os.EX_OK, current_rev != previous_rev) + + def retrieve_head(self, **kwargs): + '''Get information about the head commit''' + if kwargs: + self._kwargs(kwargs) + rev_cmd = [self.bin_command, "id", "--id", "--rev", "tip"] + try: + ret = (os.EX_OK, + portage._unicode_decode(subprocess.check_output(rev_cmd, + cwd=portage._unicode_encode(self.repo.location)))) + except subprocess.CalledProcessError: + ret = (1, False) + return ret -- 2.15.1