class NinjaDumperTestCase(SamuraiBuildTestCase):

    def setUp(self):
        super().setUp()
        mkdir_p(self.build_dir())
        self.dumper = NinjaDumper(self.build_dir())

    def assertFileContent(self, filename, expected_content):
        with open(filename) as stream:
            self.assertMultiLineEqual(stream.read(), expected_content)

    def assertDumpedFileContent(self, filename, expected_content):
        """Like assertFileContent but caller should not include file header."""
        self.assertFileContent(filename,
                               add_generator_caution(expected_content))

    def assertBuildFile(self, expected_build_content):
        header = textwrap.dedent("""
        ninja_required_version = 1.6

        include {}
        """).format(self.dumper.decl_pathname())
        self.assertDumpedFileContent(self.dumper.build_pathname(),
                                     header + expected_build_content)

    def assertDeclFile(self, expected_decl_content):
        self.assertDumpedFileContent(self.dumper.decl_pathname(),
                                     expected_decl_content)

    def dump(self, *args, **kwargs):
        """Shortcut when the test has to dump only one thing."""
        with self.dumper:
            self.dumper.dump(*args, **kwargs)
Exemple #2
0
 def generate(self):
     samurai_sys.build_dir = self.build_dir
     samurai_sys.output = self.output
     top_build_dir = os.getenv("SAMURAI_TOP_BUILD_DIR")
     dumper = NinjaDumper(self.build_dir, top_build_dir=top_build_dir)
     with _rm_abandoned_outputs(self.output, top_build_dir=top_build_dir), \
          _TerminationLog(dumper), \
          _install_sighandlers(_on_interrupt, SIGTERM, SIGHUP), \
          dumper:
         context = Context(dumper)
         samurai_sys.context = context
         evaluator = Evaluator(self.manifest)
         evaluator.evaluate()
         dumper.dump(AutoRegen(self.manifest, self.build_dir,
                               context, evaluator))
 def test_relative_to_top_build_dir(self):
     assert self.build_dir().startswith(self.tmpdir)
     self.dumper = NinjaDumper(self.build_dir(), top_build_dir=self.tmpdir)
     self.dump(Fixture.Filter()(
         input=os.path.join(self.build_dir(), "file.in"),
         output=os.path.join(self.build_dir(), "file.out")))
     build_content = read_file(self.dumper.build_pathname())
     self.assertRegex(
         build_content,
         re.compile(r"^build _build/file.out: r0 _build/file.in "
                    "| /path/to/filter$",
                    re.MULTILINE))
class TestCommand(NinjaDumperTestCase):

    def test_simple(self):
        self.dump(Fixture.Filter()(input="file.in", output="file.out"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build file.out: r0 file.in | /path/to/myfilter
              C = /path/to/myfilter file.in file.out
              D = Filtering file.out
            """))

    def test_command_with_no_outputs(self):
        c = Fixture.Sleep()()
        with self.assertRaises(ValueError):
            self.dump(c)

    def test_dump_rule_once(self):
        Echo = Fixture.Echo()
        with self.dumper:
            self.dumper.dump(Echo(text="foo", output="foo.out"))
            self.dumper.dump(Echo(text="bar", output="bar.out"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build foo.out: r0
              C = echo foo > foo.out
              D = Echo-ing 'foo' to foo.out...

            build bar.out: r0
              C = echo bar > bar.out
              D = Echo-ing 'bar' to bar.out...
            """))
        self.assertEqual(self.dumper.rule_count, 1)
        self.assertEqual(self.dumper.build_count, 2)
        self.assertEqual(self.dumper.subgenerator_count, 0)

    def test_dump_implicit_inputs(self):
        Echo = Fixture.Echo()
        echo = Echo(text="foo", output="foo.out",
                    implicit_inputs="bar")
        with self.dumper:
            self.dumper.dump(echo)
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build foo.out: r0 | bar
              C = echo foo > foo.out
              D = Echo-ing 'foo' to foo.out...
            """))

    def test_dump_implicit_outputs(self):
        Echo = Fixture.Echo()
        echo = Echo(text="foo", output="foo.out",
                    implicit_outputs="bar")
        with self.dumper:
            self.dumper.dump(echo)
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build bar foo.out: r0
              C = echo foo > foo.out
              D = Echo-ing 'foo' to foo.out...
            """))
        self.assertEqual(self.dumper.rule_count, 1)
        self.assertEqual(self.dumper.build_count, 1)
        self.assertEqual(self.dumper.subgenerator_count, 0)

    def test_dump_generator(self):
        class Gen(Command):
            command = "mygen {o@output}"
            generator = True
        with self.dumper:
            self.dumper.dump(Gen(output="foo"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build foo: r0
              C = mygen foo
              G = 1
            """))

    def test_dump_restat(self):
        class Restat(Command):
            command = "myrestat {o@output}"
            restat = True
        self.dump(Restat(output="foo"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build foo: r0
              C = myrestat foo
              R = 1
            """))

    def test_acceptPathLib_object(self):
        Filter = Fixture.Filter()
        filter = Filter(input=PathLib("foo"), output=PathLib("bar"))
        with self.dumper:
            self.dumper.dump(filter)
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build bar: r0 foo | /path/to/myfilter
              C = /path/to/myfilter foo bar
              D = Filtering bar
            """))

    def test_call_formatter(self):
        class TrecEval(Command):
            command = "trec_eval{details} {i@relevants} {i@run} > {o@eval}"
            description = "Evaluating {details}{run}"

            def __init__(self, details=True, **kwds):
                super().__init__(details=details, **kwds)

            @details.formatter
            def details(self):
                return " -q" if self.details else ""

        with self.dumper:
            self.dumper.dump(TrecEval(relevants="file.rel",
                                      run="file.run",
                                      eval="file.eval"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build file.eval: r0 file.rel file.run
              C = trec_eval -q file.rel file.run > file.eval
              D = Evaluating  -qfile.run
            """))

    def test_escape_filenames(self):
        MultiIO = Fixture.MultiIO()
        cmd = MultiIO(threshold="42 5",
                      inp1=PathLib("i 1"), inp2="i 2",
                      out1=PathLib("o 1"), out2="o 2",
                      implicit_inputs=("ii 1", "ii 2"),
                      orderonly_inputs=("ooi 1", "ooi 2"))
        with self.dumper:
            self.dumper.dump(cmd)
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build o$ 1 o$ 2: r0 i$ 1 i$ 2 | ii$ 1 ii$ 2 || ooi$ 1 ooi$ 2
              C = multio -p 42 5 'i 1' 'i 2' 'o 1' 'o 2'
              D = Doing 'o 1' and 'o 2'
            """))

    def test_cannot_unhandled_object(self):
        with self.assertRaisesRegex(TypeError,
                                    r"cannot dump NoneType object: None"):
            self.dump(None)

    def test_relative_to_build_dir(self):
        self.dump(Fixture.Filter()(
            input=os.path.join(self.build_dir(), "file.in"),
            output=os.path.join(self.build_dir(), "file.out")))
        build_content = read_file(self.dumper.build_pathname())
        self.assertRegex(
            build_content,
            re.compile(r"^build file.out: r0 file.in | /path/to/filter$",
                       re.MULTILINE))

    def test_relative_to_top_build_dir(self):
        assert self.build_dir().startswith(self.tmpdir)
        self.dumper = NinjaDumper(self.build_dir(), top_build_dir=self.tmpdir)
        self.dump(Fixture.Filter()(
            input=os.path.join(self.build_dir(), "file.in"),
            output=os.path.join(self.build_dir(), "file.out")))
        build_content = read_file(self.dumper.build_pathname())
        self.assertRegex(
            build_content,
            re.compile(r"^build _build/file.out: r0 _build/file.in "
                       "| /path/to/filter$",
                       re.MULTILINE))

    def test_reject_empty_command_string(self):
        class Empty(Command):
            command = ""
        c = Empty(implicit_outputs="o")
        with self.assertRaisesRegex(ValueError, r"empty command string"):
            self.dump(c)

    def test_escape_dollar_in_command(self):
        class C(Command):
            command = "cat {i@input} | sed -e 's/ .*$//' > {o@output}"
            description = "Removing $ in command producing {output}"
        self.dump(C(input="i", output="o"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build o: r0 i
              C = cat i | sed -e 's/ .*$$//' > o
              D = Removing $$ in command producing o
            """))

    def test_format_io_list_value(self):
        Cat = Fixture.Cat()
        Dup = Fixture.Dup()
        with self.dumper:
            self.dumper.dump(Cat(input_files=("f 0", ["f 1"]), output="j 0"))
            self.dumper.dump(Dup(input="f 0", dupes=("d 0", ["d 1"])))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build j$ 0: r0 f$ 0 f$ 1
              C = cat 'f 0' 'f 1' > 'j 0'

            build d$ 0 d$ 1: r0 f$ 0
              C = dup 'f 0' 'd 0' 'd 1'
            """))

    def test_dump_tuple_command(self):
        class C(Command):
            command = ("cmd", "{o@output}")
        self.dump(C(output="out"))
        self.assertDeclFile(RULE0)
        self.assertBuildFile(
            textwrap.dedent("""
            build out: r0
              C = cmd out
            """))
 def setUp(self):
     super().setUp()
     mkdir_p(self.build_dir())
     self.dumper = NinjaDumper(self.build_dir())