linux - 有没有办法让 Nautilus 使用 VCS 的移动命令在版本控制下移动文件?

标签 linux version-control bazaar nautilus

例如,假设我将文件从 /project/file.cs 移动到 /project/subdir/file.cs。如果 nautilus 自动将其转换为 bzr mv/project/file.cs/project/subdir/file.cs 就好了。可以这样设置吗?

如果我在对版本控制文件执行普通的旧 mv 时收到警告,那也很好,但我想这是一个单独的问题。

最佳答案

就像您自己已经表明的那样,您基本上需要一些可以监听 Action 的东西,所以我想我应该编写一些代码来让您了解它是如何工作的。

我尝试使用 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 文件以进行添加,并在它找到的任何新工作副本上注册监视。

资源

关于linux - 有没有办法让 Nautilus 使用 VCS 的移动命令在版本控制下移动文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1932084/

相关文章:

java - 无论如何要通过 JVMTI 获得 jthread tid?

version-control - 如何在 Bazaar (bzr merge) 中进行忽略空格的合并?

php - 从 Bazaar 中删除文件

version-control - 在互联网上托管 Perforce 服务器?

rust - 这是什么意思? "This is precisely because a library should not be deterministically recompiled for all users of the library."

eclipse-plugin - bzr-eclipse 1.4 需要 xmloutput >= 0.9.2

linux - 类似系统的关键字,例如 failure、true、closed、 "unable to"在作为查询值处理时突出显示

linux - 为什么 "register"目录中名为 "/proc/sys/fs/binfmt_misc"的文件是 "write-only"?

ruby - rvm ruby​​ 更新后 Vim 不工作

version-control - 在 Wix 中修改产品版本