fix(template): move snapshot conflict check to pre-flight (before WinRM)
pypsrp alters terminal tty state during remote sessions. Any readline() call after WinRM work receives \r instead of \n on Enter (terminal in raw mode), causing the prompt to spin printing ^M and never return. Fix: check for existing snapshot and ask the user at the very beginning of the command, before any WinRM/pypsrp connections are opened, when the terminal is still in canonical mode. If the user declines, abort early. At the end, if the snapshot still exists (race-safe), delete silently and recreate — no second prompt needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -432,10 +432,26 @@ def template_prepare_win(
|
||||
if not build_password:
|
||||
build_password = click.prompt(f"New {build_username} password", hide_input=True)
|
||||
|
||||
# --- Backend: start VM and detect IP ---
|
||||
# --- Pre-flight snapshot conflict check (terminal still clean here) ---
|
||||
# Must happen before any WinRM/pypsrp calls, which alter tty state and
|
||||
# prevent readline() from receiving \n on Enter.
|
||||
config = load_config()
|
||||
backend = WorkstationVmrunBackend(vmrun_path=config.vmrun_path)
|
||||
handle = VmHandle(identifier=str(vmx_path), name=vmx_path.stem)
|
||||
existing_snapshots = backend.list_snapshots(handle)
|
||||
do_recreate_snapshot = True
|
||||
if snapshot in existing_snapshots:
|
||||
click.echo(f"[prepare-win] Snapshot '{snapshot}' already exists.")
|
||||
if recreate_snapshot:
|
||||
click.echo(f"[prepare-win] --recreate-snapshot set: will delete and recreate.")
|
||||
else:
|
||||
sys.stdout.write(f"[prepare-win] Delete and recreate '{snapshot}'? [y/N] ")
|
||||
sys.stdout.flush()
|
||||
raw = sys.stdin.readline()
|
||||
do_recreate_snapshot = raw.strip().lower() in ("y", "yes")
|
||||
if not do_recreate_snapshot:
|
||||
click.echo("[prepare-win] Keeping existing snapshot. Provisioning aborted.")
|
||||
return
|
||||
|
||||
if not backend.is_running(handle):
|
||||
click.echo(f"[prepare-win] Starting VM: {vmx_path.name} ...")
|
||||
@@ -664,22 +680,10 @@ Register-ScheduledTask -TaskName 'CI-StaticIp' `
|
||||
raise click.ClickException("VM did not power off within 120s.")
|
||||
click.echo("[prepare-win] VM powered off.")
|
||||
|
||||
# Create snapshot
|
||||
# Create snapshot — conflict already resolved at pre-flight above.
|
||||
vmrun_exe = backend.vmrun_path
|
||||
existing = backend.list_snapshots(handle)
|
||||
if snapshot in existing:
|
||||
click.echo(f"[prepare-win] Snapshot '{snapshot}' already exists.")
|
||||
if recreate_snapshot:
|
||||
do_recreate = True
|
||||
else:
|
||||
sys.stdout.write(f"[prepare-win] Delete and recreate '{snapshot}'? [y/N] ")
|
||||
sys.stdout.flush()
|
||||
raw = sys.stdin.readline()
|
||||
do_recreate = raw.strip().lower() in ("y", "yes")
|
||||
if not do_recreate:
|
||||
click.echo("[prepare-win] Keeping existing snapshot. Provisioning complete.")
|
||||
return
|
||||
click.echo(f"[prepare-win] Deleting snapshot '{snapshot}' ...")
|
||||
if snapshot in backend.list_snapshots(handle):
|
||||
click.echo(f"[prepare-win] Deleting existing snapshot '{snapshot}' ...")
|
||||
subprocess.run(
|
||||
[vmrun_exe, "-T", "ws", "deleteSnapshot", str(vmx_path), snapshot],
|
||||
check=True,
|
||||
|
||||
Reference in New Issue
Block a user