--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import re
+import sys
+import hashlib
+import requests
+import subprocess
+from datetime import datetime, timedelta
+
+LOCAL_CONF = "conf/local.conf"
+RUST_INC = "../openembedded-core/meta/recipes-devtools/rust/rust-source.inc"
+
+MACHINES = [
+ "qemux86-64",
+ "qemux86",
+ "qemuarm64",
+ "qemuarm",
+ "qemuriscv64",
+]
+
+RECIPES = [
+ "rust",
+ "cargo",
+ "nativesdk-rust",
+]
+
+def switch_machine(machine):
+ print(f"\n=== Switching MACHINE to {machine} ===")
+ with open(LOCAL_CONF, "r") as f:
+ content = f.read()
+
+ match = re.search(r'MACHINE\s*\?\?=\s*".*?"', content)
+ if not match:
+ raise RuntimeError("MACHINE ??= line not found in local.conf")
+
+ old_line = match.group(0)
+ new_line = f'MACHINE ??= "{machine}"'
+
+ if old_line != new_line:
+ content = content.replace(old_line, new_line)
+ with open(LOCAL_CONF, "w") as f:
+ f.write(content)
+ print(f"{old_line} -> {new_line}")
+ else:
+ print("MACHINE already set")
+
+def run_bitbake_with_tee(machine, recipe):
+ log_file = f"{machine}-{recipe}.log"
+
+ print(f"\nRunning bitbake {recipe} for MACHINE={machine}")
+ print(f"Logging to {log_file}")
+
+ cmd = f"set -o pipefail; bitbake {recipe} 2>&1 | tee {log_file}"
+
+ process = subprocess.Popen(["bash", "-c", cmd])
+ process.wait()
+
+ if process.returncode != 0:
+ print(f"FAILED: {recipe} for {machine}")
+ return False
+
+ print(f"SUCCESS: {recipe} for {machine}")
+ return True
+
+def run_all_recipes(machine):
+ results = {}
+ for recipe in RECIPES:
+ results[recipe] = run_bitbake_with_tee(machine, recipe)
+ return results
+
+
+def get_yesterday_date():
+ return (datetime.today() - timedelta(days=1)).strftime('%Y-%m-%d')
+
+def update_rust_url_and_sha256(file_path):
+ yesterday = get_yesterday_date()
+ new_url = f"https://static.rust-lang.org/dist/{yesterday}/rustc-nightly-src.tar.xz"
+ temp_file = "rustc-nightly-src.tar.xz"
+
+ print(f"Checking URL: {new_url}")
+ response = requests.head(new_url)
+ if response.status_code != 200:
+ print(f"URL not accessible: {new_url} (Status: {response.status_code})")
+ return False
+
+ print("Downloading tarball to compute SHA256...")
+ with open(temp_file, "wb") as f:
+ f.write(requests.get(new_url).content)
+
+ with open(temp_file, "rb") as f:
+ sha256 = hashlib.sha256(f.read()).hexdigest()
+ print(f"SHA256 computed: {sha256}")
+
+ os.remove(temp_file)
+ print("Deleted downloaded tarball.")
+
+ with open(file_path, 'r') as f:
+ content = f.read()
+
+ url_pattern = r"https://static\.rust-lang\.org/dist/\d{4}-\d{2}-\d{2}/rustc-nightly-src\.tar\.xz"
+ content, url_count = re.subn(url_pattern, new_url, content)
+
+ sha256_pattern = r'SRC_URI\[rust\.sha256sum\] = ".*?"'
+ sha256_replacement = f'SRC_URI[rust.sha256sum] = "{sha256}"'
+ content, sha256_count = re.subn(sha256_pattern, sha256_replacement, content)
+
+ with open(file_path, 'w') as f:
+ f.write(content)
+
+ print(f"Updated {url_count} URL(s) and {sha256_count} SHA256 line(s) in '{file_path}'")
+ return True
+
+def do_update_snapshot(machine):
+ switch_machine(machine)
+ snapshot_log = "snapshot.log"
+
+ print(f"\nRunning bitbake rust -c do_update_snapshot for MACHINE={machine}")
+ cmd = f"set -o pipefail; bitbake rust -c do_update_snapshot 2>&1 | tee {snapshot_log}"
+
+ process = subprocess.Popen(["bash", "-c", cmd])
+ process.wait()
+
+ if process.returncode != 0:
+ print(f"WARNING: do_update_snapshot failed. Check {snapshot_log}")
+ else:
+ print(f"do_update_snapshot completed successfully. Stage0 compiler updated.")
+
+def insert_sanity_tested_distro(conf_file):
+ with open(conf_file, "r") as f:
+ lines = f.readlines()
+
+ updated_lines = []
+ inserted = False
+ for line in lines:
+ updated_lines.append(line)
+ if not inserted and "MACHINE ??=" in line:
+ updated_lines.append('SANITY_TESTED_DISTROS = ""\n')
+ inserted = True
+
+ if inserted:
+ with open(conf_file, "w") as f:
+ f.writelines(updated_lines)
+ print("Inserted SANITY_TESTED_DISTROS after MACHINE ??=")
+ else:
+ print("MACHINE ??= not found, no changes made.")
+
+def main():
+ print("Updating rust snapshot in rust-source.inc ...")
+ if not update_rust_url_and_sha256(RUST_INC):
+ print("Failed to update rust snapshot. Exiting.")
+ sys.exit(1)
+
+ baseline_machine = "qemux86-64"
+ do_update_snapshot(baseline_machine)
+
+ all_failures = {}
+
+ try:
+ for machine in MACHINES:
+ print(f" BUILDING FOR MACHINE: {machine}")
+
+ switch_machine(machine)
+ results = run_all_recipes(machine)
+
+ failed_recipes = [r for r, ok in results.items() if not ok]
+ if failed_recipes:
+ all_failures[machine] = failed_recipes
+
+ finally:
+ switch_machine("qemux86-64")
+ print("\nMACHINE restored to qemux86-64")
+
+ insert_sanity_tested_distro(LOCAL_CONF)
+
+ for machine in MACHINES:
+ switch_machine(machine)
+
+ selftest_log = f"oe-selftest-{machine}.log"
+ cmd = f"oe-selftest -r rust -K 2>&1 | tee {selftest_log}"
+
+ print(f"Running: {cmd}")
+ process = subprocess.Popen(["bash", "-c", cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1)
+ for line in process.stdout:
+ print(line, end="")
+ process.wait()
+
+ if process.returncode != 0:
+ print(f"WARNING: oe-selftest failed for {machine}, check {selftest_log}")
+ else:
+ print(f"oe-selftest completed successfully for {machine}")
+
+ build_st_dir = "../build-st"
+ target_dir = f"../build-{machine}-st"
+ if os.path.exists(build_st_dir):
+ print(f"Moving {build_st_dir} -> {target_dir}")
+ if os.path.exists(target_dir):
+ subprocess.run(["rm", "-rf", target_dir])
+ subprocess.run(["mv", build_st_dir, target_dir])
+ else:
+ print(f"No build-st directory found for {machine}, skipping move.")
+
+ if not all_failures:
+ print("All machines and recipes completed successfully")
+ else:
+ print("Failures detected:")
+ for machine, recipes in all_failures.items():
+ print(f" {machine}: {', '.join(recipes)}")
+
+if __name__ == "__main__":
+ main()