1
# Copyright 2010-2013 Canonical Ltd. All rights reserved.
11
from bzrlib.branch import Branch
12
from bzrlib.plugin import load_plugins
14
from bzrlib.plugins.launchpad import account as lp_account
16
if 'GlobalConfig' in dir(lp_account):
17
from bzrlib.config import LocationConfig as LocationConfiguration
18
_ = LocationConfiguration
20
from bzrlib.config import LocationStack as LocationConfiguration
21
_ = LocationConfiguration
24
def get_branch_config(config_file):
26
Retrieves the sourcedeps configuration for an source dir.
27
Returns a dict of (branch, revspec) tuples, keyed by branch name.
30
with open(config_file, 'r') as stream:
32
line = line.split('#')[0].strip()
33
bzr_match = re.match(r'(\S+)\s+'
35
'(?:;revno=(\d+))?', line)
37
name, branch, revno = bzr_match.group(1, 2, 3)
42
branches[name] = (branch, revspec)
44
dir_match = re.match(r'(\S+)\s+'
45
'\(directory\)', line)
47
name = dir_match.group(1)
52
def main(config_file, parent_dir, target_dir, verbose):
56
os.makedirs(parent_dir)
58
if e.errno != errno.EEXIST:
61
branches = sorted(get_branch_config(config_file).items())
62
for branch_name, spec in branches:
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)
70
(quoted_branch_spec, revspec) = spec
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
78
source_path = os.path.join(parent_dir, branch_directory)
79
destination_path = os.path.join(target_dir, branch_name)
81
# Remove leftover symlinks/stray files.
83
os.remove(destination_path)
85
if e.errno != errno.EISDIR and e.errno != errno.ENOENT:
88
lp_url = "lp:" + quoted_branch_spec
90
# Create the local mirror branch if it doesn't already exist
92
sys.stderr.write('%30s: ' % (branch_name,))
96
if not os.path.exists(source_path):
97
subprocess.check_call(['bzr', 'branch', '-q', '--no-tree',
98
'--', lp_url, source_path])
102
source_branch = Branch.open(source_path)
104
orig_branch = Branch.open(lp_url)
105
fresh = source_branch.revno() == orig_branch.revno()
107
fresh = source_branch.revno() == revno
109
# Freshen the source branch if required.
111
subprocess.check_call(['bzr', 'pull', '-q', '--overwrite', '-r',
112
str(revno), '-d', source_path,
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',
121
'-d', destination_path, '--', source_path])
123
# Create a new branch.
124
subprocess.check_call(['bzr', 'branch', '-q', '--hardlink',
126
'--', source_path, destination_path])
128
# Check the state of the destination branch.
129
destination_branch = Branch.open(destination_path)
130
destination_revno = destination_branch.revno()
133
sys.stderr.write('checked out %4s of %s\n' %
134
("r" + str(destination_revno), lp_url))
137
if revno != -1 and destination_revno != revno:
138
raise RuntimeError("Expected revno %d but got revno %d" %
139
(revno, destination_revno))
141
if __name__ == '__main__':
142
parser = optparse.OptionParser(
143
usage="%prog [options]",
145
"Add a lightweight checkout in <target> for each "
146
"corresponding file in <parent>."),
147
add_help_option=False)
149
'-p', '--parent', dest='parent',
151
help=("The directory of the parent tree."),
154
'-t', '--target', dest='target', default=curdir,
155
help=("The directory of the target tree."),
158
'-c', '--config', dest='config', default=None,
159
help=("The config file to be used for config-manager."),
162
'-q', '--quiet', dest='verbose', action='store_false',
163
help="Be less verbose.")
165
'-v', '--verbose', dest='verbose', action='store_true',
166
help="Be more verbose.")
168
'-h', '--help', action='help',
169
help="Show this help message and exit.")
170
parser.set_defaults(verbose=True)
172
options, args = parser.parse_args()
174
if options.parent is None:
175
options.parent = os.environ.get(
177
os.path.join(curdir, ".sourcecode"))
179
if options.target is None:
181
"Target directory not specified.")
183
if options.config is None:
184
config = [arg for arg in args
186
if not config or len(config) > 1:
187
parser.error("Config not specified")
188
options.config = config[0]
190
sys.exit(main(config_file=options.config,
191
parent_dir=options.parent,
192
target_dir=options.target,
193
verbose=options.verbose))