-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathedmv
executable file
·133 lines (104 loc) · 4.35 KB
/
edmv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
# "editron move" -- rename or move files by editing filenames in your
# favorite text editron
# ------------------------------------------------------
# use with caution! this code is not sufficiently tested
# ------------------------------------------------------
# Author: David McClosky
# Homepage: http://zorglish.org
# Code: http://github.com/dmcc
# vi: syntax=python
# TODO: better assertions, assertion handling
# spit it out if there are errors and describe what we already did
# read options from .edmvrc?
# make sure we never overwrite files
# try to put temp dirs in the dir of the original files
import sys, os, os.path, shutil, tempfile
DEFAULT_EDITOR = "vim -gf '%s'" # I'm a vim-guy, myself
def saferename(source, target):
"""Do a "mv -i" and make sure that we don't overwrite any files."""
if os.path.exists(target):
raise OSError("Target %r already exists." % target)
else:
shutil.move(source, target)
file_mapping = [] # we save this so we can gracefully handle errors
def unique(seq):
"""Removes duplicate elements from a sequence. This function is
not stable at all."""
u = {}
for x in seq:
u[x] = 1
return u.keys()
def has_no_duplicates(seq):
"""Returns whether a sequence has no duplicates."""
uniq_version = unique(seq)
# if there were duplicates, len(uniq_version) should be less than the
# original
return len(seq) == len(uniq_version)
def error(message):
"""Print a message and exit, printing a log of what we did and how to
undo it."""
# TODO: actually do the graceful exit and such
print("Error:", message)
if file_mapping:
print("Mapping table:")
for old, inter, new in file_mapping:
print(repr(old), repr(inter), repr(new))
else:
print("No mapping table yet -- no changes were made.")
sys.exit(1)
def editron_move(editron=DEFAULT_EDITOR, files_to_rename=None):
old_list = files_to_rename or [] # TODO: warn when old_list is empty
with tempfile.NamedTemporaryFile(mode="w",
dir="/tmp",
prefix="edmv") as filename_list:
filename_list.write('\n'.join(old_list) + '\n')
filename_list.flush()
filename_list_file = filename_list.name
# editron must have exactly one %s
assert(editron.count('%s') == 1)
try:
command = editron % filename_list_file
except TypeError:
# we will get this if there are too many things to interpolate
error("editor ('%s') should have exactly one thing to interpolate." %
command)
print('run', command)
os.system(command)
with open(filename_list.name) as readable_filename_list:
new_list = readable_filename_list.read().splitlines()
for old, new in zip(old_list, new_list):
print(f"{old} -> {new}")
try:
perform_rename(old_list, new_list)
except AssertionError:
error("Assertion error -- descriptions coming soon")
def perform_rename(old_list, new_list):
global file_mapping
assert has_no_duplicates(old_list)
assert has_no_duplicates(new_list)
# first, create a secure temporary directory
temp_directory = tempfile.mkdtemp(prefix='edmv')
def intermediate_name(old_name):
return "%s/%d-%s" % (temp_directory, old_list.index(old_name), old_name)
file_mapping = [(old, intermediate_name(old), new)
for old, new in zip(old_list, new_list)]
# next, move every file to the temporary directory, giving it a unique
# name -- list index is sufficient in this case
for old, inter, new in file_mapping:
print(f"rename {old!r} -> {inter!r}")
shutil.move(old, inter)
for old, inter, new in file_mapping:
print(f"rename {inter!r} -> {new!r}")
shutil.move(inter, new)
# erase temporary directory -- everything should have been moved out of it
# TODO: make sure it is empty
os.removedirs(temp_directory)
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-e", "--editor",
dest="editor", default=DEFAULT_EDITOR,
help="Editron to use")
(options, files) = parser.parse_args()
editron_move(options.editor, files)