renamer.py 4.26 KB
Newer Older
1
2
3
4
5
6
7
8
9
#!/bin/env python

import os
import tempfile
import re
import logging
from io import open
from io import StringIO

10

11
def loadRenamesFile(renamesPath, reverse=False):
12
13
    """Loads the content of a rename file"""
    renamesRe = re.compile(
14
        r"\s*(?P<old>[-a-zA-Z0-9_.%]+)\s*->\s*(?P<new>[a-zA-Z0-9_.]+)\s*$")
15
16
17
18
19
20
21
22
    renames = {}
    with open(renamesPath, encoding='utf-8') as f:
        while True:
            line = f.readline()
            if not line:
                break
            m = renamesRe.match(line)
            if m:
23
24
25
26
                if reverse:
                    renames[m.group("new")] = m.group("old")
                else:
                    renames[m.group("old")] = m.group("new")
27
28
29
30
            elif not line.isspace():
                logging.warn("Unexpected line %r in %s", line, renamesPath)
    return renames

31

32
33
34
35
36
def renamesSearchRe(renames):
    """creates a regular expression that matches the words that should be renamed"""
    res = StringIO()
    res.write(r"\b(")
    first = True
37
    for k in reversed(sorted(renames.keys())):
38
39
40
41
        if not first:
            res.write("|")
        else:
            first = False
42
        res.write(k.replace(".","\\."))
43
    res.write(r")(__|\b)")
44
45
46
    renameReStr = res.getvalue()
    return re.compile(renameReStr)

47

48
49
50
51
def replaceInFile(filePath, replacements):
    """performs the replacements in the given file"""
    renameRe = renamesSearchRe(replacements)
    outF = tempfile.NamedTemporaryFile(
52
53
        mode="w", suffix='', prefix='tmp', dir=os.path.dirname(filePath),
        delete=False, encoding='utf-8')
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    didReplace = {}
    lineNr = 0
    with outF:
        with open(filePath, encoding='utf-8') as inF:
            while True:
                line = inF.readline()
                if not line:
                    break
                lineNr += 1
                ii = 0
                for m in renameRe.finditer(line):
                    old = m.group(1)
                    didReplace[old] = didReplace.get(old, []) + [lineNr]
                    outF.write(line[ii:m.start()])
                    outF.write(replacements[old])
69
70
                    if m.group(2):
                        outF.write(m.group(2))
71
72
73
                    ii = m.end()
                outF.write(line[ii:])
    if didReplace:
74
75
76
77
        import datetime
        t=datetime.date.today()
        bkPathBase = "%s.%d-%2d-%2d" % (filePath, t.year, t.month, t.day)
        bkPath = bkPathBase + ".bk"
78
79
80
81
        # non atomic (should really create if not there)
        ii = 0
        while os.path.exists(bkPath):
            ii += 1
82
            bkPath = bkPathBase + str(ii) + ".bk"
83
84
85
        os.rename(filePath, bkPath)
        os.rename(outF.name, filePath)
        print("%r: {" % filePath)
86
87
88
        for k, v in didReplace.items():
            print(k, '->', replacements[k], ":", v)
        print("}\nBackup in ", bkPath)
89
90
    else:
        os.remove(outF.name)
91
92

if __name__ == "__main__":
93
    import sys,argparse
94
    renamesPath = os.path.join(os.path.dirname(__file__), "renames.txt")
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    parser = argparse.ArgumentParser(description='Make replacements in files')
    parser.add_argument('--reverse', action='store_true',
                        help='Performs replacements in the reverse direction')
    parser.add_argument('--renames-file', nargs=1,
                        default=[renamesPath],
                        help='file containing the replacements to perform (from -> to)')
    parser.add_argument('toRename', metavar='P', nargs='+',
                        help='path to a file to rename')
    args = parser.parse_args()
    if not args.renames_file:
        baseRenames = loadRenamesFile(renamesPath, args.reverse)
    else:
        baseRenames = loadRenamesFile(args.renames_file[0], args.reverse)
    for f in args.toRename:
109
        try:
110
111
112
113
114
115
116
            basename = os.path.splitext(os.path.splitext(os.path.basename(f))[0])[0]
            specificRenames = os.path.join(os.path.dirname(renamesPath), basename + ".renames")
            if not args.renames_file and os.path.exists(specificRenames):
                renames = loadRenamesFile(specificRenames, arg.reverse)
                renames.update(baseRenames)
            else:
                renames = baseRenames
117
118
119
120
            replaceInFile(f, renames)
        except:
            logging.exception("handling file %s", f)
    print("DONE")