def main(argv):
    del argv  # Satisfy py linter's "unused" warning.
    if not FLAGS.build:
        exit("ctexplain: build efficiency measurement tool. Add --help " +
             "for usage.")
    elif len(FLAGS.build) > 1:
        exit("TODO(gregce): support multi-build shareability analysis")

    (labels, build_flags) = _get_build_flags(FLAGS.build[0])
    build_desc = ",".join(labels)
    with util.ProgressStep(f"Collecting configured targets for {build_desc}"):
        cts = lib.analyze_build(BazelApi(), labels, build_flags)
    for analysis in FLAGS.analysis:
        analyses[analysis].exec(cts)
Example #2
0
 def setUp(self):
     test_base.TestBase.setUp(self)
     self._bazel_api = BazelApi(self.RunBazel)
     self.ScratchFile('WORKSPACE')
     self.CreateWorkspaceWithDefaultRepos('repo/WORKSPACE')
Example #3
0
class BazelApiTest(test_base.TestBase):

    _bazel_api: BazelApi = None

    def setUp(self):
        test_base.TestBase.setUp(self)
        self._bazel_api = BazelApi(self.RunBazel)
        self.ScratchFile('WORKSPACE')
        self.CreateWorkspaceWithDefaultRepos('repo/WORKSPACE')

    def tearDown(self):
        test_base.TestBase.tearDown(self)

    def testBasicCquery(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        res = self._bazel_api.cquery(['//testapp:all'])
        success = res[0]
        cts = res[2]
        self.assertTrue(success)
        self.assertEqual(len(cts), 1)
        self.assertEqual(cts[0].label, '//testapp:fg')
        self.assertIsNone(cts[0].config)
        self.assertGreater(len(cts[0].config_hash), 10)
        self.assertIn('PlatformConfiguration', cts[0].transitive_fragments)

    def testFailedCquery(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        (success, stderr, cts) = self._bazel_api.cquery(['//testapp:typo'])
        self.assertFalse(success)
        self.assertEqual(len(cts), 0)
        self.assertIn("target 'typo' not declared in package 'testapp'",
                      os.linesep.join(stderr))

    def testTransitiveFragmentsAccuracy(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
            'filegroup(name = "ccfg", srcs = [":ccbin"])',
            'cc_binary(name = "ccbin", srcs = ["ccbin.cc"])'
        ])
        cts1 = self._bazel_api.cquery(['//testapp:fg'])[2]
        self.assertNotIn('CppConfiguration', cts1[0].transitive_fragments)
        cts2 = self._bazel_api.cquery(['//testapp:ccfg'])[2]
        self.assertIn('CppConfiguration', cts2[0].transitive_fragments)

    def testGetTargetConfig(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        cts = self._bazel_api.cquery(['//testapp:fg'])[2]
        config = self._bazel_api.get_config(cts[0].config_hash)
        expected_fragments = ['PlatformConfiguration', 'JavaConfiguration']
        for exp in expected_fragments:
            self.assertIn(exp, config.fragments.keys())
        core_options = config.options['CoreOptions']
        self.assertIsNotNone(core_options)
        self.assertIn(('stamp', 'false'), core_options.items())

    def testGetHostConfig(self):
        self.ScratchFile('testapp/BUILD', [
            'genrule(',
            '    name = "g",',
            '    srcs = [],',
            '    cmd = "",',
            '    outs = ["g.out"],',
            '    tools = [":fg"])',
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        query = ['//testapp:fg', '--universe_scope=//testapp:g']
        cts = self._bazel_api.cquery(query)[2]
        config = self._bazel_api.get_config(cts[0].config_hash)
        self.assertIsInstance(config, HostConfiguration)
        # We don't currently populate or read a host configuration's details.
        self.assertEqual(len(config.fragments), 0)
        self.assertEqual(len(config.options), 0)

    def testGetNullConfig(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        cts = self._bazel_api.cquery(['//testapp:a.file'])[2]
        config = self._bazel_api.get_config(cts[0].config_hash)
        self.assertIsInstance(config, NullConfiguration)
        # Null configurations have no information by definition.
        self.assertEqual(len(config.fragments), 0)
        self.assertEqual(len(config.options), 0)

    def testConfigFragmentsMap(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        cts = self._bazel_api.cquery(['//testapp:fg'])[2]
        fragments_map = self._bazel_api.get_config(
            cts[0].config_hash).fragments
        self.assertIn('PlatformOptions',
                      fragments_map['PlatformConfiguration'])
        self.assertIn('ShellConfiguration$Options',
                      fragments_map['ShellConfiguration'])

    def testConfigWithDefines(self):
        self.ScratchFile('testapp/BUILD', [
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        cquery_args = ['//testapp:fg', '--define', 'a=b']
        cts = self._bazel_api.cquery(cquery_args)[2]
        config = self._bazel_api.get_config(cts[0].config_hash)
        user_defined_options = config.options['user-defined']
        self.assertIsNotNone(user_defined_options)
        self.assertDictEqual(user_defined_options._dict, {'--define:a': 'b'})

    def testConfigWithStarlarkFlags(self):
        self.ScratchFile('testapp/defs.bzl', [
            'def _flag_impl(settings, attr):',
            '  pass',
            'string_flag = rule(',
            '  implementation = _flag_impl,',
            '  build_setting = config.string(flag = True)',
            ')',
        ])
        self.ScratchFile('testapp/BUILD', [
            'load(":defs.bzl", "string_flag")',
            'string_flag(name = "my_flag", build_setting_default = "nada")',
            'filegroup(name = "fg", srcs = ["a.file"])',
        ])
        cquery_args = ['//testapp:fg', '--//testapp:my_flag', 'algo']
        cts = self._bazel_api.cquery(cquery_args)[2]
        config = self._bazel_api.get_config(cts[0].config_hash)
        user_defined_options = config.options['user-defined']
        self.assertIsNotNone(user_defined_options)
        self.assertDictEqual(user_defined_options._dict,
                             {'//testapp:my_flag': 'algo'})
Example #4
0
# Lint as: python3
# Copyright 2020 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""ctexplain main entry point.

Currently a stump.
"""
from tools.ctexplain.bazel_api import BazelApi

bazel_api = BazelApi()

# TODO(gregce): move all logic to a _lib library so we can easily include
# end-to-end testing. We'll only handle flag parsing here, which we pass
# into the main invoker as standard Python args.