crosvm/tools/contrib/cargo_refactor.py

128 lines
3.8 KiB
Python
Raw Normal View History

# Copyright 2021 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Refactoring tools for moving around crates and updating dependencies
# in toml files.
#
# Contains the last run refactoring for reference. Don't run this script, it'll
# fail, but use it as a foundation for other refactorings.
from pathlib import Path
import os
import re
import shutil
import subprocess
def replace_in_file(file_path: Path, search: str, replace: str):
with open(file_path, "r") as file:
contents = file.read()
(contents, count) = re.subn(search, replace, contents)
if count > 0:
print(file_path, search, replace)
with open(file_path, "w") as file:
file.write(contents)
def replace_path_in_all_cargo_toml(old_path: Path, new_path: Path):
"Replace path in all cargo.toml files, accounting for relative paths."
for toml in Path(".").glob("**/Cargo.toml"):
crate_dir = toml.parent
old_rel = os.path.relpath(old_path, crate_dir)
new_rel = os.path.relpath(new_path, crate_dir)
replace_in_file(
toml, re.escape(f'path = "{old_rel}"'), f'path = "{new_rel}"'
)
def replace_in_all_workspace_toml(search: str, replace: str):
for toml in sorted(Path(".").glob("*/Cargo.toml")):
replace_in_file(toml, search, replace)
def update_path_deps(toml: Path, from_path: Path, to_path: Path):
"Update path deps in toml file after moving it"
with open(toml, "r") as file:
contents = file.read()
for old_dep in re.findall('{ path = "([^"]+)"', contents):
new_dep = os.path.relpath((from_path / old_dep).resolve(), to_path)
contents = contents.replace(
f'path = "{old_dep}"', f'path = "{new_dep}"'
)
with open(toml, "w") as file:
file.write(contents)
def move_crate(from_path: Path, to_path: Path):
"Move crate and update dependencies"
print(f"{from_path} -> {to_path}")
if to_path.exists():
shutil.rmtree(to_path)
subprocess.check_call(["git", "mv", str(from_path), str(to_path)])
update_path_deps(to_path / "Cargo.toml", from_path, to_path)
replace_path_in_all_cargo_toml(from_path, to_path)
def update_workspace_members():
"To copy/paste into the main cargo.toml"
members: list[str] = []
members.append("members = [")
for toml in sorted(Path(".").glob("*/Cargo.toml")):
members.append(f' "{toml.parent}",')
members.append("]")
replace_in_file(
Path("Cargo.toml"), r"members = \[[^\]]+\]", "\n".join(members)
)
exclude: list[str] = []
exclude.append("exclude = [")
for toml in sorted(Path(".").glob("common/*/Cargo.toml")):
exclude.append(f' "{toml.parent}",')
exclude.append("]")
replace_in_file(
Path("Cargo.toml"), r"exclude = \[[^\]]+\]", "\n".join(exclude)
)
def main():
# Move crates from the root to common/
crates_to_move = [
"assertions",
"audio_streams",
"base",
"cros_async",
"data_model",
"io_uring",
"sync",
"sys_util",
]
for crate in crates_to_move:
move_crate(Path(crate), Path("common") / crate)
# Rename fuzz crate to match package name
move_crate(Path("fuzz"), Path("crosvm-fuzz"))
replace_in_file(
Path("tools/impl/test_config.py"),
r'"fuzz"',
r'"crosvm-fuzz"',
)
# Remove old ebuild annotations from crosvm internal crates
replace_in_all_workspace_toml(
r"\ #\ [a-zA-Z0-9_]+\ by\ ebuild",
r"",
)
# Remove separate workspaces from top level crates
replace_in_all_workspace_toml(
r"\[workspace\]",
r"",
)
update_workspace_members()
main()