From b4d21be26cc2ad1e978eed692761843a08f5bc1c Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Wed, 12 Jul 2023 08:17:13 +0800 Subject: [PATCH] update install --- src/contributes/commandsBase.ts | 46 +----- src/panel/statusBarViewBase.ts | 9 ++ tools/install.py | 274 +++++++++++++++++++++++++------- 3 files changed, 231 insertions(+), 98 deletions(-) diff --git a/src/contributes/commandsBase.ts b/src/contributes/commandsBase.ts index a76b81a..1cbef6e 100644 --- a/src/contributes/commandsBase.ts +++ b/src/contributes/commandsBase.ts @@ -24,54 +24,14 @@ function locateCommand(command): string | undefined { } export function checkDevChatDependency(pythonCommand: string, showError: boolean = true): boolean { - let pipxBinPath: string | undefined = undefined; - try { - const binPath = getPipxEnvironmentPath(pythonCommand); - pipxBinPath = binPath; - - if (binPath) { - updateEnvironmentPath(binPath); - - const error_status = `Updated pipx environment path.`; - if (pipxPathStatus !== error_status) { - logger.channel()?.info(error_status); - pipxPathStatus = error_status; - } - } else { - const error_status = `Failed to obtain the pipx environment path.`; - if (pipxPathStatus !== error_status && showError) { - logger.channel()?.warn(error_status); - logger.channel()?.show(); - pipxPathStatus = error_status; - } - - return false; - } - } catch (error) { - // DevChat dependency check failed - // log out detail error message - const error_status = `Failed to check DevChat dependency due to error: ${error}`; - if (pipxPathStatus !== error_status && showError) { - logger.channel()?.warn(error_status); - logger.channel()?.show(); - pipxPathStatus = error_status; - } - + let devChat: string | undefined = UiUtilWrapper.getConfiguration('DevChat', 'DevChatPath'); + if (!devChat) { return false; } try { // Check if DevChat is installed - const pipxDevChat = path.join(pipxBinPath!, 'devchat'); - runCommand(`"${pipxDevChat}" --help`); - - UiUtilWrapper.updateConfiguration('DevChat', 'DevChatPath', pipxDevChat); - const error_status = `DevChat has installed.`; - if (devchatStatus !== error_status) { - logger.channel()?.info(error_status); - devchatStatus = error_status; - } - + runCommand(`"${devChat}" --help`); return true; } catch(error) { const error_status = `Failed to check DevChat dependency due to error: ${error}`; diff --git a/src/panel/statusBarViewBase.ts b/src/panel/statusBarViewBase.ts index a9fc8fc..a73ff1f 100644 --- a/src/panel/statusBarViewBase.ts +++ b/src/panel/statusBarViewBase.ts @@ -89,8 +89,10 @@ export async function dependencyCheck(): Promise<[string, string]> { }; let errorInstall = false; + let installLogs = ''; await run.spawnAsync(pythonCommand!, [UiUtilWrapper.extensionPath() + "/tools/install.py"], options, (data) => { + installLogs += data; logger.channel()?.info(data.trim()); }, (data) => { @@ -102,6 +104,13 @@ export async function dependencyCheck(): Promise<[string, string]> { if (errorInstall) { devchatStatus = 'An error occurred during the installation of DevChat'; } else { + // ==> devchatCommandEnv: /Users/admin/work/devchat-vscode/tools/devchat/bin/devchat + const devchatCommandEnv = installLogs.match(/devchatCommandEnv: (.*)/)?.[1]; + logger.channel()?.info(`devchatCommandEnv: ${devchatCommandEnv}`); + if (devchatCommandEnv) { + UiUtilWrapper.updateConfiguration('DevChat', 'DevChatPath', devchatCommandEnv); + } + devchatStatus = 'DevChat has been installed'; } isVersionChangeCompare = true; diff --git a/tools/install.py b/tools/install.py index db04189..f44d083 100644 --- a/tools/install.py +++ b/tools/install.py @@ -8,75 +8,239 @@ print('Python command:', pythonCommand) tools_dir = os.path.dirname(os.path.realpath(__file__)) -def ensure_pip_installed(): - print("install pip ...") + +def get_pythoncmd_in_env(venvdir, envname): + """ + return pythoncmd in virtual env + """ + pythonCommandEnv = venvdir + "/" + envname + "/Scripts/python" try: - subprocess.run([pythonCommand, "-m", "pip", "--version"], check=True) - return True - except Exception as e: + subprocess.run([pythonCommandEnv, "-V"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return pythonCommandEnv + except Exception: pass - + + pythonCommandEnv = venvdir + "/" + envname + "/bin/python" try: - subprocess.run([pythonCommand, tools_dir + "/get-pip.py", "--force-reinstall"], check=True) - return True - except Exception as e: - print(e) + subprocess.run([pythonCommandEnv, "-V"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return pythonCommandEnv + except Exception: return False -def check_pipx_installed(): + +# install devchat +# devchat is a python package +# devchat should install in a virtual env +# virtualenv is installed by: pip install virtualenv + +def pip_install_devchat(pythoncmd): + # run command: {pythoncmd} -m pip install devchat + # check if devchat is installed + # if not, install devchat + + # first step: check if devchat is installed try: - subprocess.run([pythonCommand, "-m", "pipx", "--version"], check=True) + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "show", "devchat") + subprocess.run([pythoncmd, "-m", "pip", "show", "devchat"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + + pipCommandEnv = pythoncmd.replace("/python", "/devchat") + print("==> devchatCommandEnv: ", pipCommandEnv) + return True - except Exception as e: + except Exception as error: + # devchat is not installed + print('devchat is not installed') + print(error) + pass + + # second step: install devchat + try: + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "install", "devchat") + # redirect output to stdout + subprocess.run([pythoncmd, "-m", "pip", "install", "devchat"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + + pipCommandEnv = pythoncmd.replace("/python", "/devchat") + print("==> devchatCommandEnv: ", pipCommandEnv) + + return True + except Exception as error: + print('devchat install failed') + print(error) + + # reinstall 3 times + for i in range(0,3): + try: + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "install", "devchat", "-i", "https://pypi.tuna.tsinghua.edu.cn/simple") + # redirect output to stdout + subprocess.run([pythoncmd, "-m", "pip", "install", "devchat", "-i", "https://pypi.tuna.tsinghua.edu.cn/simple"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + + pipCommandEnv = pythoncmd.replace("/python", "/devchat") + print("==> devchatCommandEnv: ", pipCommandEnv) + + return True + except Exception as error: + print('devchat install failed') + print(error) + if i >= 2: + return False + +def virtualenv_create_venv(pythoncmd, venvdir, envname): + """ + virtualenvcmd is virtualenv with absolute path + create virtual env by virtualenvcmd + if env already exists, and pip has installed, then return pipcmd in virtual env + else if env already exists, delete it. + return pipcmd in virtual env + """ + def pipcmd_exists(pythoncmd, venvdir, envname): + """ + check whether pip command installed + """ + try: + pythonCommandEnv = get_pythoncmd_in_env(venvdir, envname) + if not pythonCommandEnv: + return False + + # before command run, output runnning command + print("run command: ", pythonCommandEnv, "-m", "pip", "--version") + subprocess.run([pythonCommandEnv, "-m", "pip", "--version"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception: + return False + + # second step: check if env already exists + if os.path.exists(venvdir + "/" + envname): + # check if pip is installed + # if pip is installed, return pipcmd in virtual env + # else delete env + # call pipcmd --version to check if pip is installed + if pipcmd_exists(pythoncmd, venvdir, envname): + return get_pythoncmd_in_env(venvdir, envname) + else: + # delete env by virtualenvcmd + print("delete env: ", venvdir + "/" + envname) + try: + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "virtualenv", "--clear", venvdir + "/" + envname) + subprocess.run([pythoncmd, "-m", "virtualenv", "--clear", venvdir + "/" + envname], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + except Exception as error: + print('delete env failed') + print(error) + return False + + # third step: create env by virtualenvcmd + # handle error while creating env + print("create env: ", venvdir + "/" + envname) + try: + # before command run, output runnning command + print("run command: ", pythoncmd, "-m virtualenv", venvdir + "/" + envname) + subprocess.run([pythoncmd, "-m", "virtualenv", venvdir + "/" + envname], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return get_pythoncmd_in_env(venvdir, envname) + except Exception as error: + print('create env failed') + print(error) return False + +def pip_install_virtualenv(pythoncmd): + # run command: {pythoncmd} -m pip install virtualenv + # check if virtualenv is installed + # if not, install virtualenv -def install_pipx(): - print("Installing pipx...") + # first step: check if virtualenv is installed try: - subprocess.run([pythonCommand, "-m", "pip", "install", "--user", "pipx", "--force-reinstall"], check=True) - print("pipx installed successfully.") - except subprocess.CalledProcessError as e: - print("Error installing pipx:", e, file=sys.stderr) - sys.exit(1) - -def add_pipx_to_path(): - print("Adding pipx to PATH...") - subprocess.run([pythonCommand, "-m", "pipx", "ensurepath"], check=True) - result = subprocess.run([pythonCommand, "-m", "pipx", "environment"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - pipx_path_line = [line for line in result.stdout.splitlines() if "PIPX_BIN_DIR" in line] - if pipx_path_line: - pipx_path = pipx_path_line[0].split('=')[-1].strip() - os.environ["PATH"] += os.pathsep + pipx_path - print("pipx path added to environment variables.") - else: - print("Error: Could not find pipx path in environment output.", file=sys.stderr) - sys.exit(1) - -def install_devchat(): - print("Installing devchat...") + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "show", "virtualenv") + subprocess.run([pythoncmd, "-m", "pip", "show", "virtualenv"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception: + # virtualenv is not installed + print('virtualenv is not installed') + pass + + # second step: install virtualenv try: - subprocess.run([pythonCommand, "-m", "pipx", "install", "devchat", "--force"], check=True) - print("devchat installed successfully.") - except subprocess.CalledProcessError as e: - print("Error installing devchat:", e, file=sys.stderr) - sys.exit(1) + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "install", "--user", "virtualenv") + # redirect output to stdout + subprocess.run([pythoncmd, "-m", "pip", "install", "--user", "virtualenv"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception as error: + print('virtualenv install failed') + print(error) + + + # reinstall 3 times + for i in range(0,3): + try: + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "install", "--user", "virtualenv", "-i", "https://pypi.tuna.tsinghua.edu.cn/simple") + # redirect output to stdout + subprocess.run([pythoncmd, "-m", "pip", "install", "--user", "virtualenv", "-i", "https://pypi.tuna.tsinghua.edu.cn/simple"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception as error: + print('virtualenv install failed') + print(error) + if i >= 2: + return False + +def install_pip(pythoncmd): + # run command: {pythoncmd} {tools_dir}/get-pip.py --force-reinstall + # check if pip is installed + # if not, install pip -def upgrade_devchat(): - print("Upgrading devchat...") + # first step: check if pip is installed try: - subprocess.run([pythonCommand, "-m", "pipx", "upgrade", "devchat"], check=True) - print("devchat upgraded successfully.") - except subprocess.CalledProcessError as e: - print("Error upgrading devchat:", e, file=sys.stderr) - sys.exit(1) + # before command run, output runnning command + print("run command: ", pythoncmd, "-m", "pip", "--version") + subprocess.run([pythoncmd, "-m", "pip", "--version"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception: + # pip is not installed + print('pip is not installed') + pass + + # second step: install pip + try: + # before command run, output runnning command + print("run command: ", pythoncmd, tools_dir + "/get-pip.py", "--force-reinstall") + # redirect output to stdout + subprocess.run([pythoncmd, tools_dir + "/get-pip.py", "--force-reinstall"], check=True, stdout=sys.stdout, stderr=sys.stderr, text=True) + return True + except Exception as error: + print('pip install failed') + print(error) + return False + def main(): - ensure_pip_installed() - if not check_pipx_installed(): - install_pipx() - add_pipx_to_path() - install_devchat() - upgrade_devchat() + """ + install pip + install virtualenv + create virtualenv + install devchat + """ + pythoncommand = pythonCommand + venvdir = tools_dir + envname = "devchat" + # install pip + if not install_pip(pythoncommand): + return False + # install virtualenv + if not pip_install_virtualenv(pythoncommand): + return False + # create virtualenv + envPythonCmd = virtualenv_create_venv(pythoncommand, venvdir, envname) + if not envPythonCmd: + return False + # install devchat + if not pip_install_devchat(envPythonCmd): + return False + return True if __name__ == "__main__": - main() \ No newline at end of file + if not main(): + sys.exit(1) + sys.exit(0) \ No newline at end of file