예제 #1
0
  def testEnvironmentCommand(self):
    dir = VirtualDirectory()
    bar = Artifact("env/BAR", None)
    bar_set = Artifact("env/set/BAR", None)
    output = Artifact("foo", None)
    command = EnvironmentCommand(MockRuleContext(bar, bar_set), "BAR", output)

    enumerator = MockArtifactEnumerator({bar_set: "false"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([bar_set], enumerator.reads)
    self.assertEquals([], enumerator.inputs)
    self.assertEquals([output], enumerator.outputs)

    enumerator = MockArtifactEnumerator({bar_set: "true"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([bar_set], enumerator.reads)
    self.assertEquals([bar], enumerator.inputs)
    self.assertEquals([output], enumerator.outputs)

    context = MockCommandContext(dir)

    dir.write("env/set/BAR", "false")
    log = cStringIO.StringIO()
    self.assertFalse(command.run(context, log))
    self.assertFalse(dir.exists("foo"))
    self.assertEquals("Environment variable not set: BAR\n", log.getvalue())

    dir.write("env/set/BAR", "true")
    dir.write("env/BAR", "baz")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("baz", dir.read("foo"))
    self.assertEquals("", log.getvalue())

    self.assertEquals("echo $BAR > foo\n", _print_command(command))
예제 #2
0
class VirtualDirectoryTest(DirectoryTest, unittest.TestCase):
  def setUp(self):
    self.dir = VirtualDirectory()
    super(VirtualDirectoryTest, self).setUp()

  def addFile(self, name, mtime, content):
    self.dir.add(name, mtime, content)

  def addDirectory(self, name):
    self.dir.add_directory(name)

  def testGetDiskPath(self):
    self.assertEquals(None, self.dir.get_disk_path("foo/bar"))
예제 #3
0
class VirtualDirectoryTest(DirectoryTest, unittest.TestCase):
    def setUp(self):
        self.dir = VirtualDirectory()
        super(VirtualDirectoryTest, self).setUp()

    def addFile(self, name, mtime, content):
        self.dir.add(name, mtime, content)

    def addDirectory(self, name):
        self.dir.add_directory(name)

    def testGetDiskPath(self):
        self.assertEquals(None, self.dir.get_disk_path("foo/bar"))
예제 #4
0
  def __init__(self, output_path, all_configs = None):
    # We want to make sure to construct only one copy of each config, even
    # if configs refer to each other or multiple configs refer to a shared
    # config.  So, all_configs maps names to configs that we have already
    # constructed.
    if all_configs is None:
      # Note that if we just make all_configs default to {} in the method
      # signature, then Python will create a single empty map to use as the
      # default value for all calls rather than create a new one every call.
      # Since we modify all_configs during this method, we would be modifying
      # the shared default value, which would be bad.  If you don't understand
      # what I mean, try typing the following into the interpreter and then
      # calling it several times with no argument:
      #   def f(l = []):
      #     l.append("foo")
      #     return l
      # Ouchies.
      all_configs = {}
    if output_path is None:
      all_configs[""] = self
    else:
      all_configs[output_path] = self

    self.name = output_path
    self.source_dir = DiskDirectory(".")
    if output_path is None:
      self.output_dir = self.source_dir
    else:
      self.source_dir.mkdir(output_path)
      self.output_dir = DiskDirectory(output_path)
    self.mem_dir = VirtualDirectory()
    self.env_dir = VirtualDirectory()
    _restore_pickle(self.mem_dir, self.output_dir, "mem.pickle")
    _restore_pickle(self.env_dir, self.output_dir, "env.pickle")
    self.alt_configs = {}
    self.__make_root_dir()

    self.alt_configs["host"] = self

    if self.env_dir.exists("$mappings"):
      mappings = self.env_dir.read("$mappings").split(":")
      for mapping in mappings:
        if mapping == "":
          continue
        alias, name = mapping.split("=", 1)
        if name in all_configs:
          self.alt_configs[alias] = all_configs[name]
        else:
          if name == "":
            name = None
          self.alt_configs[alias] = Configuration(name, all_configs)
예제 #5
0
    def __init__(self, output_path, all_configs=None):
        # We want to make sure to construct only one copy of each config, even
        # if configs refer to each other or multiple configs refer to a shared
        # config.  So, all_configs maps names to configs that we have already
        # constructed.
        if all_configs is None:
            # Note that if we just make all_configs default to {} in the method
            # signature, then Python will create a single empty map to use as the
            # default value for all calls rather than create a new one every call.
            # Since we modify all_configs during this method, we would be modifying
            # the shared default value, which would be bad.  If you don't understand
            # what I mean, try typing the following into the interpreter and then
            # calling it several times with no argument:
            #   def f(l = []):
            #     l.append("foo")
            #     return l
            # Ouchies.
            all_configs = {}
        if output_path is None:
            all_configs[""] = self
        else:
            all_configs[output_path] = self

        self.name = output_path
        self.source_dir = DiskDirectory(".")
        if output_path is None:
            self.output_dir = self.source_dir
        else:
            self.source_dir.mkdir(output_path)
            self.output_dir = DiskDirectory(output_path)
        self.mem_dir = VirtualDirectory()
        self.env_dir = VirtualDirectory()
        _restore_pickle(self.mem_dir, self.output_dir, "mem.pickle")
        _restore_pickle(self.env_dir, self.output_dir, "env.pickle")
        self.alt_configs = {}
        self.__make_root_dir()

        self.alt_configs["host"] = self

        if self.env_dir.exists("$mappings"):
            mappings = self.env_dir.read("$mappings").split(":")
            for mapping in mappings:
                if mapping == "":
                    continue
                alias, name = mapping.split("=", 1)
                if name in all_configs:
                    self.alt_configs[alias] = all_configs[name]
                else:
                    if name == "":
                        name = None
                    self.alt_configs[alias] = Configuration(name, all_configs)
예제 #6
0
  def testEchoCommand(self):
    dir = VirtualDirectory()
    output = Artifact("foo", None)
    command = EchoCommand("bar", output)

    enumerator = MockArtifactEnumerator()
    command.enumerate_artifacts(enumerator)
    self.assertEquals([], enumerator.reads)
    self.assertEquals([], enumerator.inputs)
    self.assertEquals([output], enumerator.outputs)

    context = MockCommandContext(dir)
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("bar", dir.read("foo"))
    self.assertEquals("", log.getvalue())

    self.assertEquals("echo 'bar' > foo\n", _print_command(command))
예제 #7
0
    def testEchoCommand(self):
        dir = VirtualDirectory()
        output = Artifact("foo", None)
        command = EchoCommand("bar", output)

        enumerator = MockArtifactEnumerator()
        command.enumerate_artifacts(enumerator)
        self.assertEquals([], enumerator.reads)
        self.assertEquals([], enumerator.inputs)
        self.assertEquals([output], enumerator.outputs)

        context = MockCommandContext(dir)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("bar", dir.read("foo"))
        self.assertEquals("", log.getvalue())

        self.assertEquals("echo 'bar' > foo\n", _print_command(command))
예제 #8
0
  def clean(self, expunge=False):
    for dir in ["tmp", "bin", "lib", "share", "include", "mem", "env"]:
      if self.root_dir.exists(dir):
        shutil.rmtree(self.root_dir.get_disk_path(dir))

    for file in [ "mem.pickle", "env.pickle" ]:
      if self.root_dir.exists(file):
        os.remove(self.root_dir.get_disk_path(file))

    self.mem_dir = VirtualDirectory()

    if expunge:
      # Try to remove the output directory itself -- will fail if not empty.
      outdir = self.root_dir.get_disk_path(".")
      if outdir.endswith("/."):
        # rmdir doesn't like a trailing "/.".
        outdir = outdir[:-2]
      try:
        os.rmdir(outdir)
      except os.error:
        pass
    else:
      # Restore the parts of env.pickle that were set explicitly.
      new_env_dir = VirtualDirectory()

      if self.env_dir.exists("$mappings"):
        new_env_dir.write("$mappings", self.env_dir.read("$mappings"))
      if self.env_dir.exists("$config"):
        locked_vars = self.env_dir.read("$config")
        new_env_dir.write("$config", locked_vars)

        for var in locked_vars.split(","):
          if var != "":
            new_env_dir.write(var, self.env_dir.read(var))
            new_env_dir.write("set/" + var,
              self.env_dir.read("set/" + var))

      self.env_dir = new_env_dir

    self.__make_root_dir()
예제 #9
0
    def testEnvironmentCommand(self):
        dir = VirtualDirectory()
        bar = Artifact("env/BAR", None)
        bar_set = Artifact("env/set/BAR", None)
        output = Artifact("foo", None)
        command = EnvironmentCommand(MockRuleContext(bar, bar_set), "BAR",
                                     output)

        enumerator = MockArtifactEnumerator({bar_set: "false"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([bar_set], enumerator.reads)
        self.assertEquals([], enumerator.inputs)
        self.assertEquals([output], enumerator.outputs)

        enumerator = MockArtifactEnumerator({bar_set: "true"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([bar_set], enumerator.reads)
        self.assertEquals([bar], enumerator.inputs)
        self.assertEquals([output], enumerator.outputs)

        context = MockCommandContext(dir)

        dir.write("env/set/BAR", "false")
        log = cStringIO.StringIO()
        self.assertFalse(command.run(context, log))
        self.assertFalse(dir.exists("foo"))
        self.assertEquals("Environment variable not set: BAR\n",
                          log.getvalue())

        dir.write("env/set/BAR", "true")
        dir.write("env/BAR", "baz")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("baz", dir.read("foo"))
        self.assertEquals("", log.getvalue())

        self.assertEquals("echo $BAR > foo\n", _print_command(command))
예제 #10
0
    def testDoAllCommand(self):
        dir = VirtualDirectory()

        inputs = [Artifact("input1", None), Artifact("input2", None)]
        outputs = [Artifact("output1", None), Artifact("output2", None)]

        mock_command1 = MockCommand("command1", inputs[:1], outputs[:1])
        mock_command2 = MockCommand("command2", inputs[1:], outputs[1:])
        command = DoAllCommand([mock_command1, mock_command2])

        enumerator = MockArtifactEnumerator()
        command.enumerate_artifacts(enumerator)
        self.assertEquals([], enumerator.reads)
        self.assertEquals(inputs, enumerator.inputs)
        self.assertEquals(outputs, enumerator.outputs)

        context = MockCommandContext(dir)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals(
            "Ran MockCommand command1\n"
            "Ran MockCommand command2\n", log.getvalue())

        mock_command2.fails = True
        log = cStringIO.StringIO()
        self.assertFalse(command.run(context, log))
        self.assertEquals(
            "Ran MockCommand command1\n"
            "Ran MockCommand command2\n", log.getvalue())

        mock_command1.fails = True
        log = cStringIO.StringIO()
        self.assertFalse(command.run(context, log))
        self.assertEquals("Ran MockCommand command1\n", log.getvalue())

        self.assertEquals("mock_command command1\n"
                          "mock_command command2\n", _print_command(command))
예제 #11
0
  def testEnvironmentCommandWithDefault(self):
    bar = Artifact("env/BAR", None)
    bar_set = Artifact("env/set/BAR", None)
    default = Artifact("default", None)
    output = Artifact("foo", None)
    command = EnvironmentCommand(MockRuleContext(bar, bar_set),
                                 "BAR", output, default)

    enumerator = MockArtifactEnumerator({bar_set: "false"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([bar_set], enumerator.reads)
    self.assertEquals([default], enumerator.inputs)
    self.assertEquals([output], enumerator.outputs)

    enumerator = MockArtifactEnumerator({bar_set: "true"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([bar_set], enumerator.reads)
    self.assertEquals([bar], enumerator.inputs)
    self.assertEquals([output], enumerator.outputs)

    dir = VirtualDirectory()
    dir.write("env/set/BAR", "true")
    dir.write("env/BAR", "baz")
    context = MockCommandContext(dir)
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("baz", dir.read("foo"))
    self.assertEquals("", log.getvalue())

    dir = VirtualDirectory()
    dir.write("env/set/BAR", "false")
    dir.write("default", "qux")
    context = MockCommandContext(dir)
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("qux", dir.read("foo"))
    self.assertEquals("", log.getvalue())

    self.assertEquals("echo ${BAR:$(default)} > foo\n", _print_command(command))
예제 #12
0
    def testEnvironmentCommandWithDefault(self):
        bar = Artifact("env/BAR", None)
        bar_set = Artifact("env/set/BAR", None)
        default = Artifact("default", None)
        output = Artifact("foo", None)
        command = EnvironmentCommand(MockRuleContext(bar, bar_set), "BAR",
                                     output, default)

        enumerator = MockArtifactEnumerator({bar_set: "false"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([bar_set], enumerator.reads)
        self.assertEquals([default], enumerator.inputs)
        self.assertEquals([output], enumerator.outputs)

        enumerator = MockArtifactEnumerator({bar_set: "true"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([bar_set], enumerator.reads)
        self.assertEquals([bar], enumerator.inputs)
        self.assertEquals([output], enumerator.outputs)

        dir = VirtualDirectory()
        dir.write("env/set/BAR", "true")
        dir.write("env/BAR", "baz")
        context = MockCommandContext(dir)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("baz", dir.read("foo"))
        self.assertEquals("", log.getvalue())

        dir = VirtualDirectory()
        dir.write("env/set/BAR", "false")
        dir.write("default", "qux")
        context = MockCommandContext(dir)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("qux", dir.read("foo"))
        self.assertEquals("", log.getvalue())

        self.assertEquals("echo ${BAR:$(default)} > foo\n",
                          _print_command(command))
예제 #13
0
class SubprocessCommandTest(unittest.TestCase):
    def setUp(self):
        self.__action = Action(None, "dummy", "dummy")
        self.__artifact = Artifact("filename", None)
        self.__dir = VirtualDirectory()

    def testVerifyArgs(self):
        action = self.__action
        artifact = self.__artifact

        self.assertRaises(TypeError, SubprocessCommand, action, [0])
        self.assertRaises(TypeError, SubprocessCommand, action, [[0]])
        self.assertRaises(TypeError, SubprocessCommand, action, [artifact, 0])

        SubprocessCommand(action, ["foo"])
        SubprocessCommand(action, [artifact])
        SubprocessCommand(action, [artifact])
        SubprocessCommand(action, [[artifact]])
        SubprocessCommand(action, [[artifact]])
        SubprocessCommand(action, [artifact.contents()])

    def testEnumerateArtifacts(self):
        action = self.__action

        inputs = [Artifact("input1", None), Artifact("input2", None)]
        outputs = [Artifact("output1", action), Artifact("output2", action)]

        command = SubprocessCommand(action, ["foo", inputs[0], outputs[0]],
                                    implicit=[inputs[1], outputs[1]])
        enumerator = MockArtifactEnumerator()
        command.enumerate_artifacts(enumerator)
        self.assertEquals([], enumerator.reads)
        self.assertEquals(set(inputs), set(enumerator.inputs))
        self.assertEquals(set(outputs), set(enumerator.outputs))

        stdout = Artifact("stdout", None)
        stderr = Artifact("stderr", None)
        exit_code = Artifact("error_code", None)
        command = SubprocessCommand(action,
                                    inputs + outputs,
                                    capture_stdout=stdout,
                                    capture_stderr=stderr,
                                    capture_exit_status=exit_code)
        enumerator = MockArtifactEnumerator()
        command.enumerate_artifacts(enumerator)
        self.assertEquals([], enumerator.reads)
        self.assertEquals(set(inputs), set(enumerator.inputs))
        self.assertEquals(set(outputs + [stdout, stderr, exit_code]),
                          set(enumerator.outputs))

    def testFormatArgs(self):
        artifact = self.__artifact

        self.__dir.write(self.__artifact.filename, "content")

        self.assertFormattedAs(["foo"], ["foo"])
        self.assertFormattedAs([artifact], ["disk/filename"], "filename")
        self.assertFormattedAs([artifact.contents()], ["content"],
                               "$(filename)")
        self.assertFormattedAs([["foo"]], ["foo"])
        self.assertFormattedAs([[artifact]], ["disk/filename"], "filename")
        self.assertFormattedAs([[artifact.contents()]], ["content"],
                               "$(filename)")

        self.assertFormattedAs(
            ["foo", ["bar", ["baz", "qux"], "corge"], "grault"],
            ["foo", "barbazquxcorge", "grault"])

        self.assertFormattedAs(["(", artifact, ")"],
                               ["(", "disk/filename", ")"], "( filename )")
        self.assertFormattedAs([["(", artifact, ")"]], ["(disk/filename)"],
                               "(filename)")

        self.__dir.write(self.__artifact.filename, "content   with\nspaces")

        self.assertFormattedAs(["(", artifact.contents(), ")"],
                               ["(", "content", "with", "spaces", ")"],
                               "( $(filename) )")
        self.assertFormattedAs([["(", artifact.contents(), ")"]],
                               ["(content   with\nspaces)"], "($(filename))")

        self.assertFormattedAs(
            ["(", SubprocessCommand.Quoted(["foo bar", "baz"]), ")"],
            ["(", "'foo bar' baz", ")"])
        self.assertFormattedAs([SubprocessCommand.Quoted(["'hello'"])],
                               ["\"'hello'\""])
        self.assertFormattedAs(
            [SubprocessCommand.Quoted(["(", artifact, ")"])],
            ["'(' disk/filename ')'"], "'(' filename ')'")

    def assertFormattedAs(self, args, result, printed=None):
        context = MockCommandContext(self.__dir, diskpath_prefix="disk/")
        command = SubprocessCommand(self.__action, list(args))
        self.assertTrue(command.run(context, cStringIO.StringIO()))
        self.assertEquals(result, context.subprocess_args)

        if printed is None:
            printed = " ".join(result)
        self.assertEquals(printed + "\n", _print_command(command))

    def testRedirectStreams(self):
        # No redirection.
        command = SubprocessCommand(self.__action, ["foo"])
        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "some text", None)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
        self.assertTrue(
            context.subprocess_kwargs["stderr"] is subprocess.STDOUT)
        self.assertEquals("some text", log.getvalue())
        self.assertEquals("foo\n", _print_command(command))

        # Redirect stdout.
        command = SubprocessCommand(self.__action, ["foo"],
                                    capture_stdout=self.__artifact)
        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "some text", "error text")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
        self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
        self.assertEquals("some text", self.__dir.read("filename"))
        self.assertEquals("error text", log.getvalue())
        self.assertEquals("foo > filename\n", _print_command(command))

        # Redirect stderr.
        command = SubprocessCommand(self.__action, ["foo"],
                                    capture_stderr=self.__artifact)
        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "some text", "error text")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        # TODO(kenton): Uncomment when bug with writing to log is solved.
        #self.assertTrue(context.subprocess_kwargs["stdout"] is log)
        self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
        self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
        self.assertEquals("some text", log.getvalue())
        self.assertEquals("error text", self.__dir.read("filename"))
        self.assertEquals("foo 2> filename\n", _print_command(command))

        # Redirect both.
        command = SubprocessCommand(self.__action, ["foo"],
                                    capture_stdout=self.__artifact,
                                    capture_stderr=Artifact("file2", None))
        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "output", "error")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
        self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
        self.assertEquals("output", self.__dir.read("filename"))
        self.assertEquals("error", self.__dir.read("file2"))
        self.assertEquals("foo > filename 2> file2\n", _print_command(command))

        # Redirect both to same destination.
        command = SubprocessCommand(self.__action, ["foo"],
                                    capture_stdout=self.__artifact,
                                    capture_stderr=self.__artifact)
        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "combined text", None)
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
        self.assertTrue(
            context.subprocess_kwargs["stderr"] is subprocess.STDOUT)
        self.assertEquals("combined text", self.__dir.read("filename"))
        self.assertEquals("foo > filename 2>&1\n", _print_command(command))

    def testExitStatus(self):
        command = SubprocessCommand(self.__action, ["foo"])

        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "", None)
        self.assertTrue(command.run(context, cStringIO.StringIO()))

        context = MockCommandContext(self.__dir)
        context.subprocess_result = (1, "", None)
        self.assertFalse(command.run(context, cStringIO.StringIO()))

        context = MockCommandContext(self.__dir)
        context.subprocess_result = (-1, "", None)
        self.assertFalse(command.run(context, cStringIO.StringIO()))

        # Redirect exit status.
        command = SubprocessCommand(self.__action, ["foo"],
                                    capture_exit_status=self.__artifact)
        self.assertEquals(
            "foo && echo true > filename || echo false > filename\n",
            _print_command(command))

        context = MockCommandContext(self.__dir)
        context.subprocess_result = (0, "", None)
        self.assertTrue(command.run(context, cStringIO.StringIO()))
        self.assertEquals("true", self.__dir.read("filename"))

        context = MockCommandContext(self.__dir)
        context.subprocess_result = (1, "", None)
        self.assertTrue(command.run(context, cStringIO.StringIO()))
        self.assertEquals("false", self.__dir.read("filename"))
예제 #14
0
 def setUp(self):
     self.dir = VirtualDirectory()
     self.context = MockContext("mock.sebs", "src/mock.sebs")
     self.rule = Rule(self.context)
     self.console = make_console(cStringIO.StringIO())  # ignore output
예제 #15
0
class LoaderTest(unittest.TestCase):
  def setUp(self):
    self.dir = VirtualDirectory()
    self.loader = Loader(self.dir)

  def testBasics(self):
    self.dir.add("src/foo.sebs", 0, """
x = 123
_private = "hi"
a_rule = sebs.Rule()
nested_rule = [sebs.Rule()]
def func():
  return _private
""")
    file = self.loader.load("foo.sebs")

    self.assertTrue("sebs" not in file.__dict__)
    self.assertTrue("_private" not in file.__dict__)
    self.assertEqual(123, file.x)
    self.assertEqual("a_rule", file.a_rule.label)
    self.assertTrue(file.nested_rule[0].label is None)
    self.assertEqual(4, file.a_rule.line)
    self.assertEqual(5, file.nested_rule[0].line)
    self.assertEqual("foo.sebs:a_rule", file.a_rule.name)
    self.assertEqual("foo.sebs:5", file.nested_rule[0].name)
    self.assertEqual("hi", file.func())

  def testImport(self):
    self.dir.add("src/foo.sebs", 0, """bar = sebs.import_("bar.sebs")""")
    self.dir.add("src/bar.sebs", 0, """x = 123""")
    file = self.loader.load("foo.sebs")
    self.assertTrue(file.bar is self.loader.load("bar.sebs"))
    self.assertEqual(123, file.bar.x)

  def testCycle(self):
    self.dir.add("src/foo.sebs", 0, """sebs.import_("foo.sebs")""")
    self.assertRaises(DefinitionError, self.loader.load, "foo.sebs")

  def testAbsoluteImport(self):
    self.dir.add("src/foo/foo.sebs", 0, """
bar1 = sebs.import_("bar.sebs")
bar2 = sebs.import_("//foo/bar.sebs")
bar3 = sebs.import_("//bar/bar.sebs")
""")
    self.dir.add("src/foo/bar.sebs", 0, """x = 123""")
    self.dir.add("src/bar/bar.sebs", 0, """x = 321""")
    file = self.loader.load("foo/foo.sebs")
    self.assertTrue(file.bar1 is self.loader.load("foo/bar.sebs"))
    self.assertTrue(file.bar2 is self.loader.load("foo/bar.sebs"))
    self.assertTrue(file.bar3 is self.loader.load("bar/bar.sebs"))
    self.assertEqual(123, file.bar1.x)
    self.assertEqual(123, file.bar2.x)
    self.assertEqual(321, file.bar3.x)

  def testLazyImportProhibited(self):
    self.dir.add("src/foo.sebs", 0, "x = sebs")
    self.dir.add("src/bar.sebs", 0, "")
    foo = self.loader.load("foo.sebs")
    bar = self.loader.load("bar.sebs")
    self.assertRaises(DefinitionError, foo.x.import_, "bar.sebs")

  def testOverrideBuiltins(self):
    self.dir.add("src/foo.sebs", 0, """sebs = 123""")
    file = self.loader.load("foo.sebs")

    self.assertEqual(123, file.sebs)

  def testLoadDirectory(self):
    self.dir.add("src/foo/bar/SEBS", 0, "x = 123")
    file = self.loader.load("foo/bar")
    self.assertEqual(123, file.x)

  def testLoadTarget(self):
    self.dir.add("src/foo/bar/SEBS", 0, "x = 123")
    self.dir.add("src/baz.sebs", 0, "y = 'abc'")
    self.assertEqual(123, self.loader.load("foo/bar:x"))
    self.assertEqual("abc", self.loader.load("baz.sebs:y"))

  def testTimestamp(self):
    self.dir.add("src/foo.sebs", 1, """""")
    self.dir.add("src/bar.sebs", 0, """sebs.import_("foo.sebs")""")
    self.dir.add("src/baz.sebs", 2, """sebs.import_("foo.sebs")""")
    self.dir.add("src/qux.sebs", 0, """sebs.import_("bar.sebs")""")
    self.dir.add("src/quux.sebs", 0, """
sebs.import_("baz.sebs")
sebs.import_("qux.sebs")
""")

    self.assertEqual(1, self.loader.load_with_timestamp("foo.sebs")[1])
    self.assertEqual(1, self.loader.load_with_timestamp("bar.sebs")[1])
    self.assertEqual(2, self.loader.load_with_timestamp("baz.sebs")[1])
    self.assertEqual(1, self.loader.load_with_timestamp("qux.sebs")[1])
    self.assertEqual(2, self.loader.load_with_timestamp("quux.sebs")[1])
예제 #16
0
 def setUp(self):
   self.__action = Action(None, "dummy", "dummy")
   self.__artifact = Artifact("filename", None)
   self.__dir = VirtualDirectory()
예제 #17
0
class Configuration(object):
  def __init__(self, output_path, all_configs = None):
    # We want to make sure to construct only one copy of each config, even
    # if configs refer to each other or multiple configs refer to a shared
    # config.  So, all_configs maps names to configs that we have already
    # constructed.
    if all_configs is None:
      # Note that if we just make all_configs default to {} in the method
      # signature, then Python will create a single empty map to use as the
      # default value for all calls rather than create a new one every call.
      # Since we modify all_configs during this method, we would be modifying
      # the shared default value, which would be bad.  If you don't understand
      # what I mean, try typing the following into the interpreter and then
      # calling it several times with no argument:
      #   def f(l = []):
      #     l.append("foo")
      #     return l
      # Ouchies.
      all_configs = {}
    if output_path is None:
      all_configs[""] = self
    else:
      all_configs[output_path] = self

    self.name = output_path
    self.source_dir = DiskDirectory(".")
    if output_path is None:
      self.output_dir = self.source_dir
    else:
      self.source_dir.mkdir(output_path)
      self.output_dir = DiskDirectory(output_path)
    self.mem_dir = VirtualDirectory()
    self.env_dir = VirtualDirectory()
    _restore_pickle(self.mem_dir, self.output_dir, "mem.pickle")
    _restore_pickle(self.env_dir, self.output_dir, "env.pickle")
    self.alt_configs = {}
    self.__make_root_dir()

    self.alt_configs["host"] = self

    if self.env_dir.exists("$mappings"):
      mappings = self.env_dir.read("$mappings").split(":")
      for mapping in mappings:
        if mapping == "":
          continue
        alias, name = mapping.split("=", 1)
        if name in all_configs:
          self.alt_configs[alias] = all_configs[name]
        else:
          if name == "":
            name = None
          self.alt_configs[alias] = Configuration(name, all_configs)

  def __make_root_dir(self):
    self.mapping = _WorkingDirMapping(self.source_dir, self.output_dir,
                                      self.mem_dir, self.env_dir,
                                      self.alt_configs)
    self.root_dir = MappedDirectory(self.mapping)

  def save(self):
    if not self.mem_dir.empty():
      _save_pickle(self.mem_dir, self.root_dir, "mem.pickle")
    if not self.env_dir.empty():
      _save_pickle(self.env_dir, self.root_dir, "env.pickle")

  def getenv(self, name):
    if self.root_dir.read("env/set/" + name) == "true":
      return self.root_dir.read("env/" + name)
    else:
      return None

  def clean(self, expunge=False):
    for dir in ["tmp", "bin", "lib", "share", "include", "mem", "env"]:
      if self.root_dir.exists(dir):
        shutil.rmtree(self.root_dir.get_disk_path(dir))

    for file in [ "mem.pickle", "env.pickle" ]:
      if self.root_dir.exists(file):
        os.remove(self.root_dir.get_disk_path(file))

    self.mem_dir = VirtualDirectory()

    if expunge:
      # Try to remove the output directory itself -- will fail if not empty.
      outdir = self.root_dir.get_disk_path(".")
      if outdir.endswith("/."):
        # rmdir doesn't like a trailing "/.".
        outdir = outdir[:-2]
      try:
        os.rmdir(outdir)
      except os.error:
        pass
    else:
      # Restore the parts of env.pickle that were set explicitly.
      new_env_dir = VirtualDirectory()

      if self.env_dir.exists("$mappings"):
        new_env_dir.write("$mappings", self.env_dir.read("$mappings"))
      if self.env_dir.exists("$config"):
        locked_vars = self.env_dir.read("$config")
        new_env_dir.write("$config", locked_vars)

        for var in locked_vars.split(","):
          if var != "":
            new_env_dir.write(var, self.env_dir.read(var))
            new_env_dir.write("set/" + var,
              self.env_dir.read("set/" + var))

      self.env_dir = new_env_dir

    self.__make_root_dir()

  def get_all_linked_configs(self):
    result = set()
    self.__get_all_linked_configs_recursive(result)
    return result

  def __get_all_linked_configs_recursive(self, result):
    if self in result:
      return

    result.add(self)
    for link in self.alt_configs.values():
      link.__get_all_linked_configs_recursive(result)
예제 #18
0
    def testConditionalCommandWithNoElse(self):
        dir = VirtualDirectory()

        inputs = [Artifact("input1", None), Artifact("input2", None)]
        outputs = [Artifact("output1", None), Artifact("output2", None)]
        condition = Artifact("condition", None)

        mock_command1 = MockCommand("command1", inputs[:1], outputs[:1])
        command = ConditionalCommand(condition, mock_command1)

        enumerator = MockArtifactEnumerator()
        command.enumerate_artifacts(enumerator)
        self.assertEquals([condition], enumerator.reads)
        self.assertEquals([], enumerator.inputs)
        self.assertEquals([], enumerator.outputs)

        enumerator = MockArtifactEnumerator({condition: "true"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([condition], enumerator.reads)
        self.assertEquals(inputs[:1], enumerator.inputs)
        self.assertEquals(outputs[:1], enumerator.outputs)

        enumerator = MockArtifactEnumerator({condition: "false"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([condition], enumerator.reads)
        self.assertEquals([], enumerator.inputs)
        self.assertEquals([], enumerator.outputs)

        enumerator = MockArtifactEnumerator({condition: "blah"})
        command.enumerate_artifacts(enumerator)
        self.assertEquals([condition], enumerator.reads)
        self.assertEquals([], enumerator.inputs)
        self.assertEquals([], enumerator.outputs)

        context = MockCommandContext(dir)

        dir.write("condition", "true")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("Ran MockCommand command1\n", log.getvalue())

        mock_command1.fails = True
        log = cStringIO.StringIO()
        self.assertFalse(command.run(context, log))
        self.assertEquals("Ran MockCommand command1\n", log.getvalue())

        dir.write("condition", "false")
        log = cStringIO.StringIO()
        self.assertTrue(command.run(context, log))
        self.assertEquals("", log.getvalue())

        dir.write("condition", "blah")
        log = cStringIO.StringIO()
        self.assertFalse(command.run(context, log))
        self.assertEquals(
            "Condition artifact was not true or false: %s\n" % condition,
            log.getvalue())

        self.assertEquals("if condition {\n"
                          "  mock_command command1\n"
                          "}\n", _print_command(command))
예제 #19
0
 def setUp(self):
   self.virtual_dir = VirtualDirectory()
   self.dir = MappedDirectory(
       MappedDirectoryTest.MappingImpl("mapped_prefix", self.virtual_dir))
   super(MappedDirectoryTest, self).setUp()
예제 #20
0
class MappedDirectoryTest(DirectoryTest, unittest.TestCase):
  class MappingImpl(MappedDirectory.Mapping):
    def __init__(self, prefix, real_dir):
      super(MappedDirectoryTest.MappingImpl, self).__init__()
      self.__prefix = prefix
      self.__real_dir = real_dir

    def map(self, filename):
      return (self.__real_dir, os.path.join(self.__prefix, filename))

  def setUp(self):
    self.virtual_dir = VirtualDirectory()
    self.dir = MappedDirectory(
        MappedDirectoryTest.MappingImpl("mapped_prefix", self.virtual_dir))
    super(MappedDirectoryTest, self).setUp()

  def addFile(self, name, mtime, content):
    self.virtual_dir.add(os.path.join("mapped_prefix", name), mtime, content)

  def addDirectory(self, name):
    self.virtual_dir.add_directory(os.path.join("mapped_prefix", name))

  def testGetDiskPath(self):
    self.assertEquals(None, self.dir.get_disk_path("foo/bar"))

  def testGlob(self):
    # Must test with disk directory...
    tempdir = tempfile.mkdtemp()
    try:
      disk_dir = DiskDirectory(tempdir)

      disk_dir.write("foo.qux", "")
      disk_dir.write("bar.qux", "")
      disk_dir.write("baz.qux", "")
      disk_dir.write("foo.corge", "")
      disk_dir.write("bar.corge", "")
      disk_dir.write("baz.corge", "")

      class PrefixRemovingMapping(MappedDirectory.Mapping):
        def __init__(self, prefix, real_dir):
          super(PrefixRemovingMapping, self).__init__()
          self.__prefix = prefix
          self.__real_dir = real_dir

        def map(self, filename):
          assert filename.startswith(self.__prefix)
          return (self.__real_dir, filename[len(self.__prefix):])

      dir = MappedDirectory(PrefixRemovingMapping("a/", disk_dir))

      self.assertEquals(set(["a/foo.qux"]),
                        set(dir.expand_glob("a/foo.qux")))
      self.assertEquals(set(["a/foo.qux", "a/bar.qux", "a/baz.qux"]),
                        set(dir.expand_glob("a/*.qux")))
      self.assertEquals(set(["a/foo.corge", "a/bar.corge", "a/baz.corge"]),
                        set(dir.expand_glob("a/*.corge")))
      self.assertEquals(set(["a/foo.qux", "a/foo.corge"]),
                        set(dir.expand_glob("a/foo.*")))
      self.assertEquals(set(["a/foo.qux", "a/bar.qux", "a/baz.qux",
                             "a/foo.corge", "a/bar.corge", "a/baz.corge"]),
                        set(dir.expand_glob("a/*")))
      self.assertEquals(set([]),
                        set(dir.expand_glob("a/grault")))
    finally:
      shutil.rmtree(tempdir)
예제 #21
0
 def setUp(self):
   self.dir = VirtualDirectory()
   super(VirtualDirectoryTest, self).setUp()
예제 #22
0
  def testConditionalCommandWithNoElse(self):
    dir = VirtualDirectory()

    inputs = [ Artifact("input1", None), Artifact("input2", None) ]
    outputs = [ Artifact("output1", None), Artifact("output2", None) ]
    condition = Artifact("condition", None)

    mock_command1 = MockCommand("command1", inputs[:1], outputs[:1])
    command = ConditionalCommand(condition, mock_command1)

    enumerator = MockArtifactEnumerator()
    command.enumerate_artifacts(enumerator)
    self.assertEquals([condition], enumerator.reads)
    self.assertEquals([], enumerator.inputs)
    self.assertEquals([], enumerator.outputs)

    enumerator = MockArtifactEnumerator({condition: "true"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([condition], enumerator.reads)
    self.assertEquals(inputs[:1], enumerator.inputs)
    self.assertEquals(outputs[:1], enumerator.outputs)

    enumerator = MockArtifactEnumerator({condition: "false"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([condition], enumerator.reads)
    self.assertEquals([], enumerator.inputs)
    self.assertEquals([], enumerator.outputs)

    enumerator = MockArtifactEnumerator({condition: "blah"})
    command.enumerate_artifacts(enumerator)
    self.assertEquals([condition], enumerator.reads)
    self.assertEquals([], enumerator.inputs)
    self.assertEquals([], enumerator.outputs)

    context = MockCommandContext(dir)

    dir.write("condition", "true")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("Ran MockCommand command1\n", log.getvalue())

    mock_command1.fails = True
    log = cStringIO.StringIO()
    self.assertFalse(command.run(context, log))
    self.assertEquals("Ran MockCommand command1\n", log.getvalue())

    dir.write("condition", "false")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertEquals("", log.getvalue())

    dir.write("condition", "blah")
    log = cStringIO.StringIO()
    self.assertFalse(command.run(context, log))
    self.assertEquals(
        "Condition artifact was not true or false: %s\n" % condition,
        log.getvalue())

    self.assertEquals(
        "if condition {\n"
        "  mock_command command1\n"
        "}\n",
        _print_command(command))
예제 #23
0
 def setUp(self):
   self.dir = VirtualDirectory()
   self.context = MockContext("mock.sebs", "src/mock.sebs")
   self.rule = Rule(self.context)
   self.console = make_console(cStringIO.StringIO())  # ignore output
예제 #24
0
class SubprocessCommandTest(unittest.TestCase):
  def setUp(self):
    self.__action = Action(None, "dummy", "dummy")
    self.__artifact = Artifact("filename", None)
    self.__dir = VirtualDirectory()

  def testVerifyArgs(self):
    action = self.__action
    artifact = self.__artifact

    self.assertRaises(TypeError, SubprocessCommand, action, [0])
    self.assertRaises(TypeError, SubprocessCommand, action, [[0]])
    self.assertRaises(TypeError, SubprocessCommand, action, [artifact, 0])

    SubprocessCommand(action, ["foo"])
    SubprocessCommand(action, [artifact])
    SubprocessCommand(action, [artifact])
    SubprocessCommand(action, [[artifact]])
    SubprocessCommand(action, [[artifact]])
    SubprocessCommand(action, [artifact.contents()])

  def testEnumerateArtifacts(self):
    action = self.__action

    inputs = [ Artifact("input1", None), Artifact("input2", None) ]
    outputs = [ Artifact("output1", action), Artifact("output2", action) ]

    command = SubprocessCommand(action, ["foo", inputs[0], outputs[0]],
                                implicit = [inputs[1], outputs[1]])
    enumerator = MockArtifactEnumerator()
    command.enumerate_artifacts(enumerator)
    self.assertEquals([], enumerator.reads)
    self.assertEquals(set(inputs), set(enumerator.inputs))
    self.assertEquals(set(outputs), set(enumerator.outputs))

    stdout = Artifact("stdout", None)
    stderr = Artifact("stderr", None)
    exit_code = Artifact("error_code", None)
    command = SubprocessCommand(action, inputs + outputs,
                                capture_stdout = stdout,
                                capture_stderr = stderr,
                                capture_exit_status = exit_code)
    enumerator = MockArtifactEnumerator()
    command.enumerate_artifacts(enumerator)
    self.assertEquals([], enumerator.reads)
    self.assertEquals(set(inputs), set(enumerator.inputs))
    self.assertEquals(set(outputs + [stdout, stderr, exit_code]),
                      set(enumerator.outputs))

  def testFormatArgs(self):
    artifact = self.__artifact

    self.__dir.write(self.__artifact.filename, "content")

    self.assertFormattedAs(["foo"], ["foo"])
    self.assertFormattedAs([artifact], ["disk/filename"], "filename")
    self.assertFormattedAs([artifact.contents()],
                           ["content"], "$(filename)")
    self.assertFormattedAs([["foo"]], ["foo"])
    self.assertFormattedAs([[artifact]], ["disk/filename"], "filename")
    self.assertFormattedAs([[artifact.contents()]],
                           ["content"], "$(filename)")

    self.assertFormattedAs(["foo", ["bar", ["baz", "qux"], "corge"], "grault"],
                           ["foo", "barbazquxcorge", "grault"])

    self.assertFormattedAs(["(", artifact, ")"],
                           ["(", "disk/filename", ")"],
                           "( filename )")
    self.assertFormattedAs([["(", artifact, ")"]],
                           ["(disk/filename)"],
                           "(filename)")

    self.__dir.write(self.__artifact.filename, "content   with\nspaces")

    self.assertFormattedAs(["(", artifact.contents(), ")"],
                           ["(", "content", "with", "spaces", ")"],
                           "( $(filename) )")
    self.assertFormattedAs([["(", artifact.contents(), ")"]],
                           ["(content   with\nspaces)"],
                           "($(filename))")

    self.assertFormattedAs(["(", SubprocessCommand.Quoted(["foo bar", "baz"]),
                            ")"],
                           ["(", "'foo bar' baz", ")"])
    self.assertFormattedAs([SubprocessCommand.Quoted(["'hello'"])],
                           ["\"'hello'\""])
    self.assertFormattedAs([SubprocessCommand.Quoted(["(", artifact, ")"])],
                           ["'(' disk/filename ')'"],
                           "'(' filename ')'")

  def assertFormattedAs(self, args, result, printed = None):
    context = MockCommandContext(self.__dir, diskpath_prefix = "disk/")
    command = SubprocessCommand(self.__action, list(args))
    self.assertTrue(command.run(context, cStringIO.StringIO()))
    self.assertEquals(result, context.subprocess_args)

    if printed is None:
      printed = " ".join(result)
    self.assertEquals(printed + "\n", _print_command(command))

  def testRedirectStreams(self):
    # No redirection.
    command = SubprocessCommand(self.__action, ["foo"])
    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "some text", None)
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
    self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.STDOUT)
    self.assertEquals("some text", log.getvalue())
    self.assertEquals("foo\n", _print_command(command))

    # Redirect stdout.
    command = SubprocessCommand(self.__action, ["foo"],
                                capture_stdout = self.__artifact)
    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "some text", "error text")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
    self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
    self.assertEquals("some text", self.__dir.read("filename"))
    self.assertEquals("error text", log.getvalue())
    self.assertEquals("foo > filename\n", _print_command(command))

    # Redirect stderr.
    command = SubprocessCommand(self.__action, ["foo"],
                                capture_stderr = self.__artifact)
    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "some text", "error text")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    # TODO(kenton): Uncomment when bug with writing to log is solved.
    #self.assertTrue(context.subprocess_kwargs["stdout"] is log)
    self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
    self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
    self.assertEquals("some text", log.getvalue())
    self.assertEquals("error text", self.__dir.read("filename"))
    self.assertEquals("foo 2> filename\n", _print_command(command))

    # Redirect both.
    command = SubprocessCommand(self.__action, ["foo"],
                                capture_stdout = self.__artifact,
                                capture_stderr = Artifact("file2", None))
    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "output", "error")
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
    self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.PIPE)
    self.assertEquals("output", self.__dir.read("filename"))
    self.assertEquals("error", self.__dir.read("file2"))
    self.assertEquals("foo > filename 2> file2\n", _print_command(command))

    # Redirect both to same destination.
    command = SubprocessCommand(self.__action, ["foo"],
                                capture_stdout = self.__artifact,
                                capture_stderr = self.__artifact)
    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "combined text", None)
    log = cStringIO.StringIO()
    self.assertTrue(command.run(context, log))
    self.assertTrue(context.subprocess_kwargs["stdout"] is subprocess.PIPE)
    self.assertTrue(context.subprocess_kwargs["stderr"] is subprocess.STDOUT)
    self.assertEquals("combined text", self.__dir.read("filename"))
    self.assertEquals("foo > filename 2>&1\n", _print_command(command))

  def testExitStatus(self):
    command = SubprocessCommand(self.__action, ["foo"])

    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "", None)
    self.assertTrue(command.run(context, cStringIO.StringIO()))

    context = MockCommandContext(self.__dir)
    context.subprocess_result = (1, "", None)
    self.assertFalse(command.run(context, cStringIO.StringIO()))

    context = MockCommandContext(self.__dir)
    context.subprocess_result = (-1, "", None)
    self.assertFalse(command.run(context, cStringIO.StringIO()))

    # Redirect exit status.
    command = SubprocessCommand(self.__action, ["foo"],
                                capture_exit_status = self.__artifact)
    self.assertEquals("foo && echo true > filename || echo false > filename\n",
                      _print_command(command))

    context = MockCommandContext(self.__dir)
    context.subprocess_result = (0, "", None)
    self.assertTrue(command.run(context, cStringIO.StringIO()))
    self.assertEquals("true", self.__dir.read("filename"))

    context = MockCommandContext(self.__dir)
    context.subprocess_result = (1, "", None)
    self.assertTrue(command.run(context, cStringIO.StringIO()))
    self.assertEquals("false", self.__dir.read("filename"))
예제 #25
0
 def setUp(self):
     self.dir = VirtualDirectory()
     super(VirtualDirectoryTest, self).setUp()
예제 #26
0
class BuilderTest(unittest.TestCase):
    def setUp(self):
        self.dir = VirtualDirectory()
        self.context = MockContext("mock.sebs", "src/mock.sebs")
        self.rule = Rule(self.context)
        self.console = make_console(cStringIO.StringIO())  # ignore output

    def doBuild(self, *artifacts):
        builder = Builder(self.console)
        runner = MockRunner()
        config = MockConfiguration(self.dir)
        for artifact in artifacts:
            builder.add_artifact(config, artifact)
        builder.build(runner)
        return runner.actions

    def testNoAciton(self):
        input = Artifact("input", None)

        self.assertRaises(DefinitionError, self.doBuild, input)
        self.dir.add("input", 20, "")
        self.assertEqual([], self.doBuild(input))

    def testSimpleAction(self):
        input = Artifact("input", None)
        action = Action(self.rule, "")
        output = Artifact("output", action)
        action.command = MockCommand([input], [output])

        # output doesn't exist.
        self.dir.add("input", 20, "")
        self.assertEqual([action], self.doBuild(output))

        # output exists but is older than input.
        self.dir.add("output", 10, "")
        self.assertEqual([action], self.doBuild(output))

        # output exists and is newer than input.
        self.dir.add("output", 40, "")
        self.assertEqual([], self.doBuild(output))

        # SEBS file is newer than output.
        self.context.timestamp = 50
        self.assertEqual([action], self.doBuild(output))

    def testMultipleInputsAndOutputs(self):
        in1 = Artifact("in1", None)
        in2 = Artifact("in2", None)
        action = Action(self.rule, "")
        out1 = Artifact("out1", action)
        out2 = Artifact("out2", action)
        action.command = MockCommand([in1, in2], [out1, out2])

        # outputs don't exist.
        self.dir.add("in1", 20, "")
        self.dir.add("in2", 40, "")
        self.assertEqual([action], self.doBuild(out1, out2))

        # only one output exists
        self.dir.add("out1", 50, "")
        self.assertEqual([action], self.doBuild(out1, out2))
        self.assertEqual([], self.doBuild(out1))

        # both outputs exist, one is outdated
        self.dir.add("out2", 10, "")
        self.assertEqual([action], self.doBuild(out1, out2))
        self.assertEqual([], self.doBuild(out1))

        # both outputs exist, one is older than *one* of the inputs
        self.dir.add("out2", 30, "")
        self.assertEqual([action], self.doBuild(out1, out2))
        self.assertEqual([], self.doBuild(out1))

        # both outputs exist and are up-to-date.
        self.dir.add("out2", 50, "")
        self.assertEqual([], self.doBuild(out1, out2))

    def testActionWithDependency(self):
        input = Artifact("input", None)
        action1 = Action(self.rule, "")
        temp = Artifact("temp", action1)
        action1.command = MockCommand([input], [temp])
        action2 = Action(self.rule, "")
        output = Artifact("output", action2)
        action2.command = MockCommand([temp], [output])

        # outputs don't exist.
        self.dir.add("input", 20, "")
        self.assertEqual([action1, action2], self.doBuild(output))
        self.assertEqual([action1], self.doBuild(temp))

        # temp exists but is outdated.
        self.dir.add("temp", 10, "")
        self.assertEqual([action1, action2], self.doBuild(output))
        self.assertEqual([action1], self.doBuild(temp))

        # temp exists and is up-to-date.
        self.dir.add("temp", 30, "")
        self.assertEqual([action2], self.doBuild(output))
        self.assertEqual([], self.doBuild(temp))

        # output exists but is outdated.
        self.dir.add("output", 10, "")
        self.assertEqual([action2], self.doBuild(output))
        self.assertEqual([], self.doBuild(temp))

        # output exists and is up-to-date.
        self.dir.add("output", 40, "")
        self.assertEqual([], self.doBuild(output))
        self.assertEqual([], self.doBuild(temp))

        # temp is outdated but output is up-to-date.
        self.dir.add("temp", 10, "")
        self.assertEqual([action1, action2], self.doBuild(output))
        self.assertEqual([action1], self.doBuild(temp))

    def testDiamondDependency(self):
        input = Artifact("input", None)
        action1 = Action(self.rule, "")
        temp1 = Artifact("temp1", action1)
        action1.command = MockCommand([input], [temp1])
        action2 = Action(self.rule, "")
        temp2 = Artifact("temp2", action2)
        action2.command = MockCommand([input], [temp2])
        action3 = Action(self.rule, "")
        output = Artifact("output", action3)
        action3.command = MockCommand([temp1, temp2], [output])

        # outputs don't exist.
        self.dir.add("input", 20, "")
        self.assertEqual([action1, action2, action3], self.doBuild(output))
        self.assertEqual([action1], self.doBuild(temp1))
        self.assertEqual([action2], self.doBuild(temp2))

        # one side is up-to-date, other isn't.
        self.dir.add("temp1", 30, "")
        self.dir.add("output", 40, "")
        self.assertEqual([action2, action3], self.doBuild(output))
        self.assertEqual([], self.doBuild(temp1))
        self.assertEqual([action2], self.doBuild(temp2))

        # everything up-to-date.
        self.dir.add("temp2", 30, "")
        self.assertEqual([], self.doBuild(output))
        self.assertEqual([], self.doBuild(temp1))
        self.assertEqual([], self.doBuild(temp2))

        # original input too new.
        self.dir.add("input", 60, "")
        self.assertEqual([action1, action2, action3], self.doBuild(output))
        self.assertEqual([action1], self.doBuild(temp1))
        self.assertEqual([action2], self.doBuild(temp2))

    def testConditionalInputs(self):
        input = Artifact("input", None)
        condition = Artifact("cond", None)
        conditional_action = Action(self.rule, "", "conditional_action")
        conditional_input = Artifact("cond_input", conditional_action)
        conditional_action.command = MockCommand([], [conditional_input])
        action = Action(self.rule, "", "action")
        output = Artifact("output", action)
        action.command = ConditionalMockCommand(condition, [input],
                                                [conditional_input], [output])

        # output doesn't exist, condition is false.
        self.dir.add("cond", 20, "false")
        self.dir.add("input", 20, "")
        self.assertEqual([action], self.doBuild(output))

        # output exists, condition still false.
        self.dir.add("output", 30, "")
        self.assertEqual([], self.doBuild(output))

        # condition newer than output.
        self.dir.add("cond", 40, "")
        self.assertEqual([action], self.doBuild(output))
        self.dir.add("cond", 20, "")

        # input newer than output.
        self.dir.add("input", 40, "")
        self.assertEqual([action], self.doBuild(output))
        self.dir.add("input", 20, "")

        # condition is true, cond_input doesn't exist.
        self.dir.add("cond", 20, "true")
        self.assertEqual([conditional_action, action], self.doBuild(output))

        # cond_input newer than output -- doesn't matter since cond is false.
        self.dir.add("cond_input", 40, "")
        self.dir.add("cond", 20, "false")
        self.assertEqual([], self.doBuild(output))

        # condition is true, cond_input is newer than output.
        self.dir.add("cond", 20, "true")
        self.assertEqual([action], self.doBuild(output))

        # output newer than cond_input.
        self.dir.add("cond_input", 20, "")
        self.assertEqual([], self.doBuild(output))

    def testDerivedCondition(self):
        condition_dep = Artifact("cond_dep", None)

        # Note that MockRunner special-cases this action to make it copy cond_dep
        # to cond.
        condition_builder = Action(self.rule, "", "condition_builder")
        condition = Artifact("cond", condition_builder)
        condition_builder.command = MockCommand([condition_dep], [condition])

        conditional_action = Action(self.rule, "", "conditional_action")
        conditional_input = Artifact("cond_input", conditional_action)
        conditional_action.command = MockCommand([], [conditional_input])

        action = Action(self.rule, "", "action")
        output = Artifact("output", action)
        action.command = ConditionalMockCommand(condition, [],
                                                [conditional_input], [output])

        # Condition is false.
        self.dir.add("cond_dep", 20, "false")
        self.assertEqual([condition_builder, action], self.doBuild(output))

        # Condition is "true" but will become "false" when rebuilt.  This should
        # not cause conditional_action to be triggered because action should not
        # be allowed to read "cond" while it is dirty.
        self.dir.add("cond_dep", 30, "false")
        self.dir.add("cond", 20, "true")
        self.assertEqual([condition_builder, action], self.doBuild(output))

        # Condition is "false" but will become "true" when rebuilt.  This should
        # trigger conditional_action *even though* conditional_input was not listed
        # among the inputs in the first pass.
        self.dir.add("cond_dep", 30, "true")
        self.dir.add("cond", 20, "false")
        self.assertEqual([condition_builder, conditional_action, action],
                         self.doBuild(output))
예제 #27
0
class MappedDirectoryTest(DirectoryTest, unittest.TestCase):
    class MappingImpl(MappedDirectory.Mapping):
        def __init__(self, prefix, real_dir):
            super(MappedDirectoryTest.MappingImpl, self).__init__()
            self.__prefix = prefix
            self.__real_dir = real_dir

        def map(self, filename):
            return (self.__real_dir, os.path.join(self.__prefix, filename))

    def setUp(self):
        self.virtual_dir = VirtualDirectory()
        self.dir = MappedDirectory(
            MappedDirectoryTest.MappingImpl("mapped_prefix", self.virtual_dir))
        super(MappedDirectoryTest, self).setUp()

    def addFile(self, name, mtime, content):
        self.virtual_dir.add(os.path.join("mapped_prefix", name), mtime,
                             content)

    def addDirectory(self, name):
        self.virtual_dir.add_directory(os.path.join("mapped_prefix", name))

    def testGetDiskPath(self):
        self.assertEquals(None, self.dir.get_disk_path("foo/bar"))

    def testGlob(self):
        # Must test with disk directory...
        tempdir = tempfile.mkdtemp()
        try:
            disk_dir = DiskDirectory(tempdir)

            disk_dir.write("foo.qux", "")
            disk_dir.write("bar.qux", "")
            disk_dir.write("baz.qux", "")
            disk_dir.write("foo.corge", "")
            disk_dir.write("bar.corge", "")
            disk_dir.write("baz.corge", "")

            class PrefixRemovingMapping(MappedDirectory.Mapping):
                def __init__(self, prefix, real_dir):
                    super(PrefixRemovingMapping, self).__init__()
                    self.__prefix = prefix
                    self.__real_dir = real_dir

                def map(self, filename):
                    assert filename.startswith(self.__prefix)
                    return (self.__real_dir, filename[len(self.__prefix):])

            dir = MappedDirectory(PrefixRemovingMapping("a/", disk_dir))

            self.assertEquals(set(["a/foo.qux"]),
                              set(dir.expand_glob("a/foo.qux")))
            self.assertEquals(set(["a/foo.qux", "a/bar.qux", "a/baz.qux"]),
                              set(dir.expand_glob("a/*.qux")))
            self.assertEquals(
                set(["a/foo.corge", "a/bar.corge", "a/baz.corge"]),
                set(dir.expand_glob("a/*.corge")))
            self.assertEquals(set(["a/foo.qux", "a/foo.corge"]),
                              set(dir.expand_glob("a/foo.*")))
            self.assertEquals(
                set([
                    "a/foo.qux", "a/bar.qux", "a/baz.qux", "a/foo.corge",
                    "a/bar.corge", "a/baz.corge"
                ]), set(dir.expand_glob("a/*")))
            self.assertEquals(set([]), set(dir.expand_glob("a/grault")))
        finally:
            shutil.rmtree(tempdir)
예제 #28
0
class Configuration(object):
    def __init__(self, output_path, all_configs=None):
        # We want to make sure to construct only one copy of each config, even
        # if configs refer to each other or multiple configs refer to a shared
        # config.  So, all_configs maps names to configs that we have already
        # constructed.
        if all_configs is None:
            # Note that if we just make all_configs default to {} in the method
            # signature, then Python will create a single empty map to use as the
            # default value for all calls rather than create a new one every call.
            # Since we modify all_configs during this method, we would be modifying
            # the shared default value, which would be bad.  If you don't understand
            # what I mean, try typing the following into the interpreter and then
            # calling it several times with no argument:
            #   def f(l = []):
            #     l.append("foo")
            #     return l
            # Ouchies.
            all_configs = {}
        if output_path is None:
            all_configs[""] = self
        else:
            all_configs[output_path] = self

        self.name = output_path
        self.source_dir = DiskDirectory(".")
        if output_path is None:
            self.output_dir = self.source_dir
        else:
            self.source_dir.mkdir(output_path)
            self.output_dir = DiskDirectory(output_path)
        self.mem_dir = VirtualDirectory()
        self.env_dir = VirtualDirectory()
        _restore_pickle(self.mem_dir, self.output_dir, "mem.pickle")
        _restore_pickle(self.env_dir, self.output_dir, "env.pickle")
        self.alt_configs = {}
        self.__make_root_dir()

        self.alt_configs["host"] = self

        if self.env_dir.exists("$mappings"):
            mappings = self.env_dir.read("$mappings").split(":")
            for mapping in mappings:
                if mapping == "":
                    continue
                alias, name = mapping.split("=", 1)
                if name in all_configs:
                    self.alt_configs[alias] = all_configs[name]
                else:
                    if name == "":
                        name = None
                    self.alt_configs[alias] = Configuration(name, all_configs)

    def __make_root_dir(self):
        self.mapping = _WorkingDirMapping(self.source_dir, self.output_dir,
                                          self.mem_dir, self.env_dir,
                                          self.alt_configs)
        self.root_dir = MappedDirectory(self.mapping)

    def save(self):
        if not self.mem_dir.empty():
            _save_pickle(self.mem_dir, self.root_dir, "mem.pickle")
        if not self.env_dir.empty():
            _save_pickle(self.env_dir, self.root_dir, "env.pickle")

    def getenv(self, name):
        if self.root_dir.read("env/set/" + name) == "true":
            return self.root_dir.read("env/" + name)
        else:
            return None

    def clean(self, expunge=False):
        for dir in ["tmp", "bin", "lib", "share", "include", "mem", "env"]:
            if self.root_dir.exists(dir):
                shutil.rmtree(self.root_dir.get_disk_path(dir))

        for file in ["mem.pickle", "env.pickle"]:
            if self.root_dir.exists(file):
                os.remove(self.root_dir.get_disk_path(file))

        self.mem_dir = VirtualDirectory()

        if expunge:
            # Try to remove the output directory itself -- will fail if not empty.
            outdir = self.root_dir.get_disk_path(".")
            if outdir.endswith("/."):
                # rmdir doesn't like a trailing "/.".
                outdir = outdir[:-2]
            try:
                os.rmdir(outdir)
            except os.error:
                pass
        else:
            # Restore the parts of env.pickle that were set explicitly.
            new_env_dir = VirtualDirectory()

            if self.env_dir.exists("$mappings"):
                new_env_dir.write("$mappings", self.env_dir.read("$mappings"))
            if self.env_dir.exists("$config"):
                locked_vars = self.env_dir.read("$config")
                new_env_dir.write("$config", locked_vars)

                for var in locked_vars.split(","):
                    if var != "":
                        new_env_dir.write(var, self.env_dir.read(var))
                        new_env_dir.write("set/" + var,
                                          self.env_dir.read("set/" + var))

            self.env_dir = new_env_dir

        self.__make_root_dir()

    def get_all_linked_configs(self):
        result = set()
        self.__get_all_linked_configs_recursive(result)
        return result

    def __get_all_linked_configs_recursive(self, result):
        if self in result:
            return

        result.add(self)
        for link in self.alt_configs.values():
            link.__get_all_linked_configs_recursive(result)
예제 #29
0
 def setUp(self):
     self.virtual_dir = VirtualDirectory()
     self.dir = MappedDirectory(
         MappedDirectoryTest.MappingImpl("mapped_prefix", self.virtual_dir))
     super(MappedDirectoryTest, self).setUp()
예제 #30
0
    def clean(self, expunge=False):
        for dir in ["tmp", "bin", "lib", "share", "include", "mem", "env"]:
            if self.root_dir.exists(dir):
                shutil.rmtree(self.root_dir.get_disk_path(dir))

        for file in ["mem.pickle", "env.pickle"]:
            if self.root_dir.exists(file):
                os.remove(self.root_dir.get_disk_path(file))

        self.mem_dir = VirtualDirectory()

        if expunge:
            # Try to remove the output directory itself -- will fail if not empty.
            outdir = self.root_dir.get_disk_path(".")
            if outdir.endswith("/."):
                # rmdir doesn't like a trailing "/.".
                outdir = outdir[:-2]
            try:
                os.rmdir(outdir)
            except os.error:
                pass
        else:
            # Restore the parts of env.pickle that were set explicitly.
            new_env_dir = VirtualDirectory()

            if self.env_dir.exists("$mappings"):
                new_env_dir.write("$mappings", self.env_dir.read("$mappings"))
            if self.env_dir.exists("$config"):
                locked_vars = self.env_dir.read("$config")
                new_env_dir.write("$config", locked_vars)

                for var in locked_vars.split(","):
                    if var != "":
                        new_env_dir.write(var, self.env_dir.read(var))
                        new_env_dir.write("set/" + var,
                                          self.env_dir.read("set/" + var))

            self.env_dir = new_env_dir

        self.__make_root_dir()
예제 #31
0
 def setUp(self):
     self.__action = Action(None, "dummy", "dummy")
     self.__artifact = Artifact("filename", None)
     self.__dir = VirtualDirectory()
예제 #32
0
 def setUp(self):
   self.dir = VirtualDirectory()
   self.loader = Loader(self.dir)
예제 #33
0
class BuilderTest(unittest.TestCase):
  def setUp(self):
    self.dir = VirtualDirectory()
    self.context = MockContext("mock.sebs", "src/mock.sebs")
    self.rule = Rule(self.context)
    self.console = make_console(cStringIO.StringIO())  # ignore output

  def doBuild(self, *artifacts):
    builder = Builder(self.console)
    runner = MockRunner()
    config = MockConfiguration(self.dir)
    for artifact in artifacts:
      builder.add_artifact(config, artifact)
    builder.build(runner)
    return runner.actions

  def testNoAciton(self):
    input = Artifact("input", None)

    self.assertRaises(DefinitionError, self.doBuild, input)
    self.dir.add("input", 20, "")
    self.assertEqual([], self.doBuild(input))

  def testSimpleAction(self):
    input = Artifact("input", None)
    action = Action(self.rule, "")
    output = Artifact("output", action)
    action.command = MockCommand([input], [output])

    # output doesn't exist.
    self.dir.add("input", 20, "")
    self.assertEqual([action], self.doBuild(output))

    # output exists but is older than input.
    self.dir.add("output", 10, "")
    self.assertEqual([action], self.doBuild(output))

    # output exists and is newer than input.
    self.dir.add("output", 40, "")
    self.assertEqual([], self.doBuild(output))

    # SEBS file is newer than output.
    self.context.timestamp = 50
    self.assertEqual([action], self.doBuild(output))

  def testMultipleInputsAndOutputs(self):
    in1 = Artifact("in1", None)
    in2 = Artifact("in2", None)
    action = Action(self.rule, "")
    out1 = Artifact("out1", action)
    out2 = Artifact("out2", action)
    action.command = MockCommand([in1, in2], [out1, out2])

    # outputs don't exist.
    self.dir.add("in1", 20, "")
    self.dir.add("in2", 40, "")
    self.assertEqual([action], self.doBuild(out1, out2))

    # only one output exists
    self.dir.add("out1", 50, "")
    self.assertEqual([action], self.doBuild(out1, out2))
    self.assertEqual([], self.doBuild(out1))

    # both outputs exist, one is outdated
    self.dir.add("out2", 10, "")
    self.assertEqual([action], self.doBuild(out1, out2))
    self.assertEqual([], self.doBuild(out1))

    # both outputs exist, one is older than *one* of the inputs
    self.dir.add("out2", 30, "")
    self.assertEqual([action], self.doBuild(out1, out2))
    self.assertEqual([], self.doBuild(out1))

    # both outputs exist and are up-to-date.
    self.dir.add("out2", 50, "")
    self.assertEqual([], self.doBuild(out1, out2))

  def testActionWithDependency(self):
    input = Artifact("input", None)
    action1 = Action(self.rule, "")
    temp = Artifact("temp", action1)
    action1.command = MockCommand([input], [temp])
    action2 = Action(self.rule, "")
    output = Artifact("output", action2)
    action2.command = MockCommand([temp], [output])

    # outputs don't exist.
    self.dir.add("input", 20, "")
    self.assertEqual([action1, action2], self.doBuild(output))
    self.assertEqual([action1], self.doBuild(temp))

    # temp exists but is outdated.
    self.dir.add("temp", 10, "")
    self.assertEqual([action1, action2], self.doBuild(output))
    self.assertEqual([action1], self.doBuild(temp))

    # temp exists and is up-to-date.
    self.dir.add("temp", 30, "")
    self.assertEqual([action2], self.doBuild(output))
    self.assertEqual([], self.doBuild(temp))

    # output exists but is outdated.
    self.dir.add("output", 10, "")
    self.assertEqual([action2], self.doBuild(output))
    self.assertEqual([], self.doBuild(temp))

    # output exists and is up-to-date.
    self.dir.add("output", 40, "")
    self.assertEqual([], self.doBuild(output))
    self.assertEqual([], self.doBuild(temp))

    # temp is outdated but output is up-to-date.
    self.dir.add("temp", 10, "")
    self.assertEqual([action1, action2], self.doBuild(output))
    self.assertEqual([action1], self.doBuild(temp))

  def testDiamondDependency(self):
    input = Artifact("input", None)
    action1 = Action(self.rule, "")
    temp1 = Artifact("temp1", action1)
    action1.command = MockCommand([input], [temp1])
    action2 = Action(self.rule, "")
    temp2 = Artifact("temp2", action2)
    action2.command = MockCommand([input], [temp2])
    action3 = Action(self.rule, "")
    output = Artifact("output", action3)
    action3.command = MockCommand([temp1, temp2], [output])

    # outputs don't exist.
    self.dir.add("input", 20, "")
    self.assertEqual([action1, action2, action3], self.doBuild(output))
    self.assertEqual([action1], self.doBuild(temp1))
    self.assertEqual([action2], self.doBuild(temp2))

    # one side is up-to-date, other isn't.
    self.dir.add("temp1", 30, "")
    self.dir.add("output", 40, "")
    self.assertEqual([action2, action3], self.doBuild(output))
    self.assertEqual([], self.doBuild(temp1))
    self.assertEqual([action2], self.doBuild(temp2))

    # everything up-to-date.
    self.dir.add("temp2", 30, "")
    self.assertEqual([], self.doBuild(output))
    self.assertEqual([], self.doBuild(temp1))
    self.assertEqual([], self.doBuild(temp2))

    # original input too new.
    self.dir.add("input", 60, "")
    self.assertEqual([action1, action2, action3], self.doBuild(output))
    self.assertEqual([action1], self.doBuild(temp1))
    self.assertEqual([action2], self.doBuild(temp2))

  def testConditionalInputs(self):
    input = Artifact("input", None)
    condition = Artifact("cond", None)
    conditional_action = Action(self.rule, "", "conditional_action")
    conditional_input = Artifact("cond_input", conditional_action)
    conditional_action.command = MockCommand([], [conditional_input])
    action = Action(self.rule, "", "action")
    output = Artifact("output", action)
    action.command = ConditionalMockCommand(
        condition, [input], [conditional_input], [output])

    # output doesn't exist, condition is false.
    self.dir.add("cond", 20, "false")
    self.dir.add("input", 20, "")
    self.assertEqual([action], self.doBuild(output))

    # output exists, condition still false.
    self.dir.add("output", 30, "")
    self.assertEqual([], self.doBuild(output))

    # condition newer than output.
    self.dir.add("cond", 40, "")
    self.assertEqual([action], self.doBuild(output))
    self.dir.add("cond", 20, "")

    # input newer than output.
    self.dir.add("input", 40, "")
    self.assertEqual([action], self.doBuild(output))
    self.dir.add("input", 20, "")

    # condition is true, cond_input doesn't exist.
    self.dir.add("cond", 20, "true")
    self.assertEqual([conditional_action, action], self.doBuild(output))

    # cond_input newer than output -- doesn't matter since cond is false.
    self.dir.add("cond_input", 40, "")
    self.dir.add("cond", 20, "false")
    self.assertEqual([], self.doBuild(output))

    # condition is true, cond_input is newer than output.
    self.dir.add("cond", 20, "true")
    self.assertEqual([action], self.doBuild(output))

    # output newer than cond_input.
    self.dir.add("cond_input", 20, "")
    self.assertEqual([], self.doBuild(output))

  def testDerivedCondition(self):
    condition_dep = Artifact("cond_dep", None)

    # Note that MockRunner special-cases this action to make it copy cond_dep
    # to cond.
    condition_builder = Action(self.rule, "", "condition_builder")
    condition = Artifact("cond", condition_builder)
    condition_builder.command = MockCommand([condition_dep], [condition])

    conditional_action = Action(self.rule, "", "conditional_action")
    conditional_input = Artifact("cond_input", conditional_action)
    conditional_action.command = MockCommand([], [conditional_input])

    action = Action(self.rule, "", "action")
    output = Artifact("output", action)
    action.command = ConditionalMockCommand(
        condition, [], [conditional_input], [output])

    # Condition is false.
    self.dir.add("cond_dep", 20, "false")
    self.assertEqual([condition_builder, action], self.doBuild(output))

    # Condition is "true" but will become "false" when rebuilt.  This should
    # not cause conditional_action to be triggered because action should not
    # be allowed to read "cond" while it is dirty.
    self.dir.add("cond_dep", 30, "false")
    self.dir.add("cond", 20, "true")
    self.assertEqual([condition_builder, action], self.doBuild(output))

    # Condition is "false" but will become "true" when rebuilt.  This should
    # trigger conditional_action *even though* conditional_input was not listed
    # among the inputs in the first pass.
    self.dir.add("cond_dep", 30, "true")
    self.dir.add("cond", 20, "false")
    self.assertEqual([condition_builder, conditional_action, action],
                     self.doBuild(output))