xref: /aosp_15_r20/bootable/libbootloader/gbl/rewrite_rust_project_path.py (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1# Copyright (C) 2024 The Android Open Source Project
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
15import json
16import os
17import logging
18import tempfile
19
20# To generate rust-project.json from bazel, run
21# bazel run @rules_rust//tools/rust_analyzer:gen_rust_project --norepository_disable_download @gbl//efi:main
22# However, this yields incorrect source path.
23# Your source file
24# /usr/local/google/home/zhangkelvin/uefi-gbl-mainline/bootable/libbootloader/gbl/efi/src/main.rs
25# would turn into
26# /usr/local/google/home/uefi-gbl-mainline/out/bazel/output_user_root/e14d642d361d598c63507c64a56ecbc7/execroot/_main/external/gbl/efi/src/main.rs
27# and this confuses the rust-analyzer. This script will resolve the right
28# source path for you by checking if any of the parent path is a symlink,
29# and resolve all symlinks to final destination.
30
31
32def traverse(obj: dict):
33  if isinstance(obj, dict):
34    for (key, val) in obj.items():
35      if key == "root_module" or key == "CARGO_MANIFEST_DIR":
36        obj[key] = os.path.realpath(val)
37        continue
38      elif key == "include_dirs" or key == "exclude_dirs":
39        obj[key] = [os.path.realpath(d) for d in val]
40        continue
41      elif key == "cfg" and isinstance(val, list):
42        obj[key] = [o for o in val if o != "test"]
43        continue
44      traverse(val)
45  elif isinstance(obj, list):
46    for item in obj:
47      traverse(item)
48
49
50def main(argv):
51  logging.basicConfig(level=logging.INFO)
52  rust_project_json_path = "rust-project.json"
53  if len(argv) == 2:
54    rust_project_json_path = argv[1]
55  rust_project_json_path = os.path.realpath(rust_project_json_path)
56  project_root_path = os.path.dirname(rust_project_json_path)
57  logging.info("Using %s as project root path", project_root_path)
58  with open(rust_project_json_path, "r") as fp:
59    data = json.load(fp)
60    traverse(data)
61
62  with tempfile.NamedTemporaryFile("w+") as fp:
63    json.dump(data, fp.file, indent=True)
64    os.rename(fp.name, rust_project_json_path)
65    # create the tempfile again so deleting it works after exiting this scope
66    with open(fp.name, "w"):
67      pass
68
69
70if __name__ == "__main__":
71  import sys
72
73  main(sys.argv)
74