Colin Watson has proposed merging ~cjwatson/lp-mailman:simplify-sourcecode into lp-mailman:master.
Commit message: Replace devscripts with a small shell script Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/lp-mailman/+git/lp-mailman/+merge/437825 The complexity in `devscripts` and `update-sourcecode` was inherited from Launchpad, and made a certain amount of sense when there were many entries in `utilities/sourcedeps.conf`. Now that there's only one thing there, `update-sourcecode` can be replaced with a 20-line shell script with no loss of functionality that we care about. (As far as I can see, none of our infrastructure relies on any of the command-line options that I haven't bothered to implement.) This also makes some progress towards making it possible to bootstrap lp-mailman on focal. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/lp-mailman:simplify-sourcecode into lp-mailman:master.
diff --git a/Makefile b/Makefile index 3c7c5cb..9f358b7 100644 --- a/Makefile +++ b/Makefile @@ -138,8 +138,6 @@ $(subst $(PY),,$(PIP_BIN)): $(PY) # a prerequisite, to make sure it's up to date when doing deployments. compile: $(PY) ${SHHH} utilities/relocate-virtualenv env - ${SHHH} $(MAKE) -C sourcecode build PYTHON=${PYTHON} \ - LPCONFIG=${LPCONFIG} ${SHHH} LPCONFIG=${LPCONFIG} ${PY} -t buildmailman.py scripts/update-version-info.sh diff --git a/lib/devscripts/__init__.py b/lib/devscripts/__init__.py deleted file mode 100644 index 748fe27..0000000 --- a/lib/devscripts/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2009 Canonical Ltd. This software is licensed under the -# GNU Affero General Public License version 3 (see the file LICENSE). - -"""Scripts that are used in developing Launchpad.""" - -import os - - -def get_launchpad_root(): - return os.path.dirname(os.path.dirname(os.path.dirname(__file__))) diff --git a/lib/devscripts/sourcecode.py b/lib/devscripts/sourcecode.py deleted file mode 100644 index 0ab7650..0000000 --- a/lib/devscripts/sourcecode.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright 2009 Canonical Ltd. This software is licensed under the -# GNU Affero General Public License version 3 (see the file LICENSE). - -"""Tools for maintaining the Launchpad source code.""" - -from __future__ import ( - absolute_import, - print_function, - ) - - -__metaclass__ = type -__all__ = [ - 'interpret_config', - 'parse_config_file', - 'plan_update', - ] - -import errno -import json -import optparse -import os -import shutil -import sys - - -try: - from breezy import ui - from breezy.branch import Branch - from breezy.errors import ( - BzrError, - IncompatibleRepositories, - NotBranchError, - ) - from breezy.plugin import load_plugins - from breezy.revisionspec import RevisionSpec - from breezy.trace import ( - enable_default_logging, - report_exception, - ) - from breezy.upgrade import upgrade - from breezy.workingtree import WorkingTree -except ImportError: - from bzrlib import ui - from bzrlib.branch import Branch - from bzrlib.errors import ( - BzrError, - IncompatibleRepositories, - NotBranchError, - ) - from bzrlib.plugin import load_plugins - from bzrlib.revisionspec import RevisionSpec - from bzrlib.trace import ( - enable_default_logging, - report_exception, - ) - from bzrlib.upgrade import upgrade - from bzrlib.workingtree import WorkingTree - -from devscripts import get_launchpad_root - - -def parse_config_file(file_handle): - """Parse the source code config file 'file_handle'. - - :param file_handle: A file-like object containing sourcecode - configuration. - :return: A sequence of lines of either '[key, value]' or - '[key, value, optional]'. - """ - for line in file_handle: - if line == '\n' or line.startswith('#'): - continue - yield line.split() - - -def interpret_config_entry(entry, use_http=False): - """Interpret a single parsed line from the config file.""" - branch_name = entry[0] - components = entry[1].split(';revno=') - branch_url = components[0] - if use_http: - branch_url = branch_url.replace('lp:', 'http://bazaar.launchpad.net/') - if len(components) == 1: - revision = None - else: - assert len(components) == 2, 'Bad branch URL: ' + entry[1] - revision = components[1] or None - if len(entry) > 2: - assert len(entry) == 3 and entry[2].lower() == 'optional', ( - 'Bad configuration line: should be space delimited values of ' - 'sourcecode directory name, branch URL [, "optional"]\n' + - ' '.join(entry)) - optional = True - else: - optional = False - return branch_name, branch_url, revision, optional - - -def load_cache(cache_filename): - try: - cache_file = open(cache_filename, 'r') - except IOError as e: - if e.errno == errno.ENOENT: - return {} - else: - raise - with cache_file: - return json.load(cache_file) - - -def interpret_config(config_entries, public_only, use_http=False): - """Interpret a configuration stream, as parsed by 'parse_config_file'. - - :param configuration: A sequence of parsed configuration entries. - :param public_only: If true, ignore private/optional branches. - :param use_http: If True, force all branch URLs to use http:// - :return: A dict mapping the names of the sourcecode dependencies to a - 2-tuple of their branches and whether or not they are optional. - """ - config = {} - for entry in config_entries: - branch_name, branch_url, revision, optional = interpret_config_entry( - entry, use_http) - if not optional or not public_only: - config[branch_name] = (branch_url, revision, optional) - return config - - -def _subset_dict(d, keys): - """Return a dict that's a subset of 'd', based on the keys in 'keys'.""" - return dict((key, d[key]) for key in keys) - - -def plan_update(existing_branches, configuration): - """Plan the update to existing branches based on 'configuration'. - - :param existing_branches: A sequence of branches that already exist. - :param configuration: A dictionary of sourcecode configuration, such as is - returned by `interpret_config`. - :return: (new_branches, update_branches, removed_branches), where - 'new_branches' are the branches in the configuration that don't exist - yet, 'update_branches' are the branches in the configuration that do - exist, and 'removed_branches' are the branches that exist locally, but - not in the configuration. 'new_branches' and 'update_branches' are - dicts of the same form as 'configuration', 'removed_branches' is a - set of the same form as 'existing_branches'. - """ - existing_branches = set(existing_branches) - config_branches = set(configuration.keys()) - new_branches = config_branches - existing_branches - removed_branches = existing_branches - config_branches - update_branches = config_branches.intersection(existing_branches) - return ( - _subset_dict(configuration, new_branches), - _subset_dict(configuration, update_branches), - removed_branches) - - -def find_branches(directory): - """List the directory names in 'directory' that are branches.""" - branches = [] - for name in os.listdir(directory): - if name in ('.', '..'): - continue - try: - Branch.open(os.path.join(directory, name)) - branches.append(name) - except NotBranchError: - pass - return branches - - -def get_revision_id(revision, from_branch, tip=False): - """Return revision id for a revision number and a branch. - - If the revision is empty, the revision_id will be None. - - If ``tip`` is True, the revision value will be ignored. - """ - if not tip and revision: - spec = RevisionSpec.from_string(revision) - return spec.as_revision_id(from_branch) - # else return None - - -def _format_revision_name(revision, tip=False): - """Formatting helper to return human-readable identifier for revision. - - If ``tip`` is True, the revision value will be ignored. - """ - if not tip and revision: - return 'revision %s' % (revision,) - else: - return 'tip' - - -def get_controldir(branch): - try: - # Breezy - return branch.controldir - except AttributeError: - # Bazaar - return branch.bzrdir - - -def get_branches(sourcecode_directory, new_branches, - possible_transports=None, tip=False, quiet=False): - """Get the new branches into sourcecode.""" - for project, (branch_url, revision, optional) in new_branches.items(): - destination = os.path.join(sourcecode_directory, project) - try: - remote_branch = Branch.open( - branch_url, possible_transports=possible_transports) - except BzrError: - if optional: - report_exception(sys.exc_info(), sys.stderr) - continue - else: - raise - possible_transports.append( - get_controldir(remote_branch).root_transport) - if not quiet: - print('Getting %s from %s at %s' % ( - project, branch_url, _format_revision_name(revision, tip))) - # If the 'optional' flag is set, then it's a branch that shares - # history with Launchpad, so we should share repositories. Otherwise, - # we should avoid sharing repositories to avoid format - # incompatibilities. - force_new_repo = not optional - revision_id = get_revision_id(revision, remote_branch, tip) - get_controldir(remote_branch).sprout( - destination, revision_id=revision_id, create_tree_if_local=True, - source_branch=remote_branch, force_new_repo=force_new_repo, - possible_transports=possible_transports) - - -def find_stale(updated, cache, sourcecode_directory, quiet): - """Find branches whose revision info doesn't match the cache.""" - new_updated = dict(updated) - for project, (branch_url, revision, optional) in updated.items(): - cache_revision_info = cache.get(project) - if cache_revision_info is None: - continue - cache_revno = cache_revision_info[0] - cache_revision_id = cache_revision_info[1].encode('ASCII') - if cache_revno != int(revision): - continue - destination = os.path.join(sourcecode_directory, project) - try: - branch = Branch.open(destination) - except BzrError: - continue - last_revno, last_revision_id = branch.last_revision_info() - if last_revno != cache_revno or last_revision_id != cache_revision_id: - continue - if not quiet: - print('%s is already up to date.' % project) - del new_updated[project] - return new_updated - - -def update_cache(cache, cache_filename, changed, sourcecode_directory, quiet): - """Update the cache with the changed branches.""" - old_cache = dict(cache) - for project, (branch_url, revision, optional) in changed.items(): - destination = os.path.join(sourcecode_directory, project) - branch = Branch.open(destination) - last_revno, last_revision_id = branch.last_revision_info() - if not isinstance(last_revision_id, str): # Python 3 - last_revision_id = last_revision_id.decode('ASCII') - cache[project] = [last_revno, last_revision_id] - if cache == old_cache: - return - with open(cache_filename, 'w') as cache_file: - # XXX cjwatson 2020-01-21: Stop explicitly specifying separators - # once we require Python >= 3.4 (where this is the default). - json.dump( - cache, cache_file, indent=4, separators=(',', ': '), - sort_keys=True) - if not quiet: - print('Cache updated. Please commit "%s".' % cache_filename) - - -def update_branches(sourcecode_directory, update_branches, - possible_transports=None, tip=False, quiet=False): - """Update the existing branches in sourcecode.""" - if possible_transports is None: - possible_transports = [] - # XXX: JonathanLange 2009-11-09: Rather than updating one branch after - # another, we could instead try to get them in parallel. - for project, (branch_url, revision, optional) in update_branches.items(): - # Update project from branch_url. - destination = os.path.join(sourcecode_directory, project) - if not quiet: - print('Updating %s to %s' % ( - project, _format_revision_name(revision, tip))) - local_tree = WorkingTree.open(destination) - try: - remote_branch = Branch.open( - branch_url, possible_transports=possible_transports) - except BzrError: - if optional: - report_exception(sys.exc_info(), sys.stderr) - continue - else: - raise - possible_transports.append( - get_controldir(remote_branch).root_transport) - revision_id = get_revision_id(revision, remote_branch, tip) - try: - result = local_tree.pull( - remote_branch, stop_revision=revision_id, overwrite=True, - possible_transports=possible_transports) - except IncompatibleRepositories: - # XXX JRV 20100407: Ideally get_controldir(remote_branch)._format - # should be passed into upgrade() to ensure the format is the same - # locally and remotely. Unfortunately smart server branches - # have their _format set to RemoteFormat rather than an actual - # format instance. - upgrade(destination) - # Upgraded, repoen working tree - local_tree = WorkingTree.open(destination) - result = local_tree.pull( - remote_branch, stop_revision=revision_id, overwrite=True, - possible_transports=possible_transports) - if result.old_revid == result.new_revid: - if not quiet: - print(' (No change)') - else: - if result.old_revno < result.new_revno: - change = 'Updated' - else: - change = 'Reverted' - if not quiet: - print(' (%s from %s to %s)' % ( - change, result.old_revno, result.new_revno)) - - -def remove_branches(sourcecode_directory, removed_branches, quiet=False): - """Remove sourcecode that's no longer there.""" - for project in removed_branches: - destination = os.path.join(sourcecode_directory, project) - if not quiet: - print('Removing %s' % project) - try: - shutil.rmtree(destination) - except OSError: - os.unlink(destination) - - -def update_sourcecode(sourcecode_directory, config_filename, cache_filename, - public_only, tip, dry_run, quiet=False, use_http=False): - """Update the sourcecode.""" - config_file = open(config_filename) - config = interpret_config( - parse_config_file(config_file), public_only, use_http) - config_file.close() - cache = load_cache(cache_filename) - branches = find_branches(sourcecode_directory) - new, updated, removed = plan_update(branches, config) - possible_transports = [] - if dry_run: - print('Branches to fetch:', new.keys()) - print('Branches to update:', updated.keys()) - print('Branches to remove:', list(removed)) - else: - get_branches( - sourcecode_directory, new, possible_transports, tip, quiet) - updated = find_stale(updated, cache, sourcecode_directory, quiet) - update_branches( - sourcecode_directory, updated, possible_transports, tip, quiet) - changed = dict(updated) - changed.update(new) - update_cache( - cache, cache_filename, changed, sourcecode_directory, quiet) - remove_branches(sourcecode_directory, removed, quiet) - - -# XXX: JonathanLange 2009-09-11: By default, the script will operate on the -# current checkout. Most people only have symlinks to sourcecode in their -# checkouts. This is fine for updating, but breaks for removing (you can't -# shutil.rmtree a symlink) and breaks for adding, since it adds the new branch -# to the checkout, rather than to the shared sourcecode area. Ideally, the -# script would see that the sourcecode directory is full of symlinks and then -# follow these symlinks to find the shared source directory. If the symlinks -# differ from each other (because of developers fiddling with things), we can -# take a survey of all of them, and choose the most popular. - - -def main(args): - parser = optparse.OptionParser("usage: %prog [options] [root [conffile]]") - parser.add_option( - '--public-only', action='store_true', - help='Only fetch/update the public sourcecode branches.') - parser.add_option( - '--tip', action='store_true', - help='Ignore revision constraints for all branches and pull tip') - parser.add_option( - '--dry-run', action='store_true', - help='Do nothing, but report what would have been done.') - parser.add_option( - '--quiet', action='store_true', - help="Don't print informational messages.") - parser.add_option( - '--use-http', action='store_true', - help="Force bzr to use http to get the sourcecode branches " - "rather than using bzr+ssh.") - options, args = parser.parse_args(args) - root = get_launchpad_root() - if len(args) > 1: - sourcecode_directory = args[1] - else: - sourcecode_directory = os.path.join(root, 'sourcecode') - if len(args) > 2: - config_filename = args[2] - else: - config_filename = os.path.join(root, 'utilities', 'sourcedeps.conf') - cache_filename = os.path.join( - root, 'utilities', 'sourcedeps.cache') - if len(args) > 3: - parser.error("Too many arguments.") - if not options.quiet: - print('Sourcecode: %s' % (sourcecode_directory,)) - print('Config: %s' % (config_filename,)) - enable_default_logging() - # Tell bzr to use the terminal (if any) to show progress bars - ui.ui_factory = ui.make_ui_for_terminal( - sys.stdin, sys.stdout, sys.stderr) - load_plugins() - update_sourcecode( - sourcecode_directory, config_filename, cache_filename, - options.public_only, options.tip, options.dry_run, options.quiet, - options.use_http) - return 0 diff --git a/lib/devscripts/tests/__init__.py b/lib/devscripts/tests/__init__.py deleted file mode 100644 index 62d7904..0000000 --- a/lib/devscripts/tests/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2009 Canonical Ltd. This software is licensed under the -# GNU Affero General Public License version 3 (see the file LICENSE). - -"""Tests for devscripts.""" diff --git a/lib/devscripts/tests/test_sourcecode.py b/lib/devscripts/tests/test_sourcecode.py deleted file mode 100644 index 8f4748f..0000000 --- a/lib/devscripts/tests/test_sourcecode.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright 2009 Canonical Ltd. This software is licensed under the -# GNU Affero General Public License version 3 (see the file LICENSE). - -"""Module docstring goes here.""" - -from __future__ import ( - absolute_import, - print_function, - ) - - -__metaclass__ = type - -import os -import shutil -from StringIO import StringIO -import tempfile -import unittest - - -try: - from breezy.bzr.bzrdir import BzrDir - from breezy.tests import TestCase - from breezy.transport import get_transport -except ImportError: - from bzrlib.bzrdir import BzrDir - from bzrlib.tests import TestCase - from bzrlib.transport import get_transport - -from devscripts import get_launchpad_root -from devscripts.sourcecode import ( - find_branches, - interpret_config, - parse_config_file, - plan_update, - ) - - -class TestParseConfigFile(unittest.TestCase): - """Tests for the config file parser.""" - - def makeFile(self, contents): - return StringIO(contents) - - def test_empty(self): - # Parsing an empty config file returns an empty sequence. - empty_file = self.makeFile("") - self.assertEqual([], list(parse_config_file(empty_file))) - - def test_single_value(self): - # Parsing a file containing a single key=value pair returns a sequence - # containing the (key, value) as a list. - config_file = self.makeFile("key value") - self.assertEqual( - [['key', 'value']], list(parse_config_file(config_file))) - - def test_comment_ignored(self): - # If a line begins with a '#', then its a comment. - comment_only = self.makeFile('# foo') - self.assertEqual([], list(parse_config_file(comment_only))) - - def test_optional_value(self): - # Lines in the config file can have a third optional entry. - config_file = self.makeFile('key value optional') - self.assertEqual( - [['key', 'value', 'optional']], - list(parse_config_file(config_file))) - - def test_whitespace_stripped(self): - # Any whitespace around any of the tokens in the config file are - # stripped out. - config_file = self.makeFile(' key value optional ') - self.assertEqual( - [['key', 'value', 'optional']], - list(parse_config_file(config_file))) - - -class TestInterpretConfiguration(unittest.TestCase): - """Tests for the configuration interpreter.""" - - def test_empty(self): - # An empty configuration stream means no configuration. - config = interpret_config([], False) - self.assertEqual({}, config) - - def test_key_value(self): - # A (key, value) pair without a third optional value is returned in - # the configuration as a dictionary entry under 'key' with '(value, - # None, False)' as its value. - config = interpret_config([['key', 'value']], False) - self.assertEqual({'key': ('value', None, False)}, config) - - def test_key_value_public_only(self): - # A (key, value) pair without a third optional value is returned in - # the configuration as a dictionary entry under 'key' with '(value, - # None, False)' as its value when public_only is true. - config = interpret_config([['key', 'value']], True) - self.assertEqual({'key': ('value', None, False)}, config) - - def test_key_value_optional(self): - # A (key, value, optional) entry is returned in the configuration as a - # dictionary entry under 'key' with '(value, True)' as its value. - config = interpret_config([['key', 'value', 'optional']], False) - self.assertEqual({'key': ('value', None, True)}, config) - - def test_key_value_optional_public_only(self): - # A (key, value, optional) entry is not returned in the configuration - # when public_only is true. - config = interpret_config([['key', 'value', 'optional']], True) - self.assertEqual({}, config) - - def test_key_value_revision(self): - # A (key, value) pair without a third optional value when the - # value has a suffix of ``;revno=[REVISION]`` is returned in the - # configuration as a dictionary entry under 'key' with '(value, - # None, False)' as its value. - config = interpret_config([['key', 'value;revno=45']], False) - self.assertEqual({'key': ('value', '45', False)}, config) - - def test_key_value_revision(self): - # A (key, value) pair without a third optional value when the - # value has multiple suffixes of ``;revno=[REVISION]`` raises an - # error. - self.assertRaises( - AssertionError, - interpret_config, [['key', 'value;revno=45;revno=47']], False) - - def test_too_many_values(self): - # A line with too many values raises an error. - self.assertRaises( - AssertionError, - interpret_config, [['key', 'value', 'optional', 'extra']], False) - - def test_bad_optional_value(self): - # A third value that is not the "optional" string raises an error. - self.assertRaises( - AssertionError, - interpret_config, [['key', 'value', 'extra']], False) - - def test_use_http(self): - # If use_http=True is passed to interpret_config, all lp: branch - # URLs will be transformed into http:// URLs. - config = interpret_config( - [['key', 'lp:~sabdfl/foo/trunk']], False, use_http=True) - expected_url = 'http://bazaar.launchpad.net/~sabdfl/foo/trunk' - self.assertEqual(expected_url, config['key'][0]) - - -class TestPlanUpdate(unittest.TestCase): - """Tests for how to plan the update.""" - - def test_trivial(self): - # In the trivial case, there are no existing branches and no - # configured branches, so there are no branches to add, none to - # update, and none to remove. - new, existing, removed = plan_update([], {}) - self.assertEqual({}, new) - self.assertEqual({}, existing) - self.assertEqual(set(), removed) - - def test_all_new(self): - # If there are no existing branches, then the all of the configured - # branches are new, none are existing and none have been removed. - new, existing, removed = plan_update([], {'a': ('b', False)}) - self.assertEqual({'a': ('b', False)}, new) - self.assertEqual({}, existing) - self.assertEqual(set(), removed) - - def test_all_old(self): - # If there configuration is now empty, but there are existing - # branches, then that means all the branches have been removed from - # the configuration, none are new and none are updated. - new, existing, removed = plan_update(['a', 'b', 'c'], {}) - self.assertEqual({}, new) - self.assertEqual({}, existing) - self.assertEqual(set(['a', 'b', 'c']), removed) - - def test_all_same(self): - # If the set of existing branches is the same as the set of - # non-existing branches, then they all need to be updated. - config = {'a': ('b', False), 'c': ('d', True)} - new, existing, removed = plan_update(config.keys(), config) - self.assertEqual({}, new) - self.assertEqual(config, existing) - self.assertEqual(set(), removed) - - def test_smoke_the_default_config(self): - # Make sure we can parse, interpret and plan based on the default - # config file. - root = get_launchpad_root() - config_filename = os.path.join(root, 'utilities', 'sourcedeps.conf') - config_file = open(config_filename) - config = interpret_config(parse_config_file(config_file), False) - config_file.close() - plan_update([], config) - - -class TestFindBranches(TestCase): - """Tests the way that we find branches.""" - - def setUp(self): - TestCase.setUp(self) - self.disable_directory_isolation() - - def makeBranch(self, path): - transport = get_transport(path) - transport.ensure_base() - BzrDir.create_branch_convenience( - transport.base, possible_transports=[transport]) - - def makeDirectory(self): - directory = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, directory) - return directory - - def test_empty_directory_has_no_branches(self): - # An empty directory has no branches. - empty = self.makeDirectory() - self.assertEqual([], list(find_branches(empty))) - - def test_directory_with_branches(self): - # find_branches finds branches in the directory. - directory = self.makeDirectory() - self.makeBranch('%s/a' % directory) - self.assertEqual(['a'], list(find_branches(directory))) - - def test_ignores_files(self): - # find_branches ignores any files in the directory. - directory = self.makeDirectory() - some_file = open('%s/a' % directory, 'w') - some_file.write('hello\n') - some_file.close() - self.assertEqual([], list(find_branches(directory))) diff --git a/setup.cfg b/setup.cfg index 8069514..3946819 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ combine_as_imports = true force_grid_wrap = 2 force_sort_within_sections = true include_trailing_comma = true -known_first_party = lp,devscripts +known_first_party = lp known_pythonpath = _pythonpath line_length = 78 lines_after_imports = 2 diff --git a/sourcecode/Makefile b/sourcecode/Makefile deleted file mode 100644 index ee5dad1..0000000 --- a/sourcecode/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -PYTHON=python -# Not all packages have a working Makefile. Work around this by hardcoding -# the ones we test. If we fix them all to have EITHER a good makefile -# (build and check targets work), or no makefile we can reenable auto -# detection. -build_dirs:=cscvs pygettextpo -test_dirs:=cscvs pygettextpo - -TEST_ENV_VARS = PYTHON=$(PYTHON) - -all: - -check: build - @ for subdir in ${test_dirs}; do \ - $(MAKE) -C $$subdir check $(TEST_ENV_VARS) || exit $$?;\ - done - -build: - @ for subdir in ${build_dirs}; do\ - if [ -e $$subdir/Makefile ]; then\ - $(MAKE) -C $$subdir $(TEST_ENV_VARS) || exit $$?;\ - fi;\ - done - -clean: - @ for subdir in ${build_dirs}; do\ - if [ -e $$subdir/Makefile ]; then\ - (cd $$subdir && bzr clean-tree --ignored --force) || exit $$?;\ - fi;\ - done - -.PHONY: check all build clean diff --git a/utilities/sourcedeps.cache b/utilities/sourcedeps.cache deleted file mode 100644 index 85a0ad3..0000000 --- a/utilities/sourcedeps.cache +++ /dev/null @@ -1,6 +0,0 @@ -{ - "mailman": [ - 977, - "launch...@pqm.canonical.com-20130405041235-9ud0xancja2eefd7" - ] -} \ No newline at end of file diff --git a/utilities/sourcedeps.conf b/utilities/sourcedeps.conf deleted file mode 100644 index 3b934e1..0000000 --- a/utilities/sourcedeps.conf +++ /dev/null @@ -1,10 +0,0 @@ -# If you're adding items to this file you _must_ use the full path to -# the branch after lp: rather than just trusting that bzr/lp will expand -# the series for you. If you don't, update-sourcecode will break when -# running parallelised tests inside lxc containers. - -######################################################### -#### DEPRECATED. NO NEW ITEMS. NO NO NO NO NO NONONONONO -######################################################### - -mailman lp:~launchpad-pqm/mailman/2.1;revno=977 diff --git a/utilities/update-sourcecode b/utilities/update-sourcecode index a10eb01..671a073 100755 --- a/utilities/update-sourcecode +++ b/utilities/update-sourcecode @@ -1,19 +1,20 @@ -#!/usr/bin/python2 -u +#! /bin/sh # -# Copyright 2009 Canonical Ltd. This software is licensed under the +# Copyright 2023 Canonical Ltd. This software is licensed under the # GNU Affero General Public License version 3 (see the file LICENSE). -"""Update the sourcecode managed in sourcecode/.""" +# Update the sourcecode managed in sourcecode/. -import os -import sys +set -e +# r977 +mailman_revid=launch...@pqm.canonical.com-20130405041235-9ud0xancja2eefd7 -sys.path.insert(0, - os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib')) - -from devscripts import sourcecode - - -if __name__ == '__main__': - sys.exit(sourcecode.main(sys.argv)) +mkdir -p sourcecode +if [ -d sourcecode/mailman/.bzr ]; then + bzr pull -d sourcecode/mailman -rrevid:"$mailman_revid" +else + rm -rf sourcecode/mailman + bzr branch -rrevid:"$mailman_revid" \ + lp:~launchpad-pqm/mailman/2.1 sourcecode/mailman +fi
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp