Example #1
0
    def push(self, repo, orig, dest, rev=None, ref_name=None):
        """ Inherited method
        :func:`~repoman.repository.Repository.push`
        """
        def update_repo(repo, orig):
            command_config = ["--config", "extensions.rebase="]
            command = ["pull", "--rebase", orig, "--tool=false"]
            repo.rawcommand(command_config + command)
            return self._new_changeset_object(repo.tip()).hash

        # Push method should always be ready for the case where there is a new
        # remote head
        push_succeded = False
        last_exception = None
        MAX_RETRIES = 15
        if not rev:
            rev_hash = "tip"
        else:
            rev_hash = rev.hash
        logger.info("Pushing %s from %s to %s" % (rev_hash, self.path, dest))

        retries = 0
        while not push_succeded and retries < MAX_RETRIES:
            try:
                retries += 1
                push_result = repo.push(dest=dest,
                                        rev=rev_hash,
                                        newbranch=True)
                if not push_result:
                    logger.info(
                        "hglib.push returned False in %s, retrying..." %
                        self.path)
                    last_exception = "hglib.push returned False..."
                    time.sleep(1)
                    rev_hash = update_repo(repo, orig)
                else:
                    push_succeded = True
            except hglib.error.CommandError as e:
                last_exception = e
                logger.exception("Push didn't work, why?")
                logger.debug(e.__str__())
                if self.NEW_REMOTE_HEAD_LITERAL not in str(e):
                    logger.error("Error pushing: %s" % e)
                    raise RepositoryError("Error pushing: %s" % e)
                logger.debug("Error pushing, maybe two heads...")
                try:
                    rev_hash = update_repo(repo, orig)
                except hglib.error.CommandError as ex:
                    # Conflicts??
                    logger.exception("Error merging!")
                    raise RepositoryError("Error merging: %s (%s)" % (e, ex))
        if not push_succeded:
            raise RepositoryError("Five attempts for pushing failed: %s" %
                                  last_exception)
        else:
            return self[rev_hash]
Example #2
0
 def wrapped(they, *args, **kwargs):
     try:
         with hglib.open(they.path) as repo:
             return f(they, repo, *args, **kwargs)
     except self.exceptions as e:
         if self.error_message:
             arguments = ", ".join(str(arg) for arg in args)
             arguments += ", " + str(kwargs)
             logger.exception("%s (%s)" %
                              (self.error_message, arguments))
             raise RepositoryError(self.error_message + str(e))
         else:
             logger.exception(e)
             raise RepositoryError(e)
Example #3
0
    def terminate_branch(self, branch_name, repo_origin, repo_dest):
        """ Inherited method
        :func:`~repoman.repository.Repository.terminate_branch`
        """
        repo = None
        try:
            with hglib.open(self.path) as repo:
                try:
                    repo.pull(repo_origin, branch=branch_name)
                except hglib.error.CommandError:
                    # Ignore this error, the branch could be only local thus
                    # the pull can safely fail
                    pass
                repo.update(branch_name, clean=True)
                repo.commit(message=str(
                    self.message_builder.close_branch(branch=branch_name)),
                            user=self.signature.user,
                            closebranch=True)

                parents = repo.parents()
                self.push(repo_origin, repo_dest,
                          self._new_changeset_object(parents[0]))
        except hglib.error.CommandError as e:
            if 'can only close branch heads' in e.err:
                logger.exception(
                    "Cannot close %s branch, it's already closed" %
                    branch_name)
                return
            logger.exception("Error closing the release branch %s: %s" %
                             (branch_name, e))
            raise RepositoryError(e)
Example #4
0
    def push(self, orig, dest, rev=None, ref_name=None, force=False):
        """Inherited method
        :func:`~repoman.repository.Repository.push`
        """
        all_tags_option = "--tags"
        all_notes_refspec = "refs/notes/*:refs/notes/*"

        if rev is None and ref_name is None:
            # Push everything
            refspec = "refs/*:refs/*"
        elif rev is None:
            refspec = "%s:%s" % (ref_name, ref_name)
        elif ref_name is None:
            raise RepositoryError(
                "When pushing, revision specified but not reference name")
        else:
            if self.tag_exists(ref_name):
                # We don't know what this ref is in remote, but here it is a tag
                ref_name = "refs/tags/%s" % ref_name
                all_tags_option = ""
            else:
                # In any other case, we assume it is a branch
                ref_name = "refs/heads/%s" % ref_name
            refspec = "%s:%s" % (rev, ref_name)

        if all_tags_option:
            self._git("push",
                      dest,
                      refspec,
                      all_tags_option,
                      all_notes_refspec,
                      f=force)
        else:
            self._git("push", dest, refspec, all_notes_refspec, f=force)
        return self.tip()
Example #5
0
    def push(self, orig, dest, rev=None, ref_name=None, force=False):
        """Inherited method
        :func:`~repoman.repository.Repository.push`
        """
        if rev == None and ref_name == None:
            # Push everything
            refspec = "refs/*:refs/*"
        elif rev == None:
            refspec = "%s:%s" % (ref_name, ref_name)
        elif ref_name == None:
            raise RepositoryError(
                "When pushing, revision specified but not reference name")
        else:
            remote_refs = list(
                self._git("ls-remote",
                          "--tags",
                          "--heads",
                          dest,
                          ref_name,
                          _iter=True))
            if len(remote_refs) == 0:
                # Reference is not qualified
                if self.tag_exists(ref_name):
                    # We don't know what this ref is in remote, but here it is a tag
                    ref_name = "refs/tags/%s" % ref_name
                else:
                    # In any other case, we assume it is a branch
                    ref_name = "refs/heads/%s" % ref_name
            refspec = "%s:%s" % (rev, ref_name)

        self._git("push", dest, refspec, f=force)
        return self.tip()
Example #6
0
 def get_ancestor(self, cs1, cs2):
     """Inherited method :func:`~repoman.repository.Repository.get_ancestor`
     """
     if not cs1 or not cs2:
         error = "Error getting ancestor, " +\
             "either rev1 or rev2 are None: %s , %s" % (cs1, cs2)
         logger.error(error)
         raise RepositoryError(error)
     return self[self._git('merge-base', cs1.hash, cs2.hash)]
Example #7
0
    def get_revset(self,
                   cs_from=None,
                   cs_to=None,
                   branch=None,
                   keyword=None,
                   date=None):
        """ Inherited method
        :func:`~repoman.repository.Repository.get_revset`
        """
        repo = None
        if cs_from:
            if cs_to:
                revset = "%s::%s" % (cs_from, cs_to)
            else:
                revset = cs_from
        else:
            revset = None

        with hglib.open(self.path) as repo:
            try:
                # If a revset is given, not heavy, not needed to split
                # the log in chunks
                if revset:
                    # Adding cs_from because it's not added due to the :: usage
                    result = [
                        self._new_changeset_object(
                            repo.log(revrange=cs_from)[0])
                    ]
                    for revision in repo.log(revrange=revset, branch=branch):
                        changeset = self._new_changeset_object(revision)
                        if changeset not in result:
                            result.append(changeset)
                    for changeset in result:
                        yield changeset
                else:
                    chunk_size = 15
                    first = repo.log(limit=1, branch=branch)[0]
                    previous_hash = None
                    first_hash = first.node
                    revrange = None

                    while previous_hash != first_hash:
                        changesets = repo.log(limit=chunk_size,
                                              branch=branch,
                                              revrange=revrange)
                        previous_hash = first_hash
                        if len(changesets) > chunk_size:
                            first = changesets.pop(-1)
                            first_hash = first.node
                            revrange = "%s:%s" % (first_hash, chunk_size)
                        while changesets:
                            cs = self._new_changeset_object(changesets.pop(0))
                            yield cs

            except hglib.error.CommandError as e:
                logger.exception(e)
                raise RepositoryError(e)
Example #8
0
 def parents(self, repo):
     """ Inherited method
     :func:`~repoman.repository.Repository.parents`
     """
     repo = hglib.open(self.path)
     try:
         return [self._new_changeset_object(cs) for cs in repo.parents()]
     except TypeError:
         raise RepositoryError("Working copy for repo %s has no parents "
                               "(is it bare?)" % self.path)
Example #9
0
 def add(self, files):
     """ Inherited method
     :func:`~repoman.repository.Repository.add`
     """
     if not isinstance(files, list):
         files = [files]
     with hglib.open(self.path) as repo:
         for file in files:
             if not repo.add(os.path.join(self.path, file)):
                 raise RepositoryError("Could not add file '%s'" % file)
Example #10
0
    def _validate_local_branch(self):
        if self.local_branch is None:
            self.local_branch = self.repository.get_branch()
            return

        if not isinstance(self.local_branch, Reference):
            raise RepositoryError(
                "In merge, local branch must be a Reference object")

        self._git('checkout', self.local_branch.name)
Example #11
0
 def get_branch(self, repo, branch_name=None):
     """ Inherited method
     :func:`~repoman.repository.Repository.get_branch`
     """
     if not branch_name:
         repo = hglib.open(self.path)
         branch_name = repo.branch()
     else:
         if not self.branch_exists(branch_name):
             raise RepositoryError("Branch %s does not exist in repo %s" %
                                   (branch_name, self.path))
     return self._new_branch_object(branch_name)
Example #12
0
    def __call__(self, *args, **kwargs):
        try:
            cmd = sh.git(_cwd=self.path, _tty_out=False, *args, **kwargs)
        except sh.ErrorReturnCode as e:
            raise RepositoryError("'%s' failed in %s: %s" %
                                  (e.full_cmd, self.path, e.message))

        if '_iter' in kwargs and kwargs['_iter'] != None:
            return cmd

        # For convenience, remove last new line of command output
        return re.sub('(\n|\n\r)$', '', cmd.stdout)
Example #13
0
    def get_branch(self, branch_name=None):
        """Inherited method
        :func:`~repoman.repository.Repository.get_branch`
        """
        if not branch_name:
            branch_name = self._git('rev-parse', '--abbrev-ref', 'HEAD')
        else:
            if not self.branch_exists(branch_name):
                raise RepositoryError('Branch %s does not exist in repo %s' %
                                      (branch_name, self.path))

        return self._new_branch_object(branch_name)
Example #14
0
    def _get_tag_changeset(self, tag_name):
        """
        Gets the changeset that correspond to the given tag

        :param tag_name: name of the tag
        :type string
        """
        with hglib.open(self.path) as repo:
            try:
                repo = hglib.open(self.path)
                rev = [t[2] for t in repo.tags() if t[0] == tag_name][0]
                return self._new_changeset_object(self[rev])
            except (IndexError, hglib.error.CommandError) as e:
                logger.exception("Eror getting tag '%s': %s" % (tag_name, e))
                raise RepositoryError(e)
Example #15
0
 def get_ancestor(self, repo, cs1, cs2):
     """ Inherited method
     :func:`~repoman.repository.Repository.get_ancestor`
     """
     if not cs1 or not cs2:
         error = "Error getting ancestor, either \
         rev1 or rev2 are None: %s , %s" % (cs1, cs2)
         logger.error(error)
         raise RepositoryError(error)
     rev1 = cs1.hash
     rev2 = cs2.hash
     logger.debug("Getting ancestor for: %s, %s" % (rev1, rev2))
     ancestor_rev = repo.log(revrange="ancestor('%s', '%s')" %
                             (rev1, rev2))[0]
     return self._new_changeset_object(ancestor_rev)
Example #16
0
    def _get_sorted_branches(self, active=False, closed=False):
        """
        Get the underlaying repository branches, sorted by name

        :param active: indicates active branches
        :type active: bool
        :param closed: indicates closed branches
        :type closed: bool
        """
        # TODO implement sorted branches with repo indexers
        try:
            with hglib.open(self.path) as repo:
                branches = repo.branches(active, closed)
                branches.sort(key=lambda branch: branch[0], reverse=True)
                for branch in branches:
                    yield self._new_branch_object(branch[0])
        except (hglib.error.CommandError, hglib.error.ServerError) as e:
            logger.exception(e)
            raise RepositoryError(e)
Example #17
0
    def _get_branch_tip(self, branch_name):
        """
        Returns the changeset being the branch tip

        :param branch_name: name of the branch
        :type string
        """
        with hglib.open(self.path) as repo:
            try:
                tip = repo.log(revrange="'%s'" % branch_name)[0]
                return self._new_changeset_object(tip)
            except hglib.error.CommandError as e:
                # Checking if it's a branch recently created, if so, returning
                # current changeset (due to hglib.log does not work with not
                # commited branches)
                if repo.branch() == branch_name:
                    return self._new_changeset_object(repo.parents()[0])
                logger.exception("Error getting branch '%s' tip: %s" %
                                 (branch_name, e))
                raise RepositoryError(e)
Example #18
0
    def merge(self,
              local_branch=None,
              other_rev=None,
              other_branch_name=None,
              dry_run=False):
        """ Inherited method
        :func:`~repoman.repository.Repository.merge`
        """
        log_message = 'Initiating merge. Local branch: %s. ' + \
                      'Other branch: %s@%s.'
        logger.debug(log_message %
                     (local_branch, other_branch_name, other_rev))
        if not other_rev:
            raise RepositoryError("No revision to merge with specified")
        if local_branch and not type(local_branch) == Reference:
            raise RepositoryError(
                "local_branch (%s) parameter must be a Reference " +
                "instead of %s" % (local_branch, type(local_branch)))

        commit = None
        repo = None
        try:
            repo = hglib.open(self.path)
            if local_branch:
                repo.update(rev=local_branch.name, clean=True)
            else:
                local_branch = self._new_branch_object(repo.branch())
            try:
                repo.merge(rev=other_rev.hash, tool='false')
            except hglib.error.CommandError as e:
                if dry_run:
                    # Restoring state
                    repo.update(rev=local_branch.name, clean=True)
                # Error can mean either no need to commit, or conflicts
                basic_error_msg = \
                    'Found an error during merge. local: %s, remote: %s@%s' % \
                    (local_branch.name, other_branch_name, other_rev.hash)
                if "merging" in str(e) and "failed" in str(e):
                    logger.exception("Merging failed with conflicts:")
                    raise MergeConflictError(e.out)
                elif self.MERGING_WITH_ANCESTOR_LITERAL in e.err:
                    # Ugly way to detect this error, but the e.ret is not
                    # correct
                    logger.info("Nothing to merge, already merged: %s" % e.err)
                    return None
                elif e.ret == -1:
                    logger.exception(basic_error_msg)
                    if 'response expected' in e.err:
                        raise RepositoryError(e.out)
                    else:
                        # Unknown error
                        logger.exception(e)
                        raise RepositoryError(e)
                else:
                    # Merge failed because it was not needed
                    return None

            if not dry_run:
                commit_message = self.message_builder.merge(
                    other_branch=other_branch_name or "",
                    other_revision=other_rev.shorthash,
                    local_branch=local_branch.name,
                    local_revision=local_branch.get_changeset().shorthash)
                commit = repo.commit(message=str(commit_message),
                                     user=self.signature.user)
                return self._new_changeset_object(repo.tip())
            else:
                # Restoring state
                repo.update(rev=local_branch.name, clean=True)
                return None

        except hglib.error.CommandError as e:
            logger.exception("Error merging branch %s into %s" %
                             (other_rev.hash, local_branch.name))
            # Undoing the merge to get rid of partial merges
            repo.update(clean=True)
            raise RepositoryError(e)
        finally:
            if repo:
                repo.close()
        return commit