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