about summary refs log tree commit diff
path: root/src/ci
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-08-15 16:03:56 +0200
committerGitHub <noreply@github.com>2025-08-15 16:03:56 +0200
commitb474f89d5ebf378f4758b8e9a4da3bf600058d21 (patch)
tree867dbe1508978f789ae7298fd40a0bfcb1aa13f2 /src/ci
parent87d677b7d0375c0c06255d23fc7d55e7e37521e0 (diff)
parent75b7d24a985ef9f6bab00414752dd74ceb47d114 (diff)
downloadrust-b474f89d5ebf378f4758b8e9a4da3bf600058d21.tar.gz
rust-b474f89d5ebf378f4758b8e9a4da3bf600058d21.zip
Rollup merge of #145311 - marcoieni:clean-disk-in-background-windows, r=Kobzol
ci: clean windows disk space in background
Diffstat (limited to 'src/ci')
-rw-r--r--src/ci/scripts/free-disk-space-windows-start.py72
-rw-r--r--src/ci/scripts/free-disk-space-windows-wait.py77
-rwxr-xr-xsrc/ci/scripts/free-disk-space.sh2
-rw-r--r--src/ci/scripts/free_disk_space_windows_util.py29
4 files changed, 179 insertions, 1 deletions
diff --git a/src/ci/scripts/free-disk-space-windows-start.py b/src/ci/scripts/free-disk-space-windows-start.py
new file mode 100644
index 00000000000..fbaad722bff
--- /dev/null
+++ b/src/ci/scripts/free-disk-space-windows-start.py
@@ -0,0 +1,72 @@
+"""
+Start freeing disk space on Windows in the background by launching
+the PowerShell cleanup script, and recording the PID in a file,
+so later steps can wait for completion.
+"""
+
+import subprocess
+from pathlib import Path
+from free_disk_space_windows_util import get_pid_file, get_log_file, run_main
+
+
+def get_cleanup_script() -> Path:
+    script_dir = Path(__file__).resolve().parent
+    cleanup_script = script_dir / "free-disk-space-windows.ps1"
+    if not cleanup_script.exists():
+        raise Exception(f"Cleanup script '{cleanup_script}' not found")
+    return cleanup_script
+
+
+def write_pid(pid: int):
+    pid_file = get_pid_file()
+    if pid_file.exists():
+        raise Exception(f"Pid file '{pid_file}' already exists")
+    pid_file.write_text(str(pid))
+    print(f"wrote pid {pid} in file {pid_file}")
+
+
+def launch_cleanup_process():
+    cleanup_script = get_cleanup_script()
+    log_file_path = get_log_file()
+    # Launch the PowerShell cleanup in the background and redirect logs.
+    try:
+        with open(log_file_path, "w", encoding="utf-8") as log_file:
+            proc = subprocess.Popen(
+                [
+                    "pwsh",
+                    # Suppress PowerShell startup banner/logo for cleaner logs.
+                    "-NoLogo",
+                    # Don't load user/system profiles. Ensures a clean, predictable environment.
+                    "-NoProfile",
+                    # Disable interactive prompts. Required for CI to avoid hangs.
+                    "-NonInteractive",
+                    # Execute the specified script file (next argument).
+                    "-File",
+                    str(cleanup_script),
+                ],
+                # Write child stdout to the log file.
+                stdout=log_file,
+                # Merge stderr into stdout for a single, ordered log stream.
+                stderr=subprocess.STDOUT,
+            )
+            print(
+                f"Started free-disk-space cleanup in background. "
+                f"pid={proc.pid}; log_file={log_file_path}"
+            )
+            return proc
+    except FileNotFoundError as e:
+        raise Exception("pwsh not found on PATH; cannot start disk cleanup.") from e
+
+
+def main() -> int:
+    proc = launch_cleanup_process()
+
+    # Write pid of the process to a file, so that later steps can read it and wait
+    # until the process completes.
+    write_pid(proc.pid)
+
+    return 0
+
+
+if __name__ == "__main__":
+    run_main(main)
diff --git a/src/ci/scripts/free-disk-space-windows-wait.py b/src/ci/scripts/free-disk-space-windows-wait.py
new file mode 100644
index 00000000000..b8612bb71c2
--- /dev/null
+++ b/src/ci/scripts/free-disk-space-windows-wait.py
@@ -0,0 +1,77 @@
+"""
+Wait for the background Windows disk cleanup process.
+"""
+
+import ctypes
+import time
+from free_disk_space_windows_util import get_pid_file, get_log_file, run_main
+
+
+def is_process_running(pid: int) -> bool:
+    PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
+    processHandle = ctypes.windll.kernel32.OpenProcess(
+        PROCESS_QUERY_LIMITED_INFORMATION, 0, pid
+    )
+    if processHandle == 0:
+        # The process is not running.
+        # If you don't have the sufficient rights to check if a process is running,
+        # zero is also returned. But in GitHub Actions we have these rights.
+        return False
+    else:
+        ctypes.windll.kernel32.CloseHandle(processHandle)
+        return True
+
+
+def print_logs():
+    """Print the logs from the cleanup script."""
+    log_file = get_log_file()
+    if log_file.exists():
+        print("free-disk-space logs:")
+        # Print entire log; replace undecodable bytes to avoid exceptions.
+        try:
+            with open(log_file, "r", encoding="utf-8", errors="replace") as f:
+                print(f.read())
+        except Exception as e:
+            raise Exception(f"Failed to read log file '{log_file}'") from e
+    else:
+        print(f"::warning::Log file '{log_file}' not found")
+
+
+def read_pid_from_file() -> int:
+    """Read the PID from the pid file."""
+
+    pid_file = get_pid_file()
+    if not pid_file.exists():
+        raise Exception(
+            f"No background free-disk-space process to wait for: pid file {pid_file} not found"
+        )
+
+    pid_file_content = pid_file.read_text().strip()
+
+    # Delete the file if it exists
+    pid_file.unlink(missing_ok=True)
+
+    try:
+        # Read the first line and convert to int.
+        pid = int(pid_file_content.splitlines()[0])
+        return pid
+    except Exception as e:
+        raise Exception(
+            f"Error while parsing the pid file with content '{pid_file_content!r}'"
+        ) from e
+
+
+def main() -> int:
+    pid = read_pid_from_file()
+
+    # Poll until process exits
+    while is_process_running(pid):
+        time.sleep(3)
+
+    print_logs()
+
+    return 0
+
+
+if __name__ == "__main__":
+    run_main(main)
diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh
index 062ad801cd8..9264fe4de6d 100755
--- a/src/ci/scripts/free-disk-space.sh
+++ b/src/ci/scripts/free-disk-space.sh
@@ -4,7 +4,7 @@ set -euo pipefail
 script_dir=$(dirname "$0")
 
 if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
-    pwsh $script_dir/free-disk-space-windows.ps1
+    python3 "$script_dir/free-disk-space-windows-start.py"
 else
     $script_dir/free-disk-space-linux.sh
 fi
diff --git a/src/ci/scripts/free_disk_space_windows_util.py b/src/ci/scripts/free_disk_space_windows_util.py
new file mode 100644
index 00000000000..488187864c2
--- /dev/null
+++ b/src/ci/scripts/free_disk_space_windows_util.py
@@ -0,0 +1,29 @@
+"""
+Utilities for Windows disk space cleanup scripts.
+"""
+
+import os
+from pathlib import Path
+import sys
+
+
+def get_temp_dir() -> Path:
+    """Get the temporary directory set by GitHub Actions."""
+    return Path(os.environ.get("RUNNER_TEMP"))
+
+
+def get_pid_file() -> Path:
+    return get_temp_dir() / "free-disk-space.pid"
+
+
+def get_log_file() -> Path:
+    return get_temp_dir() / "free-disk-space.log"
+
+
+def run_main(main_fn):
+    exit_code = 1
+    try:
+        exit_code = main_fn()
+    except Exception as e:
+        print(f"::error::{e}")
+    sys.exit(exit_code)