Bug 707976 - Remove manifestdestiny from its old location in m-c and use that in testing/mozbase;r=ahal
authorJeff Hammel <jhammel@mozilla.com>
Fri, 07 Jun 2013 12:30:11 -0700
changeset 145909 b7d48e8170414f79ac688de30ca5b559f525240d
parent 145908 00c0970b6926c96363a3f595d3378adc81d1d276
child 145910 7266f50150f1a4a2555c1bcdf28a4faabadfb3ee
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs707976
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 707976 - Remove manifestdestiny from its old location in m-c and use that in testing/mozbase;r=ahal
build/Makefile.in
build/manifestparser.py
build/tests/filter-example.ini
build/tests/fleem
build/tests/include-example.ini
build/tests/include/bar.ini
build/tests/include/crash-handling
build/tests/include/flowers
build/tests/include/foo.ini
build/tests/mozmill-example.ini
build/tests/mozmill-restart-example.ini
build/tests/path-example.ini
build/tests/test.py
build/tests/test_expressionparser.txt
build/tests/test_manifestparser.txt
build/tests/test_testmanifest.txt
testing/mochitest/Makefile.in
testing/xpcshell/runxpcshelltests.py
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -73,20 +73,16 @@ endif
 
 # Put a useful .gdbinit in the bin directory, to be picked up automatically
 # by GDB when we debug executables there.
 # NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
 GDBINIT_FILES := $(topsrcdir)/.gdbinit
 GDBINIT_DEST = $(FINAL_TARGET)
 INSTALL_TARGETS += GDBINIT
 
-PYTHON_UNIT_TESTS := \
-  tests/test.py \
-  $(NULL)
-
 include $(topsrcdir)/config/rules.mk
 
 # we install to _leaktest/
 TARGET_DEPTH = ..
 include $(srcdir)/automation-build.mk
 
 _LEAKTEST_DIR = $(DEPTH)/_leaktest
 
deleted file mode 100644
--- a/build/manifestparser.py
+++ /dev/null
@@ -1,1079 +0,0 @@
-#!/usr/bin/env python
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-"""
-Mozilla universal manifest parser
-"""
-
-# this file lives at
-# http://hg.mozilla.org/automation/ManifestDestiny/raw-file/tip/manifestparser.py
-
-__all__ = ['read_ini', # .ini reader
-           'ManifestParser', 'TestManifest', 'convert', # manifest handling
-           'parse', 'ParseError', 'ExpressionParser'] # conditional expression parser
-
-import os
-import re
-import shutil
-import sys
-from fnmatch import fnmatch
-from optparse import OptionParser
-
-version = '0.5.3' # package version
-try:
-    from setuptools import setup
-except:
-    setup = None
-
-# we need relpath, but it is introduced in python 2.6
-# http://docs.python.org/library/os.path.html
-try:
-    relpath = os.path.relpath
-except AttributeError:
-    def relpath(path, start):
-        """
-        Return a relative version of a path
-        from /usr/lib/python2.6/posixpath.py
-        """
-
-        if not path:
-            raise ValueError("no path specified")
-
-        start_list = os.path.abspath(start).split(os.path.sep)
-        path_list = os.path.abspath(path).split(os.path.sep)
-
-        # Work out how much of the filepath is shared by start and path.
-        i = len(os.path.commonprefix([start_list, path_list]))
-
-        rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
-        if not rel_list:
-            return os.curdir
-        return os.path.join(*rel_list)
-
-# expr.py
-# from:
-# http://k0s.org/mozilla/hg/expressionparser
-# http://hg.mozilla.org/users/tmielczarek_mozilla.com/expressionparser
-
-# Implements a top-down parser/evaluator for simple boolean expressions.
-# ideas taken from http://effbot.org/zone/simple-top-down-parsing.htm
-#
-# Rough grammar:
-# expr := literal
-#       | '(' expr ')'
-#       | expr '&&' expr
-#       | expr '||' expr
-#       | expr '==' expr
-#       | expr '!=' expr
-# literal := BOOL
-#          | INT
-#          | STRING
-#          | IDENT
-# BOOL   := true|false
-# INT    := [0-9]+
-# STRING := "[^"]*"
-# IDENT  := [A-Za-z_]\w*
-
-# Identifiers take their values from a mapping dictionary passed as the second
-# argument.
-
-# Glossary (see above URL for details):
-# - nud: null denotation
-# - led: left detonation
-# - lbp: left binding power
-# - rbp: right binding power
-
-class ident_token(object):
-    def __init__(self, value):
-        self.value = value
-    def nud(self, parser):
-        # identifiers take their value from the value mappings passed
-        # to the parser
-        return parser.value(self.value)
-
-class literal_token(object):
-    def __init__(self, value):
-        self.value = value
-    def nud(self, parser):
-        return self.value
-
-class eq_op_token(object):
-    "=="
-    def led(self, parser, left):
-        return left == parser.expression(self.lbp)
-    
-class neq_op_token(object):
-    "!="
-    def led(self, parser, left):
-        return left != parser.expression(self.lbp)
-
-class not_op_token(object):
-    "!"
-    def nud(self, parser):
-        return not parser.expression()
-
-class and_op_token(object):
-    "&&"
-    def led(self, parser, left):
-        right = parser.expression(self.lbp)
-        return left and right
-    
-class or_op_token(object):
-    "||"
-    def led(self, parser, left):
-        right = parser.expression(self.lbp)
-        return left or right
-
-class lparen_token(object):
-    "("
-    def nud(self, parser):
-        expr = parser.expression()
-        parser.advance(rparen_token)
-        return expr
-
-class rparen_token(object):
-    ")"
-
-class end_token(object):
-    """always ends parsing"""
-
-### derived literal tokens
-
-class bool_token(literal_token):
-    def __init__(self, value):
-        value = {'true':True, 'false':False}[value]
-        literal_token.__init__(self, value)
-
-class int_token(literal_token):
-    def __init__(self, value):
-        literal_token.__init__(self, int(value))
-
-class string_token(literal_token):
-    def __init__(self, value):
-        literal_token.__init__(self, value[1:-1])
-
-precedence = [(end_token, rparen_token),
-              (or_op_token,),
-              (and_op_token,),
-              (eq_op_token, neq_op_token),
-              (lparen_token,),
-              ]
-for index, rank in enumerate(precedence):
-    for token in rank:
-        token.lbp = index # lbp = lowest left binding power
-
-class ParseError(Exception):
-    """errror parsing conditional expression"""
-
-class ExpressionParser(object):
-    def __init__(self, text, valuemapping, strict=False):
-        """
-        Initialize the parser with input |text|, and |valuemapping| as
-        a dict mapping identifier names to values.
-        """
-        self.text = text
-        self.valuemapping = valuemapping
-        self.strict = strict
-
-    def _tokenize(self):
-        """
-        Lex the input text into tokens and yield them in sequence.
-        """
-        # scanner callbacks
-        def bool_(scanner, t): return bool_token(t)
-        def identifier(scanner, t): return ident_token(t)
-        def integer(scanner, t): return int_token(t)
-        def eq(scanner, t): return eq_op_token()
-        def neq(scanner, t): return neq_op_token()
-        def or_(scanner, t): return or_op_token()
-        def and_(scanner, t): return and_op_token()
-        def lparen(scanner, t): return lparen_token()
-        def rparen(scanner, t): return rparen_token()
-        def string_(scanner, t): return string_token(t)
-        def not_(scanner, t): return not_op_token()
-
-        scanner = re.Scanner([
-            (r"true|false", bool_),
-            (r"[a-zA-Z_]\w*", identifier),
-            (r"[0-9]+", integer),
-            (r'("[^"]*")|(\'[^\']*\')', string_),
-            (r"==", eq),
-            (r"!=", neq),
-            (r"\|\|", or_),
-            (r"!", not_),
-            (r"&&", and_),
-            (r"\(", lparen),
-            (r"\)", rparen),
-            (r"\s+", None), # skip whitespace
-            ])
-        tokens, remainder = scanner.scan(self.text)
-        for t in tokens:
-            yield t
-        yield end_token()
-
-    def value(self, ident):
-        """
-        Look up the value of |ident| in the value mapping passed in the
-        constructor.
-        """
-        if self.strict:
-            return self.valuemapping[ident]
-        else:
-            return self.valuemapping.get(ident, None)
-
-    def advance(self, expected):
-        """
-        Assert that the next token is an instance of |expected|, and advance
-        to the next token.
-        """
-        if not isinstance(self.token, expected):
-            raise Exception, "Unexpected token!"
-        self.token = self.iter.next()
-        
-    def expression(self, rbp=0):
-        """
-        Parse and return the value of an expression until a token with
-        right binding power greater than rbp is encountered.
-        """
-        t = self.token
-        self.token = self.iter.next()
-        left = t.nud(self)
-        while rbp < self.token.lbp:
-            t = self.token
-            self.token = self.iter.next()
-            left = t.led(self, left)
-        return left
-
-    def parse(self):
-        """
-        Parse and return the value of the expression in the text
-        passed to the constructor. Raises a ParseError if the expression
-        could not be parsed.
-        """
-        try:
-            self.iter = self._tokenize()
-            self.token = self.iter.next()
-            return self.expression()
-        except:
-            raise ParseError("could not parse: %s; variables: %s" % (self.text, self.valuemapping))
-
-    __call__ = parse
-
-def parse(text, **values):
-    """
-    Parse and evaluate a boolean expression in |text|. Use |values| to look
-    up the value of identifiers referenced in the expression. Returns the final
-    value of the expression. A ParseError will be raised if parsing fails.
-    """
-    return ExpressionParser(text, values).parse()
-
-def normalize_path(path):
-    """normalize a relative path"""
-    if sys.platform.startswith('win'):
-        return path.replace('/', os.path.sep)
-    return path
-
-def denormalize_path(path):
-    """denormalize a relative path"""
-    if sys.platform.startswith('win'):
-        return path.replace(os.path.sep, '/')
-    return path
-    
-
-def read_ini(fp, variables=None, default='DEFAULT',
-             comments=';#', separators=('=', ':'),
-             strict=True):
-    """
-    read an .ini file and return a list of [(section, values)]
-    - fp : file pointer or path to read
-    - variables : default set of variables
-    - default : name of the section for the default section
-    - comments : characters that if they start a line denote a comment
-    - separators : strings that denote key, value separation in order
-    - strict : whether to be strict about parsing
-    """
-
-    if variables is None:
-        variables = {}
-
-    if isinstance(fp, basestring):
-        fp = file(fp)
-
-    sections = []
-    key = value = None
-    section_names = set([])
-
-    # read the lines
-    for line in fp.readlines():
-
-        stripped = line.strip()
-
-        # ignore blank lines
-        if not stripped:
-            # reset key and value to avoid continuation lines
-            key = value = None
-            continue
-
-        # ignore comment lines
-        if stripped[0] in comments:
-            continue
-
-        # check for a new section
-        if len(stripped) > 2 and stripped[0] == '[' and stripped[-1] == ']':
-            section = stripped[1:-1].strip()
-            key = value = None
-
-            # deal with DEFAULT section
-            if section.lower() == default.lower():
-                if strict:
-                    assert default not in section_names
-                section_names.add(default)
-                current_section = variables
-                continue
-
-            if strict:
-                # make sure this section doesn't already exist
-                assert section not in section_names
-
-            section_names.add(section)
-            current_section = {}
-            sections.append((section, current_section))
-            continue
-
-        # if there aren't any sections yet, something bad happen
-        if not section_names:
-            raise Exception('No sections found')
-
-        # (key, value) pair
-        for separator in separators:
-            if separator in stripped:
-                key, value = stripped.split(separator, 1)
-                key = key.strip()
-                value = value.strip()
-
-                if strict:
-                    # make sure this key isn't already in the section or empty
-                    assert key
-                    if current_section is not variables:
-                        assert key not in current_section
-
-                current_section[key] = value
-                break
-        else:
-            # continuation line ?
-            if line[0].isspace() and key:
-                value = '%s%s%s' % (value, os.linesep, stripped)
-                current_section[key] = value
-            else:
-                # something bad happen!
-                raise Exception("Not sure what you're trying to do")
-
-    # interpret the variables
-    def interpret_variables(global_dict, local_dict):
-        variables = global_dict.copy()
-        variables.update(local_dict)
-        return variables
-
-    sections = [(i, interpret_variables(variables, j)) for i, j in sections]
-    return sections
-
-
-### objects for parsing manifests
-
-class ManifestParser(object):
-    """read .ini manifests"""
-
-    ### methods for reading manifests
-
-    def __init__(self, manifests=(), defaults=None, strict=True):
-        self._defaults = defaults or {}
-        self.tests = []
-        self.strict = strict
-        self.rootdir = None
-        self.relativeRoot = None
-        if manifests:
-            self.read(*manifests)
-
-    def getRelativeRoot(self, root):
-        return root
-
-    def read(self, *filenames, **defaults):
-
-        # ensure all files exist
-        missing = [ filename for filename in filenames
-                    if not os.path.exists(filename) ]
-        if missing:
-            raise IOError('Missing files: %s' % ', '.join(missing))
-
-        # process each file
-        for filename in filenames:
-
-            # set the per file defaults
-            defaults = defaults.copy() or self._defaults.copy()
-            here = os.path.dirname(os.path.abspath(filename))
-            defaults['here'] = here
-
-            if self.rootdir is None:
-                # set the root directory
-                # == the directory of the first manifest given
-                self.rootdir = here
-
-            # read the configuration
-            sections = read_ini(fp=filename, variables=defaults, strict=self.strict)
-
-            # get the tests
-            for section, data in sections:
-
-                # a file to include
-                # TODO: keep track of included file structure:
-                # self.manifests = {'manifest.ini': 'relative/path.ini'}
-                if section.startswith('include:'):
-                    include_file = section.split('include:', 1)[-1]
-                    include_file = normalize_path(include_file)
-                    if not os.path.isabs(include_file):
-                        include_file = os.path.join(self.getRelativeRoot(here), include_file)
-                    if not os.path.exists(include_file):
-                        if self.strict:
-                            raise IOError("File '%s' does not exist" % include_file)
-                        else:
-                            continue
-                    include_defaults = data.copy()
-                    self.read(include_file, **include_defaults)
-                    continue
-
-                # otherwise an item
-                test = data
-                test['name'] = section
-                test['manifest'] = os.path.abspath(filename)
-
-                # determine the path
-                path = test.get('path', section)
-                if '://' not in path: # don't futz with URLs
-                    path = normalize_path(path)
-                    if not os.path.isabs(path):
-                        path = os.path.join(here, path)
-                test['path'] = path
-
-                # append the item
-                self.tests.append(test)
-
-    ### methods for querying manifests
-
-    def query(self, *checks, **kw):
-        """
-        general query function for tests
-        - checks : callable conditions to test if the test fulfills the query
-        """
-        tests = kw.get('tests', None)
-        if tests is None:
-            tests = self.tests
-        retval = []
-        for test in tests:
-            for check in checks:
-                if not check(test):
-                    break
-            else:
-                retval.append(test)
-        return retval
-
-    def get(self, _key=None, inverse=False, tags=None, tests=None, **kwargs):
-        # TODO: pass a dict instead of kwargs since you might hav
-        # e.g. 'inverse' as a key in the dict
-
-        # TODO: tags should just be part of kwargs with None values
-        # (None == any is kinda weird, but probably still better)
-
-        # fix up tags
-        if tags:
-            tags = set(tags)
-        else:
-            tags = set()
-
-        # make some check functions
-        if inverse:
-            has_tags = lambda test: not tags.intersection(test.keys())
-            def dict_query(test):
-                for key, value in kwargs.items():
-                    if test.get(key) == value:
-                        return False
-                return True
-        else:
-            has_tags = lambda test: tags.issubset(test.keys())
-            def dict_query(test):
-                for key, value in kwargs.items():
-                    if test.get(key) != value:
-                        return False
-                return True
-
-        # query the tests
-        tests = self.query(has_tags, dict_query, tests=tests)
-
-        # if a key is given, return only a list of that key
-        # useful for keys like 'name' or 'path'
-        if _key:
-            return [test[_key] for test in tests]
-
-        # return the tests
-        return tests
-
-    def missing(self, tests=None):
-        """return list of tests that do not exist on the filesystem"""
-        if tests is None:
-            tests = self.tests
-        return [test for test in tests
-                if not os.path.exists(test['path'])]
-
-    def manifests(self, tests=None):
-        """
-        return manifests in order in which they appear in the tests
-        """
-        if tests is None:
-            tests = self.tests
-        manifests = []
-        for test in tests:
-            manifest = test.get('manifest')
-            if not manifest:
-                continue
-            if manifest not in manifests:
-                manifests.append(manifest)
-        return manifests
-
-    ### methods for outputting from manifests
-
-    def write(self, fp=sys.stdout, rootdir=None,
-              global_tags=None, global_kwargs=None,
-              local_tags=None, local_kwargs=None):
-        """
-        write a manifest given a query
-        global and local options will be munged to do the query
-        globals will be written to the top of the file
-        locals (if given) will be written per test
-        """
-
-        # root directory
-        if rootdir is None:
-            rootdir = self.rootdir
-
-        # sanitize input
-        global_tags = global_tags or set()
-        local_tags = local_tags or set()
-        global_kwargs = global_kwargs or {}
-        local_kwargs = local_kwargs or {}
-        
-        # create the query
-        tags = set([])
-        tags.update(global_tags)
-        tags.update(local_tags)
-        kwargs = {}
-        kwargs.update(global_kwargs)
-        kwargs.update(local_kwargs)
-
-        # get matching tests
-        tests = self.get(tags=tags, **kwargs)
-
-        # print the .ini manifest
-        if global_tags or global_kwargs:
-            print >> fp, '[DEFAULT]'
-            for tag in global_tags:
-                print >> fp, '%s =' % tag
-            for key, value in global_kwargs.items():
-                print >> fp, '%s = %s' % (key, value)
-            print >> fp
-
-        for test in tests:
-            test = test.copy() # don't overwrite
-
-            path = test['name']
-            if not os.path.isabs(path):
-                path = denormalize_path(relpath(test['path'], self.rootdir))
-            print >> fp, '[%s]' % path
-          
-            # reserved keywords:
-            reserved = ['path', 'name', 'here', 'manifest']
-            for key in sorted(test.keys()):
-                if key in reserved:
-                    continue
-                if key in global_kwargs:
-                    continue
-                if key in global_tags and not test[key]:
-                    continue
-                print >> fp, '%s = %s' % (key, test[key])
-            print >> fp
-
-    def copy(self, directory, rootdir=None, *tags, **kwargs):
-        """
-        copy the manifests and associated tests
-        - directory : directory to copy to
-        - rootdir : root directory to copy to (if not given from manifests)
-        - tags : keywords the tests must have
-        - kwargs : key, values the tests must match
-        """
-        # XXX note that copy does *not* filter the tests out of the
-        # resulting manifest; it just stupidly copies them over.
-        # ideally, it would reread the manifests and filter out the
-        # tests that don't match *tags and **kwargs
-        
-        # destination
-        if not os.path.exists(directory):
-            os.path.makedirs(directory)
-        else:
-            # sanity check
-            assert os.path.isdir(directory)
-
-        # tests to copy
-        tests = self.get(tags=tags, **kwargs)
-        if not tests:
-            return # nothing to do!
-
-        # root directory
-        if rootdir is None:
-            rootdir = self.rootdir
-
-        # copy the manifests + tests
-        manifests = [relpath(manifest, rootdir) for manifest in self.manifests()]
-        for manifest in manifests:
-            destination = os.path.join(directory, manifest)
-            dirname = os.path.dirname(destination)
-            if not os.path.exists(dirname):
-                os.makedirs(dirname)
-            else:
-                # sanity check
-                assert os.path.isdir(dirname)
-            shutil.copy(os.path.join(rootdir, manifest), destination)
-        for test in tests:
-            if os.path.isabs(test['name']):
-                continue
-            source = test['path']
-            if not os.path.exists(source):
-                print >> sys.stderr, "Missing test: '%s' does not exist!" % source
-                continue
-                # TODO: should err on strict
-            destination = os.path.join(directory, relpath(test['path'], rootdir))
-            shutil.copy(source, destination)
-            # TODO: ensure that all of the tests are below the from_dir
-
-    def update(self, from_dir, rootdir=None, *tags, **kwargs):
-        """
-        update the tests as listed in a manifest from a directory
-        - from_dir : directory where the tests live
-        - rootdir : root directory to copy to (if not given from manifests)
-        - tags : keys the tests must have
-        - kwargs : key, values the tests must match
-        """
-    
-        # get the tests
-        tests = self.get(tags=tags, **kwargs)
-
-        # get the root directory
-        if not rootdir:
-            rootdir = self.rootdir
-
-        # copy them!
-        for test in tests:
-            if not os.path.isabs(test['name']):
-                _relpath = relpath(test['path'], rootdir)
-                source = os.path.join(from_dir, _relpath)
-                if not os.path.exists(source):
-                    # TODO err on strict
-                    print >> sys.stderr, "Missing test: '%s'; skipping" % test['name']
-                    continue
-                destination = os.path.join(rootdir, _relpath)
-                shutil.copy(source, destination)
-
-
-class TestManifest(ManifestParser):
-    """
-    apply logic to manifests;  this is your integration layer :)
-    specific harnesses may subclass from this if they need more logic
-    """
-
-    def filter(self, values, tests):
-        """
-        filter on a specific list tag, e.g.:
-        run-if.os = win linux
-        skip-if.os = mac
-        """
-
-        # tags:
-        run_tag = 'run-if'
-        skip_tag = 'skip-if'
-        fail_tag = 'fail-if'
-
-        # loop over test
-        for test in tests:
-            reason = None # reason to disable
-            
-            # tagged-values to run
-            if run_tag in test:
-                condition = test[run_tag]
-                if not parse(condition, **values):
-                    reason = '%s: %s' % (run_tag, condition)
-
-            # tagged-values to skip
-            if skip_tag in test:
-                condition = test[skip_tag]
-                if parse(condition, **values):
-                    reason = '%s: %s' % (skip_tag, condition)
-
-            # mark test as disabled if there's a reason
-            if reason:
-                test.setdefault('disabled', reason)        
-
-            # mark test as a fail if so indicated
-            if fail_tag in test:
-                condition = test[fail_tag]
-                if parse(condition, **values):
-                    test['expected'] = 'fail'
-
-    def active_tests(self, exists=True, disabled=True, **values):
-        """
-        - exists : return only existing tests
-        - disabled : whether to return disabled tests
-        - tags : keys and values to filter on (e.g. `os = linux mac`)
-        """
-
-        tests = [i.copy() for i in self.tests] # shallow copy
-
-        # mark all tests as passing unless indicated otherwise
-        for test in tests:
-            test['expected'] = test.get('expected', 'pass')
-        
-        # ignore tests that do not exist
-        if exists:
-            tests = [test for test in tests if os.path.exists(test['path'])]
-
-        # filter by tags
-        self.filter(values, tests)
-
-        # ignore disabled tests if specified
-        if not disabled:
-            tests = [test for test in tests
-                     if not 'disabled' in test]
-
-        # return active tests
-        return tests
-
-    def test_paths(self):
-        return [test['path'] for test in self.active_tests()]
-
-
-### utility function(s); probably belongs elsewhere
-
-def convert(directories, pattern=None, ignore=(), write=None):
-    """
-    convert directories to a simple manifest
-    """
-
-    retval = []
-    include = []
-    for directory in directories:
-        for dirpath, dirnames, filenames in os.walk(directory):
-
-            # filter out directory names
-            dirnames = [ i for i in dirnames if i not in ignore ]
-            dirnames.sort()
-
-            # reference only the subdirectory
-            _dirpath = dirpath
-            dirpath = dirpath.split(directory, 1)[-1].strip(os.path.sep)
-
-            if dirpath.split(os.path.sep)[0] in ignore:
-                continue
-
-            # filter by glob
-            if pattern:
-                filenames = [filename for filename in filenames
-                             if fnmatch(filename, pattern)]
-
-            filenames.sort()
-
-            # write a manifest for each directory
-            if write and (dirnames or filenames):
-                manifest = file(os.path.join(_dirpath, write), 'w')
-                for dirname in dirnames:
-                    print >> manifest, '[include:%s]' % os.path.join(dirname, write)
-                for filename in filenames:
-                    print >> manifest, '[%s]' % filename
-                manifest.close()
-
-            # add to the list
-            retval.extend([denormalize_path(os.path.join(dirpath, filename))
-                           for filename in filenames])
-
-    if write:
-        return # the manifests have already been written!
-  
-    retval.sort()
-    retval = ['[%s]' % filename for filename in retval]
-    return '\n'.join(retval)
-
-### command line attributes
-
-class ParserError(Exception):
-  """error for exceptions while parsing the command line"""
-
-def parse_args(_args):
-    """
-    parse and return:
-    --keys=value (or --key value)
-    -tags
-    args
-    """
-
-    # return values
-    _dict = {}
-    tags = []
-    args = []
-
-    # parse the arguments
-    key = None
-    for arg in _args:
-        if arg.startswith('---'):
-            raise ParserError("arguments should start with '-' or '--' only")
-        elif arg.startswith('--'):
-            if key:
-                raise ParserError("Key %s still open" % key)
-            key = arg[2:]
-            if '=' in key:
-                key, value = key.split('=', 1)
-                _dict[key] = value
-                key = None
-                continue
-        elif arg.startswith('-'):
-            if key:
-                raise ParserError("Key %s still open" % key)
-            tags.append(arg[1:])
-            continue
-        else:
-            if key:
-                _dict[key] = arg
-                continue
-            args.append(arg)
-
-    # return values
-    return (_dict, tags, args)
-
-
-### classes for subcommands
-
-class CLICommand(object):
-    usage = '%prog [options] command'
-    def __init__(self, parser):
-      self._parser = parser # master parser
-    def parser(self):
-      return OptionParser(usage=self.usage, description=self.__doc__,
-                          add_help_option=False)
-
-class Copy(CLICommand):
-    usage = '%prog [options] copy manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ...'
-    def __call__(self, options, args):
-      # parse the arguments
-      try:
-        kwargs, tags, args = parse_args(args)
-      except ParserError, e:
-        self._parser.error(e.message)
-
-      # make sure we have some manifests, otherwise it will
-      # be quite boring
-      if not len(args) == 2:
-        HelpCLI(self._parser)(options, ['copy'])
-        return
-
-      # read the manifests
-      # TODO: should probably ensure these exist here
-      manifests = ManifestParser()
-      manifests.read(args[0])
-
-      # print the resultant query
-      manifests.copy(args[1], None, *tags, **kwargs)
-
-
-class CreateCLI(CLICommand):
-    """
-    create a manifest from a list of directories
-    """
-    usage = '%prog [options] create directory <directory> <...>'
-
-    def parser(self):
-        parser = CLICommand.parser(self)
-        parser.add_option('-p', '--pattern', dest='pattern',
-                          help="glob pattern for files")
-        parser.add_option('-i', '--ignore', dest='ignore',
-                          default=[], action='append',
-                          help='directories to ignore')
-        parser.add_option('-w', '--in-place', dest='in_place',
-                          help='Write .ini files in place; filename to write to')
-        return parser
-
-    def __call__(self, _options, args):
-        parser = self.parser()
-        options, args = parser.parse_args(args)
-
-        # need some directories
-        if not len(args):
-            parser.print_usage()
-            return
-
-        # add the directories to the manifest
-        for arg in args:
-            assert os.path.exists(arg)
-            assert os.path.isdir(arg)
-            manifest = convert(args, pattern=options.pattern, ignore=options.ignore,
-                               write=options.in_place)
-        if manifest:
-            print manifest
-
-
-class WriteCLI(CLICommand):
-    """
-    write a manifest based on a query
-    """
-    usage = '%prog [options] write manifest <manifest> -tag1 -tag2 --key1=value1 --key2=value2 ...'
-    def __call__(self, options, args):
-
-        # parse the arguments
-        try:
-            kwargs, tags, args = parse_args(args)
-        except ParserError, e:
-            self._parser.error(e.message)
-
-        # make sure we have some manifests, otherwise it will
-        # be quite boring
-        if not args:
-            HelpCLI(self._parser)(options, ['write'])
-            return
-
-        # read the manifests
-        # TODO: should probably ensure these exist here
-        manifests = ManifestParser()
-        manifests.read(*args)
-
-        # print the resultant query
-        manifests.write(global_tags=tags, global_kwargs=kwargs)
-      
-
-class HelpCLI(CLICommand):
-    """
-    get help on a command
-    """
-    usage = '%prog [options] help [command]'
-
-    def __call__(self, options, args):
-        if len(args) == 1 and args[0] in commands:
-            commands[args[0]](self._parser).parser().print_help()
-        else:
-            self._parser.print_help()
-            print '\nCommands:'
-            for command in sorted(commands):
-                print '  %s : %s' % (command, commands[command].__doc__.strip())
-
-class SetupCLI(CLICommand):
-    """
-    setup using setuptools
-    """
-    # use setup.py from the repo when you want to distribute to python!
-    # otherwise setuptools will complain that it can't find setup.py
-    # and result in a useless package
-    
-    usage = '%prog [options] setup [setuptools options]'
-    
-    def __call__(self, options, args):
-        sys.argv = [sys.argv[0]] + args
-        assert setup is not None, "You must have setuptools installed to use SetupCLI"
-        here = os.path.dirname(os.path.abspath(__file__))
-        try:
-            filename = os.path.join(here, 'README.txt')
-            description = file(filename).read()
-        except:    
-            description = ''
-        os.chdir(here)
-
-        setup(name='ManifestDestiny',
-              version=version,
-              description="Universal manifests for Mozilla test harnesses",
-              long_description=description,
-              classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
-              keywords='mozilla manifests',
-              author='Jeff Hammel',
-              author_email='jhammel@mozilla.com',
-              url='https://wiki.mozilla.org/Auto-tools/Projects/ManifestDestiny',
-              license='MPL',
-              zip_safe=False,
-              py_modules=['manifestparser'],
-              install_requires=[
-                  # -*- Extra requirements: -*-
-                  ],
-              entry_points="""
-              [console_scripts]
-              manifestparser = manifestparser:main
-              """,
-              )
-
-
-class UpdateCLI(CLICommand):
-    """
-    update the tests as listed in a manifest from a directory
-    """
-    usage = '%prog [options] update manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ...'
-
-    def __call__(self, options, args):
-        # parse the arguments
-        try:
-            kwargs, tags, args = parse_args(args)
-        except ParserError, e:
-            self._parser.error(e.message)
-
-        # make sure we have some manifests, otherwise it will
-        # be quite boring
-        if not len(args) == 2:
-            HelpCLI(self._parser)(options, ['update'])
-            return
-
-        # read the manifests
-        # TODO: should probably ensure these exist here
-        manifests = ManifestParser()
-        manifests.read(args[0])
-
-        # print the resultant query
-        manifests.update(args[1], None, *tags, **kwargs)
-
-
-# command -> class mapping
-commands = { 'create': CreateCLI,
-             'help': HelpCLI,
-             'update': UpdateCLI,
-             'write': WriteCLI }
-if setup is not None:
-    commands['setup'] = SetupCLI
-
-def main(args=sys.argv[1:]):
-    """console_script entry point"""
-
-    # set up an option parser
-    usage = '%prog [options] [command] ...'
-    description = __doc__
-    parser = OptionParser(usage=usage, description=description)
-    parser.add_option('-s', '--strict', dest='strict',
-                      action='store_true', default=False,
-                      help='adhere strictly to errors')
-    parser.disable_interspersed_args()
-
-    options, args = parser.parse_args(args)
-
-    if not args:
-        HelpCLI(parser)(options, args)
-        parser.exit()
-
-    # get the command
-    command = args[0]
-    if command not in commands:
-        parser.error("Command must be one of %s (you gave '%s')" % (', '.join(sorted(commands.keys())), command))
-
-    handler = commands[command](parser)
-    handler(options, args[1:])
-
-if __name__ == '__main__':
-    main()
deleted file mode 100644
--- a/build/tests/filter-example.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-# illustrate test filters based on various categories
-
-[windowstest]
-run-if = os == 'win'
-
-[fleem]
-skip-if = os == 'mac'
-
-[linuxtest]
-skip-if = (os == 'mac') || (os == 'win')
-fail-if = toolkit == 'cocoa'
deleted file mode 100644
--- a/build/tests/fleem
+++ /dev/null
@@ -1,1 +0,0 @@
-# dummy spot for "fleem" test
deleted file mode 100644
--- a/build/tests/include-example.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[DEFAULT]
-foo = bar
-
-[include:include/bar.ini]
-
-[fleem]
-
-[include:include/foo.ini]
-red = roses
-blue = violets
-yellow = daffodils
\ No newline at end of file
deleted file mode 100644
--- a/build/tests/include/bar.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-foo = fleem
-
-[crash-handling]
\ No newline at end of file
deleted file mode 100644
--- a/build/tests/include/crash-handling
+++ /dev/null
@@ -1,1 +0,0 @@
-# dummy spot for "crash-handling" test
deleted file mode 100644
--- a/build/tests/include/flowers
+++ /dev/null
@@ -1,1 +0,0 @@
-# dummy spot for "flowers" test
deleted file mode 100644
--- a/build/tests/include/foo.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[DEFAULT]
-blue = ocean
-
-[flowers]
-yellow = submarine
\ No newline at end of file
deleted file mode 100644
--- a/build/tests/mozmill-example.ini
+++ /dev/null
@@ -1,80 +0,0 @@
-[testAddons/testDisableEnablePlugin.js]
-[testAddons/testGetAddons.js]
-[testAddons/testSearchAddons.js]
-[testAwesomeBar/testAccessLocationBar.js]
-[testAwesomeBar/testCheckItemHighlight.js]
-[testAwesomeBar/testEscapeAutocomplete.js]
-[testAwesomeBar/testFaviconInAutocomplete.js]
-[testAwesomeBar/testGoButton.js]
-[testAwesomeBar/testLocationBarSearches.js]
-[testAwesomeBar/testPasteLocationBar.js]
-[testAwesomeBar/testSuggestHistoryBookmarks.js]
-[testAwesomeBar/testVisibleItemsMax.js]
-[testBookmarks/testAddBookmarkToMenu.js]
-[testCookies/testDisableCookies.js]
-[testCookies/testEnableCookies.js]
-[testCookies/testRemoveAllCookies.js]
-[testCookies/testRemoveCookie.js]
-[testDownloading/testCloseDownloadManager.js]
-[testDownloading/testDownloadStates.js]
-[testDownloading/testOpenDownloadManager.js]
-[testFindInPage/testFindInPage.js]
-[testFormManager/testAutoCompleteOff.js]
-[testFormManager/testBasicFormCompletion.js]
-[testFormManager/testClearFormHistory.js]
-[testFormManager/testDisableFormManager.js]
-[testGeneral/testGoogleSuggestions.js]
-[testGeneral/testStopReloadButtons.js]
-[testInstallation/testBreakpadInstalled.js]
-[testLayout/testNavigateFTP.js]
-[testPasswordManager/testPasswordNotSaved.js]
-[testPasswordManager/testPasswordSavedAndDeleted.js]
-[testPopups/testPopupsAllowed.js]
-[testPopups/testPopupsBlocked.js]
-[testPreferences/testPaneRetention.js]
-[testPreferences/testPreferredLanguage.js]
-[testPreferences/testRestoreHomepageToDefault.js]
-[testPreferences/testSetToCurrentPage.js]
-[testPreferences/testSwitchPanes.js]
-[testPrivateBrowsing/testAboutPrivateBrowsing.js]
-[testPrivateBrowsing/testCloseWindow.js]
-[testPrivateBrowsing/testDisabledElements.js]
-[testPrivateBrowsing/testDisabledPermissions.js]
-[testPrivateBrowsing/testDownloadManagerClosed.js]
-[testPrivateBrowsing/testGeolocation.js]
-[testPrivateBrowsing/testStartStopPBMode.js]
-[testPrivateBrowsing/testTabRestoration.js]
-[testPrivateBrowsing/testTabsDismissedOnStop.js]
-[testSearch/testAddMozSearchProvider.js]
-[testSearch/testFocusAndSearch.js]
-[testSearch/testGetMoreSearchEngines.js]
-[testSearch/testOpenSearchAutodiscovery.js]
-[testSearch/testRemoveSearchEngine.js]
-[testSearch/testReorderSearchEngines.js]
-[testSearch/testRestoreDefaults.js]
-[testSearch/testSearchSelection.js]
-[testSearch/testSearchSuggestions.js]
-[testSecurity/testBlueLarry.js]
-[testSecurity/testDefaultPhishingEnabled.js]
-[testSecurity/testDefaultSecurityPrefs.js]
-[testSecurity/testEncryptedPageWarning.js]
-[testSecurity/testGreenLarry.js]
-[testSecurity/testGreyLarry.js]
-[testSecurity/testIdentityPopupOpenClose.js]
-[testSecurity/testSSLDisabledErrorPage.js]
-[testSecurity/testSafeBrowsingNotificationBar.js]
-[testSecurity/testSafeBrowsingWarningPages.js]
-[testSecurity/testSecurityInfoViaMoreInformation.js]
-[testSecurity/testSecurityNotification.js]
-[testSecurity/testSubmitUnencryptedInfoWarning.js]
-[testSecurity/testUnknownIssuer.js]
-[testSecurity/testUntrustedConnectionErrorPage.js]
-[testSessionStore/testUndoTabFromContextMenu.js]
-[testTabbedBrowsing/testBackgroundTabScrolling.js]
-[testTabbedBrowsing/testCloseTab.js]
-[testTabbedBrowsing/testNewTab.js]
-[testTabbedBrowsing/testNewWindow.js]
-[testTabbedBrowsing/testOpenInBackground.js]
-[testTabbedBrowsing/testOpenInForeground.js]
-[testTechnicalTools/testAccessPageInfoDialog.js]
-[testToolbar/testBackForwardButtons.js]
deleted file mode 100644
--- a/build/tests/mozmill-restart-example.ini
+++ /dev/null
@@ -1,26 +0,0 @@
-[DEFAULT]
-type = restart
-
-[restartTests/testExtensionInstallUninstall/test2.js]
-foo = bar
-
-[restartTests/testExtensionInstallUninstall/test1.js]
-foo = baz
-
-[restartTests/testExtensionInstallUninstall/test3.js]
-[restartTests/testSoftwareUpdateAutoProxy/test2.js]
-[restartTests/testSoftwareUpdateAutoProxy/test1.js]
-[restartTests/testMasterPassword/test1.js]
-[restartTests/testExtensionInstallGetAddons/test2.js]
-[restartTests/testExtensionInstallGetAddons/test1.js]
-[restartTests/testMultipleExtensionInstallation/test2.js]
-[restartTests/testMultipleExtensionInstallation/test1.js]
-[restartTests/testThemeInstallUninstall/test2.js]
-[restartTests/testThemeInstallUninstall/test1.js]
-[restartTests/testThemeInstallUninstall/test3.js]
-[restartTests/testDefaultBookmarks/test1.js]
-[softwareUpdate/testFallbackUpdate/test2.js]
-[softwareUpdate/testFallbackUpdate/test1.js]
-[softwareUpdate/testFallbackUpdate/test3.js]
-[softwareUpdate/testDirectUpdate/test2.js]
-[softwareUpdate/testDirectUpdate/test1.js]
deleted file mode 100644
--- a/build/tests/path-example.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[foo]
-path = fleem
\ No newline at end of file
deleted file mode 100755
--- a/build/tests/test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-"""tests for ManifestDestiny"""
-
-import doctest
-import os
-import sys
-from optparse import OptionParser
-
-def run_tests(raise_on_error=False, report_first=False):
-
-    # add results here
-    results = {}
-
-    # doctest arguments
-    directory = os.path.dirname(os.path.abspath(__file__))
-    extraglobs = {}
-    doctest_args = dict(extraglobs=extraglobs,
-                        module_relative=False,
-                        raise_on_error=raise_on_error)
-    if report_first:
-        doctest_args['optionflags'] = doctest.REPORT_ONLY_FIRST_FAILURE
-                                
-    # gather tests
-    directory = os.path.dirname(os.path.abspath(__file__))
-    tests =  [ test for test in os.listdir(directory)
-               if test.endswith('.txt') and test.startswith('test_')]
-    os.chdir(directory)
-
-    # run the tests
-    for test in tests:
-        try:
-            results[test] = doctest.testfile(test, **doctest_args)
-        except doctest.DocTestFailure, failure:
-            raise
-        except doctest.UnexpectedException, failure:
-            raise failure.exc_info[0], failure.exc_info[1], failure.exc_info[2]
-        
-    return results
-                                
-
-def main(args=sys.argv[1:]):
-
-    # parse command line options
-    parser = OptionParser(description=__doc__)
-    parser.add_option('--raise', dest='raise_on_error',
-                      default=False, action='store_true',
-                      help="raise on first error")
-    parser.add_option('--report-first', dest='report_first',
-                      default=False, action='store_true',
-                      help="report the first error only (all tests will still run)")
-    parser.add_option('-q', '--quiet', dest='quiet',
-                      default=False, action='store_true',
-                      help="minimize output")
-    options, args = parser.parse_args(args)
-    quiet = options.__dict__.pop('quiet')
-
-    # run the tests
-    results = run_tests(**options.__dict__)
-
-    # check for failure
-    failed = False
-    for result in results.values():
-        if result[0]: # failure count; http://docs.python.org/library/doctest.html#basic-api
-            failed = True
-            break
-    if failed:
-        sys.exit(1) # error
-    if not quiet:
-        # print results
-        print "manifestparser.py: All tests pass!"
-        for test in sorted(results.keys()):
-            result = results[test]
-            print "%s: failed=%s, attempted=%s" % (test, result[0], result[1])
-               
-if __name__ == '__main__':
-    main()
deleted file mode 100644
--- a/build/tests/test_expressionparser.txt
+++ /dev/null
@@ -1,120 +0,0 @@
-Test Expressionparser
-=====================
-
-Test the conditional expression parser.
-
-Boilerplate::
-
-    >>> from manifestparser import parse
-
-Test basic values::
-
-    >>> parse("1")
-    1
-    >>> parse("100")
-    100
-    >>> parse("true")
-    True
-    >>> parse("false")
-    False
-    >>> '' == parse('""')
-    True
-    >>> parse('"foo bar"')
-    'foo bar'
-    >>> parse("'foo bar'")
-    'foo bar'
-    >>> parse("foo", foo=1)
-    1
-    >>> parse("bar", bar=True)
-    True
-    >>> parse("abc123", abc123="xyz")
-    'xyz'
-
-Test equality::
-
-    >>> parse("true == true")
-    True
-    >>> parse("false == false")
-    True
-    >>> parse("false == false")
-    True
-    >>> parse("1 == 1")
-    True
-    >>> parse("100 == 100")
-    True
-    >>> parse('"some text" == "some text"')
-    True
-    >>> parse("true != false")
-    True
-    >>> parse("1 != 2")
-    True
-    >>> parse('"text" != "other text"')
-    True
-    >>> parse("foo == true", foo=True)
-    True
-    >>> parse("foo == 1", foo=1)
-    True
-    >>> parse('foo == "bar"', foo='bar')
-    True
-    >>> parse("foo == bar", foo=True, bar=True)
-    True
-    >>> parse("true == foo", foo=True)
-    True
-    >>> parse("foo != true", foo=False)
-    True
-    >>> parse("foo != 2", foo=1)
-    True
-    >>> parse('foo != "bar"', foo='abc')
-    True
-    >>> parse("foo != bar", foo=True, bar=False)
-    True
-    >>> parse("true != foo", foo=False)
-    True
-    >>> parse("!false")
-    True
-
-Test conjunctions::
-    
-    >>> parse("true && true")
-    True
-    >>> parse("true || false")
-    True
-    >>> parse("false || false")
-    False
-    >>> parse("true && false")
-    False
-    >>> parse("true || false && false")
-    True
-
-Test parentheses::
-    
-    >>> parse("(true)")
-    True
-    >>> parse("(10)")
-    10
-    >>> parse('("foo")')
-    'foo'
-    >>> parse("(foo)", foo=1)
-    1
-    >>> parse("(true == true)")
-    True
-    >>> parse("(true != false)")
-    True
-    >>> parse("(true && true)")
-    True
-    >>> parse("(true || false)")
-    True
-    >>> parse("(true && true || false)")
-    True
-    >>> parse("(true || false) && false")
-    False
-    >>> parse("(true || false) && true")
-    True
-    >>> parse("true && (true || false)")
-    True
-    >>> parse("true && (true || false)")
-    True
-    >>> parse("(true && false) || (true && (true || false))")
-    True
-        
-
deleted file mode 100644
--- a/build/tests/test_manifestparser.txt
+++ /dev/null
@@ -1,217 +0,0 @@
-Test the manifest parser
-========================
-
-You must have ManifestDestiny installed before running these tests.
-Run ``python manifestparser.py setup develop`` with setuptools installed.
-
-Ensure basic parser is sane::
-
-    >>> from manifestparser import ManifestParser
-    >>> parser = ManifestParser()
-    >>> parser.read('mozmill-example.ini')
-    >>> tests = parser.tests
-    >>> len(tests) == len(file('mozmill-example.ini').read().strip().splitlines())
-    True
-    
-Ensure that capitalization and order aren't an issue:
-
-    >>> lines = ['[%s]' % test['name'] for test in tests]
-    >>> lines == file('mozmill-example.ini').read().strip().splitlines()
-    True
-
-Show how you select subsets of tests:
-
-    >>> parser.read('mozmill-restart-example.ini')
-    >>> restart_tests = parser.get(type='restart')
-    >>> len(restart_tests) < len(parser.tests)
-    True
-    >>> import os
-    >>> len(restart_tests) == len(parser.get(manifest=os.path.abspath('mozmill-restart-example.ini')))
-    True
-    >>> assert not [test for test in restart_tests if test['manifest'] != os.path.abspath('mozmill-restart-example.ini')]
-    >>> parser.get('name', tags=['foo'])
-    ['restartTests/testExtensionInstallUninstall/test2.js', 'restartTests/testExtensionInstallUninstall/test1.js']
-    >>> parser.get('name', foo='bar')
-    ['restartTests/testExtensionInstallUninstall/test2.js']
-
-Illustrate how include works::
-
-    >>> parser = ManifestParser(manifests=('include-example.ini',))
-
-All of the tests should be included, in order::
-
-    >>> parser.get('name')
-    ['crash-handling', 'fleem', 'flowers']
-    >>> [(test['name'], os.path.basename(test['manifest'])) for test in parser.tests]
-    [('crash-handling', 'bar.ini'), ('fleem', 'include-example.ini'), ('flowers', 'foo.ini')]
-
-The manifests should be there too::
-
-    >>> len(parser.manifests())
-    3
-
-We're already in the root directory::
-
-    >>> os.getcwd() == parser.rootdir
-    True
-
-DEFAULT values should persist across includes, unless they're
-overwritten.  In this example, include-example.ini sets foo=bar, but
-its overridden to fleem in bar.ini::
-
-    >>> parser.get('name', foo='bar')
-    ['fleem', 'flowers']
-    >>> parser.get('name', foo='fleem')
-    ['crash-handling']
-
-Passing parameters in the include section allows defining variables in
-the submodule scope:
-
-    >>> parser.get('name', tags=['red'])
-    ['flowers']
-
-However, this should be overridable from the DEFAULT section in the
-included file and that overridable via the key directly connected to
-the test::
-
-    >>> parser.get(name='flowers')[0]['blue']
-    'ocean'
-    >>> parser.get(name='flowers')[0]['yellow']
-    'submarine'
-
-You can query multiple times if you need to::
-
-    >>> flowers = parser.get(foo='bar')
-    >>> len(flowers)
-    2
-    >>> roses = parser.get(tests=flowers, red='roses')
-
-Using the inverse flag should invert the set of tests returned::
-
-    >>> parser.get('name', inverse=True, tags=['red'])
-    ['crash-handling', 'fleem']
-
-All of the included tests actually exist::
-
-    >>> [i['name'] for i in parser.missing()]
-    []
-
-Write the output to a manifest:
-
-    >>> from StringIO import StringIO
-    >>> buffer = StringIO()
-    >>> parser.write(fp=buffer, global_kwargs={'foo': 'bar'})
-    >>> buffer.getvalue().strip()
-    '[DEFAULT]\nfoo = bar\n\n[fleem]\n\n[include/flowers]\nblue = ocean\nred = roses\nyellow = submarine'
-
-Test our ability to convert a static directory structure to a
-manifest. First, stub out a directory with files in it::
-
-    >>> import shutil, tempfile
-    >>> def create_stub():
-    ...     directory = tempfile.mkdtemp()
-    ...     for i in 'foo', 'bar', 'fleem':
-    ...         file(os.path.join(directory, i), 'w').write(i)
-    ...     subdir = os.path.join(directory, 'subdir')
-    ...     os.mkdir(subdir)
-    ...     file(os.path.join(subdir, 'subfile'), 'w').write('baz')
-    ...     return directory
-    >>> stub = create_stub()
-    >>> os.path.exists(stub) and os.path.isdir(stub)
-    True
-
-Make a manifest for it::
-
-    >>> from manifestparser import convert
-    >>> print convert([stub])
-    [bar]
-    [fleem]
-    [foo]
-    [subdir/subfile]
-    >>> shutil.rmtree(stub)
-
-Now do the same thing but keep the manifests in place::
-
-    >>> stub = create_stub()
-    >>> convert([stub], write='manifest.ini')
-    >>> sorted(os.listdir(stub))
-    ['bar', 'fleem', 'foo', 'manifest.ini', 'subdir']
-    >>> parser = ManifestParser()
-    >>> parser.read(os.path.join(stub, 'manifest.ini'))
-    >>> [i['name'] for i in parser.tests]
-    ['subfile', 'bar', 'fleem', 'foo']
-    >>> parser = ManifestParser()
-    >>> parser.read(os.path.join(stub, 'subdir', 'manifest.ini'))
-    >>> len(parser.tests)
-    1
-    >>> parser.tests[0]['name']
-    'subfile'
-    >>> shutil.rmtree(stub)
-
-Test our ability to copy a set of manifests::
-
-    >>> tempdir = tempfile.mkdtemp()
-    >>> manifest = ManifestParser(manifests=('include-example.ini',))
-    >>> manifest.copy(tempdir)
-    >>> sorted(os.listdir(tempdir))
-    ['fleem', 'include', 'include-example.ini']
-    >>> sorted(os.listdir(os.path.join(tempdir, 'include')))
-    ['bar.ini', 'crash-handling', 'flowers', 'foo.ini']
-    >>> from_manifest = ManifestParser(manifests=('include-example.ini',))
-    >>> to_manifest = os.path.join(tempdir, 'include-example.ini')
-    >>> to_manifest = ManifestParser(manifests=(to_manifest,))
-    >>> to_manifest.get('name') == from_manifest.get('name')
-    True
-    >>> shutil.rmtree(tempdir)
-
-Test our ability to update tests from a manifest and a directory of
-files::
-
-    >>> tempdir = tempfile.mkdtemp()
-    >>> for i in range(10):
-    ...     file(os.path.join(tempdir, str(i)), 'w').write(str(i))
-
-First, make a manifest::
-
-    >>> manifest = convert([tempdir])
-    >>> newtempdir = tempfile.mkdtemp()
-    >>> manifest_file = os.path.join(newtempdir, 'manifest.ini')
-    >>> file(manifest_file,'w').write(manifest)
-    >>> manifest = ManifestParser(manifests=(manifest_file,))
-    >>> manifest.get('name') == [str(i) for i in range(10)]
-    True
-
-All of the tests are initially missing::
-
-    >>> [i['name'] for i in manifest.missing()] == [str(i) for i in range(10)]
-    True
-
-But then we copy one over::
-
-    >>> manifest.get('name', name='1')
-    ['1']
-    >>> manifest.update(tempdir, name='1')
-    >>> sorted(os.listdir(newtempdir))
-    ['1', 'manifest.ini']
-
-Update that one file and copy all the "tests"::
-   
-    >>> file(os.path.join(tempdir, '1'), 'w').write('secret door')
-    >>> manifest.update(tempdir)
-    >>> sorted(os.listdir(newtempdir))
-    ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'manifest.ini']
-    >>> file(os.path.join(newtempdir, '1')).read().strip()
-    'secret door'
-
-Clean up::
-
-    >>> shutil.rmtree(tempdir)
-    >>> shutil.rmtree(newtempdir)
-
-You can override the path in the section too.  This shows that you can
-use a relative path::
-
-    >>> manifest = ManifestParser(manifests=('path-example.ini',))
-    >>> manifest.tests[0]['path'] == os.path.abspath('fleem')
-    True
-
deleted file mode 100644
--- a/build/tests/test_testmanifest.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Test the Test Manifest
-======================
-
-Boilerplate::
-
-    >>> import os
-
-Test filtering based on platform::
-
-    >>> from manifestparser import TestManifest
-    >>> manifest = TestManifest(manifests=('filter-example.ini',))
-    >>> [i['name'] for i in manifest.active_tests(os='win', disabled=False, exists=False)]
-    ['windowstest', 'fleem']
-    >>> [i['name'] for i in manifest.active_tests(os='linux', disabled=False, exists=False)]
-    ['fleem', 'linuxtest']
-
-Look for existing tests.  There is only one::
-
-    >>> [i['name'] for i in manifest.active_tests()]
-    ['fleem']
-
-You should be able to expect failures::
-
-    >>> last_test = manifest.active_tests(exists=False, toolkit='gtk2')[-1]
-    >>> last_test['name']
-    'linuxtest'
-    >>> last_test['expected']
-    'pass'
-    >>> last_test = manifest.active_tests(exists=False, toolkit='cocoa')[-1]
-    >>> last_test['expected']
-    'fail'
-
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -35,20 +35,20 @@ include $(topsrcdir)/build/automation-bu
 		automation.py \
 		runtestsb2g.py \
 		runtestsremote.py \
 		runtestsvmware.py \
 		manifest.webapp \
 		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
 		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
 		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
+		$(topsrcdir)/testing/mozbase/manifestdestiny/manifestparser/manifestparser.py \
 		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/droid.py \
 		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/Zeroconf.py \
 		$(topsrcdir)/build/automationutils.py \
-		$(topsrcdir)/build/manifestparser.py \
 		$(topsrcdir)/build/mobile/remoteautomation.py \
 		$(topsrcdir)/build/mobile/b2gautomation.py \
 		gen_template.pl \
 		server.js \
 		harness-overlay.xul \
 		harness.xul \
 		browser-test-overlay.xul \
 		browser-test.js \
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -6,46 +6,47 @@
 
 import re, sys, os, os.path, logging, shutil, signal, math, time, traceback
 import xml.dom.minidom
 from glob import glob
 from optparse import OptionParser
 from subprocess import Popen, PIPE, STDOUT
 from tempfile import mkdtemp, gettempdir
 from threading import Timer
-import manifestparser
 import mozinfo
 import random
 import socket
 import time
 
 from automation import Automation, getGlobalLog, resetGlobalLog
 from automationutils import *
 
 HARNESS_TIMEOUT = 5 * 60
 
 # --------------------------------------------------------------
 # TODO: this is a hack for mozbase without virtualenv, remove with bug 849900
 #
 here = os.path.dirname(__file__)
 mozbase = os.path.realpath(os.path.join(os.path.dirname(here), 'mozbase'))
 
-try:
-    import mozcrash
-except:
-    deps = ['mozcrash',
-            'mozfile',
-            'mozlog']
-    for dep in deps:
-        module = os.path.join(mozbase, dep)
-        if module not in sys.path:
-            sys.path.append(module)
-    import mozcrash
+# hand enumerate our own deps
+modules = [('mozcrash', ['mozcrash', 'mozfile', 'mozlog']),
+           ('manifestparser', ['manifestdestiny'])]
+
+for module, deps in modules:
+    try:
+        globals()[module] = __import__(module)
+    except ImportError:
+        for dep in deps:
+            module_path = os.path.join(mozbase, dep)
+            if module_path not in sys.path:
+                sys.path.append(module_path)
+        globals()[module] = __import__(module)
+
 # ---------------------------------------------------------------
-
 #TODO: replace this with json.loads when Python 2.6 is required.
 def parse_json(j):
     """
     Awful hack to parse a restricted subset of JSON strings into Python dicts.
     """
     return eval(j, {'true':True,'false':False,'null':None})
 
 """ Control-C handling """