Open abrichr opened 4 weeks ago
As part of fixing this, please also add a test 🙏
Hi @abrichr are you trying this on a new system? Could you check if running node
in the same terminal raises any errors. As far as I understand, the node exectuable is not where it should be (in one of the bin
directories added to PATH
)
@KIRA009
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % python -m openadapt.app.dashboard.run
Exception in thread Thread-1 (run_client):
Traceback (most recent call last):
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/Users/abrichr/oa/OpenAdapt/openadapt/app/dashboard/run.py", line 35, in run_client
dashboard_process = subprocess.Popen(
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/subprocess.py", line 971, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/subprocess.py", line 1863, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'node'
^C2024-06-08 23:43:40.067 | DEBUG | __main__:cleanup:59 - Terminating the dashboard client.
2024-06-08 23:43:40.068 | DEBUG | __main__:cleanup:64 - Dashboard client terminated.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % node
zsh: command not found: node
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % poetry run install-dashboard
N/A: version "N/A -> N/A" is not yet installed.
You need to run "nvm install N/A" to install it before using it.
v21.7.3 is already installed.
Now using node v21.7.3 (npm v10.5.0)
Found '/Users/abrichr/oa/OpenAdapt/openadapt/app/dashboard/.nvmrc' with version <21>
Now using node v21.7.3 (npm v10.5.0)
up to date, audited 460 packages in 1s
173 packages are looking for funding
run `npm fund` for details
3 moderate severity vulnerabilities
To address issues that do not require attention, run:
npm audit fix
To address all issues, run:
npm audit fix --force
Run `npm audit` for details.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % node
zsh: command not found: node
I tried manually running nvm use 21
then poetry install-dashboard
:
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % poetry run install-dashboard
v21.7.3 is already installed.
Now using node v21.7.3 (npm v10.5.0)
No .nvmrc file found
Node Version Manager
Note: <version> refers to any version-like string nvm understands. This includes:
- full or partial version numbers, starting with an optional "v" (0.10, v0.1.2, v1)
- default (built-in) aliases: node, stable, unstable, iojs, system
- custom aliases you define with `nvm alias foo`
Any options that produce colorized output should respect the `--no-colors` option.
Usage:
nvm --help Show this message
...
Any suggestions? 🙏
In the provided run.py
script, the main problem is related to the subprocess not finding the node
executable, as seen from the error message FileNotFoundError: [Errno 2] No such file or directory: 'node'
. This is typically because the environment in which Python's subprocess.Popen
is running does not have the correct paths to node
, which should be set by nvm
.
Here’s how you can modify run.py
to dynamically include the correct path to node
in the subprocess environment:
Load the correct node
environment: Before starting the subprocess, ensure that nvm
is sourced and the correct version of node
is used. This setup needs to be done within the same context as the subprocess.Popen
command because environment settings in a shell script (like entrypoint.sh
) or in a different subprocess do not persist across separate subprocess invocations.
Modify run_client()
: You can modify the run_client()
function to dynamically set the environment for the subprocess. This involves sourcing nvm
and adding the directory containing the node
binary to the PATH of the subprocess environment.
Here’s a way to implement these changes:
from threading import Thread
import os
import pathlib
import subprocess
import webbrowser
from loguru import logger
from openadapt.build_utils import is_running_from_executable
from openadapt.config import POSTHOG_HOST, POSTHOG_PUBLIC_KEY, config
from .api.index import run_app
dashboard_process = None
def run() -> Thread:
"""Run the dashboard web application."""
cur_dir = pathlib.Path(__file__).parent
def run_client() -> subprocess.Popen:
"""The entry point for the thread that runs the dashboard client."""
if is_running_from_executable():
webbrowser.open(
f"http://localhost:{config.DASHBOARD_SERVER_PORT}/recordings"
)
run_app()
return
global dashboard_process
# Load nvm and get node path
nvm_path = os.path.expanduser('~/.nvm')
nvm_init_script = os.path.join(nvm_path, 'nvm.sh')
command = f'source {nvm_init_script} && nvm use 21 && which node'
node_path = subprocess.check_output(command, shell=True, executable='/bin/bash').decode().strip()
env = {
**os.environ,
"PATH": f"{os.path.dirname(node_path)}:{os.environ['PATH']}",
"DASHBOARD_CLIENT_PORT": str(config.DASHBOARD_CLIENT_PORT),
"DASHBOARD_SERVER_PORT": str(config.DASHBOARD_SERVER_PORT),
"NEXT_PUBLIC_POSTHOG_HOST": POSTHOG_HOST,
"NEXT_PUBLIC_POSTHOG_PUBLIC_KEY": POSTHOG_PUBLIC_KEY,
"NEXT_PUBLIC_MODE": "production" if is_running_from_executable() else "development",
}
dashboard_process = subprocess.Popen(
["node", "index.js"],
cwd=cur_dir,
env=env,
)
return Thread(
target=run_client,
daemon=True,
)
def cleanup() -> None:
"""Cleanup the dashboard web application process."""
logger.debug("Terminating the dashboard client.")
global dashboard_process
if dashboard_process:
dashboard_process.terminate()
dashboard_process.wait()
logger.debug("Dashboard client terminated.")
if __name__ == "__main__":
dashboard_thread = run()
dashboard_thread.start()
try:
while True:
pass
except KeyboardInterrupt:
cleanup()
This implementation uses the subprocess.check_output
to dynamically load nvm
and get the path to the node
binary, ensuring it is included in the subprocess's PATH. This way, your subprocess will correctly locate and execute node
.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % python -m openadapt.app.dashboard.run 00:21:40 [5/324]
2024-06-09 00:20:35.979 | INFO | __main__:run_client:36 - command='source /Users/abrichr/.nvm/nvm.sh && nvm use 21 && which node'
Exception in thread Thread-1 (run_client):
Traceback (most recent call last):
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/Users/abrichr/oa/OpenAdapt/openadapt/app/dashboard/run.py", line 37, in run_client
node_path = subprocess.check_output(
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/subprocess.py", line 421, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/subprocess.py", line 526, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'source /Users/abrichr/.nvm/nvm.sh && nvm use 21 && which node' returned non-zero exit status 3.
^C2024-06-09 00:20:38.087 | DEBUG | __main__:cleanup:67 - Terminating the dashboard client.
2024-06-09 00:20:38.088 | DEBUG | __main__:cleanup:72 - Dashboard client terminated.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % source /Users/abrichr/.nvm/nvm.sh && nvm use 21 && which node
N/A: version "N/A -> N/A" is not yet installed.
You need to run "nvm install N/A" to install it before using it.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % nvm install N/A
Version 'N/A' not found - try `nvm ls-remote` to browse available versions.
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % nv use 21
zsh: command not found: nv
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % nvm use 21
Now using node v21.7.3 (npm v10.5.0)
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % which node
/Users/abrichr/.nvm/versions/node/v21.7.3/bin/node
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % source /Users/abrichr/.nvm/nvm.sh && nvm use 21 && which node
Now using node v21.7.3 (npm v10.5.0)
/Users/abrichr/.nvm/versions/node/v21.7.3/bin/node
(openadapt-py3.10) abrichr@MacBook-Pro-5 OpenAdapt % python -m openadapt.app.dashboard.run
2024-06-09 00:21:38.120 | INFO | __main__:run_client:36 - command='source /Users/abrichr/.nvm/nvm.sh && nvm use 21 && which node'
> nextjs-fastapi@0.1.0 dev
> concurrently "npm run next-dev" "npm run fastapi-dev"
[1]
[1] > nextjs-fastapi@0.1.0 fastapi-dev
[1] > python3 -m uvicorn api.index:app --port $DASHBOARD_SERVER_PORT --reload
[1]
[0]
[0] > nextjs-fastapi@0.1.0 next-dev
[0] > next dev -p $DASHBOARD_CLIENT_PORT
[0]
[1] INFO: Will watch for changes in these directories: ['/Users/abrichr/oa/OpenAdapt/openadapt/app/dashboard']
[1] INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
[1] INFO: Started reloader process [61914] using WatchFiles
[0] ⚠ Specified "rewrites" will not automatically work with "output: export". See more info here: https://nextjs.org/docs/messages/export-no-custom-routes
[0] ⚠ Specified "rewrites" will not automatically work with "output: export". See more info here: https://nextjs.org/docs/messages/export-no-custom-routes
[0] ▲ Next.js 14.1.4
[0] - Local: http://localhost:5173
I'm not sure why this fixed it. @KIRA009 any thoughts on how we can detect this situation, and ideally fix it (or at least warn the user)?
Describe the bug
To Reproduce
See above