~bloodearnest/charms/precise/squid-reverseproxy/trunk

« back to all changes in this revision

Viewing changes to cm.py

  • Committer: Marco Ceppi
  • Date: 2013-11-07 01:40:09 UTC
  • mfrom: (28.1.85 master)
  • Revision ID: marco@ceppi.net-20131107014009-lqqg63wkyt6ot2ou
[sidnei] Greatly improve test coverage
[sidnei] Allow the use of an X-Balancer-Name header to select which cache_peer backend will be used for a specific request.
[sidnei] Support 'all-services' being set in the relation, in the way that the haproxy sets it, in addition to the previously supported 'sitenames' setting. Makes it compatible with the haproxy charm.
[sidnei] When the list of supported 'sitenames' (computed from dstdomain acls) changes, notify services related via the 'cached-website' relation. This allows to add new services in the haproxy service (or really, any other service related), which notifies the squid service, which then bubbles up to services related via cached-website.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010-2013 Canonical Ltd. All rights reserved.
 
2
import os
 
3
import re
 
4
import sys
 
5
import errno
 
6
import hashlib
 
7
import subprocess
 
8
import optparse
 
9
 
 
10
from os import curdir
 
11
from bzrlib.branch import Branch
 
12
from bzrlib.plugin import load_plugins
 
13
load_plugins()
 
14
from bzrlib.plugins.launchpad import account as lp_account
 
15
 
 
16
if 'GlobalConfig' in dir(lp_account):
 
17
    from bzrlib.config import LocationConfig as LocationConfiguration
 
18
    _ = LocationConfiguration
 
19
else:
 
20
    from bzrlib.config import LocationStack as LocationConfiguration
 
21
    _ = LocationConfiguration
 
22
 
 
23
 
 
24
def get_branch_config(config_file):
 
25
    """
 
26
    Retrieves the sourcedeps configuration for an source dir.
 
27
    Returns a dict of (branch, revspec) tuples, keyed by branch name.
 
28
    """
 
29
    branches = {}
 
30
    with open(config_file, 'r') as stream:
 
31
        for line in stream:
 
32
            line = line.split('#')[0].strip()
 
33
            bzr_match = re.match(r'(\S+)\s+'
 
34
                                 'lp:([^;]+)'
 
35
                                 '(?:;revno=(\d+))?', line)
 
36
            if bzr_match:
 
37
                name, branch, revno = bzr_match.group(1, 2, 3)
 
38
                if revno is None:
 
39
                    revspec = -1
 
40
                else:
 
41
                    revspec = revno
 
42
                branches[name] = (branch, revspec)
 
43
                continue
 
44
            dir_match = re.match(r'(\S+)\s+'
 
45
                                 '\(directory\)', line)
 
46
            if dir_match:
 
47
                name = dir_match.group(1)
 
48
                branches[name] = None
 
49
    return branches
 
50
 
 
51
 
 
52
def main(config_file, parent_dir, target_dir, verbose):
 
53
    """Do the deed."""
 
54
 
 
55
    try:
 
56
        os.makedirs(parent_dir)
 
57
    except OSError, e:
 
58
        if e.errno != errno.EEXIST:
 
59
            raise
 
60
 
 
61
    branches = sorted(get_branch_config(config_file).items())
 
62
    for branch_name, spec in branches:
 
63
        if spec is None:
 
64
            # It's a directory, just create it and move on.
 
65
            destination_path = os.path.join(target_dir, branch_name)
 
66
            if not os.path.isdir(destination_path):
 
67
                os.makedirs(destination_path)
 
68
            continue
 
69
 
 
70
        (quoted_branch_spec, revspec) = spec
 
71
        revno = int(revspec)
 
72
 
 
73
        # qualify mirror branch name with hash of remote repo path to deal
 
74
        # with changes to the remote branch URL over time
 
75
        branch_spec_digest = hashlib.sha1(quoted_branch_spec).hexdigest()
 
76
        branch_directory = branch_spec_digest
 
77
 
 
78
        source_path = os.path.join(parent_dir, branch_directory)
 
79
        destination_path = os.path.join(target_dir, branch_name)
 
80
 
 
81
        # Remove leftover symlinks/stray files.
 
82
        try:
 
83
            os.remove(destination_path)
 
84
        except OSError, e:
 
85
            if e.errno != errno.EISDIR and e.errno != errno.ENOENT:
 
86
                raise
 
87
 
 
88
        lp_url = "lp:" + quoted_branch_spec
 
89
 
 
90
        # Create the local mirror branch if it doesn't already exist
 
91
        if verbose:
 
92
            sys.stderr.write('%30s: ' % (branch_name,))
 
93
            sys.stderr.flush()
 
94
 
 
95
        fresh = False
 
96
        if not os.path.exists(source_path):
 
97
            subprocess.check_call(['bzr', 'branch', '-q', '--no-tree',
 
98
                                   '--', lp_url, source_path])
 
99
            fresh = True
 
100
 
 
101
        if not fresh:
 
102
            source_branch = Branch.open(source_path)
 
103
            if revno == -1:
 
104
                orig_branch = Branch.open(lp_url)
 
105
                fresh = source_branch.revno() == orig_branch.revno()
 
106
            else:
 
107
                fresh = source_branch.revno() == revno
 
108
 
 
109
        # Freshen the source branch if required.
 
110
        if not fresh:
 
111
            subprocess.check_call(['bzr', 'pull', '-q', '--overwrite', '-r',
 
112
                                   str(revno), '-d', source_path,
 
113
                                   '--', lp_url])
 
114
 
 
115
        if os.path.exists(destination_path):
 
116
            # Overwrite the destination with the appropriate revision.
 
117
            subprocess.check_call(['bzr', 'clean-tree', '--force', '-q',
 
118
                                   '--ignored', '-d', destination_path])
 
119
            subprocess.check_call(['bzr', 'pull', '-q', '--overwrite',
 
120
                                   '-r', str(revno),
 
121
                                   '-d', destination_path, '--', source_path])
 
122
        else:
 
123
            # Create a new branch.
 
124
            subprocess.check_call(['bzr', 'branch', '-q', '--hardlink',
 
125
                                   '-r', str(revno),
 
126
                                   '--', source_path, destination_path])
 
127
 
 
128
        # Check the state of the destination branch.
 
129
        destination_branch = Branch.open(destination_path)
 
130
        destination_revno = destination_branch.revno()
 
131
 
 
132
        if verbose:
 
133
            sys.stderr.write('checked out %4s of %s\n' %
 
134
                             ("r" + str(destination_revno), lp_url))
 
135
            sys.stderr.flush()
 
136
 
 
137
        if revno != -1 and destination_revno != revno:
 
138
            raise RuntimeError("Expected revno %d but got revno %d" %
 
139
                               (revno, destination_revno))
 
140
 
 
141
if __name__ == '__main__':
 
142
    parser = optparse.OptionParser(
 
143
        usage="%prog [options]",
 
144
        description=(
 
145
            "Add a lightweight checkout in <target> for each "
 
146
            "corresponding file in <parent>."),
 
147
        add_help_option=False)
 
148
    parser.add_option(
 
149
        '-p', '--parent', dest='parent',
 
150
        default=None,
 
151
        help=("The directory of the parent tree."),
 
152
        metavar="DIR")
 
153
    parser.add_option(
 
154
        '-t', '--target', dest='target', default=curdir,
 
155
        help=("The directory of the target tree."),
 
156
        metavar="DIR")
 
157
    parser.add_option(
 
158
        '-c', '--config', dest='config', default=None,
 
159
        help=("The config file to be used for config-manager."),
 
160
        metavar="DIR")
 
161
    parser.add_option(
 
162
        '-q', '--quiet', dest='verbose', action='store_false',
 
163
        help="Be less verbose.")
 
164
    parser.add_option(
 
165
        '-v', '--verbose', dest='verbose', action='store_true',
 
166
        help="Be more verbose.")
 
167
    parser.add_option(
 
168
        '-h', '--help', action='help',
 
169
        help="Show this help message and exit.")
 
170
    parser.set_defaults(verbose=True)
 
171
 
 
172
    options, args = parser.parse_args()
 
173
 
 
174
    if options.parent is None:
 
175
        options.parent = os.environ.get(
 
176
            "SOURCEDEPS_DIR",
 
177
            os.path.join(curdir, ".sourcecode"))
 
178
 
 
179
    if options.target is None:
 
180
        parser.error(
 
181
            "Target directory not specified.")
 
182
 
 
183
    if options.config is None:
 
184
        config = [arg for arg in args
 
185
                  if arg != "update"]
 
186
        if not config or len(config) > 1:
 
187
            parser.error("Config not specified")
 
188
        options.config = config[0]
 
189
 
 
190
    sys.exit(main(config_file=options.config,
 
191
                  parent_dir=options.parent,
 
192
                  target_dir=options.target,
 
193
                  verbose=options.verbose))