xref: /OpenGrok/tools/src/main/python/opengrok_tools/scm/git.py (revision f8b2d387364065cf0db7de33af31ffd9acd8ec9a)
12d57dc69SVladimir Kotal#
22d57dc69SVladimir Kotal# CDDL HEADER START
32d57dc69SVladimir Kotal#
42d57dc69SVladimir Kotal# The contents of this file are subject to the terms of the
52d57dc69SVladimir Kotal# Common Development and Distribution License (the "License").
62d57dc69SVladimir Kotal# You may not use this file except in compliance with the License.
72d57dc69SVladimir Kotal#
82d57dc69SVladimir Kotal# See LICENSE.txt included in this distribution for the specific
92d57dc69SVladimir Kotal# language governing permissions and limitations under the License.
102d57dc69SVladimir Kotal#
112d57dc69SVladimir Kotal# When distributing Covered Code, include this CDDL HEADER in each
122d57dc69SVladimir Kotal# file and include the License file at LICENSE.txt.
132d57dc69SVladimir Kotal# If applicable, add the following below this CDDL HEADER, with the
142d57dc69SVladimir Kotal# fields enclosed by brackets "[]" replaced with your own identifying
152d57dc69SVladimir Kotal# information: Portions Copyright [yyyy] [name of copyright owner]
162d57dc69SVladimir Kotal#
172d57dc69SVladimir Kotal# CDDL HEADER END
182d57dc69SVladimir Kotal#
192d57dc69SVladimir Kotal
202d57dc69SVladimir Kotal#
21f321caadSVladimir Kotal# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
222d57dc69SVladimir Kotal# Portions Copyright (c) 2020, Krystof Tulinger <k.tulinger@seznam.cz>
232d57dc69SVladimir Kotal#
242d57dc69SVladimir Kotal
252d57dc69SVladimir Kotalfrom shutil import which
262d57dc69SVladimir Kotal
272d57dc69SVladimir Kotalfrom .repository import Repository, RepositoryException
282d57dc69SVladimir Kotalfrom ..utils.command import Command
292d57dc69SVladimir Kotal
302d57dc69SVladimir Kotal
312d57dc69SVladimir Kotalclass GitRepository(Repository):
32ae5b3cb8SVladimir Kotal    def __init__(self, name, logger, path, project, command, env, hooks, timeout):
33ae5b3cb8SVladimir Kotal        super().__init__(name, logger, path, project, command, env, hooks, timeout)
342d57dc69SVladimir Kotal
352d57dc69SVladimir Kotal        self.command = self._repository_command(command, default=lambda: which('git'))
362d57dc69SVladimir Kotal
372d57dc69SVladimir Kotal        if not self.command:
382d57dc69SVladimir Kotal            raise RepositoryException("Cannot get git command")
392d57dc69SVladimir Kotal
40ae5b3cb8SVladimir Kotal    def _configure_git_pull(self):
412d57dc69SVladimir Kotal        # The incoming() check relies on empty output so configure
422d57dc69SVladimir Kotal        # the repository first to avoid getting extra output.
432d57dc69SVladimir Kotal        git_command = [self.command, "config", "--local", "pull.ff", "only"]
44ae5b3cb8SVladimir Kotal        cmd = self.get_command(git_command, work_dir=self.path,
452d57dc69SVladimir Kotal                               env_vars=self.env, logger=self.logger)
462d57dc69SVladimir Kotal        cmd.execute()
472d57dc69SVladimir Kotal        if cmd.getretcode() != 0 or cmd.getstate() != Command.FINISHED:
482d57dc69SVladimir Kotal            cmd.log_error("failed to configure git pull.ff")
492d57dc69SVladimir Kotal
502d57dc69SVladimir Kotal    def reposync(self):
51ae5b3cb8SVladimir Kotal        self._configure_git_pull()
522d57dc69SVladimir Kotal        return self._run_custom_sync_command([self.command, 'pull', '--ff-only'])
532d57dc69SVladimir Kotal
542d57dc69SVladimir Kotal    def incoming_check(self):
55ae5b3cb8SVladimir Kotal        self._configure_git_pull()
562d57dc69SVladimir Kotal        return self._run_custom_incoming_command([self.command, 'pull', '--dry-run'])
57f321caadSVladimir Kotal
58b2d60571SVladimir Kotal    def get_branch(self):
59b2d60571SVladimir Kotal        status, out = self._run_command([self.command, 'branch', '--show-current'])
60b2d60571SVladimir Kotal        if status != 0:
61b2d60571SVladimir Kotal            raise RepositoryException("cannot get branch of {}: {}".format(self, out))
62b2d60571SVladimir Kotal
63b2d60571SVladimir Kotal        branch = out.split('\n')[0]
64b2d60571SVladimir Kotal
65b2d60571SVladimir Kotal        return branch
66b2d60571SVladimir Kotal
67*f8b2d387SVladimir Kotal    def fetch(self):
68*f8b2d387SVladimir Kotal        status, out = self._run_command([self.command, 'fetch'])
69*f8b2d387SVladimir Kotal        if status != 0:
70*f8b2d387SVladimir Kotal            raise RepositoryException("cannot fetch {}: {}".format(self, out))
71*f8b2d387SVladimir Kotal
72f321caadSVladimir Kotal    def strip_outgoing(self):
73*f8b2d387SVladimir Kotal        """
74*f8b2d387SVladimir Kotal        Check for outgoing changes and if found, strip them.
75*f8b2d387SVladimir Kotal        :return: True if there were any changes stripped, False otherwise.
76*f8b2d387SVladimir Kotal        """
77f321caadSVladimir Kotal        self._configure_git_pull()
78*f8b2d387SVladimir Kotal        self.fetch()
79b2d60571SVladimir Kotal        branch = self.get_branch()
80f321caadSVladimir Kotal        status, out = self._run_command([self.command, 'log',
81b2d60571SVladimir Kotal                                        '--pretty=tformat:%H', '--reverse', 'origin/' + branch + '..'])
82f321caadSVladimir Kotal        if status == 0:
83673b41abSVladimir Kotal            lines = out.split('\n')
84673b41abSVladimir Kotal            if len(lines) == 0:
85673b41abSVladimir Kotal                return False
86673b41abSVladimir Kotal
87673b41abSVladimir Kotal            cset = lines[0]
88673b41abSVladimir Kotal            if len(cset) > 0:
89673b41abSVladimir Kotal                self.logger.debug("Resetting the repository {} to parent of changeset '{}'".
90f321caadSVladimir Kotal                                  format(self, cset))
91f321caadSVladimir Kotal                status, out = self._run_command([self.command, 'reset', '--hard',
92f321caadSVladimir Kotal                                                 cset + '^'])
93f321caadSVladimir Kotal                if status != 0:
94f321caadSVladimir Kotal                    raise RepositoryException("failed to reset {} to parent of changeset {}: {}".
95f321caadSVladimir Kotal                                              format(self, cset, out))
96f321caadSVladimir Kotal                else:
97f321caadSVladimir Kotal                    return True
98f321caadSVladimir Kotal        else:
99f321caadSVladimir Kotal            raise RepositoryException("failed to check for outgoing changes in {}: {}".
100f321caadSVladimir Kotal                                      format(self, status))
101673b41abSVladimir Kotal
102673b41abSVladimir Kotal        return False
103