~launchpad-pqm/launchpad/devel

6247.1.2 by Barry Warsaw
Set up links
1
#!/usr/bin/python
8452.3.3 by Karl Fogel
* utilities/: Add copyright header block to source files that were
2
#
8687.15.2 by Karl Fogel
In files modified by r8688, change "<YEARS>" to "2009", as per
3
# Copyright 2009 Canonical Ltd.  This software is licensed under the
8687.15.3 by Karl Fogel
Shorten the copyright header block to two lines.
4
# GNU Affero General Public License version 3 (see the file LICENSE).
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
5
6
import optparse
7
7162.4.1 by Gavin Panella
Fix broken/dangling symlinks gracefully.
8
from os import curdir, listdir, sep, symlink, unlink
9
from os.path import abspath, basename, exists, islink, join, realpath
10
from sys import stderr, stdout
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
11
from urllib import unquote
12
from urlparse import urlparse
13
8698.6.2 by Aaron Bentley
Add comment.
14
# This comes before other bzrlib stuff, because imports may cause warnings,
15
# etc.
8698.6.1 by Aaron Bentley
Enable warnings and logging
16
from bzrlib.trace import enable_default_logging
17
enable_default_logging()
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
18
from bzrlib.branch import Branch
6567.1.1 by Barry Warsaw
Be sure to load bzr plugins so this script works in say a loomified branch.
19
from bzrlib.plugin import load_plugins
20
21
load_plugins()
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
22
23
24
def url2path(url):
25
    """Convert a URL to a local filesystem path.
26
27
    Returns `None` if the URL does not reference the local filesystem.
28
    """
29
    scheme, netloc, path, params, query, fragment = urlparse(url)
30
    if scheme == 'file' and netloc in ['', 'localhost']:
31
        return unquote(path)
32
    return None
33
34
35
def get_parent(branch_dir):
36
    """Return the parent branch directory, otherwise `None`."""
37
    parent_dir = Branch.open(branch_dir).get_parent()
38
    if parent_dir is not None:
39
        return url2path(parent_dir)
40
    return None
41
42
43
def gen_missing_files(source, destination):
7162.4.1 by Gavin Panella
Fix broken/dangling symlinks gracefully.
44
    """Generate info on every file in source not in destination.
45
8234.1.7 by Gary Poster
rocketfuel scripts and download cache are in place now.
46
    Yields `(source, destination)` tuples.
7162.4.1 by Gavin Panella
Fix broken/dangling symlinks gracefully.
47
    """
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
48
    for name in listdir(source):
49
        destination_file = join(destination, name)
50
        if not exists(destination_file):
51
            source_file = join(source, name)
8234.1.7 by Gary Poster
rocketfuel scripts and download cache are in place now.
52
            yield source_file, destination_file,
53
54
55
def link(source, destination):
56
    """Symlink source to destination.
57
8329.1.5 by Gary Poster
fix spelling error
58
    Assumes destination is missing or broken.
8234.1.7 by Gary Poster
rocketfuel scripts and download cache are in place now.
59
    """
60
    try:
61
        if islink(destination):
62
            unlink(destination)
63
        symlink(source, destination)
64
    except OSError, error:
65
        stderr.write(
66
            '  Error linking %s: %s\n' % (basename(destination), error))
67
    else:
68
        if options.verbose:
69
            stdout.write('%s -> %s\n' % (
70
                    sep.join(destination.rsplit(sep, 3)[-3:]), source))
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
71
72
73
if __name__ == '__main__':
74
    parser = optparse.OptionParser(
6130.9.3 by Gavin Panella
Fix a few small mistakes.
75
        usage="%prog [options] [parent]",
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
76
        description=(
77
            "Add a symlink in <target>/sourcecode for each corresponding "
78
            "file in <parent>/sourcecode."),
79
        epilog=(
80
            "Most of the time this does the right thing if run "
81
            "with no arguments."),
82
        add_help_option=False)
83
    parser.add_option(
84
        '-p', '--parent', dest='parent', default=None,
85
        help=("The directory of the parent tree. If not specified, "
86
              "the Bazaar parent branch."),
87
        metavar="DIR")
88
    parser.add_option(
89
        '-t', '--target', dest='target', default=curdir,
90
        help=("The directory of the target tree. If not specified, "
91
              "the current working directory."),
92
        metavar="DIR")
93
    parser.add_option(
94
        '-q', '--quiet', dest='verbose', action='store_false',
95
        help="Be less verbose.")
96
    parser.add_option(
97
        '-h', '--help', action='help',
98
        help="Show this help message and exit.")
99
    parser.set_defaults(verbose=True)
100
101
    options, args = parser.parse_args()
102
103
    # Be compatible with link-external-sourcecode.sh.
104
    if len(args) == 1:
105
        if options.parent is None:
106
            options.parent = args[0]
107
        else:
108
            parser.error("Cannot specify parent tree as named "
109
                         "argument and positional argument.")
6130.9.3 by Gavin Panella
Fix a few small mistakes.
110
    elif len(args) >= 2:
111
        parser.error("Too many arguments.")
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
112
113
    # Discover the parent branch using Bazaar.
114
    if options.parent is None:
115
        options.parent = get_parent(options.target)
116
117
    if options.parent is None:
118
        parser.error(
119
            "Parent branch not specified, and could not be discovered.")
120
6410.12.13 by Leonard Richardson
Corrected spacing.
121
    missing_files = gen_missing_files(
122
        realpath(join(options.parent, 'sourcecode')),
123
        abspath(join(options.target, 'sourcecode')))
6410.12.12 by Leonard Richardson
Restored missing code.
124
8234.1.7 by Gary Poster
rocketfuel scripts and download cache are in place now.
125
    for source, destination in missing_files:
126
        link(source, destination)
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
127
8329.1.7 by Gary Poster
convert layout to have eggs and download-cache on top; and add make target for eggs folder, for deployment.
128
    for folder_name in ('eggs', 'download-cache'):
129
        source = join(options.parent, folder_name)
130
        destination = join(options.target, folder_name)
131
        if not exists(destination):
8502.2.2 by Gary Poster
make link-external-sourcecode more robust to unusual usage
132
            if not exists(source):
133
                stderr.write(
134
                    '  Wanted to link %s to %s but source does not exist\n' %
135
                    (source, destination))
136
            else:
137
                link(source, destination)
6130.9.1 by Gavin Panella
New link-external-sourcecode utility that uses Bazaar to find parent dir.
138
139
# End