Skip to content

Commit

Permalink
Delete all packages during deploy if we're about to install
Browse files Browse the repository at this point in the history
- We check to see if all installed packages are in the cache, so this
  should be safe unless the user messes with their cache or does a
manual install we don't know about
- Just in case, we always ask the user before doing a deploy
- Fixes #82
  • Loading branch information
virtuald committed Jan 17, 2024
1 parent 424d54e commit 52ead32
Showing 1 changed file with 63 additions and 9 deletions.
72 changes: 63 additions & 9 deletions robotpy_installer/cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ def __init__(self, parser: argparse.ArgumentParser):
help="Force installation of packages required by pyproject.toml",
)

parser.add_argument(
"--no-uninstall",
action="store_true",
default=False,
help="Do not uninstall packages from the RoboRIO",
)

parser.add_argument(
"--large",
action="store_true",
Expand All @@ -135,6 +142,7 @@ def __init__(self, parser: argparse.ArgumentParser):
)

self._packages_in_cache: typing.Optional[pypackages.Packages] = None
self._robot_packages: typing.Optional[pypackages.Packages] = None

@handle_cli_error
def run(
Expand All @@ -150,6 +158,7 @@ def run(
ignore_image_version: bool,
no_install: bool,
no_verify: bool,
no_uninstall: bool,
force_install: bool,
large: bool,
robot: typing.Optional[str],
Expand Down Expand Up @@ -245,6 +254,7 @@ def run(
ignore_image_version,
no_install,
force_install,
no_uninstall,
)

if not self._do_deploy(ssh, debug, nc, nc_ds, robot_filename, project_path):
Expand Down Expand Up @@ -331,6 +341,14 @@ def _get_cached_packages(self, installer: RobotpyInstaller) -> pypackages.Packag
)
return self._packages_in_cache

def _get_robot_packages(
self, ssh: sshcontroller.SshController
) -> pypackages.Packages:
if self._robot_packages is None:
rio_packages = roborio_utils.get_rio_py_packages(ssh)
self._robot_packages = pypackages.make_packages(rio_packages)
return self._robot_packages

def _ensure_requirements(
self,
project: typing.Optional[pyproject.RobotPyProjectToml],
Expand All @@ -340,6 +358,7 @@ def _ensure_requirements(
ignore_image_version: bool,
no_install: bool,
force_install: bool,
no_uninstall: bool,
):
python_exists = False
requirements_installed = False
Expand All @@ -362,15 +381,15 @@ def _ensure_requirements(
if no_install:
requirements_installed = True
elif not force_install:
pkgdata = roborio_utils.get_rio_py_packages(ssh)
pkgdata = self._get_robot_packages(ssh)

logger.debug("Roborio has these packages installed:")
for pkg, version in pkgdata.items():
logger.debug("- %s (%s)", pkg, version)
logger.debug("- %s (%s)", pkg, version[0])

assert project is not None
requirements_installed, desc = project.are_requirements_met(
pypackages.make_packages(pkgdata),
pkgdata,
pypackages.roborio_env(),
pypackages.make_cache_extra_resolver(
self._get_cached_packages(installer)
Expand All @@ -389,6 +408,28 @@ def _ensure_requirements(

if force_install:
requirements_installed = False
elif python_exists and not requirements_installed:
# if this is a pre-existing robotpy install, warn the user
# before changing their rio
print(
"\n"
"Deployer has detected that the packages installed on your RoboRIO do not match\n"
"the requirements in pyproject.toml. The installer will now:\n"
)
if not no_uninstall:
prompt = "Continue with uninstall + install?"
print("* Uninstall ALL Python packages from the RoboRIO")
else:
prompt = "Continue with install?"

print(
"* Install required packages on the RoboRIO\n"
"\n"
"If you do not wish to do this, specify --no-install as a deploy argument, or answer 'n'.\n"
)

if not yesno(prompt):
requirements_installed = True

if cpp_java_exists or not python_exists or not requirements_installed:
if no_install and not python_exists:
Expand Down Expand Up @@ -424,14 +465,8 @@ def _ensure_requirements(
) from e

if not requirements_installed:
# pip is greedy
installer.ensure_more_memory()

logger.info("Installing project requirements on RoboRIO:")
assert project is not None
packages = project.get_install_list()
for package in packages:
logger.info("- %s", package)

# Check if everything is in the cache before doing the install
cached = self._get_cached_packages(installer)
Expand All @@ -450,6 +485,25 @@ def _ensure_requirements(
]
raise Error("\n".join(errmsg))

if not no_uninstall:
logger.info(
"Clearing existing packages on RoboRIO before install (specify --no-uninstall to not do this)"
)
# The user may have deleted something from the project
# requirements so the only way to ensure the exact
# environment is to first clear the environment.
# - can't do a partial uninstall without completely
# resolving everything

rio_packages = self._get_robot_packages(installer.ssh)
installer.pip_uninstall(
[p for p in rio_packages.keys() if p != "pip"]
)

logger.info("Installing project requirements on RoboRIO:")
for package in packages:
logger.info("- %s", package)

try:
installer.pip_install(False, False, False, False, [], packages)
except PipInstallError as e:
Expand Down

0 comments on commit 52ead32

Please sign in to comment.