# HG changeset patch # User Bernhard Herzog # Date 1189531496 0 # Node ID 3ed079a7174a7e73346b52fcae183aaefdab3bcf # Parent 6ed1c881ee1be56faea3b6390e6b71ebbd71890b Implement a way to stop a running treepackager. diff -r 6ed1c881ee1b -r 3ed079a7174a bin/telltreepkg.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/telltreepkg.py Tue Sep 11 17:24:56 2007 +0000 @@ -0,0 +1,31 @@ +#! /usr/bin/python2.4 +# Copyright (C) 2007 by Intevation GmbH +# Authors: +# Bernhard Herzog +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +"""Sends instructions to a running packager""" + +import sys + +import treepkgcmd +from treepkg.options import create_parser +from treepkg.readconfig import read_config +from treepkg.util import writefile + +def main(): + options, args = create_parser().parse_args() + + if len(args) != 1: + print >>sys.stderr, "The command to send to treepkg must be given" + sys.exit(1) + + treepkg_opts, packager_opts = read_config(options.config_file) + + filename = treepkg_opts.get("instructions_file") + if filename: + writefile(filename, args[0]) + +main() diff -r 6ed1c881ee1b -r 3ed079a7174a test/test_packager.py --- a/test/test_packager.py Tue Sep 11 13:58:28 2007 +0000 +++ b/test/test_packager.py Tue Sep 11 17:24:56 2007 +0000 @@ -131,6 +131,75 @@ ["testpkg_2-kk1_all.deb", "testpkg_2-kk1_i386.changes"]) +class StoppingPackager(treepkg.packager.RevisionPackager): + + def package(self): + pass + +class StoppingTrack(treepkg.packager.PackageTrack): + + def __init__(self, do_package, do_stop, instructions_file, name, trackdir): + super(StoppingTrack, self).__init__(name, trackdir, "", "", "", + "", "") + self.do_package = do_package + self.do_stop = do_stop + self.instructions_file = instructions_file + + def package_if_updated(self, revision): + if self.do_stop: + writefile(self.instructions_file, "stop") + if self.do_package: + return StoppingPackager(self, 1) + else: + return None + + +class TestPackageGroupStop(unittest.TestCase, FileTestMixin): + + def setUp(self): + self.trackdir = self.create_temp_dir(self.id() + "-track") + self.instructions_file = os.path.join(self.trackdir, "instructions") + + def group(self, do_package=True, do_stop=True): + return PackagerGroup([StoppingTrack(do_package, do_stop, + self.instructions_file, + "test", self.trackdir)], + 1, instructions_file=self.instructions_file) + + def test_stop(self): + group = self.group(do_package=True, do_stop=True) + self.failUnless(group.check_package_tracks()) + + def test_no_stop(self): + group = self.group(do_package=True, do_stop=False) + self.failIf(group.check_package_tracks()) + + def test_instruction_removal(self): + # run once with stopping + group = self.group(do_package=True, do_stop=True) + self.failUnless(group.check_package_tracks()) + + # run again without stopping but using the same files. The + # instructions file should be removed automatically + group = self.group(do_package=True, do_stop=False) + self.failIf(group.check_package_tracks()) + + def test_stopping_without_packaging(self): + group = self.group(do_package=False, do_stop=True) + self.failUnless(group.check_package_tracks()) + + def test_stopping_between_checks(self): + group = self.group(do_package=False, do_stop=False) + # run check_package_tracks once + self.failIf(group.check_package_tracks()) + + # tell treepkg to stop + writefile(self.instructions_file, "stop") + + # check again. The check_package_tracks() may remove the + # instructions file but it must do so only the first time + self.failUnless(group.check_package_tracks()) + class TestPackageTrack(unittest.TestCase, FileTestMixin): diff -r 6ed1c881ee1b -r 3ed079a7174a treepkg/packager.py --- a/treepkg/packager.py Tue Sep 11 13:58:28 2007 +0000 +++ b/treepkg/packager.py Tue Sep 11 17:24:56 2007 +0000 @@ -396,10 +396,13 @@ class PackagerGroup(object): - def __init__(self, package_tracks, check_interval, revision=None): + def __init__(self, package_tracks, check_interval, revision=None, + instructions_file=None): self.package_tracks = package_tracks self.check_interval = check_interval self.revision = revision + self.instructions_file = instructions_file + self.instructions_file_removed = False def run(self): """Runs the packager group indefinitely""" @@ -409,7 +412,8 @@ while 1: now = time.time() if now > last_check + self.check_interval: - self.check_package_tracks() + if self.check_package_tracks(): + break last_check = now next_check = now + self.check_interval to_sleep = next_check - time.time() @@ -420,14 +424,21 @@ time.sleep(to_sleep) else: logging.info("Next check now") + if self.should_stop(): + logging.info("Received stop instruction. Stopping.") + return def check_package_tracks(self): logging.info("Checking package tracks") + self.clear_instruction() for track in self.package_tracks: try: packager = track.package_if_updated(revision=self.revision) if packager: packager.package() + if self.should_stop(): + logging.info("Received stop instruction. Stopping.") + return True except: logging.exception("An error occurred while" " checking packager track %r", track.name) @@ -435,3 +446,25 @@ def get_package_tracks(self): return self.package_tracks + + def read_instruction(self): + if not self.instructions_file: + return "" + try: + f = open(self.instructions_file) + except (IOError, OSError): + return "" + try: + return f.read().strip() + finally: + f.close() + self.clear_instruction() + + def clear_instruction(self, force=False): + if self.instructions_file and (not self.instructions_file_removed + or force): + util.writefile(self.instructions_file, "") + self.instructions_file_removed = True + + def should_stop(self): + return self.read_instruction() == "stop" diff -r 6ed1c881ee1b -r 3ed079a7174a treepkg/readconfig.py --- a/treepkg/readconfig.py Tue Sep 11 13:58:28 2007 +0000 +++ b/treepkg/readconfig.py Tue Sep 11 17:24:56 2007 +0000 @@ -23,6 +23,7 @@ treepkg_desc = [ ("check_interval", int), + "instructions_file", ]