Skip to content

Commit

Permalink
Merge branch 'dev/chenyin/pf_service' into chenyin/validate_msi
Browse files Browse the repository at this point in the history
  • Loading branch information
Ying Chen committed Mar 30, 2024
2 parents e9197a8 + 7324751 commit 7cb5642
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 309 deletions.
3 changes: 0 additions & 3 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
"**/setup.py",
"scripts/installer/curl_install_pypi/**",
"scripts/installer/windows/**",
"src/promptflow/promptflow/_sdk/_service/pfsvc.py",
"src/promptflow-devkit/promptflow/_sdk/_service/pfsvc.py",
".github/workflows/**",
".github/actions/**",
".github/pipelines/**"
Expand Down Expand Up @@ -94,7 +92,6 @@
"nunit",
"astext",
"Likert",
"pfsvc",
"geval",
"Summ",
"Bhavik",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promptflow-sdk-cli-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,4 @@ jobs:
osVersion: ubuntu-latest
pythonVersion: 3.9
coverageThreshold: 40
context: test/sdk_cli
context: test/sdk_cli
5 changes: 1 addition & 4 deletions scripts/installer/curl_install_pypi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@ Uninstall the promptflow by directly deleting the files from the location chosen
```bash
# The default install/executable location is the user's home directory ($HOME).
rm -r $HOME/lib/promptflow
rm $HOME/bin/pf
rm $HOME/bin/pfs
rm $HOME/bin/pfazure
```

2. Modify your `$HOME/.bash_profile` or `$HOME/.bashrc` file to remove the following line:

```text
export PATH=$PATH:$HOME/bin
export PATH=$PATH:$HOME/lib/promptflow/bin
```

3. If using `bash` or `zsh`, reload your shell's command cache.
Expand Down
130 changes: 16 additions & 114 deletions scripts/installer/curl_install_pypi/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,15 @@
import os
import sys
import platform
import stat
import tempfile
import shutil
import subprocess
import hashlib


PF_DISPATCH_TEMPLATE = """#!/usr/bin/env bash
export PF_INSTALLER=Script
{install_dir}/bin/python -m promptflow._cli._pf.entry "$@"
"""

PFAZURE_DISPATCH_TEMPLATE = """#!/usr/bin/env bash
{install_dir}/bin/python -m promptflow.azure._cli.entry "$@"
"""

PFS_DISPATCH_TEMPLATE = """#!/usr/bin/env bash
{install_dir}/bin/python -m promptflow._sdk._service.entry "$@"
"""

DEFAULT_INSTALL_DIR = os.path.expanduser(os.path.join('~', 'lib', 'promptflow'))
DEFAULT_EXEC_DIR = os.path.expanduser(os.path.join('~', 'bin'))
PF_EXECUTABLE_NAME = 'pf'
PFAZURE_EXECUTABLE_NAME = 'pfazure'
PFS_EXECUTABLE_NAME = 'pfs'


USER_BASH_RC = os.path.expanduser(os.path.join('~', '.bashrc'))
Expand Down Expand Up @@ -96,46 +80,22 @@ def create_dir(dir):
os.makedirs(dir)


def is_valid_sha256sum(a_file, expected_sum):
sha256 = hashlib.sha256()
with open(a_file, 'rb') as f:
sha256.update(f.read())
computed_hash = sha256.hexdigest()
return expected_sum == computed_hash


def create_virtualenv(install_dir):
cmd = [sys.executable, '-m', 'venv', install_dir]
exec_command(cmd)


def install_cli(install_dir, tmp_dir):
path_to_pip = os.path.join(install_dir, 'bin', 'pip')
cmd = [path_to_pip, 'install', '--cache-dir', tmp_dir, 'promptflow[azure,executable,azureml-serving]',
'--upgrade']
cmd = [path_to_pip, 'install', '--cache-dir', tmp_dir,
'promptflow[azure,executable,azureml-serving,executor-service]', '--upgrade']
exec_command(cmd)
cmd = [path_to_pip, 'install', '--cache-dir', tmp_dir, 'promptflow-tools', '--upgrade']
exec_command(cmd)
cmd = [path_to_pip, 'install', '--cache-dir', tmp_dir, 'keyrings.alt', '--upgrade']
exec_command(cmd)


def create_executable(exec_dir, install_dir):
create_dir(exec_dir)
exec_filepaths = []
for filename, template in [(PF_EXECUTABLE_NAME, PF_DISPATCH_TEMPLATE),
(PFAZURE_EXECUTABLE_NAME, PFAZURE_DISPATCH_TEMPLATE),
(PFS_EXECUTABLE_NAME, PFS_DISPATCH_TEMPLATE)]:
exec_filepath = os.path.join(exec_dir, filename)
with open(exec_filepath, 'w') as exec_file:
exec_file.write(template.format(install_dir=install_dir))
cur_stat = os.stat(exec_filepath)
os.chmod(exec_filepath, cur_stat.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
print_status("The executable is available at '{}'.".format(exec_filepath))
exec_filepaths.append(exec_filepath)
return exec_filepaths


def get_install_dir():
install_dir = None
while not install_dir:
Expand All @@ -161,21 +121,6 @@ def get_install_dir():
return install_dir


def get_exec_dir():
exec_dir = None
while not exec_dir:
prompt_message = (f"In what directory would you like to place the "
f"'{PFS_EXECUTABLE_NAME}/{PFS_EXECUTABLE_NAME}/{PFAZURE_EXECUTABLE_NAME}' executable?")
exec_dir = prompt_input_with_default(prompt_message, DEFAULT_EXEC_DIR)
exec_dir = os.path.realpath(os.path.expanduser(exec_dir))
if ' ' in exec_dir:
print_status("The executable directory '{}' cannot contain spaces.".format(exec_dir))
exec_dir = None
create_dir(exec_dir)
print_status("The executable will be in '{}'.".format(exec_dir))
return exec_dir


def _backup_rc(rc_file):
try:
shutil.copyfile(rc_file, rc_file+'.backup')
Expand Down Expand Up @@ -240,28 +185,28 @@ def warn_other_azs_on_path(exec_dir, exec_filepath):
conflicting_paths = []
if env_path:
for p in env_path.split(':'):
for file in [PF_EXECUTABLE_NAME, PFAZURE_EXECUTABLE_NAME, PFS_EXECUTABLE_NAME]:
for file in [PF_EXECUTABLE_NAME, PFAZURE_EXECUTABLE_NAME]:
p_to_pf = os.path.join(p, file)
if p != exec_dir and os.path.isfile(p_to_pf):
conflicting_paths.append(p_to_pf)
if conflicting_paths:
print_status()
print_status(f"** WARNING: Other '{PFS_EXECUTABLE_NAME}/{PFS_EXECUTABLE_NAME}/{PFAZURE_EXECUTABLE_NAME}' "
print_status(f"** WARNING: Other '{PF_EXECUTABLE_NAME}/{PFAZURE_EXECUTABLE_NAME}' "
f"executables are on your $PATH. **")
print_status("Conflicting paths: {}".format(', '.join(conflicting_paths)))
print_status("You can run this installation of the promptflow with '{}'.".format(exec_filepath))


def handle_path_and_tab_completion(exec_filepath, exec_dir):
def handle_path_and_tab_completion(exec_filepath, install_dir):
ans_yes = prompt_y_n('Modify profile to update your $PATH now?', 'y')
if ans_yes:
rc_file_path = get_rc_file_path()
if not rc_file_path:
raise CLIInstallError('No suitable profile file found.')
_backup_rc(rc_file_path)
line_to_add = "export PATH=$PATH:{}".format(exec_dir)
line_to_add = "export PATH=$PATH:{}".format(os.path.join(install_dir, "bin"))
_modify_rc(rc_file_path, line_to_add)
warn_other_azs_on_path(exec_dir, exec_filepath)
warn_other_azs_on_path(install_dir, exec_filepath)
print_status()
print_status('** Run `exec -l $SHELL` to restart your shell. **')
print_status()
Expand All @@ -280,59 +225,16 @@ def verify_python_version():
print_status('Python version {}.{}.{} okay.'.format(v.major, v.minor, v.micro))


def _native_dependencies_for_dist(verify_cmd_args, install_cmd_args, dep_list):
try:
print_status("Executing: '{} {}'".format(' '.join(verify_cmd_args), ' '.join(dep_list)))
subprocess.check_output(verify_cmd_args + dep_list, stderr=subprocess.STDOUT)
print_status('Native dependencies okay.')
except subprocess.CalledProcessError:
err_msg = 'One or more of the following native dependencies are not currently installed and may be required.\n'
err_msg += '"{}"'.format(' '.join(install_cmd_args + dep_list))
print_status(err_msg)
ans_yes = prompt_y_n('Missing native dependencies. Attempt to continue anyway?', 'n')
if not ans_yes:
raise CLIInstallError('Please install the native dependencies and try again.')


def _get_linux_distro():
if platform.system() != 'Linux':
return None, None

try:
with open('/etc/os-release') as lines:
tokens = [line.strip() for line in lines]
except Exception:
return None, None

release_info = {}
for token in tokens:
if '=' in token:
k, v = token.split('=', 1)
release_info[k.lower()] = v.strip('"')

return release_info.get('name', None), release_info.get('version_id', None)


def verify_install_dir_exec_path_conflict(install_dir, exec_dir):
for exec_name in [PF_EXECUTABLE_NAME, PFAZURE_EXECUTABLE_NAME, PFS_EXECUTABLE_NAME]:
exec_path = os.path.join(exec_dir, exec_name)
if install_dir == exec_path:
raise CLIInstallError("The executable file '{}' would clash with the install directory of '{}'. Choose "
"either a different install directory or directory to place the "
"executable.".format(exec_path, install_dir))


def main():
verify_python_version()
tmp_dir = create_tmp_dir()
install_dir = get_install_dir()
exec_dir = get_exec_dir()
verify_install_dir_exec_path_conflict(install_dir, exec_dir)
create_virtualenv(install_dir)
install_cli(install_dir, tmp_dir)
exec_filepath = create_executable(exec_dir, install_dir)
exec_filepath = [os.path.join(install_dir, "bin", PF_EXECUTABLE_NAME),
os.path.join(install_dir, "bin", PFAZURE_EXECUTABLE_NAME)]
try:
handle_path_and_tab_completion(exec_filepath, exec_dir)
handle_path_and_tab_completion(exec_filepath, install_dir)
except Exception as e:
print_status("Unable to set up PATH. ERROR: {}".format(str(e)))
shutil.rmtree(tmp_dir)
Expand All @@ -351,10 +253,10 @@ def main():
sys.exit(1)

# SIG # Begin signature block
# Z1F07ShfIJ7kejST2NXwW1QcFPEya4xaO2xZz6vLT847zaMzbc/PaEa1RKFlD881
# 4J+i6Au2wtbHzOXDisyH6WeLQ3gh0X2gxFRa4EzW7Nzjcvwm4+WogiTcnPVVxlk3
# qafM/oyVqs3695K7W5XttOiq2guv/yedsf/TW2BKSEKruFQh9IwDfIiBoi9Zv3wa
# iuzQulRR8KyrCtjEPDV0t4WnZVB/edQea6xJZeTlMG+uLR/miBTbPhUb/VZkVjBf
# qHBv623oLXICzoTNuaPTln9OWvL2NZpisGYvNzebKO7/Ho6AOWZNs5XOVnjs0Ax2
# aeXvlwBzIQyfyxd25487/Q==
# Op0/tmmNDX4QgQefj28K91e/ClVKWeYaA1w1kb5Hi8ALJZtmvyhwvxYlCRZ9eWT+
# wFBfSvpUIzAWYxEMfVqqWy7g9AzqHGa5vE37zQ7uGkIyR0OsmO0bkauOv5FxuCWX
# U0u9d9sir6sRTb2nrEj2O1EXAcP2xNaW77w1fcOtMX9W6ytHXx/+v5p387+/HBnQ
# y00GvJrrcIJeRj4MboBdDdv0VgGJAAlTJp0hxO0lt5ZQUMJvi/sM4e1cPUTcx7uB
# djCmvSZzZrJO2ZIIWiyiP2XNYWJv4A9klJWMbWKukeZOSjxYPS0pO2mTftkKoL5U
# sOJu9RtRWIIx/kLG/Axliw==
# SIG # End signature block
15 changes: 14 additions & 1 deletion scripts/installer/windows/scripts/pf.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,17 @@ setlocal

SET PF_INSTALLER=MSI
set MAIN_EXE=%~dp0.\pfcli.exe
"%MAIN_EXE%" pf %*
REM Check if the first argument is 'start'
if "%~1"=="service" (
REM Check if the second argument is 'start'
if "%~2"=="start" (
cscript //nologo %~dp0.\start_pfs.vbs """%MAIN_EXE%"" pf %*"
REM since we won't wait for vbs to finish, we need to wait for the output file to be flushed to disk
timeout /t 5 >nul
type "%~dp0output.txt"
) else (
"%MAIN_EXE%" pf %*
)
) else (
"%MAIN_EXE%" pf %*
)
8 changes: 1 addition & 7 deletions scripts/installer/windows/scripts/pfcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,5 @@
elif command == 'pfazure':
from promptflow.azure._cli.entry import main as pfazure_main
pfazure_main()
elif command == 'pfs':
from promptflow._sdk._service.entry import main as pfs_main
pfs_main()
elif command == 'pfsvc':
from promptflow._sdk._service.pfsvc import init as pfsvc_init
pfsvc_init()
else:
print(f"Invalid command {sys.argv}. Please use 'pf', 'pfazure', 'pfs' or 'pfsvc'.")
print(f"Invalid command {sys.argv}. Please use 'pf', 'pfazure'.")
13 changes: 0 additions & 13 deletions scripts/installer/windows/scripts/pfs.bat

This file was deleted.

5 changes: 0 additions & 5 deletions scripts/installer/windows/scripts/pfsvc.bat

This file was deleted.

2 changes: 1 addition & 1 deletion scripts/installer/windows/scripts/promptflow.spec.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from PyInstaller.utils.hooks import collect_data_files, collect_all, copy_metada
datas = [('../resources/CLI_LICENSE.rtf', '.'), ('../../../../src/promptflow/NOTICE.txt', '.'),
('../../../../src/promptflow-devkit/promptflow/_sdk/data/executable/', './promptflow/_sdk/data/executable/'),
('../../../../src/promptflow-tools/promptflow/tools/', './promptflow/tools/'),
('./pf.bat', '.'), ('./pfs.bat', '.'), ('./pfazure.bat', '.'), ('./pfsvc.bat', '.'), ('./start_pfs.vbs', '.')]
('./pf.bat', '.'), ('./pfazure.bat', '.'), ('./start_pfs.vbs', '.')]


all_packages = {{all_packages}}
Expand Down
2 changes: 1 addition & 1 deletion scripts/installer/windows/scripts/promptflow_service.vbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
DIM objshell
set objshell = wscript.createobject("wscript.shell")
iReturn = objshell.run("pfcli.exe pfs start --force", 0, true)
iReturn = objshell.run("pfcli.exe pf service start --force", 0, true)
Loading

0 comments on commit 7cb5642

Please sign in to comment.