import argparse
from pathlib import Path
import shutil
import subprocess
import sys
CRATES = (
("rustclamp-core", "core"),
("rustclamp-macros", "rustclamp/macros"),
("rustclamp-kernel", "kernel"),
("rustclamp-runtime", "runtime"),
("rustclamp-messaging", "messaging"),
("rustclamp-http", "http"),
("rustclamp-postgres", "postgres"),
("rustclamp-scheduler", "scheduler"),
("rustclamp-worker", "worker"),
("rustclamp", "rustclamp"),
("rustclamp-tooling", "rustclamp/tooling"),
)
NO_SEMVER = {"rustclamp-macros", "rustclamp-tooling"}
def patches(root):
arguments = []
for name, directory in CRATES:
arguments += ["--config", f'patch.crates-io.{name}.path="{root / directory}"']
arguments += ["--config", f'patch."https://github.com/rustclamp/core".rustclamp-core.path="{root / "core"}"']
return arguments
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[2])
parser.add_argument("--execute", action="store_true", help="upload instead of a dry run")
parser.add_argument("--from", dest="start", help="resume at this crate after a failed upload")
args = parser.parse_args()
root = args.root.resolve()
names = [name for name, _ in CRATES]
if args.start and args.start not in names:
parser.error(f"unknown crate {args.start}; one of {', '.join(names)}")
crates = CRATES[names.index(args.start):] if args.start else CRATES
if not args.execute and not shutil.which("cargo-semver-checks"):
sys.exit("cargo-semver-checks is missing: sudo pacman -S cargo-semver-checks")
for name, directory in crates:
if not (root / directory / "Cargo.toml").is_file():
parser.error(f"missing checkout: {root / directory}")
command = ["cargo", "publish", "--manifest-path", str(root / directory / "Cargo.toml")]
command += [] if args.execute else ["--dry-run", "--allow-dirty", *patches(root)]
print(f"{'publishing' if args.execute else 'checking'} {name}", flush=True)
lockfile = root / directory / "Cargo.lock"
locked = lockfile.read_bytes() if lockfile.is_file() else None
status = subprocess.run(command, cwd=root / directory).returncode
if not args.execute and locked is not None:
lockfile.write_bytes(locked)
if status == 0 and not args.execute and name not in NO_SEMVER:
status = subprocess.run(
["cargo", "semver-checks", "--manifest-path", str(root / directory / "Cargo.toml")],
cwd=root / directory,
).returncode
if status != 0:
sys.exit(f"{name} failed; fix it, then rerun with --from {name}")
print(f"{len(crates)} crates {'published' if args.execute else 'ready to publish'}")
if __name__ == "__main__":
main()