Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
  • 10 commits
  • 16 files changed
  • 0 commit comments
  • 2 contributors
@@ -18,9 +18,9 @@ distributions, and from Mac OSX also. Here's how you do it:
* `Download RobotPy from github <https://github.com/robotpy/robotpy-wpilib/releases>`_
* `Make sure Python 3.4 is installed <https://www.python.org/downloads/>`_
-Unzip the RobotPy zipfile somewhere, and there should be an installer.py
-there. Open up a command line, change directory to the installer location,
-and run this::
+Unzip the RobotPy zipfile somewhere on your computer (not on the RoboRIO),
+and there should be an installer.py there. Open up a command line, change
+directory to the installer location, and run this::
Windows: py installer.py install-robotpy
@@ -13,7 +13,7 @@
class MyRobot(wpilib.SampleRobot):
def robotInit(self):
- camera = wpilib.UsbCamera()
+ camera = wpilib.USBCamera()
camera.setExposureManual(50)
camera.setBrightness(80)
camera.updateSetting() # force update before we start thread
View
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# (C) 2014 Dustin Spicuzza. Distributed under MIT license.
+# (C) 2014-2015 Dustin Spicuzza. Distributed under MIT license.
#
# This is a simple (ha!) installer program that is designed to be used to
# deploy RobotPy to a roborio via SSH
@@ -11,6 +11,9 @@
# around easily without having to think about it too hard and worry about
# path issues. Reconsider this once we get to 4000+ lines of code... :p
#
+# NOTE: This file is used in robotpy-wpilib and in pyfrc, please keep the two
+# copies in sync!
+#
import argparse
@@ -29,12 +32,7 @@
from distutils.version import LooseVersion
from urllib.request import urlopen, urlretrieve
-try:
- import pip
-except ImportError:
- print("ERROR: pip must be installed for the installer to work!")
- exit(1)
-
+
is_windows = hasattr(sys, 'getwindowsversion')
@@ -259,38 +257,25 @@ class Error(Exception):
class ArgError(Error):
pass
-class RobotpyInstaller(object):
-
- cfg = abspath(join(dirname(__file__), '.installer_config'))
-
- pip_cache = abspath(join(dirname(__file__), 'pip_cache'))
- opkg_cache = abspath(join(dirname(__file__), 'opkg_cache'))
-
- win_bins = abspath(join(dirname(__file__), 'win32'))
+class SshController(object):
+ '''
+ Use this to transfer files and execute commands on a RoboRIO in a
+ cross platform manner
+ '''
# Defaults, actual values come from config file
_username = 'admin'
_password = ''
_hostname = ''
- # opkg feed
- opkg_feed = 'http://www.tortall.net/~robotpy/feeds/2014/'
- opkg_arch = 'armv7a-vfp-neon'
+ win_bins = abspath(join(dirname(__file__), 'win32'))
- commands = [
- 'install-robotpy',
- 'download-robotpy',
- 'install',
- 'download'
- ]
-
- def __init__(self):
-
- if not exists(self.pip_cache):
- os.makedirs(self.pip_cache)
+ def __init__(self, cfg_filename):
+ self.cfg_filename = cfg_filename
+ self.cfg = None
+ self.config_to_write = None
+ self.dirty = False
- self._cfg_initialized = False
-
@property
def username(self):
self._init_cfg()
@@ -308,23 +293,24 @@ def hostname(self):
def _init_cfg(self):
- if self._cfg_initialized:
+ if self.cfg is not None:
return
- self._cfg_initialized = True
+ self.cfg_initialized = True
- if not exists(self.cfg):
- self._do_config()
-
- config = configparser.ConfigParser()
- config.read(self.cfg)
+ if not exists(self.cfg_filename):
+ self.cfg = self._do_config()
+ self.dirty = True
+ else:
+ self.cfg = configparser.ConfigParser()
+ self.cfg.read(self.cfg_filename)
try:
- self._username = config['auth'].get('username', self.username)
- self._password = config['auth'].get('password', self.password)
- self._hostname = config['auth']['hostname']
- except KeyError as e:
- raise Error("Error reading %s; delete it and try again" % self.cfg)
+ self._username = self.cfg['auth'].get('username', self.username)
+ self._password = self.cfg['auth'].get('password', self.password)
+ self._hostname = self.cfg['auth']['hostname']
+ except KeyError:
+ raise Error("Error reading %s; delete it and try again" % self.cfg_filename)
def _do_config(self):
@@ -333,28 +319,32 @@ def _do_config(self):
while hostname == '':
hostname = input('Robot hostname (like roborio-XXX.local, or an IP address): ')
- username = input('Username [%s]: ' % self.username)
- password = getpass.getpass('Password [%s]: ' % self.password)
+ username = input('Username [%s]: ' % self._username)
+ password = getpass.getpass('Password [%s]: ' % self._password)
config = configparser.ConfigParser()
config['auth'] = {}
- if username != '' and username != self.username:
+ if username != '' and username != self._username:
config['auth']['username'] = username
- if password != '' and password != self.password:
+ if password != '' and password != self._password:
config['auth']['username'] = password
config['auth']['hostname'] = hostname
- with open(self.cfg, 'w') as fp:
- config.write(fp)
-
-
+ return config
+
+ def close(self):
+ '''Only call this on success'''
+ if self.dirty:
+ with open(self.cfg_filename, 'w') as fp:
+ self.cfg.write(fp)
+
#
# This sucks. We should be using paramiko here...
#
- def _ssh(self, *args, get_output=False):
+ def ssh(self, *args, get_output=False):
ssh_args = ['%s@%s' % (self.username, self.hostname)] + list(args)
@@ -386,7 +376,7 @@ def _ssh(self, *args, get_output=False):
return output.decode('utf-8')
- def _sftp(self, src, dst, mkdir=True):
+ def sftp(self, src, dst, mkdir=True):
'''
src can be a single file, list of files, or directory
dst is always a directory, for simplicity
@@ -399,14 +389,22 @@ def _sftp(self, src, dst, mkdir=True):
bfp, bfname = tempfile.mkstemp(text=True)
try:
with os.fdopen(bfp, 'w') as fp:
- if mkdir:
- fp.write('mkdir "%s"\n' % dst)
+
if isinstance(src, str):
if isdir(src):
+ if mkdir:
+ fp.write('mkdir "%s/%s"\n' % (dst, basename(src)))
+
fp.write('put -r "%s" "%s"\n' % (src, dst))
else:
+ if mkdir:
+ fp.write('mkdir "%s"\n' % dst)
+
fp.write('put "%s" "%s/%s"\n' % (src, dst, basename(src)))
else:
+ if mkdir:
+ fp.write('mkdir "%s"\n' % dst)
+
for f in src:
fp.write('put "%s" "%s/%s"\n' % (f, dst, basename(f)))
@@ -443,7 +441,7 @@ def _sftp(self, src, dst, mkdir=True):
except:
pass
- def _poor_sync(self, src, dst):
+ def poor_sync(self, src, dst):
'''
:param src: Local file, list of files, or directory to sync
:param dst: Remote directory to copy file to
@@ -472,8 +470,8 @@ def _poor_sync(self, src, dst):
local_files = {}
for fname, full_fname in files.items():
- hash = md5sum(full_fname)
- local_files[fname] = hash
+ fhash = md5sum(full_fname)
+ local_files[fname] = fhash
# Hack to determine if the directory actually exists, so that
# we create it before putting the files over (necessary because
@@ -482,7 +480,7 @@ def _poor_sync(self, src, dst):
mkdir = False
ssh_cmd = md5sum_cmd + '; [ -d "%s" ]; echo $?' % dst
- lines = self._ssh(ssh_cmd, get_output=True)
+ lines = self.ssh(ssh_cmd, get_output=True)
# once you get it, compare them
for line in lines.split('\n'):
@@ -499,7 +497,35 @@ def _poor_sync(self, src, dst):
# Finally, copy the remaining files over
if len(local_files) != 0:
local_files = [files[file] for file in local_files.keys()]
- self._sftp(local_files, dst, mkdir=mkdir)
+ self.sftp(local_files, dst, mkdir=mkdir)
+
+
+class RobotpyInstaller(object):
+ '''
+ Logic for installing RobotPy
+ '''
+
+ pip_cache = abspath(join(dirname(__file__), 'pip_cache'))
+ opkg_cache = abspath(join(dirname(__file__), 'opkg_cache'))
+
+ # opkg feed
+ opkg_feed = 'http://www.tortall.net/~robotpy/feeds/2014/'
+ opkg_arch = 'armv7a-vfp-neon'
+
+ commands = [
+ 'install-robotpy',
+ 'download-robotpy',
+ 'install',
+ 'download'
+ ]
+
+ def __init__(self):
+
+ if not exists(self.pip_cache):
+ os.makedirs(self.pip_cache)
+
+ cfg_filename = abspath(join(dirname(__file__), '.installer_config'))
+ self.ctrl = SshController(cfg_filename)
def _get_opkg(self):
return OpkgRepo(self.opkg_feed, self.opkg_arch, self.opkg_cache)
@@ -519,6 +545,9 @@ def _create_rpy_options(self, options):
if options.basever is not None:
options.packages = ['%s==%s' % (pkg, options.basever) for pkg in options.packages]
+ # Versioning for these packages are separate
+ options.packages.append('pynivision')
+
if not options.no_tools:
options.packages.append('robotpy-wpilib-utilities')
@@ -568,7 +597,7 @@ def install_robotpy(self, options):
with open(opkg_script_fname, 'w', newline='\n') as fp:
fp.write(opkg_script)
- self._poor_sync([fname, opkg_script_fname], 'opkg_cache')
+ self.ctrl.poor_sync([fname, opkg_script_fname], 'opkg_cache')
extra_cmd = 'bash opkg_cache/install_opkg.sh'
# We always add --pre to install-robotpy, in case the user downloaded
@@ -610,6 +639,11 @@ def download(self, options):
Specify python package(s) to download, and store them in the cache
'''
+ try:
+ import pip
+ except ImportError:
+ raise Error("ERROR: pip must be installed to download python packages")
+
if len(options.requirement) == 0 and len(options.packages) == 0:
raise ArgError("You must give at least one requirement to install")
@@ -652,7 +686,7 @@ def install(self, options, extra_cmd=None):
# copy the pip cache over
# .. this is inefficient
print("Copying over the pip cache...")
- retval = self._poor_sync(self.pip_cache, 'pip_cache')
+ self.ctrl.poor_sync(self.pip_cache, 'pip_cache')
print("Running installation...")
cmd = "/usr/local/bin/pip3 install --no-index --find-links=pip_cache "
@@ -669,7 +703,7 @@ def install(self, options, extra_cmd=None):
if extra_cmd is not None:
cmd = extra_cmd + ' && ' + cmd
- self._ssh(cmd)
+ self.ctrl.ssh(cmd)
print("Done.")
@@ -714,7 +748,11 @@ def main(args=None):
retval = 0
elif retval is False:
retval = 1
-
+
+ # finally.. write the config out
+ if retval == 0:
+ installer.ctrl.close()
+
return retval
View
@@ -42,7 +42,7 @@
url='https://github.com/robotpy/robotpy-wpilib',
keywords='frc first robotics wpilib',
packages=find_packages(),
- install_requires=['pynetworktables'],
+ install_requires=['pynetworktables>=2015.0.4'],
license="BSD License",
classifiers=[
"Development Status :: 5 - Production/Stable",
@@ -1,8 +1,8 @@
import threading
-__all__ = ["UsbCamera", "CameraServer"]
+__all__ = ["USBCamera", "CameraServer"]
-class UsbCamera:
+class USBCamera:
kDefaultCameraName = b"cam0"
class WhiteBalance:
@@ -14,7 +14,7 @@ class WhiteBalance:
def __init__(self, name=None):
if name is None:
- name = UsbCamera.kDefaultCameraName
+ name = USBCamera.kDefaultCameraName
self.name = name
self.id = None
self.active = False
@@ -179,7 +179,7 @@ def startAutomaticCapture(self, camera):
without doing any vision processing on the roboRIO. {@link #setImage}
shouldn't be called after this is called.
- :param camera: The camera interface (e.g. a UsbCamera instance)
+ :param camera: The camera interface (e.g. a USBCamera instance)
"""
if self.camera is not None:
return
Oops, something went wrong.

No commit comments for this range