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