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

发布于 2024-08-15 14:40:16 字数 253 浏览 7 评论 0原文

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

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

For example, say I moved a file from /project/file.cs to /project/subdir/file.cs. It would be nice if nautilus automatically converted this to bzr mv /project/file.cs /project/subdir/file.cs. Is it possible to set this up?

It would also be nice if I was warned when doing a plain old mv on version controlled files, but I suppose that's a separate question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

为你拒绝所有暧昧 2024-08-22 14:40:16

就像您已经表明的那样,您基本上需要一些能够监听动作的东西,所以我想我应该编写一些代码来告诉您这是如何工作的。

我尝试使用 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 文件用于添加内容并在其找到的任何新工作副本上注册监视。

资源

Like you already indicated yourself you basically need something that listens for moves, so I thought I'd code something up that would give you an indication of how this would work.

I tried using gio.FileMonitor but eventually went back to using plain old pyinotify because the latter has built-in support for detecting file renames/moves.

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()

Here's how it works:

$ 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

And we're back where we got started ;-)

[edit]

If you don't want to manually list the various directories to watch it might be a good idea to write a Nautilus extension which keeps track of the various working copies it encounters as you navigate. Here's something to get you started (this goes into ~/.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())

I borrowed the various docstrings from RabbitVCS's extension code ;-)

In your monitor you'll probably want to watch the workingcopies.db file for additions and register watches on any new working copies it has found.

Resources

暖风昔人 2024-08-22 14:40:16

作为 RabbitVCS 的开发人员之一,我很确定这样的事情目前是不可能的。 Nautilus 扩展 可以提供上下文菜单、属性页、附加列,并且它们可以响应文件显示在浏览器主窗口中。它们无法参与移动或删除等任意事件。 (如果是这样的话,我会很高兴,但这不是我们现在的优先事项。)您需要自己修改 Nautilus 扩展 API。

如果您愿意,但不知道从哪里开始,您应该查看 Nautilus 源代码并在 Nautilus 邮件列表。他们肯定会告诉你,如果你在这件事上找错了对象。

Nautilus 扩展可能不适合做这类事情。 也许可以使用 GVFS 而不是 Nautilus 扩展来做一些事情,但我对此还不够深入。

As one of the developers of RabbitVCS, I'm pretty sure such a thing is not currently possible. Nautilus extensions can provide context menus, property pages, additional columns and they can respond to a file being displayed in the browser main window. They can't hook into arbirtary events like moving or deletion. (I'd love it if that were the case, but it's not a priority for us right now.) You would have modify the Nautilus extension API yourself.

If you're feeling up to that, but don't know where to start, you should look at the Nautilus source and ask on the Nautilus mailing list. They could certainly tell you if you're barking up the wrong tree about this.

It's possible that a Nautilus extension is the wrong place for this sort of thing. It might be possible to do something with GVFS instead of a Nautilus extension, but I'm out of my depth on that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文