Есть ли способ заставить Nautilus перемещать файлы под контролем версий, используя команду перемещения VCS? - PullRequest
1 голос
/ 19 декабря 2009

Например, скажем, я переместил файл с /project/file.cs на /project/subdir/file.cs. Было бы неплохо, если бы nautilus автоматически преобразовал это в bzr mv /project/file.cs /project/subdir/file.cs. Можно ли это настроить?

Было бы также неплохо, если бы меня предупреждали, когда я делал простой старый mv для файлов с контролем версий, но я полагаю, это отдельный вопрос.

Ответы [ 2 ]

2 голосов
/ 15 августа 2010

Как вы уже указали себе, вам в основном нужно что-то, что слушает ходы, поэтому я подумал, что напишу что-нибудь, что даст вам представление о том, как это будет работать.

Я пытался использовать gio.FileMonitor, но в конце концов вернулся к использованию простого старого pyinotify, потому что последний имеет встроенную поддержку для обнаружения переименований / перемещений файлов.

import pyinotify

import bzrlib
from bzrlib.workingtree import WorkingTree
from bzrlib.errors import NotBranchError, BzrRenameFailedError

directories_to_watch = [
    # Add the paths to your working copies / branches to watch here
]

wm = pyinotify.WatchManager()

# When you listen to both MOVED_FROM and MOVED_TO the event for MOVED_TO will include both 
# pathname (new path) and src_pathname (previous path).
mask = pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO

class EventHandler(pyinotify.ProcessEvent):

    def process_IN_MOVED_TO(self, event):
        try:
            tree, path = WorkingTree.open_containing(event.src_pathname)
            root = event.src_pathname[:-len(path)] # Ugh, hackish

            if not path.startswith(".bzr"): # Also hackish (to exclude events for anything in the .bzr subdirectory)
                try:
                    tree.lock_tree_write()
                    source = event.src_pathname[len(root):] # Again hackish
                    target = event.pathname[len(root):] # Same
                    tree.rename_one(source, target)
                    print "Renamed %s to %s" % (source, target)
                except BzrRenameFailedError: # Same
                    pass
                finally:
                    tree.unlock()
        except NotBranchError:
            return

handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler)

for path in directories_to_watch:
    wdd = wm.add_watch(path, mask, rec=True, auto_add=True)
    print "Recursively watching %s" % path

notifier.loop()

Вот как это работает:

$ mv afile bfile
$ bzr status
renamed:
  afile => bfile

$ mv bfile foobar/
$ bzr status
renamed:
  afile => foobar/bfile

$ mv foobar/ zoobar
$ bzr status
renamed:
  afile => zoobar/bfile
  foobar/ => zoobar/

$ mv zoobar/ foobar
$ bzr status
renamed:
  afile => foobar/bfile

$ mv foobar/bfile afile

И мы вернулись туда, откуда начали; -)

[править]

Если вы не хотите вручную перечислять различные каталоги для просмотра, было бы неплохо написать расширение Nautilus, которое отслеживает различные рабочие копии, с которыми он сталкивается при навигации. Вот кое-что для начала (это относится к ~/.nautilus/python-extensions):

import os
import pickle

import nautilus 

import gio

from xdg import BaseDirectory as basedir

import bzrlib
from bzrlib.workingtree import WorkingTree
from bzrlib.errors import NotBranchError

class BzrMonitor(nautilus.InfoProvider, nautilus.MenuProvider):

    data_directory = basedir.save_data_path("bzrmonitor")
    data_filename = os.path.join(data_directory, "workingcopies.db")

    def __init__(self):
        print "Initializing BzrMonitor extension..."

        try:
            data_file = open(self.data_filename, "r")
            self.data = pickle.load(data_file)
        except IOError:
            self.data = []
            data_file = open(self.data_filename, "w")
            pickle.dump(self.data, data_file)
            data_file.close()

    def detect_and_save_branch(self, path):
        try:
            tree, rel_path = WorkingTree.open_containing(path)

            # TODO: Still can't figure out how to get the path from the tree itself
            if len(rel_path) > 0: 
                root = path[:-len(rel_path)]
            else:
                root = path

            root = root.rstrip(os.path.sep)

            if root not in self.data: 
                print "Added not seen before branch %s to cache..." % root
                self.data.append(root)
                data_file = open(self.data_filename, "w")
                pickle.dump(self.data, data_file)
                data_file.close()

        except NotBranchError:
            return

    def update_file_info(self, item):
        """
        This function is called when:

          - When you enter a directory (once for each item but only when the
            item was modified since the last time it was listed)
          - When you refresh (once for each item visible)
          - When an item viewable from the current window is created or modified
        """
        self.detect_and_save_branch(gio.File(item.get_uri()).get_path())

    def get_file_items(self, window, items):
        """
        Menu activated with items selected. Nautilus also calls this function
        when rendering submenus, even though this is not needed since the entire
        menu has already been returned.
        """

        pass

    def get_background_items(self, window, item):
        """
        Menu activated on entering a directory. Builds context menu for File
        menu and for window background.
        """

        self.detect_and_save_branch(gio.File(item.get_uri()).get_path())

Я позаимствовал различные строки документации из кода расширения RabbitVCS; -)

В вашем мониторе вы, вероятно, захотите посмотреть файл workingcopies.db на наличие дополнений и зарегистрировать часы на всех найденных им новых рабочих копиях.

Ресурсы

1 голос
/ 20 апреля 2010

Как один из разработчиков RabbitVCS , я почти уверен, что в настоящее время это невозможно. Расширения Nautilus могут предоставлять контекстные меню, страницы свойств, дополнительные столбцы, и они могут отвечать на файл, отображаемый в главном окне браузера. Они не могут подключиться к произвольным событиям, таким как перемещение или удаление. (Мне бы понравилось, если бы это было так, но сейчас это не является для нас приоритетом.) Вы бы сами изменили API расширения Nautilus.

Если вы чувствуете это, но не знаете, с чего начать, вам следует посмотреть на источник Nautilus и спросить в списке рассылки Nautilus . Они наверняка скажут вам, если вы не правильно лаете по этому поводу.

Возможно, расширение Nautilus - неподходящее место для такого рода вещей. может быть в состоянии сделать что-то с GVFS вместо расширения Nautilus, но я не в этом разбираюсь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...