diff --git a/client/starwhale/core/runtime/cli.py b/client/starwhale/core/runtime/cli.py index 26b3c9bfdb..af4165d899 100644 --- a/client/starwhale/core/runtime/cli.py +++ b/client/starwhale/core/runtime/cli.py @@ -87,8 +87,20 @@ def _quickstart_from_uri( default=False, show_default=True, ) +@click.option( + "-i", + "--interactive", + is_flag=True, + default=False, + help="Try entering the interactive shell at the end", +) def _quickstart( - workdir: str, force: bool, python_env: str, name: str, create_env: bool + workdir: str, + force: bool, + python_env: str, + name: str, + create_env: bool, + interactive: bool, ) -> None: """[Only Standalone]Quickstart Starwhale Runtime @@ -99,7 +111,7 @@ def _quickstart( p_workdir = Path(workdir).absolute() name = name or p_workdir.name RuntimeTermView.quickstart_from_ishell( - p_workdir, name, python_env, create_env, force + p_workdir, name, python_env, create_env, force, interactive ) diff --git a/client/starwhale/core/runtime/model.py b/client/starwhale/core/runtime/model.py index 14fcc0bc2e..b4d0092d46 100644 --- a/client/starwhale/core/runtime/model.py +++ b/client/starwhale/core/runtime/model.py @@ -803,6 +803,7 @@ def quickstart_from_ishell( mode: str, create_env: bool = False, force: bool = False, + interactive: bool = False, ) -> None: workdir = Path(workdir).absolute() console.print(f":printer: render runtime.yaml @ {workdir}") @@ -833,7 +834,7 @@ def quickstart_from_ishell( elif mode == PythonRunEnv.CONDA: conda_install_req(env_name=_id, req=sw_pkg, enable_pre=True) - activate_python_env(mode=mode, identity=_id) + activate_python_env(mode=mode, identity=_id, interactive=interactive) @classmethod def activate(cls, path: str = "", uri: str = "") -> None: @@ -854,7 +855,9 @@ def activate(cls, path: str = "", uri: str = "") -> None: else: raise Exception("No uri or path to activate") - activate_python_env(mode=mode, identity=str(prefix_path.resolve())) + activate_python_env( + mode=mode, identity=str(prefix_path.resolve()), interactive=True + ) @classmethod def lock( diff --git a/client/starwhale/core/runtime/view.py b/client/starwhale/core/runtime/view.py index cb76b700d7..e043c74e6b 100644 --- a/client/starwhale/core/runtime/view.py +++ b/client/starwhale/core/runtime/view.py @@ -156,11 +156,14 @@ def quickstart_from_ishell( mode: str, create_env: bool = False, force: bool = False, + interactive: bool = False, ) -> None: console.print( f":construction: quickstart Starwhale Runtime[{name}] environment..." ) - StandaloneRuntime.quickstart_from_ishell(workdir, name, mode, create_env, force) + StandaloneRuntime.quickstart_from_ishell( + workdir, name, mode, create_env, force, interactive + ) console.print(":clap: Starwhale Runtime environment is ready to use :tada:") @classmethod diff --git a/client/starwhale/utils/venv.py b/client/starwhale/utils/venv.py index 86c6335964..4026573df8 100644 --- a/client/starwhale/utils/venv.py +++ b/client/starwhale/utils/venv.py @@ -545,13 +545,7 @@ def package_python_env( return True -def activate_python_env( - mode: str, - identity: str, -) -> None: - # TODO: switch shell python environment directly - console.print(":cake: run command in shell :cake:") - +def activate_python_env(mode: str, identity: str, interactive: bool) -> None: if mode == PythonRunEnv.VENV: cmd = f"source {identity}/bin/activate" elif mode == PythonRunEnv.CONDA: @@ -559,6 +553,35 @@ def activate_python_env( else: raise NoSupportError(mode) + if interactive: + import shellingham + + try: + _name, _bin = shellingham.detect_shell() + except shellingham.ShellDetectionFailure: + _name, _bin = "", "" + + if _name == "zsh": + # https://zsh.sourceforge.io/Intro/intro_3.html + os.execl( + _bin, + _bin, + "-c", + f"""temp_dir={identity} && \ + echo ". $HOME/.zshrc && {cmd}" > $temp_dir/.zshrc && \ + ZDOTDIR=$temp_dir zsh -i""", + ) + elif _name == "bash": + # https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html + os.execl( + _bin, _bin, "-c", f'bash --rcfile <(echo ". "$HOME/.bashrc" && {cmd}")' + ) + elif _name == "fish": + # https://fishshell.com/docs/current/language.html#configuration + os.execl(_bin, _bin, "-C", cmd) + + # user executes the command manually + console.print(":cake: run command in shell :cake:") console.print(f"\t[red][bold]{cmd}") @@ -569,7 +592,6 @@ def create_python_env( python_version: str = DEFAULT_PYTHON_VERSION, force: bool = False, ) -> str: - if mode == PythonRunEnv.VENV: venvdir = workdir / ".venv" if venvdir.exists() and not force: @@ -666,7 +688,8 @@ def is_venv() -> bool: [ "python3", "-c", - "import sys; print(sys.prefix != (getattr(sys, 'base_prefix', None) or (getattr(sys, 'real_prefix', None) or sys.prefix)))", # noqa: E501 + "import sys; print(sys.prefix != (getattr(sys, 'base_prefix', None) or (getattr(sys, 'real_prefix', None) or sys.prefix)))", + # noqa: E501 ], ) return "True" in output.decode() or get_venv_env() != ""