181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org"""
281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgTestCmd.py:  a testing framework for commands and scripts.
381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCmd module provides a framework for portable automated testing
581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgof executable commands and scripts (in any language, not just Python),
681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgespecially commands and scripts that require file system interaction.
781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgIn addition to running tests and evaluating conditions, the TestCmd
981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgmodule manages and cleans up one or more temporary workspace
1081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdirectories, and provides methods for creating files and directories in
1181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgthose workspace directories from in-line data, here-documents), allowing
1281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtests to be completely self-contained.
1381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgA TestCmd environment object is created via the usual invocation:
1581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCmd
1781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd()
1881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThere are a bunch of keyword arguments available at instantiation:
2081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
2181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(description = 'string',
2281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           program = 'program_or_script_to_test',
2381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           interpreter = 'script_interpreter',
2481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           workdir = 'prefix',
2581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           subdir = 'subdir',
2681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           verbose = Boolean,
2781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           match = default_match_function,
2881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           diff = default_diff_function,
2981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           combine = Boolean)
3081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThere are a bunch of methods that let you do different things:
3281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.verbose_set(1)
3481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.description_set('string')
3681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.program_set('program_or_script_to_test')
3881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.interpreter_set('script_interpreter')
4081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.interpreter_set(['script_interpreter', 'arg'])
4181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.workdir_set('prefix')
4381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.workdir_set('')
4481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.workpath('file')
4681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.workpath('subdir', 'file')
4781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.subdir('subdir', ...)
4981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
5081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.rmdir('subdir', ...)
5181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
5281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.write('file', "contents\n")
5381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.write(['subdir', 'file'], "contents\n")
5481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
5581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.read('file')
5681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.read(['subdir', 'file'])
5781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.read('file', mode)
5881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.read(['subdir', 'file'], mode)
5981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.writable('dir', 1)
6181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.writable('dir', None)
6281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.preserve(condition, ...)
6481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.cleanup(condition)
6681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.command_args(program = 'program_or_script_to_run',
6881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                      interpreter = 'script_interpreter',
6981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                      arguments = 'arguments to pass to program')
7081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
7181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.run(program = 'program_or_script_to_run',
7281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             interpreter = 'script_interpreter',
7381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             arguments = 'arguments to pass to program',
7481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             chdir = 'directory_to_chdir_to',
7581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             stdin = 'input to feed to the program\n')
7681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             universal_newlines = True)
7781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
7881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    p = test.start(program = 'program_or_script_to_run',
7981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                   interpreter = 'script_interpreter',
8081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                   arguments = 'arguments to pass to program',
8181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                   universal_newlines = None)
8281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
8381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.finish(self, p)
8481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
8581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.pass_test()
8681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.pass_test(condition)
8781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.pass_test(condition, function)
8881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
8981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.fail_test()
9081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.fail_test(condition)
9181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.fail_test(condition, function)
9281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.fail_test(condition, function, skip)
9381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
9481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.no_result()
9581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.no_result(condition)
9681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.no_result(condition, function)
9781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.no_result(condition, function, skip)
9881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
9981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.stdout()
10081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.stdout(run)
10181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
10281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.stderr()
10381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.stderr(run)
10481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
10581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.symlink(target, link)
10681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
10781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.banner(string)
10881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.banner(string, width)
10981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
11081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.diff(actual, expected)
11181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
11281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match(actual, expected)
11381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
11481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
11581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_exact(["actual 1\n", "actual 2\n"],
11681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                     ["expected 1\n", "expected 2\n"])
11781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
11881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_re("actual 1\nactual 2\n", regex_string)
11981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_re(["actual 1\n", "actual 2\n"], list_of_regexes)
12081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
12181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_re_dotall("actual 1\nactual 2\n", regex_string)
12281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.match_re_dotall(["actual 1\n", "actual 2\n"], list_of_regexes)
12381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
12481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.tempdir()
12581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.tempdir('temporary-directory')
12681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
12781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.sleep()
12881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.sleep(seconds)
12981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
13081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.where_is('foo')
13181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.where_is('foo', 'PATH1:PATH2')
13281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
13381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
13481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.unlink('file')
13581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.unlink('subdir', 'file')
13681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
13781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCmd module provides pass_test(), fail_test(), and no_result()
13881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgunbound functions that report test results for use with the Aegis change
13981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgmanagement system.  These methods terminate the test immediately,
14081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgreporting PASSED, FAILED, or NO RESULT respectively, and exiting with
14181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgstatus 0 (success), 1 or 2 respectively.  This allows for a distinction
14281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgbetween an actual failed test and a test that could not be properly
14381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgevaluated because of an external condition (such as a full file system
14481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgor incorrect permissions).
14581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
14681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCmd
14781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
14881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.pass_test()
14981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.pass_test(condition)
15081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.pass_test(condition, function)
15181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
15281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.fail_test()
15381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.fail_test(condition)
15481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.fail_test(condition, function)
15581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.fail_test(condition, function, skip)
15681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
15781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.no_result()
15881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.no_result(condition)
15981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.no_result(condition, function)
16081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.no_result(condition, function, skip)
16181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
16281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCmd module also provides unbound functions that handle matching
16381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgin the same way as the match_*() methods described above.
16481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
16581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCmd
16681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
16781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(match = TestCmd.match_exact)
16881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
16981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(match = TestCmd.match_re)
17081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(match = TestCmd.match_re_dotall)
17281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCmd module provides unbound functions that can be used for the
17481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org"diff" argument to TestCmd.TestCmd instantiation:
17581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCmd
17781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(match = TestCmd.match_re,
17981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           diff = TestCmd.diff_re)
18081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(diff = TestCmd.simple_diff)
18281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe "diff" argument can also be used with standard difflib functions:
18481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import difflib
18681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(diff = difflib.context_diff)
18881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCmd.TestCmd(diff = difflib.unified_diff)
19081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
19181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgLastly, the where_is() method also exists in an unbound function
19281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgversion.
19381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
19481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCmd
19581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
19681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.where_is('foo')
19781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.where_is('foo', 'PATH1:PATH2')
19881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCmd.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
19981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org"""
20081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
201c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org# Copyright 2000-2010 Steven Knight
20281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# This module is free software, and you may redistribute it and/or modify
20381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# it under the same terms as Python itself, so long as this copyright message
20481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# and disclaimer are retained in their original form.
20581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org#
20681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
20781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
20881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
20981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# DAMAGE.
21081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org#
21181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
21281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
21481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
21581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
21681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
21781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org__author__ = "Steven Knight <knight at baldmt dot com>"
218c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org__revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight"
219c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org__version__ = "0.37"
22081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
22181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport errno
22281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport os
22381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport os.path
22481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport re
22581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport shutil
22681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport stat
22781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport string
22881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport sys
22981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport tempfile
23081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport time
23181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport traceback
23281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport types
23381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport UserList
23481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
23581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org__all__ = [
23681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'diff_re',
23781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'fail_test',
23881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'no_result',
23981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'pass_test',
24081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'match_exact',
24181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'match_re',
24281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'match_re_dotall',
24381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'python_executable',
24481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    'TestCmd'
24581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org]
24681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
24781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
24881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import difflib
24981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept ImportError:
25081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    __all__.append('simple_diff')
25181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
25281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef is_List(e):
25381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return type(e) is types.ListType \
25481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        or isinstance(e, UserList.UserList)
25581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
25681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
25781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    from UserString import UserString
25881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept ImportError:
25981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    class UserString:
26081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pass
26181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
26281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif hasattr(types, 'UnicodeType'):
26381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def is_String(e):
26481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return type(e) is types.StringType \
26581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            or type(e) is types.UnicodeType \
26681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            or isinstance(e, UserString)
26781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
26881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def is_String(e):
26981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return type(e) is types.StringType or isinstance(e, UserString)
27081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
27181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtempfile.template = 'testcmd.'
27281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif os.name in ('posix', 'nt'):
27381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    tempfile.template = 'testcmd.' + str(os.getpid()) + '.'
27481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
27581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    tempfile.template = 'testcmd.'
27681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
27781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgre_space = re.compile('\s')
27881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
27981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org_Cleanup = []
28081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
28181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org_chain_to_exitfunc = None
28281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
28381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef _clean():
28481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    global _Cleanup
28581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    cleanlist = filter(None, _Cleanup)
28681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    del _Cleanup[:]
28781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    cleanlist.reverse()
28881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for test in cleanlist:
28981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        test.cleanup()
29081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if _chain_to_exitfunc:
29181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        _chain_to_exitfunc()
29281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
29381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
29481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import atexit
29581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept ImportError:
29681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # TODO(1.5): atexit requires python 2.0, so chain sys.exitfunc
29781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:
29881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        _chain_to_exitfunc = sys.exitfunc
29981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except AttributeError:
30081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pass
30181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.exitfunc = _clean
30281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
30381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    atexit.register(_clean)
30481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
30581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
30681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    zip
30781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept NameError:
30881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def zip(*lists):
30981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        result = []
31081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for i in xrange(min(map(len, lists))):
31181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            result.append(tuple(map(lambda l, i=i: l[i], lists)))
31281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return result
31381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
31481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgclass Collector:
31581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __init__(self, top):
31681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.entries = [top]
31781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __call__(self, arg, dirname, names):
31881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pathjoin = lambda n, d=dirname: os.path.join(d, n)
31981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.entries.extend(map(pathjoin, names))
32081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
32181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef _caller(tblist, skip):
32281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    string = ""
32381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    arr = []
32481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for file, line, name, text in tblist:
32581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if file[-10:] == "TestCmd.py":
32681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                break
32781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        arr = [(file, line, name, text)] + arr
32881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    atfrom = "at"
32981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for file, line, name, text in arr[skip:]:
33081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if name in ("?", "<module>"):
33181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            name = ""
33281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
33381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            name = " (" + name + ")"
33481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        string = string + ("%s line %d of %s%s\n" % (atfrom, line, file, name))
33581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        atfrom = "\tfrom"
33681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return string
33781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
33881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef fail_test(self = None, condition = 1, function = None, skip = 0):
33981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """Cause the test to fail.
34081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
34181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    By default, the fail_test() method reports that the test FAILED
34281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    and exits with a status of 1.  If a condition argument is supplied,
34381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    the test fails only if the condition is true.
34481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
34581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not condition:
34681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return
34781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not function is None:
34881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function()
34981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    of = ""
35081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    desc = ""
35181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sep = " "
35281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not self is None:
35381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.program:
35481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            of = " of " + self.program
35581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sep = "\n\t"
35681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.description:
35781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            desc = " [" + self.description + "]"
35881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sep = "\n\t"
35981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
36081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    at = _caller(traceback.extract_stack(), skip)
36181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.stderr.write("FAILED test" + of + desc + sep + at)
36281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
36381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.exit(1)
36481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
36581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef no_result(self = None, condition = 1, function = None, skip = 0):
36681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """Causes a test to exit with no valid result.
36781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
36881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    By default, the no_result() method reports NO RESULT for the test
36981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    and exits with a status of 2.  If a condition argument is supplied,
37081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    the test fails only if the condition is true.
37181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
37281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not condition:
37381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return
37481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not function is None:
37581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function()
37681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    of = ""
37781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    desc = ""
37881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sep = " "
37981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not self is None:
38081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.program:
38181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            of = " of " + self.program
38281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sep = "\n\t"
38381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.description:
38481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            desc = " [" + self.description + "]"
38581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sep = "\n\t"
38681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3873afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org    if os.environ.get('TESTCMD_DEBUG_SKIPS'):
3883afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        at = _caller(traceback.extract_stack(), skip)
3893afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        sys.stderr.write("NO RESULT for test" + of + desc + sep + at)
3903afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org    else:
3913afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        sys.stderr.write("NO RESULT\n")
39281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
39381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.exit(2)
39481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
39581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef pass_test(self = None, condition = 1, function = None):
39681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """Causes a test to pass.
39781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
39881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    By default, the pass_test() method reports PASSED for the test
39981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    and exits with a status of 0.  If a condition argument is supplied,
40081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    the test passes only if the condition is true.
40181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
40281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not condition:
40381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return
40481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not function is None:
40581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function()
40681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.stderr.write("PASSED\n")
40781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    sys.exit(0)
40881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
40981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef match_exact(lines = None, matches = None):
41081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
41181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
41281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not is_List(lines):
41381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        lines = string.split(lines, "\n")
41481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not is_List(matches):
41581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        matches = string.split(matches, "\n")
41681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if len(lines) != len(matches):
41781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return
41881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for i in range(len(lines)):
41981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if lines[i] != matches[i]:
42081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
42181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return 1
42281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
42381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef match_re(lines = None, res = None):
42481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
42581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
42681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not is_List(lines):
42781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        lines = string.split(lines, "\n")
42881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not is_List(res):
42981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        res = string.split(res, "\n")
43081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if len(lines) != len(res):
43181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return
43281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for i in range(len(lines)):
43381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        s = "^" + res[i] + "$"
43481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
43581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            expr = re.compile(s)
43681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except re.error, e:
43781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            msg = "Regular expression error in %s: %s"
43881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise re.error, msg % (repr(s), e[0])
43981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not expr.search(lines[i]):
44081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
44181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return 1
44281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
44381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef match_re_dotall(lines = None, res = None):
44481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
44581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
44681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not type(lines) is type(""):
44781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        lines = string.join(lines, "\n")
44881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if not type(res) is type(""):
44981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        res = string.join(res, "\n")
45081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    s = "^" + res + "$"
45181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:
45281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        expr = re.compile(s, re.DOTALL)
45381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except re.error, e:
45481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        msg = "Regular expression error in %s: %s"
45581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        raise re.error, msg % (repr(s), e[0])
45681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if expr.match(lines):
45781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return 1
45881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
45981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
46081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import difflib
46181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept ImportError:
46281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    pass
46381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
46481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def simple_diff(a, b, fromfile='', tofile='',
46581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    fromfiledate='', tofiledate='', n=3, lineterm='\n'):
46681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
46781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        A function with the same calling signature as difflib.context_diff
46881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        (diff -c) and difflib.unified_diff (diff -u) but which prints
46981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        output like the simple, unadorned 'diff" command.
47081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
47181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        sm = difflib.SequenceMatcher(None, a, b)
47281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def comma(x1, x2):
47381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
47481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        result = []
47581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for op, a1, a2, b1, b2 in sm.get_opcodes():
47681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if op == 'delete':
47781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.append("%sd%d" % (comma(a1, a2), b1))
47881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
47981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            elif op == 'insert':
48081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.append("%da%s" % (a1, comma(b1, b2)))
48181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
48281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            elif op == 'replace':
48381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.append("%sc%s" % (comma(a1, a2), comma(b1, b2)))
48481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
48581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.append('---')
48681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
48781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return result
48881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
48981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef diff_re(a, b, fromfile='', tofile='',
49081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                fromfiledate='', tofiledate='', n=3, lineterm='\n'):
49181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
49281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    A simple "diff" of two sets of lines when the expected lines
49381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    are regular expressions.  This is a really dumb thing that
49481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    just compares each line in turn, so it doesn't look for
49581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    chunks of matching lines and the like--but at least it lets
49681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    you know exactly which line first didn't compare correctl...
49781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
49881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    result = []
49981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    diff = len(a) - len(b)
50081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if diff < 0:
50181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        a = a + ['']*(-diff)
50281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    elif diff > 0:
50381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        b = b + ['']*diff
50481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    i = 0
50581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for aline, bline in zip(a, b):
50681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        s = "^" + aline + "$"
50781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
50881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            expr = re.compile(s)
50981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except re.error, e:
51081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            msg = "Regular expression error in %s: %s"
51181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise re.error, msg % (repr(s), e[0])
51281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not expr.search(bline):
51381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            result.append("%sc%s" % (i+1, i+1))
51481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            result.append('< ' + repr(a[i]))
51581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            result.append('---')
51681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            result.append('> ' + repr(b[i]))
51781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        i = i+1
51881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return result
51981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
52081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif os.name == 'java':
52181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
52281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    python_executable = os.path.join(sys.prefix, 'jython')
52381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
52481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
52581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
52681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    python_executable = sys.executable
52781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
52881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif sys.platform == 'win32':
52981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
53081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    default_sleep_seconds = 2
53181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
53281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def where_is(file, path=None, pathext=None):
53381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if path is None:
53481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = os.environ['PATH']
53581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if is_String(path):
53681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = string.split(path, os.pathsep)
53781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if pathext is None:
53881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            pathext = os.environ['PATHEXT']
53981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if is_String(pathext):
54081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            pathext = string.split(pathext, os.pathsep)
54181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for ext in pathext:
54281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if string.lower(ext) == string.lower(file[-len(ext):]):
54381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pathext = ['']
54481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                break
54581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for dir in path:
54681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            f = os.path.join(dir, file)
54781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for ext in pathext:
54881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                fext = f + ext
54981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if os.path.isfile(fext):
55081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return fext
55181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return None
55281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
55381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
55481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
55581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def where_is(file, path=None, pathext=None):
55681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if path is None:
55781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = os.environ['PATH']
55881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if is_String(path):
55981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = string.split(path, os.pathsep)
56081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for dir in path:
56181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            f = os.path.join(dir, file)
56281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if os.path.isfile(f):
56381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                try:
56481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    st = os.stat(f)
56581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                except OSError:
56681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    continue
56781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
56881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return f
56981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return None
57081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
57181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    default_sleep_seconds = 1
57281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
57381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
57481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
57581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtry:
57681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import subprocess
57781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexcept ImportError:
57881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # The subprocess module doesn't exist in this version of Python,
57981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # so we're going to cobble up something that looks just enough
58081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # like its API for our purposes below.
58181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import new
58281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
58381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    subprocess = new.module('subprocess')
58481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
58581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    subprocess.PIPE = 'PIPE'
58681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    subprocess.STDOUT = 'STDOUT'
58781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    subprocess.mswindows = (sys.platform == 'win32')
58881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
58981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:
59081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        import popen2
59181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        popen2.Popen3
59281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except AttributeError:
59381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        class Popen3:
59481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            universal_newlines = 1
59581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def __init__(self, command, **kw):
59681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if sys.platform == 'win32' and command[0] == '"':
59781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    command = '"' + command + '"'
59881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                (stdin, stdout, stderr) = os.popen3(' ' + command)
59981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stdin = stdin
60081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stdout = stdout
60181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stderr = stderr
60281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def close_output(self):
60381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stdout.close()
60481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.resultcode = self.stderr.close()
60581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def wait(self):
60681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                resultcode = self.resultcode
60781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if os.WIFEXITED(resultcode):
60881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return os.WEXITSTATUS(resultcode)
60981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                elif os.WIFSIGNALED(resultcode):
61081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return os.WTERMSIG(resultcode)
61181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else:
61281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return None
61381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
61481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    else:
61581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
61681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            popen2.Popen4
61781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except AttributeError:
61881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # A cribbed Popen4 class, with some retrofitted code from
61981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # the Python 1.5 Popen3 class methods to do certain things
62081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # by hand.
62181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            class Popen4(popen2.Popen3):
62281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                childerr = None
62381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
62481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                def __init__(self, cmd, bufsize=-1):
62581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    p2cread, p2cwrite = os.pipe()
62681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    c2pread, c2pwrite = os.pipe()
62781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    self.pid = os.fork()
62881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    if self.pid == 0:
62981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        # Child
63081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        os.dup2(p2cread, 0)
63181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        os.dup2(c2pwrite, 1)
63281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        os.dup2(c2pwrite, 2)
63381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        for i in range(3, popen2.MAXFD):
63481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                            try:
63581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                                os.close(i)
63681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                            except: pass
63781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        try:
63881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                            os.execvp(cmd[0], cmd)
63981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        finally:
64081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                            os._exit(1)
64181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        # Shouldn't come here, I guess
64281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        os._exit(1)
64381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    os.close(p2cread)
64481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
64581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    os.close(c2pwrite)
64681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    self.fromchild = os.fdopen(c2pread, 'r', bufsize)
64781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    popen2._active.append(self)
64881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
64981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            popen2.Popen4 = Popen4
65081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
65181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        class Popen3(popen2.Popen3, popen2.Popen4):
65281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            universal_newlines = 1
65381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def __init__(self, command, **kw):
65481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if kw.get('stderr') == 'STDOUT':
65581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    apply(popen2.Popen4.__init__, (self, command, 1))
65681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else:
65781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    apply(popen2.Popen3.__init__, (self, command, 1))
65881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stdin = self.tochild
65981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stdout = self.fromchild
66081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.stderr = self.childerr
66181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def wait(self, *args, **kw):
66281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                resultcode = apply(popen2.Popen3.wait, (self,)+args, kw)
66381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if os.WIFEXITED(resultcode):
66481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return os.WEXITSTATUS(resultcode)
66581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                elif os.WIFSIGNALED(resultcode):
66681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return os.WTERMSIG(resultcode)
66781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else:
66881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return None
66981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
67081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    subprocess.Popen = Popen3
67181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
67281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
67381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
67481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# From Josiah Carlson,
67581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Windows and Posix platforms
67681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
67781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
67881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgPIPE = subprocess.PIPE
67981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
68081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif subprocess.mswindows:
68181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    from win32file import ReadFile, WriteFile
68281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    from win32pipe import PeekNamedPipe
68381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import msvcrt
68481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
68581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import select
68681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import fcntl
68781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
68881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:                    fcntl.F_GETFL
68981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except AttributeError:  fcntl.F_GETFL = 3
69081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
69181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:                    fcntl.F_SETFL
69281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except AttributeError:  fcntl.F_SETFL = 4
69381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
69481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgclass Popen(subprocess.Popen):
69581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def recv(self, maxsize=None):
69681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self._recv('stdout', maxsize)
69781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
69881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def recv_err(self, maxsize=None):
69981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self._recv('stderr', maxsize)
70081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
70181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def send_recv(self, input='', maxsize=None):
70281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
70381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
70481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def get_conn_maxsize(self, which, maxsize):
70581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if maxsize is None:
70681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            maxsize = 1024
70781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif maxsize < 1:
70881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            maxsize = 1
70981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return getattr(self, which), maxsize
71081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
71181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def _close(self, which):
71281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        getattr(self, which).close()
71381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        setattr(self, which, None)
71481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
71581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if subprocess.mswindows:
71681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def send(self, input):
71781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not self.stdin:
71881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return None
71981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
72081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
72181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                x = msvcrt.get_osfhandle(self.stdin.fileno())
72281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                (errCode, written) = WriteFile(x, input)
72381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except ValueError:
72481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return self._close('stdin')
72581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except (subprocess.pywintypes.error, Exception), why:
72681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if why[0] in (109, errno.ESHUTDOWN):
72781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return self._close('stdin')
72881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                raise
72981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
73081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return written
73181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
73281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def _recv(self, which, maxsize):
73381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            conn, maxsize = self.get_conn_maxsize(which, maxsize)
73481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if conn is None:
73581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return None
73681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
73781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
73881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                x = msvcrt.get_osfhandle(conn.fileno())
73981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
74081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if maxsize < nAvail:
74181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    nAvail = maxsize
74281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if nAvail > 0:
74381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    (errCode, read) = ReadFile(x, nAvail, None)
74481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except ValueError:
74581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return self._close(which)
74681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except (subprocess.pywintypes.error, Exception), why:
74781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if why[0] in (109, errno.ESHUTDOWN):
74881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return self._close(which)
74981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                raise
75081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
75181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            #if self.universal_newlines:
75281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            #    read = self._translate_newlines(read)
75381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return read
75481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
75581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    else:
75681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def send(self, input):
75781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not self.stdin:
75881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return None
75981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
76081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not select.select([], [self.stdin], [], 0)[1]:
76181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return 0
76281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
76381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
76481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                written = os.write(self.stdin.fileno(), input)
76581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except OSError, why:
76681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if why[0] == errno.EPIPE: #broken pipe
76781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return self._close('stdin')
76881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                raise
76981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
77081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return written
77181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
77281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def _recv(self, which, maxsize):
77381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            conn, maxsize = self.get_conn_maxsize(which, maxsize)
77481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if conn is None:
77581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return None
77681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
77781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
77881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                flags = fcntl.fcntl(conn, fcntl.F_GETFL)
77981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except TypeError:
78081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                flags = None
78181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
78281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if not conn.closed:
78381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
78481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
78581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
78681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if not select.select([conn], [], [], 0)[0]:
78781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return ''
78881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
78981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                r = conn.read(maxsize)
79081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if not r:
79181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    return self._close(which)
79281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
79381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                #if self.universal_newlines:
79481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                #    r = self._translate_newlines(r)
79581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return r
79681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            finally:
79781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                if not conn.closed and not flags is None:
79881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    fcntl.fcntl(conn, fcntl.F_SETFL, flags)
79981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
80081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdisconnect_message = "Other end disconnected!"
80181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
80281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef recv_some(p, t=.1, e=1, tr=5, stderr=0):
80381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if tr < 1:
80481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        tr = 1
80581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    x = time.time()+t
80681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    y = []
80781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    r = ''
80881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    pr = p.recv
80981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if stderr:
81081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pr = p.recv_err
81181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    while time.time() < x or r:
81281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        r = pr()
81381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if r is None:
81481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if e:
81581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                raise Exception(disconnect_message)
81681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
81781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                break
81881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif r:
81981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            y.append(r)
82081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
82181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            time.sleep(max((x-time.time())/tr, 0))
82281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return ''.join(y)
82381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
82481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# TODO(3.0:  rewrite to use memoryview()
82581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef send_all(p, data):
82681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    while len(data):
82781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        sent = p.send(data)
82881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if sent is None:
82981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise Exception(disconnect_message)
83081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        data = buffer(data, sent)
83181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
83281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
83381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
834c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.orgtry:
835c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org    object
836c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.orgexcept NameError:
837c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org    class object:
838c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        pass
839c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org
840c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org
841c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org
84281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgclass TestCmd(object):
84381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """Class TestCmd
84481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    """
84581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
84681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __init__(self, description = None,
84781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       program = None,
84881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       interpreter = None,
84981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       workdir = None,
85081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       subdir = None,
85181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       verbose = None,
85281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       match = None,
85381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       diff = None,
85481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       combine = 0,
85581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       universal_newlines = 1):
85681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._cwd = os.getcwd()
85781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.description_set(description)
85881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.program_set(program)
85981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.interpreter_set(interpreter)
86081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if verbose is None:
86181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
86281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                verbose = max( 0, int(os.environ.get('TESTCMD_VERBOSE', 0)) )
86381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except ValueError:
86481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                verbose = 0
86581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.verbose_set(verbose)
86681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.combine = combine
86781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.universal_newlines = universal_newlines
8682013ec6b77b9f4ce80b7c0d7fafd187e7b3e3f9fthakis@chromium.org        if match is not None:
86981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.match_function = match
87081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
87181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.match_function = match_re
8722013ec6b77b9f4ce80b7c0d7fafd187e7b3e3f9fthakis@chromium.org        if diff is not None:
87381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.diff_function = diff
87481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
87581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
87681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                difflib
87781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except NameError:
87881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
87981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
88081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.diff_function = simple_diff
88181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                #self.diff_function = difflib.context_diff
88281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                #self.diff_function = difflib.unified_diff
88381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._dirlist = []
88481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
88581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
88681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self._preserve['pass_test'] = os.environ['PRESERVE']
88781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self._preserve['fail_test'] = os.environ['PRESERVE']
88881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self._preserve['no_result'] = os.environ['PRESERVE']
88981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
89081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
89181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
89281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except KeyError:
89381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
89481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
89581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
89681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except KeyError:
89781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
89881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
89981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
90081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except KeyError:
90181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
90281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stdout = []
90381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stderr = []
90481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.status = None
90581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.condition = 'no_result'
90681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.workdir_set(workdir)
90781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.subdir(subdir)
90881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
90981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __del__(self):
91081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.cleanup()
91181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
91281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __repr__(self):
91381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return "%x" % id(self)
91481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
91581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    banner_char = '='
91681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    banner_width = 80
91781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
91881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def banner(self, s, width=None):
91981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if width is None:
92081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            width = self.banner_width
92181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return s + self.banner_char * (width - len(s))
92281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
92381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    if os.name == 'posix':
92481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
92581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def escape(self, arg):
92681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            "escape shell special characters"
92781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            slash = '\\'
92881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            special = '"$'
92981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
93081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            arg = string.replace(arg, slash, slash+slash)
93181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for c in special:
93281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arg = string.replace(arg, c, slash+c)
93381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
93481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if re_space.search(arg):
93581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arg = '"' + arg + '"'
93681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return arg
93781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
93881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    else:
93981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
94081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # Windows does not allow special characters in file names
94181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # anyway, so no need for an escape function, we will just quote
94281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # the arg.
94381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def escape(self, arg):
94481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if re_space.search(arg):
94581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arg = '"' + arg + '"'
94681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return arg
94781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
94881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def canonicalize(self, path):
94981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if is_List(path):
95081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = apply(os.path.join, tuple(path))
95181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not os.path.isabs(path):
95281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = os.path.join(self.workdir, path)
95381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return path
95481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
95581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def chmod(self, path, mode):
95681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Changes permissions on the specified file or directory
95781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        path name."""
95881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        path = self.canonicalize(path)
95981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.chmod(path, mode)
96081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
96181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def cleanup(self, condition = None):
96281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Removes any temporary working directories for the specified
96381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        TestCmd environment.  If the environment variable PRESERVE was
96481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        set when the TestCmd environment was created, temporary working
96581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        directories are not removed.  If any of the environment variables
96681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        PRESERVE_PASS, PRESERVE_FAIL, or PRESERVE_NO_RESULT were set
96781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        when the TestCmd environment was created, then temporary working
96881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        directories are not removed if the test passed, failed, or had
96981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        no result, respectively.  Temporary working directories are also
97081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        preserved for conditions specified via the preserve method.
97181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
97281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Typically, this method is not called directly, but is used when
97381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the script exits to clean up temporary working directories as
97481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        appropriate for the exit status.
97581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
97681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not self._dirlist:
97781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
97881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.chdir(self._cwd)
97981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.workdir = None
98081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if condition is None:
98181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            condition = self.condition
98281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self._preserve[condition]:
98381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for dir in self._dirlist:
98481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print "Preserved directory", dir
98581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
98681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            list = self._dirlist[:]
98781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            list.reverse()
98881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for dir in list:
98981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                self.writable(dir, 1)
99081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                shutil.rmtree(dir, ignore_errors = 1)
99181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self._dirlist = []
99281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
99381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
99481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            global _Cleanup
99581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            _Cleanup.remove(self)
99681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except (AttributeError, ValueError):
99781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            pass
99881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
99981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def command_args(self, program = None,
100081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           interpreter = None,
100181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                           arguments = None):
100281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if program:
100381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if type(program) == type('') and not os.path.isabs(program):
100481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                program = os.path.join(self._cwd, program)
100581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
100681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            program = self.program
100781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not interpreter:
100881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                interpreter = self.interpreter
100981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not type(program) in [type([]), type(())]:
101081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            program = [program]
101181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        cmd = list(program)
101281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if interpreter:
101381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not type(interpreter) in [type([]), type(())]:
101481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                interpreter = [interpreter]
101581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            cmd = list(interpreter) + cmd
101681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if arguments:
101781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if type(arguments) == type(''):
101881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arguments = string.split(arguments)
101981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            cmd.extend(arguments)
102081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return cmd
102181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
102281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def description_set(self, description):
102381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Set the description of the functionality being tested.
102481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
102581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.description = description
102681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
102781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    try:
102881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        difflib
102981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    except NameError:
103081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def diff(self, a, b, name, *args, **kw):
103181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('Expected %s' % name)
103281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print a
103381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('Actual %s' % name)
103481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print b
103581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    else:
103681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        def diff(self, a, b, name, *args, **kw):
103781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner(name)
103881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            args = (a.splitlines(), b.splitlines()) + args
103981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            lines = apply(self.diff_function, args, kw)
104081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for l in lines:
104181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print l
104281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
104381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def fail_test(self, condition = 1, function = None, skip = 0):
104481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Cause the test to fail.
104581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
104681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not condition:
104781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
104881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.condition = 'fail_test'
104981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        fail_test(self = self,
105081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  condition = condition,
105181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  function = function,
105281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  skip = skip)
105381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
105481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def interpreter_set(self, interpreter):
105581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Set the program to be used to interpret the program
105681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        under test as a script.
105781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
105881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.interpreter = interpreter
105981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
106081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def match(self, lines, matches):
106181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Compare actual and expected file contents.
106281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
106381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self.match_function(lines, matches)
106481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
106581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def match_exact(self, lines, matches):
106681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Compare actual and expected file contents.
106781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
106881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return match_exact(lines, matches)
106981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
107081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def match_re(self, lines, res):
107181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Compare actual and expected file contents.
107281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
107381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return match_re(lines, res)
107481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
107581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def match_re_dotall(self, lines, res):
107681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Compare actual and expected file contents.
107781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
107881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return match_re_dotall(lines, res)
107981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
108081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def no_result(self, condition = 1, function = None, skip = 0):
108181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Report that the test could not be run.
108281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
108381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not condition:
108481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
108581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.condition = 'no_result'
108681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        no_result(self = self,
108781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  condition = condition,
108881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  function = function,
108981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  skip = skip)
109081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
109181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def pass_test(self, condition = 1, function = None):
109281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Cause the test to pass.
109381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
109481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not condition:
109581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
109681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.condition = 'pass_test'
109781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pass_test(self = self, condition = condition, function = function)
109881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
109981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def preserve(self, *conditions):
110081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Arrange for the temporary working directories for the
110181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        specified TestCmd environment to be preserved for one or more
110281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        conditions.  If no conditions are specified, arranges for
110381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the temporary working directories to be preserved for all
110481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        conditions.
110581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
110681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if conditions is ():
110781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            conditions = ('pass_test', 'fail_test', 'no_result')
110881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for cond in conditions:
110981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self._preserve[cond] = 1
111081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
111181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def program_set(self, program):
111281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Set the executable program or script to be tested.
111381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
111481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if program and not os.path.isabs(program):
111581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            program = os.path.join(self._cwd, program)
111681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.program = program
111781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
111881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def read(self, file, mode = 'rb'):
111981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Reads and returns the contents of the specified file name.
112081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The file name may be a list, in which case the elements are
112181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        concatenated with the os.path.join() method.  The file is
112281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        assumed to be under the temporary working directory unless it
112381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        is an absolute path name.  The I/O mode for the file may
112481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        be specified; it must begin with an 'r'.  The default is
112581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        'rb' (binary read).
112681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
112781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file = self.canonicalize(file)
112881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if mode[0] != 'r':
112981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise ValueError, "mode must begin with 'r'"
1130fbcd968877bac98d0d6f5f61847c0232939562f4thakis@chromium.org        with open(file, mode) as f:
1131fbcd968877bac98d0d6f5f61847c0232939562f4thakis@chromium.org            result = f.read()
1132fbcd968877bac98d0d6f5f61847c0232939562f4thakis@chromium.org        return result
113381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
113481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def rmdir(self, dir):
113581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Removes the specified dir name.
113681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The dir name may be a list, in which case the elements are
113781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        concatenated with the os.path.join() method.  The dir is
113881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        assumed to be under the temporary working directory unless it
113981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        is an absolute path name.
114081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The dir must be empty.
114181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
114281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        dir = self.canonicalize(dir)
114381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.rmdir(dir)
114481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
114581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def start(self, program = None,
114681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    interpreter = None,
114781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    arguments = None,
114881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    universal_newlines = None,
114981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    **kw):
115081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
115181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Starts a program or script for the test environment.
115281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
115381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The specified program will have the original directory
115481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        prepended unless it is enclosed in a [list].
115581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
115681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        cmd = self.command_args(program, interpreter, arguments)
115781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        cmd_string = string.join(map(self.escape, cmd), ' ')
115881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.verbose:
115981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stderr.write(cmd_string + "\n")
116081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if universal_newlines is None:
116181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            universal_newlines = self.universal_newlines
116281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1163c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        # On Windows, if we make stdin a pipe when we plan to send
1164c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        # no input, and the test program exits before
1165c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        # Popen calls msvcrt.open_osfhandle, that call will fail.
1166c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        # So don't use a pipe for stdin if we don't need one.
1167c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        stdin = kw.get('stdin', None)
1168c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        if stdin is not None:
1169c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org            stdin = subprocess.PIPE
1170c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org
117181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        combine = kw.get('combine', self.combine)
117281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if combine:
117381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            stderr_value = subprocess.STDOUT
117481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
117581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            stderr_value = subprocess.PIPE
117681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
117781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return Popen(cmd,
1178c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org                     stdin=stdin,
117981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                     stdout=subprocess.PIPE,
118081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                     stderr=stderr_value,
118181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                     universal_newlines=universal_newlines)
118281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
118381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def finish(self, popen, **kw):
118481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
118581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Finishes and waits for the process being run under control of
118681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the specified popen argument, recording the exit status,
118781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        standard output and error output.
118881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
118981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        popen.stdin.close()
119081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.status = popen.wait()
119181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not self.status:
119281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.status = 0
119381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stdout.append(popen.stdout.read())
119481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if popen.stderr:
119581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            stderr = popen.stderr.read()
119681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
119781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            stderr = ''
119881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stderr.append(stderr)
119981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
120081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def run(self, program = None,
120181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  interpreter = None,
120281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  arguments = None,
120381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  chdir = None,
120481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  stdin = None,
120581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  universal_newlines = None):
120681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Runs a test of the program or script for the test
120781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        environment.  Standard output and error output are saved for
120881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        future retrieval via the stdout() and stderr() methods.
120981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
121081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The specified program will have the original directory
121181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        prepended unless it is enclosed in a [list].
121281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
121381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if chdir:
121481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            oldcwd = os.getcwd()
121581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not os.path.isabs(chdir):
121681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                chdir = os.path.join(self.workpath(chdir))
121781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if self.verbose:
121881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                sys.stderr.write("chdir(" + chdir + ")\n")
121981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.chdir(chdir)
1220c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org        p = self.start(program,
1221c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org                       interpreter,
1222c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org                       arguments,
1223c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org                       universal_newlines,
1224c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org                       stdin=stdin)
122581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if stdin:
122681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if is_List(stdin):
122781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                for line in stdin:
122881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    p.stdin.write(line)
122981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
123081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                p.stdin.write(stdin)
1231c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org            p.stdin.close()
123281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
123381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        out = p.stdout.read()
123481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if p.stderr is None:
123581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            err = ''
123681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
123781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            err = p.stderr.read()
123881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
123981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            close_output = p.close_output
124081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except AttributeError:
124181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            p.stdout.close()
124281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not p.stderr is None:
124381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                p.stderr.close()
124481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
124581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            close_output()
124681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
124781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stdout.append(out)
124881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._stderr.append(err)
124981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
125081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.status = p.wait()
125181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not self.status:
125281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.status = 0
125381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
125481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if chdir:
125581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.chdir(oldcwd)
125681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if self.verbose >= 2:
125781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            write = sys.stdout.write
125881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            write('============ STATUS: %d\n' % self.status)
125981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            out = self.stdout()
126081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if out or self.verbose >= 3:
126181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write('============ BEGIN STDOUT (len=%d):\n' % len(out))
126281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write(out)
126381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write('============ END STDOUT\n')
126481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            err = self.stderr()
126581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if err or self.verbose >= 3:
126681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write('============ BEGIN STDERR (len=%d)\n' % len(err))
126781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write(err)
126881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                write('============ END STDERR\n')
126981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
127081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def sleep(self, seconds = default_sleep_seconds):
127181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Sleeps at least the specified number of seconds.  If no
127281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        number is specified, sleeps at least the minimum number of
127381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        seconds necessary to advance file time stamps on the current
127481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        system.  Sleeping more seconds is all right.
127581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
127681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        time.sleep(seconds)
127781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
127881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def stderr(self, run = None):
127981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Returns the error output from the specified run number.
128081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        If there is no specified run number, then returns the error
128181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        output of the last run.  If the run number is less than zero,
128281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        then returns the error output from that many runs back from the
128381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        current run.
128481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
128581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not run:
128681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            run = len(self._stderr)
128781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif run < 0:
128881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            run = len(self._stderr) + run
128981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        run = run - 1
129081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self._stderr[run]
129181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
129281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def stdout(self, run = None):
129381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Returns the standard output from the specified run number.
129481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        If there is no specified run number, then returns the standard
129581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        output of the last run.  If the run number is less than zero,
129681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        then returns the standard output from that many runs back from
129781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the current run.
129881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
129981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not run:
130081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            run = len(self._stdout)
130181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif run < 0:
130281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            run = len(self._stdout) + run
130381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        run = run - 1
130481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self._stdout[run]
130581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
130681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def subdir(self, *subdirs):
130781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Create new subdirectories under the temporary working
130881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        directory, one for each argument.  An argument may be a list,
130981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        in which case the list elements are concatenated using the
131081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.path.join() method.  Subdirectories multiple levels deep
131181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        must be created using a separate argument for each level:
131281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
131381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
131481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
131581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Returns the number of subdirectories actually created.
131681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
131781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        count = 0
131881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for sub in subdirs:
131981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if sub is None:
132081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                continue
132181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if is_List(sub):
132281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                sub = apply(os.path.join, tuple(sub))
132381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            new = os.path.join(self.workdir, sub)
132481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
132581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                os.mkdir(new)
132681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except OSError:
132781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
132881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
132981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                count = count + 1
133081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return count
133181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
133281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def symlink(self, target, link):
133381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Creates a symlink to the specified target.
133481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The link name may be a list, in which case the elements are
133581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        concatenated with the os.path.join() method.  The link is
133681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        assumed to be under the temporary working directory unless it
133781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        is an absolute path name. The target is *not* assumed to be
133881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        under the temporary working directory.
133981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
134081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        link = self.canonicalize(link)
134181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.symlink(target, link)
134281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
134381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def tempdir(self, path=None):
134481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Creates a temporary directory.
134581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        A unique directory name is generated if no path name is specified.
134681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The directory is created, and will be removed when the TestCmd
134781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        object is destroyed.
134881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
134981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if path is None:
135081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
135181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                path = tempfile.mktemp(prefix=tempfile.template)
135281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except TypeError:
135381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                path = tempfile.mktemp()
135481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.mkdir(path)
135581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
135681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # Symlinks in the path will report things
135781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # differently from os.getcwd(), so chdir there
135881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # and back to fetch the canonical path.
135981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        cwd = os.getcwd()
136081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
136181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.chdir(path)
136281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = os.getcwd()
136381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        finally:
136481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.chdir(cwd)
136581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
136681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # Uppercase the drive letter since the case of drive
136781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # letters is pretty much random on win32:
136881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        drive,rest = os.path.splitdrive(path)
136981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if drive:
137081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = string.upper(drive) + rest
137181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
137281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        #
137381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._dirlist.append(path)
137481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        global _Cleanup
137581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
137681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            _Cleanup.index(self)
137781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except ValueError:
137881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            _Cleanup.append(self)
137981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
138081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return path
138181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
138281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def touch(self, path, mtime=None):
138381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Updates the modification time on the specified file or
138481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        directory path name.  The default is to update to the
138581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        current time if no explicit modification time is specified.
138681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
138781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        path = self.canonicalize(path)
138881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        atime = os.path.getatime(path)
138981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if mtime is None:
139081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            mtime = time.time()
139181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.utime(path, (atime, mtime))
139281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
139381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def unlink(self, file):
139481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Unlinks the specified file name.
139581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The file name may be a list, in which case the elements are
139681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        concatenated with the os.path.join() method.  The file is
139781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        assumed to be under the temporary working directory unless it
139881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        is an absolute path name.
139981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
140081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file = self.canonicalize(file)
140181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.unlink(file)
140281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
140381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def verbose_set(self, verbose):
140481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Set the verbose level.
140581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
140681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.verbose = verbose
140781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
140881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def where_is(self, file, path=None, pathext=None):
140981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Find an executable file.
141081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
141181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if is_List(file):
141281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            file = apply(os.path.join, tuple(file))
141381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not os.path.isabs(file):
141481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            file = where_is(file, path, pathext)
141581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return file
141681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
141781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def workdir_set(self, path):
141881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Creates a temporary working directory with the specified
141981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        path name.  If the path is a null string (''), a unique
142081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        directory name is created.
142181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
142281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if (path != None):
142381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if path == '':
142481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                path = None
142581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            path = self.tempdir(path)
142681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.workdir = path
142781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
142881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def workpath(self, *args):
142981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Returns the absolute path name to a subdirectory or file
143081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        within the current temporary working directory.  Concatenates
143181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the temporary working directory name with the specified
143281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        arguments using the os.path.join() method.
143381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
143481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return apply(os.path.join, (self.workdir,) + tuple(args))
143581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
143681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def readable(self, top, read=1):
143781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Make the specified directory tree readable (read == 1)
143881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        or not (read == None).
143981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
144081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        This method has no effect on Windows systems, which use a
144181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        completely different mechanism to control file readability.
144281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
144381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
144481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if sys.platform == 'win32':
144581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
144681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
144781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if read:
144881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def do_chmod(fname):
144981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                try: st = os.stat(fname)
145081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                except OSError: pass
145181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IREAD))
145281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
145381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def do_chmod(fname):
145481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                try: st = os.stat(fname)
145581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                except OSError: pass
145681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREAD))
145781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
145881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if os.path.isfile(top):
145981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # If it's a file, that's easy, just chmod it.
146081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            do_chmod(top)
146181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif read:
146281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # It's a directory and we're trying to turn on read
146381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # permission, so it's also pretty easy, just chmod the
146481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # directory and then chmod every entry on our walk down the
146581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # tree.  Because os.path.walk() is top-down, we'll enable
146681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # read permission on any directories that have it disabled
146781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # before os.path.walk() tries to list their contents.
146881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            do_chmod(top)
146981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
147081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
147181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                for n in names:
147281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    do_chmod(os.path.join(dirname, n))
147381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
147481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.path.walk(top, chmod_entries, None)
147581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
147681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # It's a directory and we're trying to turn off read
147781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # permission, which means we have to chmod the directoreis
147881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # in the tree bottom-up, lest disabling read permission from
147981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # the top down get in the way of being able to get at lower
148081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # parts of the tree.  But os.path.walk() visits things top
148181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # down, so we just use an object to collect a list of all
148281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # of the entries in the tree, reverse the list, and then
148381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # chmod the reversed (bottom-up) list.
148481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            col = Collector(top)
148581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.path.walk(top, col, None)
148681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            col.entries.reverse()
148781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for d in col.entries: do_chmod(d)
148881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
148981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def writable(self, top, write=1):
149081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Make the specified directory tree writable (write == 1)
149181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        or not (write == None).
149281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
149381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
149481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if sys.platform == 'win32':
149581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
149681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if write:
149781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                def do_chmod(fname):
149881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    try: os.chmod(fname, stat.S_IWRITE)
149981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    except OSError: pass
150081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
150181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                def do_chmod(fname):
150281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    try: os.chmod(fname, stat.S_IREAD)
150381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    except OSError: pass
150481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
150581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
150681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
150781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if write:
150881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                def do_chmod(fname):
150981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    try: st = os.stat(fname)
151081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    except OSError: pass
151181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200))
151281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
151381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                def do_chmod(fname):
151481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    try: st = os.stat(fname)
151581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    except OSError: pass
151681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200))
151781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
151881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if os.path.isfile(top):
151981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            do_chmod(top)
152081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
152181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            col = Collector(top)
152281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.path.walk(top, col, None)
152381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for d in col.entries: do_chmod(d)
152481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
152581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def executable(self, top, execute=1):
152681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Make the specified directory tree executable (execute == 1)
152781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        or not (execute == None).
152881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
152981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        This method has no effect on Windows systems, which use a
153081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        completely different mechanism to control file executability.
153181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
153281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
153381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if sys.platform == 'win32':
153481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return
153581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
153681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if execute:
153781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def do_chmod(fname):
153881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                try: st = os.stat(fname)
153981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                except OSError: pass
154081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IEXEC))
154181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
154281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def do_chmod(fname):
154381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                try: st = os.stat(fname)
154481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                except OSError: pass
154581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXEC))
154681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
154781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if os.path.isfile(top):
154881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # If it's a file, that's easy, just chmod it.
154981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            do_chmod(top)
155081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        elif execute:
155181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # It's a directory and we're trying to turn on execute
155281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # permission, so it's also pretty easy, just chmod the
155381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # directory and then chmod every entry on our walk down the
155481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # tree.  Because os.path.walk() is top-down, we'll enable
155581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # execute permission on any directories that have it disabled
155681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # before os.path.walk() tries to list their contents.
155781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            do_chmod(top)
155881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
155981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
156081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                for n in names:
156181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    do_chmod(os.path.join(dirname, n))
156281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
156381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.path.walk(top, chmod_entries, None)
156481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
156581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # It's a directory and we're trying to turn off execute
156681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # permission, which means we have to chmod the directories
156781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # in the tree bottom-up, lest disabling execute permission from
156881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # the top down get in the way of being able to get at lower
156981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # parts of the tree.  But os.path.walk() visits things top
157081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # down, so we just use an object to collect a list of all
157181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # of the entries in the tree, reverse the list, and then
157281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # chmod the reversed (bottom-up) list.
157381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            col = Collector(top)
157481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            os.path.walk(top, col, None)
157581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            col.entries.reverse()
157681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for d in col.entries: do_chmod(d)
157781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
157881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def write(self, file, content, mode = 'wb'):
157981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Writes the specified content text (second argument) to the
158081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        specified file name (first argument).  The file name may be
158181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        a list, in which case the elements are concatenated with the
158281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.path.join() method.  The file is created under the temporary
158381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        working directory.  Any subdirectories in the path must already
158481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        exist.  The I/O mode for the file may be specified; it must
158581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        begin with a 'w'.  The default is 'wb' (binary write).
158681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
158781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file = self.canonicalize(file)
158881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if mode[0] != 'w':
158981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise ValueError, "mode must begin with 'w'"
1590fbcd968877bac98d0d6f5f61847c0232939562f4thakis@chromium.org        with open(file, mode) as f:
1591fbcd968877bac98d0d6f5f61847c0232939562f4thakis@chromium.org            f.write(content)
159281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
159381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# Local Variables:
159481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# tab-width:4
159581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# indent-tabs-mode:nil
159681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# End:
159781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# vim: set expandtab tabstop=4 shiftwidth=4:
1598