2023-02-19 13:01:18 -05:00
|
|
|
# This script implements the workspace inheritance mechanism described
|
|
|
|
# here: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table
|
|
|
|
#
|
|
|
|
# Please run `mypy --strict`, `black`, and `isort --profile black` on this after editing, thanks!
|
|
|
|
|
|
|
|
import sys
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
import tomli
|
|
|
|
import tomli_w
|
|
|
|
|
|
|
|
|
|
|
|
def load_file(path: str) -> dict[str, Any]:
|
|
|
|
with open(path, "rb") as f:
|
|
|
|
return tomli.load(f)
|
|
|
|
|
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
# This replicates the dependency merging logic from Cargo.
|
|
|
|
# See `inner_dependency_inherit_with`:
|
|
|
|
# https://github.com/rust-lang/cargo/blob/4de0094ac78743d2c8ff682489e35c8a7cafe8e4/src/cargo/util/toml/mod.rs#L982
|
2023-02-19 13:01:18 -05:00
|
|
|
def replace_key(
|
|
|
|
workspace_manifest: dict[str, Any], table: dict[str, Any], section: str, key: str
|
|
|
|
) -> bool:
|
2023-04-29 15:48:10 +02:00
|
|
|
if (
|
|
|
|
isinstance(table[key], dict)
|
|
|
|
and "workspace" in table[key]
|
|
|
|
and table[key]["workspace"] is True
|
|
|
|
):
|
2023-02-19 13:01:18 -05:00
|
|
|
print("replacing " + key)
|
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
local_dep = table[key]
|
|
|
|
del local_dep["workspace"]
|
2023-02-19 13:01:18 -05:00
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
workspace_dep = workspace_manifest[section][key]
|
2023-02-19 13:01:18 -05:00
|
|
|
|
|
|
|
if section == "dependencies":
|
2024-05-10 15:55:42 +03:00
|
|
|
if isinstance(workspace_dep, str):
|
|
|
|
workspace_dep = {"version": workspace_dep}
|
2023-02-19 13:01:18 -05:00
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
final: dict[str, Any] = workspace_dep.copy()
|
2023-02-19 13:01:18 -05:00
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
merged_features = local_dep.pop("features", []) + workspace_dep.get("features", [])
|
|
|
|
if merged_features:
|
|
|
|
final["features"] = merged_features
|
2023-02-19 13:01:18 -05:00
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
local_default_features = local_dep.pop("default-features", None)
|
|
|
|
workspace_default_features = workspace_dep.get("default-features")
|
|
|
|
|
|
|
|
if not workspace_default_features and local_default_features:
|
|
|
|
final["default-features"] = True
|
|
|
|
|
|
|
|
optional = local_dep.pop("optional", False)
|
|
|
|
if optional:
|
|
|
|
final["optional"] = True
|
|
|
|
|
replace-workspace-values.py: Allow "package" key in Cargo.toml dependencies (#377721)
* Allow "package" key in Cargo.toml dependencies
* Update replace-workspace-values.py
Some dependencies in Cargo.toml have a "package" key, which serves as an alias:
```
foo = { package = "original-name" ... }
```
which with nixpkgs triggered
```
> Copying to /nix/store/jay72vz43afnlymsah7v543zmnv6l7ck-gcli-0.3.0-vendor/subxt-0.37.0
> Patching /nix/store/jay72vz43afnlymsah7v543zmnv6l7ck-gcli-0.3.0-vendor/subxt-0.37.0/Cargo.toml
> Traceback (most recent call last):
> File "/nix/store/harh7nnnib9896dwqr0xjqrr0l8wdcw7-replace-workspace-values/bin/replace-workspace-values", line 127, in <module>
> main()
> File "/nix/store/harh7nnnib9896dwqr0xjqrr0l8wdcw7-replace-workspace-values/bin/replace-workspace-values", line 104, in main
> changed |= replace_dependencies(workspace_manifest, crate_manifest)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/nix/store/harh7nnnib9896dwqr0xjqrr0l8wdcw7-replace-workspace-values/bin/replace-workspace-values", line 77, in replace_dependencies
> changed |= replace_key(workspace_manifest, root[key], "dependencies", k)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/nix/store/harh7nnnib9896dwqr0xjqrr0l8wdcw7-replace-workspace-values/bin/replace-workspace-values", line 58, in replace_key
> raise Exception(f"Unhandled keys in inherited dependency {key}: {local_dep}")
> Exception: Unhandled keys in inherited dependency codec: {'package': 'parity-scale-codec'}
> Traceback (most recent call last):
> File "/nix/store/qrf1j1w95va92fzv55lxpvw2dpm03bnr-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 314, in <module>
> main()
> File "/nix/store/qrf1j1w95va92fzv55lxpvw2dpm03bnr-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 310, in main
> subcommand_func()
> File "/nix/store/qrf1j1w95va92fzv55lxpvw2dpm03bnr-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 302, in <lambda>
> "create-vendor": lambda: create_vendor(vendor_staging_dir=Path(sys.argv[2]), out_dir=Path(sys.argv[3]))
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/nix/store/qrf1j1w95va92fzv55lxpvw2dpm03bnr-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 259, in create_vendor
> copy_and_patch_git_crate_subtree(git_tree, pkg["name"], crate_out_dir)
> File "/nix/store/qrf1j1w95va92fzv55lxpvw2dpm03bnr-fetch-cargo-vendor-util/bin/fetch-cargo-vendor-util", line 215, in copy_and_patch_git_crate_subtree
> subprocess.check_output(cmd)
> File "/nix/store/qrc496n6fsqp4p5m5h8wmw5d5jwyw5mr-python3-3.12.8/lib/python3.12/subprocess.py", line 466, in check_output
> return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/nix/store/qrc496n6fsqp4p5m5h8wmw5d5jwyw5mr-python3-3.12.8/lib/python3.12/subprocess.py", line 571, in run
> raise CalledProcessError(retcode, process.args,
> subprocess.CalledProcessError: Command '['replace-workspace-values', '/nix/store/jay72vz43afnlymsah7v543zmnv6l7ck-gcli-0.3.0-vendor/subxt-0.37.0/Cargo.toml', '/nix/store/c4jdggg9ihgi032pyc7g6ysdpb30xv1r-gcli-0.3.0-vendor-staging/git/00f181c1a5d8986e7146ddc72a745c793a9a1d8e/Cargo.toml']' returned non-zero exit status 1.
```
This fixes that
2025-02-08 23:44:37 +01:00
|
|
|
if "package" in local_dep:
|
|
|
|
final["package"] = local_dep.pop("package")
|
|
|
|
|
2024-05-10 15:55:42 +03:00
|
|
|
if local_dep:
|
|
|
|
raise Exception(f"Unhandled keys in inherited dependency {key}: {local_dep}")
|
|
|
|
|
|
|
|
table[key] = final
|
2023-02-19 13:01:18 -05:00
|
|
|
elif section == "package":
|
2024-05-10 15:55:42 +03:00
|
|
|
table[key] = workspace_dep
|
2023-02-19 13:01:18 -05:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def replace_dependencies(
|
|
|
|
workspace_manifest: dict[str, Any], root: dict[str, Any]
|
|
|
|
) -> bool:
|
|
|
|
changed = False
|
|
|
|
|
|
|
|
for key in ["dependencies", "dev-dependencies", "build-dependencies"]:
|
|
|
|
if key in root:
|
|
|
|
for k in root[key].keys():
|
|
|
|
changed |= replace_key(workspace_manifest, root[key], "dependencies", k)
|
|
|
|
|
|
|
|
return changed
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
2023-03-22 16:11:36 +01:00
|
|
|
top_cargo_toml = load_file(sys.argv[2])
|
|
|
|
|
|
|
|
if "workspace" not in top_cargo_toml:
|
|
|
|
# If top_cargo_toml is not a workspace manifest, then this script was probably
|
|
|
|
# ran on something that does not actually use workspace dependencies
|
|
|
|
print(f"{sys.argv[2]} is not a workspace manifest, doing nothing.")
|
|
|
|
return
|
|
|
|
|
2023-02-19 13:01:18 -05:00
|
|
|
crate_manifest = load_file(sys.argv[1])
|
2023-03-22 16:11:36 +01:00
|
|
|
workspace_manifest = top_cargo_toml["workspace"]
|
2023-02-19 13:01:18 -05:00
|
|
|
|
|
|
|
if "workspace" in crate_manifest:
|
|
|
|
return
|
|
|
|
|
|
|
|
changed = False
|
|
|
|
|
|
|
|
for key in crate_manifest["package"].keys():
|
|
|
|
changed |= replace_key(
|
|
|
|
workspace_manifest, crate_manifest["package"], "package", key
|
|
|
|
)
|
|
|
|
|
|
|
|
changed |= replace_dependencies(workspace_manifest, crate_manifest)
|
|
|
|
|
|
|
|
if "target" in crate_manifest:
|
|
|
|
for key in crate_manifest["target"].keys():
|
|
|
|
changed |= replace_dependencies(
|
|
|
|
workspace_manifest, crate_manifest["target"][key]
|
|
|
|
)
|
|
|
|
|
2023-12-16 05:27:33 +00:00
|
|
|
if (
|
|
|
|
"lints" in crate_manifest
|
|
|
|
and "workspace" in crate_manifest["lints"]
|
|
|
|
and crate_manifest["lints"]["workspace"] is True
|
|
|
|
):
|
|
|
|
crate_manifest["lints"] = workspace_manifest["lints"]
|
|
|
|
|
2023-02-19 13:01:18 -05:00
|
|
|
if not changed:
|
|
|
|
return
|
|
|
|
|
|
|
|
with open(sys.argv[1], "wb") as f:
|
|
|
|
tomli_w.dump(crate_manifest, f)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|