yellow team mailing list archive
-
yellow team
-
Mailing list archive
-
Message #00854
[Merge] lp:~bac/lpbuildbot/cleanup-testr into lp:~launchpad/lpbuildbot/public
Brad Crittenden has proposed merging lp:~bac/lpbuildbot/cleanup-testr into lp:~launchpad/lpbuildbot/public.
Requested reviews:
Launchpad Yellow Squad (yellow): code
For more details, see:
https://code.launchpad.net/~bac/lpbuildbot/cleanup-testr/+merge/106197
Add functionality at startup to clear out old run data from the testrepository directory. The init_testr script is the right place to do it.
I took the opportunity to rewrite the script in python which was faster than trying to do something mildly complicated in bash.
--
https://code.launchpad.net/~bac/lpbuildbot/cleanup-testr/+merge/106197
Your team Launchpad Yellow Squad is requested to review the proposed merge of lp:~bac/lpbuildbot/cleanup-testr into lp:~launchpad/lpbuildbot/public.
=== modified file 'master.cfg'
--- master.cfg 2012-05-08 12:06:48 +0000
+++ master.cfg 2012-05-17 14:07:23 +0000
@@ -92,11 +92,11 @@
description=['cleanup','previous','lxc','containers'],
descriptionDone=['cleaned','previous','lxc','containers']))
fac.addStep(transfer.FileDownload(
- mastersrc='scripts/init_testr.sh',
+ mastersrc='scripts/init_testr.py',
slavedest='init_testr.sh',
mode=0544))
fac.addStep(bzrbuildbot.shell.ShellCommand(
- command=['./init_testr.sh'],
+ command=['./init_testr.py'],
description=['initializing', 'testrepository'],
descriptionDone=['initialized', 'testrepository']))
# Make a temp dir, to work around bug 808557.
=== added file 'scripts/init_testr.py'
--- scripts/init_testr.py 1970-01-01 00:00:00 +0000
+++ scripts/init_testr.py 2012-05-17 14:07:23 +0000
@@ -0,0 +1,141 @@
+#!/usr/bin/python
+# Copyright 2012 Canonical Ltd. This software is licensed under the GNU
+# Affero General Public License version 3 (see the file LICENSE).
+"""
+Initialize testrepository, re-using the results from a previous run,
+if available.
+
+The results from a run will be stored in the directory above the
+current working directory and symlinked from the cwd.
+"""
+
+import os
+import subprocess
+import sys
+
+
+TESTR_DIR = ".testrepository"
+# Keep ten total runs, current run plus nine old ones.
+NUM_RESULTS_TO_KEEP = 9
+
+
+def run(cmd):
+ args = cmd.split()
+ process = subprocess.Popen(
+ args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ if process.returncode:
+ print "Error running '%s': %d" % (
+ cmd, process.returncode)
+ return process.returncode
+
+
+def is_result_file(fn):
+ """Result files are named as monotonically increasing integers.
+
+ >>> is_result_file('1')
+ True
+ >>> is_result_file('7up')
+ False
+ """
+ try:
+ int(fn)
+ except ValueError:
+ return False
+ return True
+
+
+def find_deletion_candidates(filenames, keepers=NUM_RESULTS_TO_KEEP):
+ """Given a set of files, find those that are result files that should be
+ deleted.
+
+ >>> find_deletion_candidates(['1','2','5','10','7','c','11'], keepers=1)
+ [1, 2, 5, 7, 10]
+ >>> find_deletion_candidates(['1','2','5','10','7','c','11'], keepers=4)
+ [1, 2]
+ >>> find_deletion_candidates(['1','2','5','10','7','c','11'], keepers=40)
+ []
+ """
+ results = sorted([int(fn) for fn in filenames if is_result_file(fn)])
+ return results[:-keepers]
+
+
+def remove_files(names, path):
+ """Given a list of file names and the path to them, remove the files.
+ Return a \n separated list of output messages.
+ >>> import tempfile
+ >>> def makefiles(names, path):
+ ... for n in names:
+ ... open(os.path.join(path, n), 'w').close()
+ >>> tempdir = tempfile.mkdtemp()
+ >>> print sorted(os.listdir(tempdir))
+ []
+ >>> filenames = ['1','2','3']
+ >>> makefiles(filenames, tempdir)
+ >>> print sorted(os.listdir(tempdir))
+ ['1', '2', '3']
+ >>> rc, msg = remove_files(filenames, tempdir)
+ >>> print rc
+ 0
+ >>> print msg
+ Removing 3 old testrepository runs
+ >>> print sorted(os.listdir(tempdir))
+ []
+ >>> makefiles(filenames, tempdir)
+ >>> rc, msg = remove_files(filenames + ['99'], tempdir)
+ >>> print rc
+ 1
+ >>> print msg # doctest:+ELLIPSIS
+ Removing 4 old testrepository runs
+ [Errno 2] No such file or directory:...
+ >>> os.rmdir(tempdir)
+ """
+ msg = []
+ rc = 0
+ if names:
+ msg.append("Removing %d old testrepository runs" % len(names))
+ for fn in names:
+ try:
+ filepath = os.path.join(path, str(fn))
+ os.unlink(filepath)
+ except OSError as e:
+ msg.append(str(e))
+ rc = 1
+ break
+ return rc, '\n'.join(msg)
+
+
+def main():
+ # If there is no .testrepository directory in the parent directory,
+ # make one. We keep it there so it will persist the launchpad directory
+ # being removed after a test run.
+ rc = 0
+ target_dir = os.path.join('..', TESTR_DIR)
+ if not os.path.exists(target_dir):
+ cwd = os.getcwd()
+ os.chdir('..')
+ rc = run('testr init')
+ if rc:
+ return rc
+ os.chdir(cwd)
+ # Create a symbolic link to the repository directory in the parent
+ # directory.
+ if not os.path.exists(TESTR_DIR):
+ cmd = 'ln -s %s' % target_dir
+ rc = run(cmd)
+ if rc:
+ return rc
+
+ # Each run of the slave will create a set of results in the testrepository
+ # directory. If we never clean up the old ones they will take up too much
+ # space. We'll keep a limited number and remove the rest.
+ files = os.listdir(target_dir)
+ goners = find_deletion_candidates(files)
+ rc, msg = remove_files(goners, target_dir)
+ if msg:
+ print msg
+ return rc
+
+
+if __name__ == '__main__':
+ sys.exit(main())
=== removed file 'scripts/init_testr.sh'
--- scripts/init_testr.sh 2012-04-02 18:52:40 +0000
+++ scripts/init_testr.sh 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-# Initialize testrepository, re-using the results from a previous run,
-# if available.
-
-# The results from a run will be stored in the directory above the
-# current working directory and symlinked from the cwd.
-
-# If there is no .testrepository directory in the parent directory,
-# make one.
-if [ ! -d '../.testrepository' ]]; then
- (cd ..; testr init)
-fi
-
-ln -s ../.testrepository/
Follow ups