about summary refs log tree commit diff stats
path: root/archive/2024/winter/bsc_dichler/scripts/context.py
diff options
context:
space:
mode:
authorMartin Fink <martin@finkmartin.com>2025-05-12 08:14:08 +0200
committerGitHub <noreply@github.com>2025-05-12 08:14:08 +0200
commit0866a557ac461a1b345dd9ff1e13b01105458ef8 (patch)
tree483f44335b623c1f2a8ba911d1feb776eb3df642 /archive/2024/winter/bsc_dichler/scripts/context.py
parente546f71869e32e88716c4ad05e0254ea3352a668 (diff)
parentf60cf8c4ba75eee2b25ffbeea2330206b257aae9 (diff)
downloadresearch-work-archive-artifacts-0866a557ac461a1b345dd9ff1e13b01105458ef8.tar.gz
research-work-archive-artifacts-0866a557ac461a1b345dd9ff1e13b01105458ef8.zip
Merge pull request #2 from raphaeldichler/main
Add source code of 'Evaluation of the Performance of the Memory Tagging Extensions'
Diffstat (limited to 'archive/2024/winter/bsc_dichler/scripts/context.py')
-rw-r--r--archive/2024/winter/bsc_dichler/scripts/context.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/archive/2024/winter/bsc_dichler/scripts/context.py b/archive/2024/winter/bsc_dichler/scripts/context.py
new file mode 100644
index 000000000..78cbbb689
--- /dev/null
+++ b/archive/2024/winter/bsc_dichler/scripts/context.py
@@ -0,0 +1,137 @@
+from pathlib import Path
+from typing import Protocol, Self
+from execution import run
+from log import info
+
+
+class Context(Protocol):
+
+    def context(self) -> str: ...
+
+    async def sync_to(self, experiment_root: Path) -> None: ...
+
+    async def run(self, cmd: str | list[str]) -> None: ...
+
+    async def sync_back(self, remote_path: Path, local_path: Path) -> None: ...
+
+    async def __aenter__(self) -> Self: ...
+
+    async def __aexit__(self, exc_type, exc_value, exc_tb): ...
+
+
+class RemoteContext:
+    __remote_connection: str
+    __jump_connection: str | None
+    __cwd: str | None
+    __delete: bool
+
+    def __init__(
+        self,
+        remote_user: str,
+        remote_host: str,
+        jump_user: str | None = None,
+        jump_host: str | None = None,
+        jump_port: str | None = None,
+        delete: bool = False,
+    ) -> None:
+        self.__cwd = None
+        self.__delete = delete
+        self.__remote_connection = f"{remote_user}@{remote_host}"
+        self.__jump_connection = None
+
+        if any([jump_host, jump_user, jump_port]):
+            assert all([jump_host, jump_user]), "cannot define jump partially"
+            self.__jump_connection = f"ssh -J {jump_user}@{jump_host}"
+            if jump_port:
+                self.__jump_connection += f" -p {jump_port}"
+
+    def context(self) -> str:
+        return f"Remote Context: {self.__cwd}"
+
+    async def sync_to(self, experiment_root: Path) -> None:
+        cmd = "rsync -avz"
+        if self.__jump_connection:
+            cmd += f" -e '{self.__jump_connection}'"
+
+        cmd += f" {experiment_root} {self.__remote_connection}:{self.__cwd}"
+        info(f"cmd: {cmd}")
+        _ = await run(cmd)
+
+    def __connection_cmd(self) -> str:
+        connection_cmd = f"ssh {self.__remote_connection}"
+        if self.__jump_connection:
+            connection_cmd = f"{self.__jump_connection} {self.__remote_connection}"
+
+        return connection_cmd
+
+    async def run(self, cmd: str | list[str]) -> None:
+        assert self.__cwd, "Cannot run command without setup"
+        if isinstance(cmd, list):
+            cmd = " && ".join(cmd)
+
+        cmd = cmd.strip()
+        assert cmd.startswith("&&") == False, "already prefixed with '&&'"
+
+        _ = await run([f"{self.__connection_cmd()} 'cd {self.__cwd} && {cmd}'"])
+
+    async def sync_back(self, remote_path: Path, local_path: Path) -> None:
+        cmd = "rsync -avz"
+        if self.__jump_connection:
+            cmd += f" -e '{self.__jump_connection}'"
+
+        cmd += f"{self.__remote_connection}:{self.__cwd}/{remote_path} {local_path}"
+        _ = await run(cmd)
+
+    async def __aenter__(self) -> Self:
+        info("__aenter__")
+        directory = await run(f"{self.__connection_cmd()} 'mktemp -d'")
+        assert directory, "failed to create directory on remote system"
+        self.__cwd = directory
+        return self
+
+    async def __aexit__(self, exc_type, exc_value, exc_tb):
+        assert self.__cwd, "incorrect state, cannot exit context which was not entered"
+        if self.__delete:
+            _ = await run(f"{self.__connection_cmd()} 'rm -rf {self.__cwd}'")
+
+
+class LocalContext:
+    __cwd: str | None
+    __delete: bool
+
+    def __init__(
+        self,
+        delete: bool = False,
+    ) -> None:
+        self.__cwd = None
+        self.__delete = delete
+
+    def context(self) -> str:
+        return f"Local Context: {self.__cwd}"
+
+    async def sync_to(self, experiment_root: Path) -> None:
+        _ = await run(f"rsync -av {experiment_root} {self.cwd}")
+
+    async def run(self, cmd: str | list[str]) -> None:
+        assert self.cwd, "Cannot run command without setup"
+        if isinstance(cmd, list):
+            cmd = " && ".join(cmd)
+
+        cmd = cmd.strip()
+        assert cmd.startswith("&&") == False, "already prefixed with '&&'"
+
+        _ = await run([f"cd {self.cwd} && {cmd}"])
+
+    async def sync_back(self, remote_path: Path, local_path: Path) -> None:
+        _ = await run(f"rsync -av {self.cwd}/{remote_path} {local_path}")
+
+    async def __aenter__(self) -> Self:
+        directory = await run("mktemp -d")
+        assert directory, "failed to create directory on remote system"
+        self.cwd = directory
+        return self
+
+    async def __aexit__(self, exc_type, exc_value, exc_tb):
+        assert self.cwd, "incorrect state, cannot exit context which was not entered"
+        if self.__delete:
+            _ = await run(f"rm -rf {self.__cwd}")