From ec18cfafc2f85e4dbc4ab2d61588395a59352443 Mon Sep 17 00:00:00 2001 From: Serge Broslavsky Date: Tue, 14 Feb 2012 11:55:18 +0200 Subject: Feature: pasting hardlinked trees This feature is useful when there is a need to create a directory tree, which is similar to an existing one while keeping all the files in this new tree hardlinked to those existing ones. Such functionality might be useful when rearranging a huge directory tree (or a set of directory trees) into some new layout. This operation is done synchronously (i.e. it doesn't use CommandLoader to put the ongoing operation into the task queue). Target end of the operation is handled the following way: 1. If target directory with the same name exists - it gets used. 2. If target folder does not exist - it is created with the same mode bits as corresponding source one. 3. If target file with the same name exists and is a hardlink of the source file already - it is getting left as it is. If it's not a hardlink of the source file - a new hardlink is created in a form of _, _1, ..., etc. 4. If target file does not exist - a hardlink is created. --- ranger/core/actions.py | 26 ++++++++++++++++++++++++-- ranger/defaults/rc.conf | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ranger/core/actions.py b/ranger/core/actions.py index 8106a89b..4e72de77 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -19,8 +19,8 @@ import re import shutil import string import tempfile -from os.path import join, isdir, realpath -from os import link, symlink, getcwd +from os.path import join, isdir, realpath, exists +from os import link, symlink, getcwd, listdir, stat from inspect import cleandoc import ranger @@ -1003,6 +1003,28 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): except Exception as x: self.notify(x) + def paste_hardlinked_subtree(self): + for f in self.env.copy: + try: + target_path = join(getcwd(), f.basename) + self._recurse_hardlinked_tree(f.path, target_path) + except Exception as x: + self.notify(x) + + def _recurse_hardlinked_tree(self, source_path, target_path): + if isdir(source_path): + if not exists(target_path): + os.mkdir(target_path, stat(source_path).st_mode) + for item in listdir(source_path): + self._recurse_hardlinked_tree( + join(source_path, item), + join(target_path, item)) + else: + if not exists(target_path) \ + or stat(source_path).st_ino != stat(target_path).st_ino: + link(source_path, + next_available_filename(target_path)) + def paste(self, overwrite=False): """Paste the selected items into the current directory""" copied_files = tuple(self.env.copy) diff --git a/ranger/defaults/rc.conf b/ranger/defaults/rc.conf index 1ecbc398..77ffa5c3 100644 --- a/ranger/defaults/rc.conf +++ b/ranger/defaults/rc.conf @@ -147,6 +147,7 @@ map po paste overwrite=True map pl paste_symlink relative=False map pL paste_symlink relative=True map phl paste_hardlink +map pht paste_hardlinked_subtree map dd cut map ud uncut -- cgit 1.4.1-2-gfad0