aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2022-02-01 10:19:40 +0100
committerMartin Ridgers <[email protected]>2022-02-01 10:19:46 +0100
commit9039c8066a97b09ee5848abc95d31e84529450be (patch)
treeda4ad315a40ee671a52e429c54be4ffa6f89eb65 /scripts
parentMerge branch 'main' of https://github.com/EpicGames/zen (diff)
downloadzen-9039c8066a97b09ee5848abc95d31e84529450be.tar.xz
zen-9039c8066a97b09ee5848abc95d31e84529450be.zip
Script for building a branch over SSH
Diffstat (limited to 'scripts')
-rw-r--r--scripts/remote_build.py237
1 files changed, 237 insertions, 0 deletions
diff --git a/scripts/remote_build.py b/scripts/remote_build.py
new file mode 100644
index 000000000..e83f95d8d
--- /dev/null
+++ b/scripts/remote_build.py
@@ -0,0 +1,237 @@
+import os
+import sys
+import argparse
+import subprocess
+from pathlib import Path
+
+# {{{1 misc --------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+def _header(*args, ansi=96):
+ print(f"\x1b[{ansi}m##", *args, end="")
+ print("\x1b[0m")
+
+#-------------------------------------------------------------------------------
+def _run_checked(cmd, *args, **kwargs):
+ _header(cmd, *args, ansi=97)
+ ret = subprocess.run((cmd, *args), **kwargs, bufsize=0)
+ if ret.returncode:
+ raise RuntimeError("Failed running " + str(cmd))
+
+#-------------------------------------------------------------------------------
+def _get_ip():
+ import socket
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ try:
+ s.connect(("172.31.255.255", 1))
+ return s.getsockname()[0]
+ except:
+ return "127.0.0.1"
+ finally:
+ s.close()
+
+#-------------------------------------------------------------------------------
+def _find_binary(name):
+ name += ".exe" if os.name == "nt" else ""
+ for prefix in os.getenv("PATH", "").split(os.pathsep):
+ path = Path(prefix) / name
+ if path.is_file():
+ return path
+ raise EnvironmentError(f"Unable to find '{name}' in the path")
+
+#-------------------------------------------------------------------------------
+class _AutoKill(object):
+ def __init__(self, proc):
+ self._proc = proc
+
+ def __del__(self):
+ self._proc.kill()
+ self._proc.wait()
+ pass
+
+
+
+# {{{1 local -------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+def _local(args):
+ # Parse arguments
+ desc = "Build Zen on a remote host"
+ parser = argparse.ArgumentParser(description=desc)
+ parser.add_argument("host", help="")
+ parser.add_argument("action", default="build", nargs="?", help="")
+ parser.add_argument("--keyfile", default=None, help="SSH key file")
+ args = parser.parse_args(args)
+
+ # Find the binaries we'll need
+ _header("Finding tools")
+ git_bin = _find_binary("git")
+ print(f"Using git from '{git_bin.name}' from '{git_bin.parent}'")
+
+ def find_git_tool(git_bin, tool_name):
+ print(f"Locating {tool_name}...")
+ tool_suffix = "usr/bin/" + tool_name
+ tool_suffix += ".exe" if os.name == "nt" else ""
+ for parent in git_bin.parents:
+ tool_path = parent / tool_suffix
+ if tool_path.is_file():
+ return tool_path
+ return _find_binary(tool_name)
+
+ ssh_bin = find_git_tool(git_bin, "ssh")
+ scp_bin = find_git_tool(git_bin, "scp")
+ print(f"Using ssh from '{ssh_bin.name}' from '{ssh_bin.parent}'")
+ print(f"Using scp from '{scp_bin.name}' from '{scp_bin.parent}'")
+
+ # Find the Zen repository root
+ for parent in Path(__file__).resolve().parents:
+ if (parent / ".git").is_dir():
+ zen_dir = parent
+ break;
+ else:
+ raise EnvironmentError("Unable to find '.git/' directory")
+
+ # Start a git daemon to use as a transfer mechanism
+ _header("Starting a git daemon")
+ print("Port: 4493")
+ print("Base-path: ", zen_dir)
+ print("Host: ", _get_ip())
+ daemon = subprocess.Popen(
+ ( git_bin,
+ "daemon",
+ "--port=4493",
+ "--export-all",
+ "--reuseaddr",
+ "--verbose",
+ "--informative-errors",
+ "--base-path=" + str(zen_dir) ),
+ #stdout = daemon_log,
+ stderr = subprocess.STDOUT
+ )
+ daemon_killer = _AutoKill(daemon)
+
+ # Run this script on the remote machine
+ _header("Running SSH")
+
+ remote_zen_dir = "%s_%s" % (os.getlogin(), _get_ip())
+
+ host = args.host
+ if host == "linux": host = os.getenv("ZEN_REMOTE_HOST_LINUX", "arn-lin-12345")
+ if host == "mac": host = os.getenv("ZEN_REMOTE_HOST_MAC", "imacpro-arn.local")
+ host = "zenbuild@" + host
+ print(f"Using host '{host}'")
+ print(f"Using zen '~/{remote_zen_dir}'")
+
+ print(f"Running {__file__} remotely")
+ ssh_args = ("-tA",)
+ if args.keyfile:
+ ssh_args = (*ssh_args, "-i", args.keyfile)
+ with open(__file__, "rt") as self_file:
+ _run_checked(
+ ssh_bin,
+ *ssh_args,
+ host,
+ f"python3 -u - !remote {_get_ip()} '{remote_zen_dir}' main '{args.action}'",
+ stdin=self_file)
+
+ # If we're bundling, collect zip files from the remote machine
+ if args.action == "bundle":
+ build_dir = zen_dir / "build"
+ build_dir.mkdir(exist_ok=True)
+ scp_args = (host + f":zen/{remote_zen_dir}/build/*.zip", build_dir)
+ if args.keyfile:
+ scp_args = ("-i", args.keyfile, *scp_args)
+ _run_checked("scp", *scp_args)
+
+
+
+# {{{1 remote ------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+def _remote(args):
+ # Parse arguments
+ desc = "Build Zen on a remote host"
+ parser = argparse.ArgumentParser(description=desc)
+ parser.add_argument("ip", help="Host's IP address")
+ parser.add_argument("reponame", help="Repository name clone into and work in")
+ parser.add_argument("branch", help="Zen branch to operate on")
+ parser.add_argument("action", help="The action to do")
+ args = parser.parse_args(args)
+
+ # Homeward bound and out
+ zen_dir = Path().home() / "zen"
+ os.chdir(zen_dir)
+
+ # Mutual exclusion
+ """
+ lock_path = zen_dir / "../.remote_lock"
+ try: lock_file = open(lock_path, "xb")
+ except: raise RuntimeError("Failed to lock", lock_path)
+ """
+
+ # Check for a clone, create it, chdir to it
+ _header("REMOTE:", f"Clone/pull from {args.ip}")
+ clone_dir = zen_dir / args.reponame
+ if not clone_dir.is_dir():
+ _run_checked("git", "clone", f"git://{args.ip}:4493/", clone_dir)
+ os.chdir(clone_dir)
+
+ _run_checked("git", "checkout", args.branch)
+ _run_checked("git", "pull", "-r")
+
+ _header("REMOTE:", f"Performing action '{args.action}'")
+
+ # Find xmake
+ xmake_bin = max(x for x in (zen_dir / "xmake").glob("*"))
+ xmake_bin /= "usr/local/bin/xmake"
+
+ # Run xmake
+ xmake_env = {}
+ xmake_env["VCPKG_ROOT"] = zen_dir / "vcpkg"
+ if sys.platform == "linux":
+ xmake_env["CXX"] = "g++-11"
+ print("xmake environment:")
+ for key, value in xmake_env.items():
+ print(" ", key, "=", value)
+ xmake_env.update(os.environ)
+
+ def run_xmake(*args):
+ print("starting xmake...", end="\r")
+ _run_checked(xmake_bin, args[0], "--yes", *args[1:], env=xmake_env)
+
+ if args.action.startswith("build"):
+ mode = "debug" if args.action == "build.debug" else "release"
+ run_xmake("config", "--mode=" + mode)
+ run_xmake("build")
+
+ elif args.action == "bundle":
+ run_xmake("bundle")
+
+ elif args.action == "test":
+ run_xmake("config", "--mode=debug")
+ run_xmake("test")
+
+ elif args.action == "clean":
+ _run_checked("git", "reset")
+ _run_checked("git", "checkout", ".")
+ _run_checked("git", "clean", "-xdf")
+
+
+
+# {{{1 entry -------------------------------------------------------------------
+if __name__ == "__main__":
+ if "!remote" in sys.argv[1:2]:
+ ret = _remote(sys.argv[2:])
+ raise SystemExit(ret)
+
+ try:
+ ret = _local(sys.argv[1:])
+ raise SystemExit(ret)
+ except:
+ raise
+ finally:
+ # Roundabout way to avoid orphaned git-daemon processes
+ if os.name == "nt":
+ os.system("taskkill /f /im git-daemon.exe")
+
+# vim: expandtab foldlevel=1 foldmethod=marker