1818from . import pypackages , pyproject , robot_utils , sshcontroller
1919from .installer import PipInstallError , PythonMissingError , RobotpyInstaller
2020from .installer import _ROBOTPY_PYTHON_VERSION_TUPLE as required_pyversion
21+ from .installer import _ROBOT_VENV_PYTHON
2122from .errors import Error
2223from .utils import handle_cli_error , print_err , yesno
2324
@@ -241,20 +242,18 @@ def run(
241242 )
242243 raise Error (msg )
243244
244- with sshcontroller . ssh_from_cfg (
245- project_path ,
246- main_file ,
247- username = robot_utils . ssh_username ,
248- password = robot_utils . ssh_password ,
245+ installer = RobotpyInstaller ()
246+
247+ with installer . connect_to_robot (
248+ project_path = project_path ,
249+ main_file = main_file ,
249250 robot_or_team = robot or team ,
250- no_resolve = no_resolve ,
251+ ignore_image_version = ignore_image_version ,
251252 ) as ssh :
252253 self ._ensure_requirements (
253254 project ,
254- project_path ,
255- main_file ,
255+ installer ,
256256 ssh ,
257- ignore_image_version ,
258257 no_install ,
259258 force_install ,
260259 no_uninstall ,
@@ -353,20 +352,15 @@ def _get_robot_packages(
353352 return self ._robot_packages
354353
355354 def _clear_pip_packages (self , installer : RobotpyInstaller ):
356- rio_packages = self ._get_robot_packages (installer .ssh )
357- to_uninstall = [p for p in rio_packages .keys () if p != "pip" ]
358- if to_uninstall :
359- installer .pip_uninstall (to_uninstall )
360-
355+ installer .uninstall_venv ()
361356 self ._packages_in_cache = None
357+ self ._robot_packages = None
362358
363359 def _ensure_requirements (
364360 self ,
365361 project : typing .Optional [pyproject .RobotPyProjectToml ],
366- project_path : pathlib .Path ,
367- main_file : pathlib .Path ,
362+ installer : RobotpyInstaller ,
368363 ssh : sshcontroller .SshController ,
369- ignore_image_version : bool ,
370364 no_install : bool ,
371365 force_install : bool ,
372366 no_uninstall : bool ,
@@ -375,23 +369,20 @@ def _ensure_requirements(
375369 python_invalid : typing .Union [bool , str ] = False
376370 requirements_installed = False
377371
378- installer = RobotpyInstaller ()
379-
380372 # does c++/java exist
381373 with wrap_ssh_error ("removing c++/java user programs" ):
382374 cpp_java_exists = not robot_utils .uninstall_cpp_java (ssh )
383375
384376 # does python exist
385- with wrap_ssh_error ("checking if python exists" ):
386- python_exists = (
387- ssh .exec_cmd ("[ -x /usr/local/bin/python3 ]" ).returncode == 0
388- )
377+ with wrap_ssh_error ("checking if python was installed" ):
378+ python_exists = installer .is_python_installed ()
389379 if not python_exists :
390380 logger .warning ("Python is not installed on SystemCore" )
391381
392382 if python_exists :
383+
393384 with wrap_ssh_error ("getting python version" ):
394- python_version = robot_utils . get_python3_version ( ssh )
385+ python_version = installer . get_python_version ( )
395386
396387 if python_version != required_pyversion :
397388 python_exists = False
@@ -401,14 +392,14 @@ def _ensure_requirements(
401392
402393 if no_install :
403394 raise Error (
404- f"Unsupported version of python ({ m } .{ mn } ) was found on the SystemCore \n "
395+ f"Unsupported version of python ({ m } .{ mn } ) was found on the robot \n "
405396 "- could not update it because no-install was specified\n "
406397 )
407398
408399 # Warn the user before changing their rio
409400 print (
410401 "\n "
411- f"Deployer has detected that the version of Python installed on the SystemCore ({ m } .{ mn } )\n "
402+ f"Deployer has detected that the version of Python installed on the robot ({ m } .{ mn } )\n "
412403 "is not supported by this installer. The installer will now uninstall that\n "
413404 f"and install Python { rm } .{ rmn } .\n "
414405 )
@@ -422,7 +413,7 @@ def _ensure_requirements(
422413 elif not force_install :
423414 pkgdata = self ._get_robot_packages (ssh )
424415
425- logger .debug ("SystemCore has these packages installed:" )
416+ logger .debug ("Robot has these packages installed:" )
426417 for pkg , version in pkgdata .items ():
427418 logger .debug ("- %s (%s)" , pkg , version [0 ])
428419
@@ -435,7 +426,7 @@ def _ensure_requirements(
435426 ),
436427 )
437428 if not requirements_installed :
438- logger .warning ("Project requirements not installed on SystemCore " )
429+ logger .warning ("Project requirements not installed on robot " )
439430 for msg in desc :
440431 logger .warning ("- %s" , msg )
441432 else :
@@ -452,17 +443,17 @@ def _ensure_requirements(
452443 # before changing their rio
453444 print (
454445 "\n "
455- "Deployer has detected that the packages installed on your SystemCore do not match\n "
446+ "Deployer has detected that the packages installed on your robot do not match\n "
456447 "the requirements in pyproject.toml. The installer will now:\n "
457448 )
458449 if not no_uninstall :
459450 prompt = "Continue with uninstall + install?"
460- print ("* Uninstall ALL Python packages from the SystemCore " )
451+ print ("* Uninstall ALL Python packages from the robot " )
461452 else :
462453 prompt = "Continue with install?"
463454
464455 print (
465- "* Install required packages on the SystemCore \n "
456+ "* Install required packages on the robot \n "
466457 "\n "
467458 "If you do not wish to do this, specify --no-install as a deploy argument, or answer 'n'.\n "
468459 )
@@ -478,93 +469,73 @@ def _ensure_requirements(
478469 ):
479470 if no_install and not python_exists :
480471 raise Error (
481- "python3 was not found on the SystemCore \n "
472+ "python3 was not found on the robot \n "
482473 "- could not install it because no-install was specified\n "
483474 "- Use 'python -m robotpy installer install-python' to install python separately"
484475 )
485476
486- # This also will give more memory
487- ssh .exec_bash (
488- ". /etc/profile.d/frc-path.sh" ,
489- ". /etc/profile.d/natinst-path.sh" ,
490- robot_utils .kill_robot_cmd ,
491- )
477+ ssh .exec_bash (robot_utils .kill_robot_cmd )
492478
493- with installer .connect_to_robot (
494- project_path = project_path ,
495- main_file = main_file ,
496- ignore_image_version = ignore_image_version ,
497- ssh = ssh ,
498- ):
499- if not kill_script_updated :
500- robot_utils .update_kill_script (installer .ssh )
501-
502- if cpp_java_exists :
503- robot_utils .uninstall_cpp_java_admin (installer .ssh )
504-
505- if python_invalid :
506- with wrap_ssh_error ("uninstalling python" ):
507- self ._clear_pip_packages (installer )
508- logger .info ("Uninstalling %s from SystemCore" , python_invalid )
509- installer .ssh .exec_cmd (
510- f"opkg remove { python_invalid } " ,
511- check = True ,
512- print_output = True ,
513- )
514-
515- if not python_exists :
516- try :
517- installer .install_python ()
518- except PythonMissingError as e :
519- raise PythonMissingError (
520- f"{ e } \n \n "
521- "Run 'python -m robotpy sync' to download your project requirements from the internet (or --no-install to ignore)"
522- ) from e
479+ if python_invalid :
480+ with wrap_ssh_error ("uninstalling python" ):
481+ self ._clear_pip_packages (installer )
482+ logger .info ("Uninstalling %s from robot" , python_invalid )
483+ installer .uninstall_python ()
484+ python_exists = False
523485
524- if not requirements_installed :
525- assert project is not None
526- packages = project .get_install_list ()
527-
528- # Check if everything is in the cache before doing the install
529- cached = self ._get_cached_packages (installer )
530- ok , missing = project .are_requirements_met (
531- cached ,
532- pypackages .robot_env (),
533- pypackages .make_cache_extra_resolver (cached ),
486+ if not python_exists :
487+ try :
488+ installer .install_python ()
489+ except PythonMissingError as e :
490+ raise PythonMissingError (
491+ f"{ e } \n \n "
492+ "Run 'python -m robotpy sync' to download your project requirements from the internet (or --no-install to ignore)"
493+ ) from e
494+
495+ if not requirements_installed :
496+ assert project is not None
497+ packages = project .get_install_list ()
498+
499+ # Check if everything is in the cache before doing the install
500+ cached = self ._get_cached_packages (installer )
501+ ok , missing = project .are_requirements_met (
502+ cached ,
503+ pypackages .robot_env (),
504+ pypackages .make_cache_extra_resolver (cached ),
505+ )
506+ if not ok :
507+ errmsg = ["Project requirements not found in download cache!" ]
508+ errmsg .extend ([f"- { msg } " for msg in missing ])
509+ errmsg += [
510+ "" ,
511+ "Run 'python -m robotpy sync' to download your project requirements" ,
512+ "from the internet (or specify --no-install to not attempt installation)." ,
513+ ]
514+ raise Error ("\n " .join (errmsg ))
515+
516+ if not no_uninstall :
517+ logger .info (
518+ "Clearing existing packages on robot before install (specify --no-uninstall to not do this)"
534519 )
535- if not ok :
536- errmsg = ["Project requirements not found in download cache!" ]
537- errmsg .extend ([f"- { msg } " for msg in missing ])
538- errmsg += [
539- "" ,
540- "Run 'python -m robotpy sync' to download your project requirements" ,
541- "from the internet (or specify --no-install to not attempt installation)." ,
542- ]
543- raise Error ("\n " .join (errmsg ))
544-
545- if not no_uninstall :
546- logger .info (
547- "Clearing existing packages on SystemCore before install (specify --no-uninstall to not do this)"
548- )
549- # The user may have deleted something from the project
550- # requirements so the only way to ensure the exact
551- # environment is to first clear the environment.
552- # - can't do a partial uninstall without completely
553- # resolving everything
554- self ._clear_pip_packages (installer )
555-
556- logger .info ("Installing project requirements on SystemCore:" )
557- for package in packages :
558- logger .info ("- %s" , package )
559-
560- try :
561- installer .pip_install (False , False , False , False , [], packages )
562- except PipInstallError as e :
563- raise PipInstallError (
564- f"{ e } \n \n "
565- "If 'no matching distribution found', run 'python -m robotpy sync' to download your\n "
566- "project requirements from the internet (or --no-install to ignore)."
567- ) from e
520+ # The user may have deleted something from the project
521+ # requirements so the only way to ensure the exact
522+ # environment is to first clear the environment.
523+ # - can't do a partial uninstall without completely
524+ # resolving everything
525+ self ._clear_pip_packages (installer )
526+
527+ logger .info ("Installing project requirements on robot:" )
528+ for package in packages :
529+ logger .info ("- %s" , package )
530+
531+ try :
532+ installer .pip_install (False , False , False , False , [], packages )
533+ except PipInstallError as e :
534+ raise PipInstallError (
535+ f"{ e } \n \n "
536+ "If 'no matching distribution found', run 'python -m robotpy sync' to download your\n "
537+ "project requirements from the internet (or --no-install to ignore)."
538+ ) from e
568539
569540 def _do_deploy (
570541 self ,
@@ -580,12 +551,7 @@ def _do_deploy(
580551 # GradleRIO kills the robot before deploying it, so we do that too
581552 logger .info ("Killing robot program" )
582553 with wrap_ssh_error ("killing robot program" ):
583- ssh .exec_bash (
584- ". /etc/profile.d/frc-path.sh" ,
585- ". /etc/profile.d/natinst-path.sh" ,
586- "/usr/local/frc/bin/frcKillRobot.sh -t" ,
587- check = False ,
588- )
554+ ssh .exec_bash (robot_utils .kill_robot_cmd , check = False )
589555
590556 deploy_dir = pathlib .PurePosixPath ("/home/systemcore" )
591557 py_deploy_subdir = "py"
@@ -599,18 +565,12 @@ def _do_deploy(
599565
600566 if debug :
601567 compileall_flags = ""
602- deployed_cmd = (
603- "env LD_LIBRARY_PATH=/usr/local/frc/lib/ "
604- f"/usr/local/bin/python3 -u -m robotpy --main { py_deploy_dir } /{ robot_filename } -v run"
605- )
568+ deployed_cmd = f"{ _ROBOT_VENV_PYTHON } -u -m robotpy --main { py_deploy_dir } /{ robot_filename } -v run"
606569 deployed_cmd_fname = "robotDebugCommand"
607570 bash_cmd = "/bin/bash -cex"
608571 else :
609572 compileall_flags = "-O"
610- deployed_cmd = (
611- "env LD_LIBRARY_PATH=/usr/local/frc/lib/ "
612- f"/usr/local/bin/python3 -u -O -m robotpy --main { py_deploy_dir } /{ robot_filename } run"
613- )
573+ deployed_cmd = f"{ _ROBOT_VENV_PYTHON } -u -O -m robotpy --main { py_deploy_dir } /{ robot_filename } run"
614574 deployed_cmd_fname = "robotCommand"
615575 bash_cmd = "/bin/bash -ce"
616576
@@ -622,6 +582,8 @@ def _do_deploy(
622582 f'echo "{ deployed_cmd } " > { deploy_dir } /{ deployed_cmd_fname } ' , check = True
623583 )
624584
585+ ssh .exec_cmd (f"chmod +x { robot_utils .robot_command } " , check = True )
586+
625587 if debug :
626588 with wrap_ssh_error ("touching frcDebug" ):
627589 ssh .exec_cmd ("touch /tmp/frcdebug" , check = True )
@@ -658,12 +620,10 @@ def _do_deploy(
658620 sshcmd = (
659621 f"{ bash_cmd } '"
660622 f"{ replace_cmd } ;"
661- f"/usr/local/bin/python3 { compileall_flags } -m compileall -q -r 5 /home/systemcore/py;"
662- ". /etc/profile.d/frc-path.sh; "
663- ". /etc/profile.d/natinst-path.sh; "
664- f"chown -R lvuser:ni { py_deploy_dir } ; "
665- "sync; "
666- "/usr/local/frc/bin/frcKillRobot.sh -t -r || true"
623+ f"{ _ROBOT_VENV_PYTHON } { compileall_flags } -m compileall -q -r 5 /home/systemcore/py;"
624+ "sudo sync; "
625+ "sudo systemctl enable robot;"
626+ "sudo systemctl start robot;"
667627 "'"
668628 )
669629
0 commit comments