~launchpad-pqm/launchpad/devel

9492.1.1 by Karl Fogel
Add utilities/formatdoctest.py and utilities/migrater/, both brought
1
#!/usr/bin/python
2
#
3
# Copyright 2009 Canonical Ltd.  This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
5
6
"""Move a python module in the tree.
7
8
It uses bzr mv to rename the module and will try to find all imports.
9
10
rename-module.py src_file+ target
11
12
Both files must be under lib/.
13
14
If more than one src files is given, target must be a directory.
15
"""
16
17
__metaclass__ = type
18
19
__all__ = [
20
    'bzr_add',
21
    'bzr_has_filename',
22
    'bzr_move_file',
23
    'bzr_remove_file',
24
    'rename_module',
25
    'update_references',
26
    ]
27
28
import os
29
import sys
30
31
from bzrlib import workingtree
32
from find import find_matches
33
from utils import fail, log
34
35
36
def file2module(module_file):
37
    """From a filename, return the python module name."""
38
    start_path = 'lib' + os.path.sep
39
    assert module_file.startswith(start_path), (
40
        "File should start with lib: %s" % module_file)
41
    assert module_file.endswith('.py'), (
42
        "File should end with .py: %s" % module_file)
43
    return module_file[len(start_path):-3].replace(os.path.sep, '.')
44
45
46
# Cache the working tree for speed.
47
_wt = workingtree.WorkingTree.open('.')
48
49
def bzr_move_file(src_file, target):
50
    """Move or rename a versioned file or directory."""
51
    if os.path.isdir(target):
52
        _wt.move([src_file], target)
53
    else:
54
        _wt.rename_one(src_file, target)
55
    log('    Renamed %s => %s', src_file, target)
56
57
58
def bzr_add(paths):
59
    "Version a list of paths."
60
    _wt.add(paths)
61
62
def bzr_remove_file(filename):
63
    """Remove a versioned file."""
64
    _wt.remove([filename], keep_files=False, force=True)
65
66
67
def bzr_has_filename(file_path):
68
    """Is the file versioned?"""
69
    _wt.has_filename(file_path)
70
71
72
def rename_module(src_file, target_file):
73
    """Renamed  a versioned module and update all references to it."""
74
    # Move the file using bzr.
75
    bzr_move_file(src_file, target_file)
76
    if not src_file.endswith('.py'):
77
        # It's not a module, so don't try to update imports of it.
78
        return
79
    source_module = file2module(src_file)
80
    target_module = file2module(target_file)
81
    update_references(source_module, target_module)
82
83
84
def update_references(source_module, target_module):
85
    """Update references to the source module.
86
87
    :param src_module: a string describing the old module name. May contain
88
        RE patterns
89
    :param target_module: a string representing the new module name. May
90
        contain RE groups.
91
    """
92
    source = r'\b%s\b' % source_module.replace('.', '\\.')
93
    target = target_module
94
    root_dirs = ['cronscripts', 'lib/canonical', 'lib/lp']
95
    file_pattern = '\.(py|txt|zcml)$'
96
    print "    Updating references:"
97
    for root_dir in root_dirs:
98
        for summary in find_matches(
99
            root_dir, file_pattern, source, substitution=target):
100
            print "        * %(file_path)s" % summary
101
102
103
def main():
104
    """Rename a module and update all references to it."""
105
    if len(sys.argv) < 3:
106
        fail('Usage: %s src_file+ target', os.path.basename(sys.argv[0]))
107
    src_files = sys.argv[1:-1]
108
    target = sys.argv[-1]
109
110
    if os.path.exists(target) and not os.path.isdir(target):
111
        fail('Destination file "%s" already exists.', target)
112
    if not target.startswith('lib'):
113
        fail('Destination file "%s" must be under lib.', target)
114
    if len(src_files) > 1 and not os.path.isdir(target):
115
        fail('Destination must be a directory.')
116
117
    for src_file in src_files:
118
        if not os.path.exists(src_file):
119
            log('Source file "%s" doesn\'t exists. Skipping', src_file)
120
            continue
121
        if not src_file.startswith('lib'):
122
            log('Source file "%s" must be under lib. Skipping', src_file)
123
            continue
124
125
        if os.path.isdir(target):
126
            target_file = os.path.join(target, os.path.basename(src_file))
127
        else:
128
            target_file = target
129
130
        rename_module(src_file, target_file)
131
132
133
if __name__ == '__main__':
134
    main()