[gedit-plugins] Move finding the repository to an AppActivatable



commit e878501e149913c9f0b71a69620352a15fb7c4f6
Author: Garrett Regier <garrettregier gmail com>
Date:   Sun Jun 29 04:45:36 2014 -0700

    Move finding the repository to an AppActivatable
    
    This also fixes various issues when the file browser is showing
    multiple repositories or the root itself is not a repository.

 plugins/git/Makefile.am              |    1 +
 plugins/git/git/__init__.py          |    1 +
 plugins/git/git/appactivatable.py    |   96 ++++++++++++++++++++++++++++++++++
 plugins/git/git/viewactivatable.py   |   23 ++++----
 plugins/git/git/windowactivatable.py |   79 ++++++++++++++++------------
 5 files changed, 154 insertions(+), 46 deletions(-)
---
diff --git a/plugins/git/Makefile.am b/plugins/git/Makefile.am
index 6ba229e..d66223a 100644
--- a/plugins/git/Makefile.am
+++ b/plugins/git/Makefile.am
@@ -2,6 +2,7 @@ if ENABLE_GIT
 plugins_gitdir = $(plugindir)/git
 plugins_git_PYTHON =                           \
        plugins/git/git/__init__.py             \
+       plugins/git/git/appactivatable.py       \
        plugins/git/git/debug.py                \
        plugins/git/git/diffrenderer.py         \
        plugins/git/git/viewactivatable.py      \
diff --git a/plugins/git/git/__init__.py b/plugins/git/git/__init__.py
index bcb2787..d015f98 100644
--- a/plugins/git/git/__init__.py
+++ b/plugins/git/git/__init__.py
@@ -17,6 +17,7 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330,
 #  Boston, MA 02111-1307, USA.
 
+from .appactivatable import GitAppActivatable
 from .viewactivatable import GitViewActivatable
 from .windowactivatable import GitWindowActivatable
 
diff --git a/plugins/git/git/appactivatable.py b/plugins/git/git/appactivatable.py
new file mode 100644
index 0000000..2dc6cc3
--- /dev/null
+++ b/plugins/git/git/appactivatable.py
@@ -0,0 +1,96 @@
+# -*- 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., 59 Temple Place, Suite 330,
+#  Boston, MA 02111-1307, USA.
+
+from gi.repository import GLib, GObject, Gio, Gedit, Ggit
+
+import weakref
+
+
+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.__repos = weakref.WeakValueDictionary()
+
+    def do_deactivate(self):
+        self.__repos = None
+
+    @classmethod
+    def get_instance(cls):
+        return cls.__instance
+
+    def get_repository(self, location, is_dir):
+        dir_location = location if is_dir else location.get_parent()
+        dir_uri = dir_location.get_uri()
+
+        # Fast Path
+        try:
+            return self.__repos[dir_uri]
+
+        except KeyError:
+            pass
+
+        # 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)
+            repo_uri = repo_file.get_parent().get_uri()
+
+            # Reuse the repo if requested multiple times
+            try:
+                repo = self.__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.__gtype__)
+                tree = commit.get_tree()
+
+                self.__repos[repo_uri] = repo
+                self.__repos[repo.get_workdir().get_uri()] = repo
+                #print(repo.get_workdir().get_uri())
+
+        except Exception:
+            return None
+
+        while dir_uri not in self.__repos:
+            #print(dir_uri)
+
+            self.__repos[dir_uri] = repo
+            dir_location = dir_location.get_parent()
+            dir_uri = dir_location.get_uri()
+
+        return repo
+
+# ex:ts=4:et:
diff --git a/plugins/git/git/viewactivatable.py b/plugins/git/git/viewactivatable.py
index 7eff837..f3a4173 100644
--- a/plugins/git/git/viewactivatable.py
+++ b/plugins/git/git/viewactivatable.py
@@ -18,6 +18,8 @@
 #  Boston, MA 02111-1307, USA.
 
 from gi.repository import GLib, GObject, Gtk, Gedit, Ggit
+
+from .appactivatable import GitAppActivatable
 from .diffrenderer import DiffType, DiffRenderer
 from .windowactivatable import GitWindowActivatable
 
@@ -48,6 +50,8 @@ class GitViewActivatable(GObject.Object, Gedit.ViewActivatable):
     def do_activate(self):
         GitWindowActivatable.register_view_activatable(self)
 
+        self.app_activatable = GitAppActivatable.get_instance()
+
         self.diff_renderer = DiffRenderer()
         self.gutter = self.view.get_gutter(Gtk.TextWindowType.LEFT)
 
@@ -102,19 +106,10 @@ class GitViewActivatable(GObject.Object, Gedit.ViewActivatable):
     def update_location(self, *args):
         self.location = self.buffer.get_file().get_location()
 
-        repo = None
-        if self.location is not None and self.location.has_uri_scheme('file'):
-            try:
-                repo_file = Ggit.Repository.discover(self.location)
-                repo = Ggit.Repository.open(repo_file)
-                head = repo.get_head()
-                commit = repo.lookup(head.get_target(), Ggit.Commit.__gtype__)
-                tree = commit.get_tree()
+        if self.location is not None:
+            repo = self.app_activatable.get_repository(self.location, False)
 
-            except Exception:
-                repo = None
-
-        if repo is None:
+        if self.location is None or repo is None:
             if self.file_contents_list is not None:
                 self.file_contents_list = None
                 self.gutter.remove(self.diff_renderer)
@@ -129,6 +124,10 @@ class GitViewActivatable(GObject.Object, Gedit.ViewActivatable):
                                                            self.update))
 
         try:
+            head = repo.get_head()
+            commit = repo.lookup(head.get_target(), Ggit.Commit.__gtype__)
+            tree = commit.get_tree()
+
             relative_path = repo.get_workdir().get_relative_path(self.location)
 
             entry = tree.get_by_path(relative_path)
diff --git a/plugins/git/git/windowactivatable.py b/plugins/git/git/windowactivatable.py
index 02f4cd1..6248506 100644
--- a/plugins/git/git/windowactivatable.py
+++ b/plugins/git/git/windowactivatable.py
@@ -22,6 +22,7 @@ from gi.repository import GLib, GObject, Gio, Gedit, Ggit
 import collections.abc
 import weakref
 
+from .appactivatable import GitAppActivatable
 from .debug import debug
 from .workerthread import WorkerThread
 
@@ -104,13 +105,8 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
     def __init__(self):
         super().__init__()
 
-        Ggit.init()
-
         self.view_activatables = weakref.WeakSet()
 
-        self.repo = None
-        self.tree = None
-
     @classmethod
     def register_view_activatable(cls, view_activatable):
         window = view_activatable.view.get_toplevel()
@@ -130,6 +126,8 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
         # self.window is not set until now
         self.windows[self.window] = self
 
+        self.app_activatable = GitAppActivatable.get_instance()
+
         self.bus = self.window.get_message_bus()
 
         self.git_status_thread = GitStatusThread(self.update_location)
@@ -164,8 +162,6 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
         for sid in self.bus_signals:
             self.bus.disconnect(sid)
 
-        self.repo = None
-        self.tree = None
         self.file_nodes = FileNodes()
         self.window_signals = []
         self.bus_signals = []
@@ -178,16 +174,18 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
 
     def notify_status(self, view_activatable, psepc):
         location = view_activatable.view.get_buffer().get_file().get_location()
+        if location is None:
+            return
+
+        if location not in self.file_nodes:
+            return
 
-        if location is not None:
-            self.git_status_thread.push(self.repo, location)
+        repo = self.get_repository(location)
+        if repo is not None:
+            self.git_status_thread.push(repo, location)
 
     def tab_removed(self, window, tab):
         view = tab.get_view()
-        location = view.get_buffer().get_file().get_location()
-
-        if location is None:
-            return
 
         # Need to remove the view activatable otherwise update_location()
         # might use the view's status and not the file's actual status
@@ -196,14 +194,25 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
                 self.view_activatables.remove(view_activatable)
                 break
 
-        self.git_status_thread.push(self.repo, location)
+        location = view.get_buffer().get_file().get_location()
+        if location is None:
+            return
+
+        repo = self.get_repository(location)
+        if repo is not None:
+            self.git_status_thread.push(repo, location)
 
     def focus_in_event(self, window, event):
         for view_activatable in self.view_activatables:
             view_activatable.update()
 
         for location in self.file_nodes:
-            self.git_status_thread.push(self.repo, location)
+            repo = self.get_repository(location)
+            if repo is not None:
+                self.git_status_thread.push(repo, location)
+
+    def get_repository(self, location, is_dir=False):
+        return self.app_activatable.get_repository(location, is_dir)
 
     def root_changed(self, bus, msg, data=None):
         self.clear_monitors()
@@ -211,29 +220,28 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
         self.file_nodes = FileNodes()
 
         location = msg.location
-        if not location.has_uri_scheme('file'):
-            return
 
-        try:
-            repo_file = Ggit.Repository.discover(location)
-            self.repo = Ggit.Repository.open(repo_file)
-            head = self.repo.get_head()
-            commit = self.repo.lookup(head.get_target(), Ggit.Commit.__gtype__)
-            self.tree = commit.get_tree()
+        repo = self.get_repository(location, True)
+        if repo is None:
+            return
 
-        except Exception:
-            self.repo = None
-            self.tree = None
+        # Avoid the .git dir
+        repo_location = repo.get_location()
+        if location.get_uri().startswith(repo_location.get_uri()):
+            return
 
-        else:
-            self.monitor_directory(location)
+        self.monitor_directory(location)
 
     def inserted(self, bus, msg, data=None):
-        if self.repo is None:
+        location = msg.location
+
+        repo = self.get_repository(location, msg.is_directory)
+        if repo is None:
             return
 
-        location = msg.location
-        if not location.has_uri_scheme('file'):
+        # Avoid the .git dir
+        repo_location = repo.get_location()
+        if location.get_uri().startswith(repo_location.get_uri()):
             return
 
         if msg.is_directory:
@@ -241,13 +249,14 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
 
         else:
             self.file_nodes[location] = FileNode(msg)
-            self.git_status_thread.push(self.repo, location)
+            self.git_status_thread.push(repo, location)
 
     def deleted(self, bus, msg, data=None):
         # File browser's deleted signal is broken
         return
 
-        uri = msg.location.get_uri()
+        location = msg.location
+        uri = location.get_uri()
 
         if uri in self.monitors:
             self.monitors[uri].cancel()
@@ -313,6 +322,8 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
         if event_type == Gio.FileMonitorEvent.CHANGED:
             for f in (file, other_file):
                 if f is not None and f in self.file_nodes:
-                    self.git_status_thread.push(self.repo, f)
+                    repo = self.get_repository(f)
+                    if repo is not None:
+                        self.git_status_thread.push(repo, f)
 
 # ex:ts=4:et:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]