1# Copyright 2017 The Abseil Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Internal helper for running tests on Windows Bazel."""
16
17import os
18
19from absl import flags
20
21FLAGS = flags.FLAGS
22
23
24def get_executable_path(py_binary_name):
25  """Returns the executable path of a py_binary.
26
27  This returns the executable path of a py_binary that is in another Bazel
28  target's data dependencies.
29
30  On Linux/macOS, the path and __file__ has the same root directory.
31  On Windows, bazel builds an .exe file and we need to use the MANIFEST file
32  the location the actual binary.
33
34  Args:
35    py_binary_name: string, the name of a py_binary that is in another Bazel
36        target's data dependencies.
37
38  Raises:
39    RuntimeError: Raised when it cannot locate the executable path.
40  """
41
42  if os.name == 'nt':
43    py_binary_name += '.exe'
44    manifest_file = os.path.join(FLAGS.test_srcdir, 'MANIFEST')
45    workspace_name = os.environ['TEST_WORKSPACE']
46    manifest_entry = '{}/{}'.format(workspace_name, py_binary_name)
47    with open(manifest_file, 'r') as manifest_fd:
48      for line in manifest_fd:
49        tokens = line.strip().split(' ')
50        if len(tokens) != 2:
51          continue
52        if manifest_entry == tokens[0]:
53          return tokens[1]
54    raise RuntimeError(
55        'Cannot locate executable path for {}, MANIFEST file: {}.'.format(
56            py_binary_name, manifest_file))
57  else:
58    # NOTE: __file__ may be .py or .pyc, depending on how the module was
59    # loaded and executed.
60    path = __file__
61
62    # Use the package name to find the root directory: every dot is
63    # a directory, plus one for ourselves.
64    for _ in range(__name__.count('.') + 1):
65      path = os.path.dirname(path)
66
67    root_directory = path
68    return os.path.join(root_directory, py_binary_name)
69