~launchpad-pqm/launchpad/devel

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
134
135
136
137
138
139
#!/usr/bin/python
#
# Copyright 2009 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

import optparse

from os import curdir, listdir, sep, symlink, unlink
from os.path import abspath, basename, exists, islink, join, realpath
from sys import stderr, stdout
from urllib import unquote
from urlparse import urlparse

# This comes before other bzrlib stuff, because imports may cause warnings,
# etc.
from bzrlib.trace import enable_default_logging
enable_default_logging()
from bzrlib.branch import Branch
from bzrlib.plugin import load_plugins

load_plugins()


def url2path(url):
    """Convert a URL to a local filesystem path.

    Returns `None` if the URL does not reference the local filesystem.
    """
    scheme, netloc, path, params, query, fragment = urlparse(url)
    if scheme == 'file' and netloc in ['', 'localhost']:
        return unquote(path)
    return None


def get_parent(branch_dir):
    """Return the parent branch directory, otherwise `None`."""
    parent_dir = Branch.open(branch_dir).get_parent()
    if parent_dir is not None:
        return url2path(parent_dir)
    return None


def gen_missing_files(source, destination):
    """Generate info on every file in source not in destination.

    Yields `(source, destination)` tuples.
    """
    for name in listdir(source):
        destination_file = join(destination, name)
        if not exists(destination_file):
            source_file = join(source, name)
            yield source_file, destination_file,


def link(source, destination):
    """Symlink source to destination.

    Assumes destination is missing or broken.
    """
    try:
        if islink(destination):
            unlink(destination)
        symlink(source, destination)
    except OSError, error:
        stderr.write(
            '  Error linking %s: %s\n' % (basename(destination), error))
    else:
        if options.verbose:
            stdout.write('%s -> %s\n' % (
                    sep.join(destination.rsplit(sep, 3)[-3:]), source))


if __name__ == '__main__':
    parser = optparse.OptionParser(
        usage="%prog [options] [parent]",
        description=(
            "Add a symlink in <target>/sourcecode for each corresponding "
            "file in <parent>/sourcecode."),
        epilog=(
            "Most of the time this does the right thing if run "
            "with no arguments."),
        add_help_option=False)
    parser.add_option(
        '-p', '--parent', dest='parent', default=None,
        help=("The directory of the parent tree. If not specified, "
              "the Bazaar parent branch."),
        metavar="DIR")
    parser.add_option(
        '-t', '--target', dest='target', default=curdir,
        help=("The directory of the target tree. If not specified, "
              "the current working directory."),
        metavar="DIR")
    parser.add_option(
        '-q', '--quiet', dest='verbose', action='store_false',
        help="Be less verbose.")
    parser.add_option(
        '-h', '--help', action='help',
        help="Show this help message and exit.")
    parser.set_defaults(verbose=True)

    options, args = parser.parse_args()

    # Be compatible with link-external-sourcecode.sh.
    if len(args) == 1:
        if options.parent is None:
            options.parent = args[0]
        else:
            parser.error("Cannot specify parent tree as named "
                         "argument and positional argument.")
    elif len(args) >= 2:
        parser.error("Too many arguments.")

    # Discover the parent branch using Bazaar.
    if options.parent is None:
        options.parent = get_parent(options.target)

    if options.parent is None:
        parser.error(
            "Parent branch not specified, and could not be discovered.")

    missing_files = gen_missing_files(
        realpath(join(options.parent, 'sourcecode')),
        abspath(join(options.target, 'sourcecode')))

    for source, destination in missing_files:
        link(source, destination)

    for folder_name in ('eggs', 'download-cache'):
        source = join(options.parent, folder_name)
        destination = join(options.target, folder_name)
        if not exists(destination):
            if not exists(source):
                stderr.write(
                    '  Wanted to link %s to %s but source does not exist\n' %
                    (source, destination))
            else:
                link(source, destination)

# End