diff --git a/installer/bootstrap.bash b/installer/bootstrap.bash index cbcf85350..4cb25eeb4 100755 --- a/installer/bootstrap.bash +++ b/installer/bootstrap.bash @@ -58,6 +58,11 @@ function main TUE_ROS_DISTRO= TUE_ROS_VERSION= + # Python configuration + create_virtualenv="true" + virtualenv_include_system_site_packages="false" + TUE_PPM="pip" # Default to pip + for i in "$@" do case $i in @@ -73,13 +78,29 @@ function main --create-virtualenv=* ) create_virtualenv="${i#*=}" ;; + --virtualenv-include-system-site-packages=* ) + virtualenv_include_system_site_packages="${i#*=}" + ;; + --pip ) + TUE_PPM="pip" + ;; + --poetry ) + TUE_PPM="poetry" + ;; * ) echo "[tue-env](bootstrap) Error! Unknown argument '${i}' provided to bootstrap script." - return 1 + exit 1 ;; esac done + # Poetry should only be used in combination with a virtualenv + if [[ "${TUE_PPM}" == "poetry" && "${create_virtualenv}" == "false" ]] + then + echo "[tue-env](bootstrap) Error! Poetry is not installed." + return 1 + fi + case ${DISTRIB_RELEASE} in "20.04") if [[ "${ros_version}" -eq 2 ]] @@ -200,6 +221,13 @@ function main git clone "${env_url}" "${env_dir}" fi +# Install Poetry when needed + if [[ "${TUE_PPM}" == "poetry" ]] + then + echo "[tue-env](bootstrap) Installing Poetry" + curl -sSL https://install.python-poetry.org | python3 - + fi + # Source the installer commands # No need to follow to a file which is already checked by CI # shellcheck disable=SC1090 @@ -209,11 +237,15 @@ function main mkdir -p "${workspace_dir}" # Initialize ros environment directory incl. targets - tue-env init "${workspace}" "${workspace_dir}" "--create-virtualenv=${create_virtualenv}" "--targets-url=${env_targets_url}" + tue-env init "${workspace}" "${workspace_dir}" \ + "--create-virtualenv=${create_virtualenv}" \ + "--virtualenv-include-system-site-packages=${virtualenv_include_system_site_packages}" \ + "--targets-url=${env_targets_url}" # Configure environment tue-env config "${workspace}" set "TUE_ROS_DISTRO" "${TUE_ROS_DISTRO}" tue-env config "${workspace}" set "TUE_ROS_VERSION" "${TUE_ROS_VERSION}" + tue-env config "${workspace}" set "TUE_PPM" "${TUE_PPM}" # Add loading of TU/e tools (tue-env, tue-get, etc) to bashrc # shellcheck disable=SC2088 diff --git a/installer/check-pip-pkg-installed-version.py b/installer/check-pip-pkg-installed-version.py index bc6789e50..4a073b443 100755 --- a/installer/check-pip-pkg-installed-version.py +++ b/installer/check-pip-pkg-installed-version.py @@ -1,23 +1,20 @@ #! /usr/bin/env python3 -import sys +import site +from typing import List from pip._internal.req.constructors import install_req_from_line from pip._internal.utils.virtualenv import running_under_virtualenv -def main() -> int: - if len(sys.argv) < 2: - print("Usage: check-pip-pkg-installed-version.py requirement [requirements]") - return 2 - +def main(req_strs: List[str]) -> int: return_code = 0 pkg_installed = [] try: - for arg in sys.argv[1:]: - req = install_req_from_line(arg) + for req_str in req_strs: + req = install_req_from_line(req_str) - req.check_if_exists(not running_under_virtualenv()) + req.check_if_exists(not running_under_virtualenv) if req.satisfied_by: pkg_installed.append(str(req.satisfied_by).replace(" ", "^")) @@ -34,4 +31,14 @@ def main() -> int: if __name__ == "__main__": - sys.exit(main()) + import argparse + import sys + + parser = argparse.ArgumentParser( + description="Check if a set of pip package is installed, meeting a requirement string." + ) + parser.add_argument("req_strs", nargs="+") + + args = parser.parse_args() + + sys.exit(main(**vars(args))) diff --git a/installer/tue-install-impl.bash b/installer/tue-install-impl.bash index f3bdf3f23..53e9c9e29 100755 --- a/installer/tue-install-impl.bash +++ b/installer/tue-install-impl.bash @@ -168,7 +168,7 @@ function _remove_old_target_dep_recursively old_dep_dep_file="${TUE_INSTALL_DEPENDENCIES_DIR}"/"${old_dep_target}" if [[ -f "${old_dep_dep_file}" ]] then - # Iterate over all depencies of old_dep_target, which is removed. + # Iterate over all dependencies of old_dep_target, which is removed. while read -r dep_of_old_dep do # Actually remove the deps @@ -183,11 +183,11 @@ function _remove_old_target_dep_recursively done < "${old_dep_dep_file}" rm -f "${old_dep_dep_file}" else - tue-install-debug "[remove_old_dep] No depencies file exist for target: ${old_dep_target}" + tue-install-debug "[remove_old_dep] No dependencies file exist for target: ${old_dep_target}" fi tue-install-debug "[remove_old_dep] Uninstalled '${old_dep_target}' as a dependency of '${parent_target}'" - tue-install-info "[remove_old_dep] '${old_dep_target}' has been uninstalled, you can remove it from the workspace or deinstall it in another way" + tue-install-info "[remove_old_dep] '${old_dep_target}' has been uninstalled, you can remove it from the workspace or uninstall it in another way" return ${error_code} } @@ -309,7 +309,7 @@ function tue-install-target [ "$now" == "true" ] && now_cmd="--now" # Do not use 'local cmds=' because it does not preserve command output status ($?) local cmds - if cmds=$("$TUE_INSTALL_SCRIPTS_DIR"/parse_install_yaml.py "$install_file".yaml $now_cmd) + if cmds=$(/usr/bin/python "${TUE_INSTALL_SCRIPTS_DIR}"/parse_install_yaml.py "${install_file}".yaml ${now_cmd}) then for cmd in $cmds do @@ -352,7 +352,7 @@ function tue-install-target old_deps_removed=$(comm -23 <(echo "${old_deps}") <(echo "${new_deps}")) if [[ -n ${old_deps_removed} ]] then - tue-install-debug "Following dropped depedencies need to be removed:\n${old_deps_removed}" + tue-install-debug "Following dropped dependencies need to be removed:\n${old_deps_removed}" else tue-install-debug "No dropped dependencies to be removed" fi @@ -361,7 +361,7 @@ function tue-install-target do # Remove this target from dep-on file of dep # When the dep-on file is now empty, remove it - # Recurisvely -> Remove it from the dep-on files of its deps + # Recursively -> Remove it from the dep-on files of its deps tue-install-debug "Going to remove '${dep}' as a dependency" _remove_old_target_dep_recursively "${target}" "${dep}" || tue-install-error "Something went wrong while removing '${dep}' as a dependency" done @@ -1093,6 +1093,49 @@ function tue-install-pip3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +function _handle_python_sites +{ + local pv + pv=$1 + shift + # requires the parent function to have declared the following local variables: + # python_exec, site_arg, sudo_cmd, user_arg + tue-install-debug "_handle_python${pv}_sites $*" + + local site + site=$1 + + case ${site} in + "system" ) + python_exec=/usr/bin/python"${pv}" + site_arg="-s" + sudo_cmd="sudo -H" + user_arg="" + ;; + "user" ) + python_exec=/usr/bin/python"${pv}" + site_arg="" + sudo_cmd="" + user_arg="--user" + ;; + "venv" ) + python_exec=python"${pv}" + site_arg="-s" + sudo_cmd="" + user_arg="" + ;; + * ) + tue-install-error "_handle_python${pv}_sites: Unknown input variable ${i}" + ;; + esac + + tue-install-debug "python_site: ${python_site}" + tue-install-debug "python_exec: ${python_exec}" + tue-install-debug "site_arg: ${site_arg}" + tue-install-debug "sudo_cmd: ${sudo_cmd}" + tue-install-debug "user_arg: ${user_arg}" +} + function _tue-install-pip-now { local pv @@ -1105,25 +1148,42 @@ function _tue-install-pip-now tue-install-error "Invalid tue-install-pip${pv}-now call: needs package as argument." fi - local user_arg - [[ -z "${VIRTUAL_ENV}" ]] && user_arg="--user" + local pips python_site + { [[ -n ${VIRTUAL_ENV} ]] && python_site="venv"; } || python_site="user" + if [[ -n $1 ]] + then + for i in "$@" + do + case $i in + --python-site=* ) + python_site="${i#*=}" + ;; + --* ) + tue-install-error "tue-install-pip${pv}-now: Unknown input variable ${i}" ;; + * ) + pips+=("$i") ;; + esac + done + fi + + local python_exec site_arg sudo_cmd user_arg + _handle_python_sites "${pv}" "${python_site}" # Make sure pip is up-to-date before checking version and installing local pip_version desired_pip_version - pip_version=$(python"${pv}" -m pip --version | awk '{print $2}') + pip_version=$(python"${pv}" ${site_arg} -m pip --version | awk '{print $2}') desired_pip_version="23" if version_gt "$desired_pip_version" "$pip_version" then tue-install-debug "pip${pv} not yet version >=$desired_pip_version, but $pip_version" - tue-install-pipe python"${pv}" -m pip install ${user_arg} --upgrade pip + tue-install-pipe python"${pv}" ${site_arg} -m pip install "${user_arg}" --upgrade pip hash -r else tue-install-debug "Already pip${pv}>=$desired_pip_version" fi local pips_to_check pips_to_check_w_options pips_to_install pips_to_install_w_options git_pips_to_install - # shellcheck disable=SC2048 - for pkg in $* + for pkg in "${pips[@]}" do if [[ "$pkg" == "git+"* ]] then @@ -1143,7 +1203,7 @@ function _tue-install-pip-now then local indexes_to_install # shellcheck disable=SC2086 - _tue-install-pip-check "$pv" $pips_to_check + _tue-install-pip-check "${pv}" --python-site=${python_site} ${pips_to_check} read -r -a pips_to_check <<< "$pips_to_check" @@ -1165,7 +1225,7 @@ function _tue-install-pip-now pips_to_check_options_removed="$pips_to_check_options_removed ${pkg_split[0]}" done # shellcheck disable=SC2086 - _tue-install-pip-check "$pv" $pips_to_check_options_removed + _tue-install-pip-check "${pv}" --python-site=${python_site} ${pips_to_check_options_removed} read -r -a pips_to_check_w_options <<< "$pips_to_check_w_options" @@ -1181,7 +1241,7 @@ function _tue-install-pip-now if [ -n "$pips_to_install" ] then # shellcheck disable=SC2048,SC2086 - tue-install-pipe python"${pv}" -m pip install ${user_arg} $pips_to_install <<< yes || tue-install-error "An error occurred while installing pip${pv} packages." + tue-install-pipe ${sudo_cmd} ${python_exec} ${site_arg} -m pip install ${user_arg} $pips_to_install <<< yes || tue-install-error "An error occurred while installing pip${pv} packages." fi if [ -n "$pips_to_install_w_options" ] @@ -1189,7 +1249,7 @@ function _tue-install-pip-now for pkg in $pips_to_install_w_options do # shellcheck disable=SC2048,SC2086 - tue-install-pipe python"${pv}" -m pip install ${user_arg} ${pkg//^/ } <<< yes || tue-install-error "An error occurred while installing pip${pv} packages with options." + tue-install-pipe ${sudo_cmd} ${python_exec} ${site_arg} -m pip install ${user_arg} ${pkg//^/ } <<< yes || tue-install-error "An error occurred while installing pip${pv} packages with options." done fi @@ -1198,7 +1258,7 @@ function _tue-install-pip-now for pkg in $git_pips_to_install do # shellcheck disable=SC2048,SC2086 - tue-install-pipe python"${pv}" -m pip install ${user_arg} ${pkg} <<< yes || tue-install-error "An error occurred while installing pip${pv} git packages." + tue-install-pipe ${sudo_cmd} ${python_exec} ${site_arg} -m pip install ${user_arg} ${pkg} <<< yes || tue-install-error "An error occurred while installing pip${pv} git packages." done fi } @@ -1210,12 +1270,36 @@ function _tue-install-pip-check pv=$1 shift - local pips_to_check installed_versions - pips_to_check=("$@") + local installed_versions python_site pips_to_check + if [[ -n $1 ]] + then + for i in "$@" + do + case $i in + --python-site=* ) + python_site="${i#*=}" + ;; + --* ) + tue-install-error "Unknown input variable ${i}" ;; + * ) + pips_to_check+=("$i") ;; + esac + done + fi + + if [[ -z "${VIRTUAL_ENV}" && "${site}" == "venv" ]] + then + tue-install-error "Trying to check pip packages in a virtualenv, but no virtualenv is activated" + fi + + # Set by _handle_python_sites + local python_exec sudo_cmd site_arg user_arg + _handle_python_sites "${pv}" "${python_site}" + if [ ${#pips_to_check[@]} -gt 0 ] then local error_code - installed_versions=$(python"${pv}" "$TUE_INSTALL_SCRIPTS_DIR"/check-pip-pkg-installed-version.py "${pips_to_check[@]}") + installed_versions=$(${sudo_cmd} "${python_exec}" ${site_arg} "${TUE_INSTALL_SCRIPTS_DIR}"/check-pip-pkg-installed-version.py "${pips_to_check[@]}") error_code=$? if [ "$error_code" -gt 1 ] then @@ -1493,10 +1577,11 @@ function tue-install-ros local pkg_xml="$ros_pkg_dir"/package.xml if [ -f "$pkg_xml" ] then - # Catkin + # catkin/ament/colcon tue-install-debug "Parsing $pkg_xml" + local deps - deps=$("$TUE_INSTALL_SCRIPTS_DIR"/parse_package_xml.py "$pkg_xml") + deps=$(/usr/bin/python "${TUE_INSTALL_SCRIPTS_DIR}"/parse_package_xml.py "${pkg_xml}") tue-install-debug "Parsed package.xml\n$deps" for dep in $deps @@ -1636,7 +1721,8 @@ TUE_INSTALL_INFOS= # Make sure tools used by this installer are installed tue-install-system-now curl git jq python-is-python3 python3-pip wget -tue-install-pip3-now catkin-pkg PyYAML +# Install in user or system site-packages +tue-install-pip3-now --python-site="user" catkin-pkg PyYAML # Handling of targets @@ -1674,7 +1760,7 @@ do tue-install-debug "[$target] marked as installed after a successful install" touch "$TUE_INSTALL_INSTALLED_DIR"/"$target" else - tue-install-debug "[$target] succesfully updated" + tue-install-debug "[$target] successfully updated" fi done @@ -1746,6 +1832,6 @@ fi TUE_INSTALL_CURRENT_TARGET="main-loop" -tue-install-echo "Installer completed succesfully" +tue-install-echo "Installer completed successfully" return 0 diff --git a/setup/tue-functions.bash b/setup/tue-functions.bash index 4b31c74ac..e76cd76c1 100644 --- a/setup/tue-functions.bash +++ b/setup/tue-functions.bash @@ -457,10 +457,10 @@ function tue-make # Disable symlink install for production if [ "${CI_INSTALL}" == "true" ] then - rm -rf "$TUE_SYSTEM_DIR"/install - python3 -m colcon --log-base "$TUE_SYSTEM_DIR"/log build --base-paths "$TUE_SYSTEM_DIR"/src --build-base "$TUE_SYSTEM_DIR"/build --install-base "$TUE_SYSTEM_DIR"/install "$@" + rm -rf "${TUE_SYSTEM_DIR}"/install + /usr/bin/python3 -m colcon --log-base "${TUE_SYSTEM_DIR}"/log build --base-paths "${TUE_SYSTEM_DIR}"/src --build-base "${TUE_SYSTEM_DIR}"/build --install-base "${TUE_SYSTEM_DIR}"/install "$@" else - python3 -m colcon --log-base "$TUE_SYSTEM_DIR"/log build --merge-install --symlink-install --base-paths "$TUE_SYSTEM_DIR"/src --build-base "$TUE_SYSTEM_DIR"/build --install-base "$TUE_SYSTEM_DIR"/install "$@" + /usr/bin/python3 -m colcon --log-base "${TUE_SYSTEM_DIR}"/log build --merge-install --symlink-install --base-paths "${TUE_SYSTEM_DIR}"/src --build-base "${TUE_SYSTEM_DIR}"/build --install-base "${TUE_SYSTEM_DIR}"/install "$@" fi return $? else