From 9868a66a1dfd392ca2694ce11f52852eb09e404b Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Tue, 19 Dec 2023 11:45:23 +0100 Subject: [PATCH 1/8] chore: get waved dir path via temp file #2225 --- py/h2o_wave/h2o_wave/cli.py | 11 +++++++++-- server.go | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index 39865224dd..23d803161f 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -20,6 +20,7 @@ import subprocess import sys import tarfile +import tempfile import time from contextlib import closing from pathlib import Path @@ -151,7 +152,13 @@ def run(app: str, no_reload: bool, no_autostart: bool): else: autostart = os.environ.get('H2O_WAVE_NO_AUTOSTART', 'false').lower() in ['false', '0', 'f'] - waved_path = os.path.join(sys.exec_prefix, 'waved.exe' if IS_WINDOWS else 'waved') + # Get the path of waved dir from temporary file created by waved. + temp_dir = tempfile.gettempdir() + temp_file = os.path.join(temp_dir, 'waved_dir_path') + with open(temp_file, 'r') as file: + waved_dir_path = file.read().strip() + + waved_path = os.path.join(waved_dir_path, 'waved.exe' if IS_WINDOWS else 'waved') # OS agnostic wheels do not include waved - needed for HAC. is_waved_present = os.path.isfile(waved_path) @@ -176,7 +183,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): return if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: - os.environ['H2O_WAVE_WAVED_DIR'] = sys.exec_prefix + os.environ['H2O_WAVE_WAVED_DIR'] = waved_dir_path reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: reload_exclude = reload_exclude.split(os.pathsep) diff --git a/server.go b/server.go index 5f9bed66e4..7c5d5e8db0 100644 --- a/server.go +++ b/server.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "log" "net/http" + "os" "path" "path/filepath" "strings" @@ -54,6 +55,15 @@ func resolveURL(path, baseURL string) string { return "/" + strings.TrimPrefix(path, baseURL) } +func saveCwdToTempFile() { + // Save the path to current working directory into a temporary file to be available for a python app. + dirgo, _ := filepath.Abs(filepath.Dir(os.Args[0])) + // TODO: The directory is neither guaranteed to exist nor have accessible permissions. + tempDir := os.TempDir() + tempFile := filepath.Join(tempDir, "go_app_dir") + ioutil.WriteFile(tempFile, []byte(dirgo), 0644) +} + func printLaunchBar(addr, baseURL string, isTLS bool) { if strings.HasPrefix(addr, ":") { addr = "localhost" + addr @@ -85,6 +95,8 @@ func Run(conf ServerConf) { initSite(site, conf.Init) } + saveCwdToTempFile() + handle := handleWithBaseURL(conf.BaseURL) broker := newBroker(site, conf.Editable, conf.NoStore, conf.NoLog, conf.KeepAppLive) From 5465edc076ead1285846cbb0a3c289f999c72fff Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Mon, 8 Jan 2024 17:36:22 +0100 Subject: [PATCH 2/8] feat: find waved cwd by its process id #2225 --- py/h2o_wave/h2o_wave/cli.py | 34 +++++++++++++++++++--------------- py/h2o_wave/pyproject.toml | 3 ++- server.go | 12 ------------ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index 23d803161f..03d748e8f4 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -20,7 +20,6 @@ import subprocess import sys import tarfile -import tempfile import time from contextlib import closing from pathlib import Path @@ -31,6 +30,7 @@ import click import httpx import inquirer +import psutil import uvicorn from click import Choice, option from h2o_wave.share import listen_on_socket @@ -144,7 +144,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): # Try to start Wave daemon if not running or turned off. server_port = int(os.environ.get('H2O_WAVE_LISTEN', ':10101').split(':')[-1]) - server_not_running = _scan_free_port(server_port) == server_port + server_running = _scan_free_port(server_port) != server_port waved_process = None if no_autostart: @@ -152,38 +152,42 @@ def run(app: str, no_reload: bool, no_autostart: bool): else: autostart = os.environ.get('H2O_WAVE_NO_AUTOSTART', 'false').lower() in ['false', '0', 'f'] - # Get the path of waved dir from temporary file created by waved. - temp_dir = tempfile.gettempdir() - temp_file = os.path.join(temp_dir, 'waved_dir_path') - with open(temp_file, 'r') as file: - waved_dir_path = file.read().strip() - - waved_path = os.path.join(waved_dir_path, 'waved.exe' if IS_WINDOWS else 'waved') + waved_cwd = sys.exec_prefix + proc_name = 'waved.exe' if IS_WINDOWS else 'waved' + # If waved is running, find its cwd. + if server_running: + for proc in psutil.process_iter(): + if proc.name() == proc_name: + try: + waved_cwd = psutil.Process(proc.pid).cwd() + except psutil.NoSuchProcess: + waved_cwd = "" + waved_path = os.path.join(waved_cwd, proc_name) if waved_cwd else "" # OS agnostic wheels do not include waved - needed for HAC. is_waved_present = os.path.isfile(waved_path) try: - if autostart and is_waved_present and server_not_running: + if autostart and is_waved_present and not server_running: kwargs = {} if IS_WINDOWS: kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP waved_process = subprocess.Popen([waved_path], cwd=sys.exec_prefix, env=os.environ.copy(), **kwargs) time.sleep(1) - server_not_running = _scan_free_port(server_port) == server_port + server_running = _scan_free_port(server_port) != server_port retries = 3 - while retries > 0 and server_not_running: + while retries > 0 and not server_running: print('Cannot connect to Wave server, retrying...') time.sleep(2) - server_not_running = _scan_free_port(server_port) == server_port + server_running = _scan_free_port(server_port) != server_port retries = retries - 1 - if autostart and server_not_running: + if autostart and not server_running: print('Could not connect to Wave server. Please start the Wave server (waved or waved.exe) prior to running any app.') return if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: - os.environ['H2O_WAVE_WAVED_DIR'] = waved_dir_path + os.environ['H2O_WAVE_WAVED_DIR'] = waved_cwd reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: reload_exclude = reload_exclude.split(os.pathsep) diff --git a/py/h2o_wave/pyproject.toml b/py/h2o_wave/pyproject.toml index 90ae9ea79d..4575ac30ba 100644 --- a/py/h2o_wave/pyproject.toml +++ b/py/h2o_wave/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling==1.21.0"] build-backend = "hatchling.build" [project] @@ -21,6 +21,7 @@ dependencies = [ "Click", "inquirer", "httpx>=0.16.1", + "psutil>=5.9.7", "starlette>=0.13.8", "uvicorn>=0.17.6", ] diff --git a/server.go b/server.go index 7c5d5e8db0..5f9bed66e4 100644 --- a/server.go +++ b/server.go @@ -22,7 +22,6 @@ import ( "io/ioutil" "log" "net/http" - "os" "path" "path/filepath" "strings" @@ -55,15 +54,6 @@ func resolveURL(path, baseURL string) string { return "/" + strings.TrimPrefix(path, baseURL) } -func saveCwdToTempFile() { - // Save the path to current working directory into a temporary file to be available for a python app. - dirgo, _ := filepath.Abs(filepath.Dir(os.Args[0])) - // TODO: The directory is neither guaranteed to exist nor have accessible permissions. - tempDir := os.TempDir() - tempFile := filepath.Join(tempDir, "go_app_dir") - ioutil.WriteFile(tempFile, []byte(dirgo), 0644) -} - func printLaunchBar(addr, baseURL string, isTLS bool) { if strings.HasPrefix(addr, ":") { addr = "localhost" + addr @@ -95,8 +85,6 @@ func Run(conf ServerConf) { initSite(site, conf.Init) } - saveCwdToTempFile() - handle := handleWithBaseURL(conf.BaseURL) broker := newBroker(site, conf.Editable, conf.NoStore, conf.NoLog, conf.KeepAppLive) From 34c4672c983a74e5fcb310704d5a02ad767cc767 Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Mon, 8 Jan 2024 17:38:31 +0100 Subject: [PATCH 3/8] chore: remove hatchling version lock #2225 --- py/h2o_wave/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/h2o_wave/pyproject.toml b/py/h2o_wave/pyproject.toml index 4575ac30ba..443967bc51 100644 --- a/py/h2o_wave/pyproject.toml +++ b/py/h2o_wave/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling==1.21.0"] +requires = ["hatchling"] build-backend = "hatchling.build" [project] From c4384cdc4afc04cceb1de07ea8a7db73d67b4646 Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Tue, 9 Jan 2024 12:17:14 +0100 Subject: [PATCH 4/8] fix: use sys.exec_prefix as a default waved path #2225 --- py/h2o_wave/h2o_wave/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index 03d748e8f4..dfd1dfd25f 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -161,8 +161,8 @@ def run(app: str, no_reload: bool, no_autostart: bool): try: waved_cwd = psutil.Process(proc.pid).cwd() except psutil.NoSuchProcess: - waved_cwd = "" - waved_path = os.path.join(waved_cwd, proc_name) if waved_cwd else "" + pass + waved_path = os.path.join(waved_cwd, proc_name) # OS agnostic wheels do not include waved - needed for HAC. is_waved_present = os.path.isfile(waved_path) From 6e554157c496b86023d4da18a1a2a108b164b7d4 Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Thu, 18 Jan 2024 09:46:46 +0100 Subject: [PATCH 5/8] chore: set H2O_WAVE_WAVED_DIR only when waved is not running separately #2225 --- py/h2o_wave/h2o_wave/cli.py | 30 ++++++++++-------------------- py/h2o_wave/pyproject.toml | 1 - 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index dfd1dfd25f..aa2d02b880 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -30,7 +30,6 @@ import click import httpx import inquirer -import psutil import uvicorn from click import Choice, option from h2o_wave.share import listen_on_socket @@ -144,7 +143,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): # Try to start Wave daemon if not running or turned off. server_port = int(os.environ.get('H2O_WAVE_LISTEN', ':10101').split(':')[-1]) - server_running = _scan_free_port(server_port) != server_port + server_not_running = _scan_free_port(server_port) == server_port waved_process = None if no_autostart: @@ -152,41 +151,32 @@ def run(app: str, no_reload: bool, no_autostart: bool): else: autostart = os.environ.get('H2O_WAVE_NO_AUTOSTART', 'false').lower() in ['false', '0', 'f'] - waved_cwd = sys.exec_prefix - proc_name = 'waved.exe' if IS_WINDOWS else 'waved' - # If waved is running, find its cwd. - if server_running: - for proc in psutil.process_iter(): - if proc.name() == proc_name: - try: - waved_cwd = psutil.Process(proc.pid).cwd() - except psutil.NoSuchProcess: - pass - waved_path = os.path.join(waved_cwd, proc_name) + waved_cwd = sys.exec_prefix if server_not_running else None + waved_path = os.path.join(waved_cwd, 'waved.exe' if IS_WINDOWS else 'waved') if waved_cwd else None # OS agnostic wheels do not include waved - needed for HAC. - is_waved_present = os.path.isfile(waved_path) + is_waved_present = os.path.isfile(waved_path) if waved_path else False try: - if autostart and is_waved_present and not server_running: + if autostart and is_waved_present and not server_not_running: kwargs = {} if IS_WINDOWS: kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP waved_process = subprocess.Popen([waved_path], cwd=sys.exec_prefix, env=os.environ.copy(), **kwargs) time.sleep(1) - server_running = _scan_free_port(server_port) != server_port + server_not_running = _scan_free_port(server_port) == server_port retries = 3 - while retries > 0 and not server_running: + while retries > 0 and not server_not_running: print('Cannot connect to Wave server, retrying...') time.sleep(2) - server_running = _scan_free_port(server_port) != server_port + server_not_running = _scan_free_port(server_port) == server_port retries = retries - 1 - if autostart and not server_running: + if autostart and not server_not_running: print('Could not connect to Wave server. Please start the Wave server (waved or waved.exe) prior to running any app.') return - if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: + if not os.environ.get('H2O_WAVE_WAVED_DIR') and waved_cwd: os.environ['H2O_WAVE_WAVED_DIR'] = waved_cwd reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: diff --git a/py/h2o_wave/pyproject.toml b/py/h2o_wave/pyproject.toml index 443967bc51..90ae9ea79d 100644 --- a/py/h2o_wave/pyproject.toml +++ b/py/h2o_wave/pyproject.toml @@ -21,7 +21,6 @@ dependencies = [ "Click", "inquirer", "httpx>=0.16.1", - "psutil>=5.9.7", "starlette>=0.13.8", "uvicorn>=0.17.6", ] From 9b18112f9205def52304ff778e1cf697bb9ea177 Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Thu, 18 Jan 2024 09:49:30 +0100 Subject: [PATCH 6/8] chore: remove unwanted negation #2225 --- py/h2o_wave/h2o_wave/cli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index aa2d02b880..02fa4e0b4a 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -157,7 +157,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): is_waved_present = os.path.isfile(waved_path) if waved_path else False try: - if autostart and is_waved_present and not server_not_running: + if autostart and is_waved_present and server_not_running: kwargs = {} if IS_WINDOWS: kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP @@ -166,17 +166,17 @@ def run(app: str, no_reload: bool, no_autostart: bool): time.sleep(1) server_not_running = _scan_free_port(server_port) == server_port retries = 3 - while retries > 0 and not server_not_running: + while retries > 0 and server_not_running: print('Cannot connect to Wave server, retrying...') time.sleep(2) server_not_running = _scan_free_port(server_port) == server_port retries = retries - 1 - if autostart and not server_not_running: + if autostart and server_not_running: print('Could not connect to Wave server. Please start the Wave server (waved or waved.exe) prior to running any app.') return - if not os.environ.get('H2O_WAVE_WAVED_DIR') and waved_cwd: + if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: os.environ['H2O_WAVE_WAVED_DIR'] = waved_cwd reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: From bc5bcb409752df07d1ce1d8a345aaf428ee496ad Mon Sep 17 00:00:00 2001 From: Marek Mihok Date: Thu, 18 Jan 2024 09:52:34 +0100 Subject: [PATCH 7/8] chore: simplify #2225 --- py/h2o_wave/h2o_wave/cli.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index 02fa4e0b4a..0b5e268455 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -151,10 +151,9 @@ def run(app: str, no_reload: bool, no_autostart: bool): else: autostart = os.environ.get('H2O_WAVE_NO_AUTOSTART', 'false').lower() in ['false', '0', 'f'] - waved_cwd = sys.exec_prefix if server_not_running else None - waved_path = os.path.join(waved_cwd, 'waved.exe' if IS_WINDOWS else 'waved') if waved_cwd else None + waved_path = os.path.join(sys.exec_prefix, 'waved.exe' if IS_WINDOWS else 'waved') # OS agnostic wheels do not include waved - needed for HAC. - is_waved_present = os.path.isfile(waved_path) if waved_path else False + is_waved_present = os.path.isfile(waved_path) if server_not_running else False try: if autostart and is_waved_present and server_not_running: @@ -177,7 +176,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): return if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: - os.environ['H2O_WAVE_WAVED_DIR'] = waved_cwd + os.environ['H2O_WAVE_WAVED_DIR'] = sys.exec_prefix reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: reload_exclude = reload_exclude.split(os.pathsep) From c966d9b651ecfaf8efa3c7fecaab06fa1e0e64cc Mon Sep 17 00:00:00 2001 From: Martin Turoci Date: Thu, 18 Jan 2024 14:32:07 +0100 Subject: [PATCH 8/8] chore: Refactor. --- py/h2o_wave/h2o_wave/cli.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/py/h2o_wave/h2o_wave/cli.py b/py/h2o_wave/h2o_wave/cli.py index 0b5e268455..6a06412cd5 100644 --- a/py/h2o_wave/h2o_wave/cli.py +++ b/py/h2o_wave/h2o_wave/cli.py @@ -153,7 +153,8 @@ def run(app: str, no_reload: bool, no_autostart: bool): waved_path = os.path.join(sys.exec_prefix, 'waved.exe' if IS_WINDOWS else 'waved') # OS agnostic wheels do not include waved - needed for HAC. - is_waved_present = os.path.isfile(waved_path) if server_not_running else False + is_waved_present = os.path.isfile(waved_path) + is_auto_started = server_not_running try: if autostart and is_waved_present and server_not_running: @@ -175,7 +176,7 @@ def run(app: str, no_reload: bool, no_autostart: bool): print('Could not connect to Wave server. Please start the Wave server (waved or waved.exe) prior to running any app.') return - if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_waved_present: + if not os.environ.get('H2O_WAVE_WAVED_DIR') and is_auto_started: os.environ['H2O_WAVE_WAVED_DIR'] = sys.exec_prefix reload_exclude = os.environ.get('H2O_WAVE_RELOAD_EXCLUDE', None) if reload_exclude: