Blob Blame History Raw
# -*- coding: utf-8 -*-

#  Copyright (C) 2014 - Garrett Regier
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
#  02110-1301 USA.

from gi.repository import GLib, GObject, Gio, Gedit, Ggit


class GitAppActivatable(GObject.Object, Gedit.AppActivatable):
    app = GObject.Property(type=Gedit.App)

    __instance = None

    def __init__(self):
        super().__init__()

        Ggit.init()

        GitAppActivatable.__instance = self

    def do_activate(self):
        self.clear_repositories()

    def do_deactivate(self):
        self.__git_repos = None
        self.__workdir_repos = None

    @classmethod
    def get_instance(cls):
        return cls.__instance

    def clear_repositories(self):
        self.__git_repos = {}
        self.__workdir_repos = {}

    def get_repository(self, location, is_dir, *, allow_git_dir=False):
        # The repos are cached by the directory
        dir_location = location if is_dir else location.get_parent()
        dir_uri = dir_location.get_uri()

        # Fast Path
        try:
            return self.__workdir_repos[dir_uri]

        except KeyError:
            pass

        try:
            repo = self.__git_repos[dir_uri]

        except KeyError:
            pass

        else:
            return repo if allow_git_dir else None

        # Doing remote operations is too slow
        if not location.has_uri_scheme('file'):
            return None

        # Must check every dir, otherwise submodules will have issues
        try:
            repo_file = Ggit.Repository.discover(location)

        except GLib.Error:
            # Prevent trying to find a git repository
            # for every file in this directory
            self.__workdir_repos[dir_uri] = None
            return None

        repo_uri = repo_file.get_uri()

        # Reuse the repo if requested multiple times
        try:
            repo = self.__git_repos[repo_uri]

        except KeyError:
            repo = Ggit.Repository.open(repo_file)

            # TODO: this was around even when not used, on purpose?
            head = repo.get_head()
            commit = repo.lookup(head.get_target(), Ggit.Commit)
            tree = commit.get_tree()

            self.__git_repos[repo_uri] = repo

        # Need to keep the caches for workdir and
        # the .git dir separate to support allow_git_dir
        if dir_uri.startswith(repo_uri):
            top_uri = repo_uri
            repos = self.__git_repos

        else:
            top_uri = repo.get_workdir().get_uri()
            repos = self.__workdir_repos

        # Avoid trouble with symbolic links
        while dir_uri.startswith(top_uri):
            repos[dir_uri] = repo

            dir_location = dir_location.get_parent()
            dir_uri = dir_location.get_uri()

            # Avoid caching the repo all the
            # way up to the top dir each time
            if dir_uri in repos:
                break

        if repos is self.__git_repos:
            return repo if allow_git_dir else None

        return repo

# ex:ts=4:et: