feat(git): add proxy run command with auto-unset on exit
Add `git proxy run <name>` that sets proxy, runs the associated command, and auto-restores/unsets proxy on exit or Ctrl-C. Also fix click.Exit usage for Click 8.x compatibility.
This commit is contained in:
+89
-1
@@ -1,6 +1,9 @@
|
||||
"""Git utilities including proxy management."""
|
||||
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
@@ -64,7 +67,7 @@ def proxy_set(name: str) -> None:
|
||||
if name not in proxies:
|
||||
click.echo(f"Unknown proxy: {name}", err=True)
|
||||
click.echo(f"Available: {', '.join(proxies.keys())}", err=True)
|
||||
raise click.Exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
proxy_url = proxies[name]
|
||||
subprocess.run(
|
||||
@@ -114,3 +117,88 @@ def proxy_list_cmd() -> None:
|
||||
click.secho("Available proxies:", fg="cyan")
|
||||
for name, url in proxies.items():
|
||||
click.echo(f" {name:12} {url}")
|
||||
|
||||
|
||||
@proxy_cmd.command("run")
|
||||
@click.argument("name", shell_complete=_complete_proxy_names)
|
||||
@click.argument("command", nargs=-1, required=False)
|
||||
def proxy_run(name: str, command: tuple[str, ...]) -> None:
|
||||
"""Set proxy, run a command, auto-unset on exit.
|
||||
|
||||
If no COMMAND is given, tries to run a program with the same name as the proxy.
|
||||
If that program is not found, sets the proxy and waits for Ctrl-C.
|
||||
"""
|
||||
proxies = _get_proxies()
|
||||
if name not in proxies:
|
||||
click.echo(f"Unknown proxy: {name}", err=True)
|
||||
click.echo(f"Available: {', '.join(proxies.keys())}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
# Save current state
|
||||
old_http = _get_git_proxy("http.proxy")
|
||||
old_https = _get_git_proxy("https.proxy")
|
||||
|
||||
proxy_url = proxies[name]
|
||||
subprocess.run(
|
||||
["git", "config", "--global", "http.proxy", proxy_url], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "config", "--global", "https.proxy", proxy_url], check=True
|
||||
)
|
||||
click.secho(f"Git proxy set to {name}: {proxy_url}", fg="green")
|
||||
|
||||
# Determine what to run
|
||||
cmd_to_run = list(command) if command else None
|
||||
if cmd_to_run is None:
|
||||
if shutil.which(name):
|
||||
cmd_to_run = [name]
|
||||
|
||||
def cleanup():
|
||||
if old_http == "(not set)":
|
||||
_unset_git_proxy("http.proxy")
|
||||
else:
|
||||
subprocess.run(
|
||||
["git", "config", "--global", "http.proxy", old_http],
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
if old_https == "(not set)":
|
||||
_unset_git_proxy("https.proxy")
|
||||
else:
|
||||
subprocess.run(
|
||||
["git", "config", "--global", "https.proxy", old_https],
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
click.secho("Git proxy restored", fg="green")
|
||||
|
||||
if cmd_to_run:
|
||||
click.secho(f"Running: {' '.join(cmd_to_run)}", fg="cyan")
|
||||
click.secho("Press Ctrl-C to stop and auto-unset proxy\n", fg="cyan")
|
||||
proc = None
|
||||
try:
|
||||
proc = subprocess.Popen(cmd_to_run)
|
||||
proc.wait()
|
||||
except KeyboardInterrupt:
|
||||
if proc is not None:
|
||||
proc.send_signal(signal.SIGINT)
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
finally:
|
||||
cleanup()
|
||||
if proc is not None:
|
||||
sys.exit(proc.returncode)
|
||||
sys.exit(0)
|
||||
else:
|
||||
click.secho(
|
||||
f"Proxy active. Press Ctrl-C to stop and auto-unset proxy", fg="cyan"
|
||||
)
|
||||
try:
|
||||
signal.pause()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
cleanup()
|
||||
|
||||
Reference in New Issue
Block a user