chiark / gitweb /
tmpdir: use append, not assignment, for xenv
[autopkgtest.git] / runner / adt-run
index 4b64ce87f23b1ee194bcf4004a1b7f4a585e6ebd..47036edbc912f9cb8703b79363cfdb2b2d6270c7 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.4
+#!/usr/bin/python2.6
 #
 # adt-run is part of autopkgtest
 # autopkgtest is a tool for testing Debian binary packages
@@ -40,15 +40,23 @@ import copy
 from optparse import OptionParser
 signal.signal(signal.SIGINT, signal.SIG_DFL) # undo stupid Python SIGINT thing
 
+try: our_base = os.environ['AUTOPKGTEST_BASE']+'/lib'
+except KeyError: our_base = '/usr/share/autopkgtest/python';
+sys.path.insert(1, our_base)
+
+from Autopkgtest import *
+
 #---------- global variables
 
-tmpdir = None          # pathstring on host
+tmp = None             # pathstring on host
 testbed = None         # Testbed
 errorcode = 0          # exit status that we are going to use
 timeouts = { 'short':100, 'install':3000, 'test':10000, 'build':100000 }
 binaries = None                # Binaries (.debs we have registered)
 build_essential = ["build-essential"]
 paths = []
+os.putenv("APT_LISTBUGS_FRONTEND", "none")    # do not consider using apt-listbugs
+os.putenv("APT_LISTCHANGES_FRONTEND", "none") # do not consider using apt-listchanges
 
 #---------- output handling
 #
@@ -255,7 +263,7 @@ class AutoFile:
        xtra = ''
        if p.spec is not None:
                xtra = ' spec[%s]=%s' % (p.spec, getattr(p,'spec_tb',None))
-       raise ("internal error: %s (%s)" % (how, str(p)))
+       raise Exception("internal error: %s (%s)" % (how, str(p)))
 
  def _ensure_path(p, tbp):
        if p.path[tbp] is None:
@@ -263,7 +271,7 @@ class AutoFile:
                        p._debug('tmp-parent %s...' % 'HT'[tbp])
                        TemporaryDir(os.path.dirname(p.what)).write(tbp)
                if not tbp:
-                       p.path[tbp] = tmpdir+'/'+p.what
+                       p.path[tbp] = tmp+'/'+p.what
                else:
                        p.ephem[tbp] = True
                        p.path[tbp] = testbed.scratch.path[True]+'/'+p.what
@@ -568,8 +576,8 @@ def parse_args():
        pa('--set-lang', dest='set_lang', action='store', metavar='LANGVAL',
                help='set LANG on testbed to LANGVAL', default='C')
 
-       pa('','--tmp-dir',              type='string', dest='tmpdir',
-               help='write temporary files to TMPDIR, emptying it'
+       pa('','--tmp-dir',              type='string', dest='tmp',
+               help='write temporary files to TMP, emptying it'
                     ' beforehand and leaving it behind at the end')
        pa('','--log-file',             type='string', dest='logfile',
                help='write the log LOGFILE, emptying it beforehand,'
@@ -589,7 +597,7 @@ def parse_args():
                help='run tests as USER (needs root on testbed)')
        pa('','--gain-root',            type='string', dest='gainroot',
                help='prefix debian/rules binary with GAINROOT')
-       pa('-q', '--quiet', action='store_false', dest='quiet', default=False);
+       pa('-q', '--quiet', action='store_true', dest='quiet', default=False);
        pa('-d', '--debug', action='count', dest='debuglevel', default=0);
        pa('','--gnupg-home',           type='string', dest='gnupghome',
                default='~/.autopkgtest/gpg',
@@ -638,7 +646,7 @@ def parse_args():
                elif type(act) == str:
                        act = (act,act)
                else:
-                       raise ("unknown action in list `%s' having"
+                       raise Exception("unknown action in list `%s' having"
                              " type `%s'" % (act, type(act)))
                (pathstr, kindpath) = act
 
@@ -666,21 +674,21 @@ def parse_args():
                opts.actions.append(Action(kind, af, arghandling, what))
 
 def setup_trace():
-       global trace_stream, tmpdir, summary_stream
+       global trace_stream, tmp, summary_stream
 
-       if opts.tmpdir is not None:
-               rmtree('tmpdir(specified)',opts.tmpdir)
-               mkdir_okexist(opts.tmpdir, 0700)
-               tmpdir = opts.tmpdir
+       if opts.tmp is not None:
+               rmtree('tmp(specified)',opts.tmp)
+               mkdir_okexist(opts.tmp, 0700)
+               tmp = opts.tmp
        else:
-               assert(tmpdir is None)
-               tmpdir = tempfile.mkdtemp()
+               assert(tmp is None)
+               tmp = tempfile.mkdtemp()
 
        if opts.logfile is None:
                if opts.output_dir is not None and opts.output_dir.spec_tbp:
                        opts.logfile = opts.output_dir.spec + '/log'
-               elif opts.tmpdir is not None:
-                       opts.logfile = opts.tmpdir + '/log'
+               elif opts.tmp is not None:
+                       opts.logfile = opts.tmp + '/log'
        if opts.logfile is not None:
                trace_stream = open(opts.logfile, 'w', 0)
        if opts.summary is not None:
@@ -782,17 +790,12 @@ class Testbed:
        if len(pec) < 1: tb.bomb('too few results from print-execute-command')
        cmdl = map(urllib.unquote, pec[0].split(','))
 
-       shellquote_re = regexp.compile('"')
-       def shellquote_arg(s): return "'" + shellquote_re.sub(r"'\''", s) + "'"
-       def shellquote_cmdl(l): return ' '.join(map(shellquote_arg,l))
-
        tb._debug('cmdl = %s' % (`cmdl`))
 
        tb.ec_auxverbscript = TemporaryFile('satdep-auxverb')
        print >>open(tb.ec_auxverbscript.write(),'w'), (
 '''#!/bin/sh
-set -ex
-echo >&2 ": $*"
+set -e
 if [ $# = 2 ] && [ "x$1" = xdpkg-architecture ] && [ "x$2" = x-qDEB_HOST_ARCH ]; then
        # This is a pretty nasty hack.  Hopefully it can go away
        #  eventually.  See #635763.
@@ -813,6 +816,14 @@ exec '''+shellquote_cmdl(cmdl)+' "$@"'+"\n"
        if rc:
                pstderr("\n" "warning: failed to restore"
                        " testbed apt cache, exit code %d" % rc)
+       what = 'aptconf-reset'
+       cmdl = ['rm','-f','/etc/apt/apt.conf.d/90autopkgtest',
+               '/etc/apt/sources.list.d/autopkgtest.list',
+               '/etc/apt/preferences.d/90autopkgtest']
+       rc = tb.execute(what, cmdl, kind='install')
+       if rc:
+               pstderr("\n" "warning: failed to reset changes"
+                       " made to testbed apt configuration, exit code %d" % rc)
        tb._need_reset_apt = False
  def close(tb):
        tb._debug('close, scratch=%s' % tb.scratch)
@@ -907,7 +918,7 @@ exec '''+shellquote_cmdl(cmdl)+' "$@"'+"\n"
        return rl[0]
  def execute(tb, what, cmdl,
                si='/dev/null', so='/dev/null', se=None, cwd=None,
-               script=False, tmpdir=None, kind='short'):
+               script=False, xenv=[], kind='short'):
        # Options for script:
        #   False - do not call debug_subprocess, no synch. reporting required
        #   None or string - call debug_subprocess with that value,
@@ -942,7 +953,7 @@ exec '''+shellquote_cmdl(cmdl)+' "$@"'+"\n"
                cmdl.append('timeout=%d' % timeout)
 
        if xdump is not None and 'execute-debug' in tb.caps: cmdl += [xdump]
-       if tmpdir is not None: cmdl.append('env=TMPDIR=%s' % tmpdir)
+       for e in xenv: cmdl.append('env=%s' % e)
        if kind=='install': cmdl.append('env=DEBIAN_FRONTEND=noninteractive')
        if opts.set_lang is not False:
                cmdl.append('env=LANG=%s' % opts.set_lang)
@@ -1012,15 +1023,16 @@ class Restriction:
  def __init__(r,rname,base): pass
 
 class Restriction_rw_build_tree(Restriction): pass
+class Restriction_build_needed(Restriction): pass
 class Restriction_breaks_testbed(Restriction):
  def __init__(r, rname, base):
-       if 'revert' not in testbed.caps:
-               raise Unsupported(f.lno,
-                       'Test breaks testbed but testbed cannot revert')
+       if 'revert-full-system' not in testbed.caps:
+               raise Unsupported(-1,
+       'Test breaks testbed but testbed does not advertise revert-full-system')
 class Restriction_needs_root(Restriction):
  def __init__(r, rname, base):
        if 'root-on-testbed' not in testbed.caps:
-               raise Unsupported(f.lno,
+               raise Unsupported(-1,
                        'Test needs root on testbed which is not available')
 
 class Field_Restrictions(FieldBase):
@@ -1050,7 +1062,7 @@ class Field_Tests(FieldIgnore): pass
 
 class Field_Depends(FieldBase):
  def parse(f):
-       print >>sys.stderr, "Field_Depends:", `f.stz`, `f.base`, `f.tnames`, `f.vl`
+       debug("Field_DependS: %s %s %s %s" % (f.stz, f.base, f.tnames, f.vl), 2)
        dl = map(lambda x: x.strip(),
                flatten(map(lambda (lno, v): v.split(','), f.vl)))
        re = regexp.compile('[^-.+:~0-9a-z()<>=*@]')
@@ -1114,9 +1126,9 @@ class Test:
                        dn.append(d)
                else:
                        for (pkg,bin) in t.act.binaries:
-                               d = d.replace('@',pkg)
-                               t._debug('  synthesised dependency '+d)
-                               dn.append(d)
+                               dp = d.replace('@',pkg)
+                               t._debug('  synthesised dependency '+dp)
+                               dn.append(dp)
        testbed.prepare(dn)
  def run(t, tree):
        t._debug('[----------------------------------------')
@@ -1136,29 +1148,30 @@ class Test:
        se = stdouterr('stderr')
 
        tf = af.read(True)
-       tmpdir = None
+       xenv = []
 
        rc = testbed.execute('testchmod-'+t.what, ['chmod','+x','--',tf])
        if rc: bomb('failed to chmod +x %s' % tf)
 
        if 'needs-root' not in t.restriction_names and opts.user is not None:
                tfl = ['su',opts.user,'-c',tf]
-               tmpdir = '%s%s-tmpdir' % (testbed.scratch.read(True), t.what)
+               testtmp = '%s%s-testtmp' % (testbed.scratch.read(True), t.what)
                script = 'rm -rf -- "$1"; mkdir -- "$1"'
                if opts.user:
                        script += '; chown %s "$1"' % opts.user
                        if 'rw-build-tree' in t.restriction_names:
                                script += '; chown -R %s "$2"' % opts.user
+               xenv.append('TMPDIR=%s' % testtmp)
                rc = testbed.execute('mktmpdir-'+t.what,
-                       ['sh','-xec',script,'x',tmpdir,tree.read(True)])
-               if rc: bomb("could not create test tmpdir `%s', exit code %d"
-                               % (tmpdir, rc))
+                       ['sh','-xec',script,'x',xenv=xenv,tree.read(True)])
+               if rc: bomb("could not create test tmp `%s', exit code %d"
+                               % (testtmp, rc))
        else:
                tfl = [tf]
 
        rc = testbed.execute('test-'+t.what, tfl,
                so=so.write(True), se=se.write(True), cwd=tree.read(True),
-               tmpdir=tmpdir, kind='test')
+               xenv=xenv, kind='test')
 
        so_read = so.read()
        se_read = se.read()
@@ -1202,19 +1215,22 @@ def read_control(act, tree, control_override):
                return []
 
        lno = 0
-       def badctrl(m): act.bomb('tests/control line %d: %s' % (lno, m))
-       stz = None      # stz[field_name][index] = (lno, value)
+       def badctrl(m): testbed.bomb('tests/control line %d: %s' % (lno, m))
+       stz = { }       # stz[field_name][index] = (lno, value)
                        # special field names:
                        # stz[' lno'] = number
                        # stz[' tests'] = list of Test objects
+                       # empty dictionary means we're between stanzas
+       def in_stanza(stz):
+               return stz.has_key(' lno')
        def end_stanza(stz):
-               if stz is None: return
+               if not in_stanza(stz): return
                stz[' errs'] = 0
-               stanzas.append(stz)
-               stz = None
+               stanzas.append(stz.copy())
+               stz.clear()
                hcurrent = None
 
-       initre = regexp.compile('([A-Z][-0-9a-z]*)\s*\:\s*(.*)$')
+       initre = regexp.compile('([A-Z][-0-9a-zA-Z]*)\s*\:\s*(.*)$')
        while 1:
                l = control.readline()
                if not l: break
@@ -1226,7 +1242,7 @@ def read_control(act, tree, control_override):
                if initmat:
                        (fname, l) = initmat.groups()
                        fname = string.capwords(fname)
-                       if stz is None:
+                       if not in_stanza(stz):
                                stz = { ' lno': lno, ' tests': [] }
                        if not stz.has_key(fname): stz[fname] = [ ]
                        hcurrent = stz[fname]
@@ -1297,8 +1313,8 @@ def cleanup():
                if testbed is not None:
                        testbed.reset_apt()
                        testbed.stop()
-               if opts.tmpdir is None and tmpdir is not None:
-                       rmtree('tmpdir', tmpdir)
+               if opts.tmp is None and tmp is not None:
+                       rmtree('tmp', tmp)
                if trace_stream is not None:
                        trace_stream.close()
                        trace_stream = None
@@ -1329,7 +1345,7 @@ class Binaries:
        ok = False
 
        if opts.gnupghome is None:
-               opts.gnupghome = tmpdir+'/gnupg'
+               opts.gnupghome = tmp+'/gnupg'
 
        b._debug('initialising')
        try:
@@ -1663,12 +1679,8 @@ def build_source(act, control_override):
                stanzas = read_control(act, result_pwd_af, control_override)
                for stanza in stanzas:
                        for t in stanza[' tests']:
-                               if 'no-build-needed' not in t.feature_names:
+                               if 'build-needed' in t.restriction_names:
                                        build_needed('test %s' % t.tname)
-                               for d in t.depends:
-                                       if '@' in d:
-                                               build_needed('test %s '
-                                                'dependency %s' % (t.tname,d))
 
                debug_b('build not needed')
                built = False
@@ -1819,7 +1831,7 @@ def process_actions():
 
 def main():
        global testbed
-       global tmpdir
+       global tmp
        try:
                parse_args()
        except SystemExit, se: