From cad30d0fe93b37f0fd98e5b81da488052cb2b5b2 Mon Sep 17 00:00:00 2001 From: zifengqi123 Date: Thu, 4 Nov 2021 17:04:36 +0800 Subject: [PATCH 01/27] ros2 foxy --- package.xml | 26 +++++++------------------- scripts/mklaunch | 2 +- setup.py | 30 ++++++++++++++++++++++++------ templates/job-start.em | 18 +++++++++--------- templates/job-stop.em | 2 +- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/package.xml b/package.xml index 0605a1f..8a0cfd1 100644 --- a/package.xml +++ b/package.xml @@ -1,5 +1,6 @@ - + + robot_upstart 0.4.2 @@ -7,25 +8,12 @@ and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. - Chris Iverach-Brereton - Tony Baltovski - Mike Purvis - - BSD - - catkin - - daemontools - net-tools - roslaunch - util-linux - xacro - - roslint - rosunit + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest - - + ament_python diff --git a/scripts/mklaunch b/scripts/mklaunch index c9dc875..d1be78d 100755 --- a/scripts/mklaunch +++ b/scripts/mklaunch @@ -28,7 +28,7 @@ # Please send comments, questions, or patches to code@clearpathrobotics.com path=$1 -files=$(ls $path/*.launch) +files=$(ls $path/*.launch.py) if [[ "$?" != "0" ]]; then echo "" exit 1 diff --git a/setup.py b/setup.py index 44a5214..ad26661 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,25 @@ -from distutils.core import setup -from catkin_pkg.python_setup import generate_distutils_setup +import os +from setuptools import setup +from glob import glob -setup(**generate_distutils_setup( - packages=['robot_upstart'], - package_dir={'': 'src'} -)) +package_name = 'robot_upstart' + +setup( + name=package_name, + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('lib', package_name, 'scripts'), glob('scripts/*')), + (os.path.join('share', package_name, 'scripts'), glob('scripts/*')), + (os.path.join('share', package_name, 'templates'), glob('templates/*')), + ], + install_requires=['setuptools'], + zip_safe=True, + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + ], + }, +) diff --git a/templates/job-start.em b/templates/job-start.em index d69fd03..84ec7c2 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -53,9 +53,9 @@ if [[ ! -d $log_path ]]; then fi @[if interface]@ -export ROS_IP=`rosrun robot_upstart getifip @(interface)` +export ROS_IP=`ros2 run robot_upstart getifip @(interface)` if [ "$ROS_IP" = "" ]; then - log err "@(name): No IP address on @(interface), cannot roslaunch." + log err "@(name): No IP address on @(interface), cannot ros2 launch." exit 1 fi @[else]@ @@ -75,10 +75,10 @@ log info "@(name): Launching ROS_HOSTNAME=$ROS_HOSTNAME, ROS_IP=$ROS_IP, ROS_MAS # If xacro files are present in job folder, generate and expand an amalgamated urdf. XACRO_FILENAME=$log_path/@(name).xacro XACRO_ROBOT_NAME=$(echo "@(name)" | cut -d- -f1) -rosrun robot_upstart mkxacro $JOB_FOLDER $XACRO_ROBOT_NAME > $XACRO_FILENAME +ros2 run robot_upstart mkxacro $JOB_FOLDER $XACRO_ROBOT_NAME > $XACRO_FILENAME if [[ "$?" == "0" ]]; then URDF_FILENAME=$log_path/@(name).urdf - rosrun xacro xacro $XACRO_FILENAME -o $URDF_FILENAME + ros2 run xacro xacro $XACRO_FILENAME -o $URDF_FILENAME if [[ "$?" == "0" ]]; then log info "@(name): Generated URDF: $URDF_FILENAME" else @@ -88,10 +88,10 @@ if [[ "$?" == "0" ]]; then fi # Assemble amalgamated launchfile. -LAUNCH_FILENAME=$log_path/@(name).launch -rosrun robot_upstart mklaunch $JOB_FOLDER > $LAUNCH_FILENAME +LAUNCH_FILENAME=$log_path/@(name).launch.py +ros2 run robot_upstart mklaunch $JOB_FOLDER > $LAUNCH_FILENAME if [[ "$?" != "0" ]]; then - log err "@(name): Unable to generate amalgamated launchfile." + log err "@(name): Unable to generate amalgamated launchfile. $JOB_FOLDER $LAUNCH_FILENAME" exit 1 fi log info "@(name): Generated launchfile: $LAUNCH_FILENAME" @@ -104,10 +104,10 @@ if [ "$?" != "0" ]; then fi # Punch it. -setpriv --reuid @(user) --regid @(user) --init-groups roslaunch $LAUNCH_FILENAME @(roslaunch_wait?'--wait ')& +setpriv --reuid @(user) ros2 launch $LAUNCH_FILENAME @(roslaunch_wait?'--wait ')& PID=$! -log info "@(name): Started roslaunch as background process, PID $PID, ROS_LOG_DIR=$ROS_LOG_DIR" +log info "@(name): Started ros2 launch as background process, PID $PID, ROS_LOG_DIR=$ROS_LOG_DIR" echo "$PID" > $log_path/@(name).pid wait "$PID" diff --git a/templates/job-stop.em b/templates/job-stop.em index 245250c..b47c257 100644 --- a/templates/job-stop.em +++ b/templates/job-stop.em @@ -31,5 +31,5 @@ PID=$(cat @(log_path)/@(name).pid) logger -p user.info "Attempting to stop @(name) (PID $PID)" kill $PID -logger -s -p user.info "Waiting for roslaunch process to end" +logger -s -p user.info "Waiting for ros2 launch process to end" while kill -0 $PID 2>/dev/null; do sleep 0.2; done From d83ba7f9f3d872f5e233df6c7f354fe57ec67207 Mon Sep 17 00:00:00 2001 From: zifengqi123 Date: Thu, 4 Nov 2021 17:06:28 +0800 Subject: [PATCH 02/27] ros2 foxy --- resource/robot_upstart | 0 robot_upstart/__init__.py | 26 ++++ robot_upstart/install_script.py | 134 +++++++++++++++++ robot_upstart/job.py | 233 +++++++++++++++++++++++++++++ robot_upstart/providers.py | 234 ++++++++++++++++++++++++++++++ robot_upstart/uninstall_script.py | 50 +++++++ setup.cfg | 4 + 7 files changed, 681 insertions(+) create mode 100644 resource/robot_upstart create mode 100644 robot_upstart/__init__.py create mode 100644 robot_upstart/install_script.py create mode 100644 robot_upstart/job.py create mode 100644 robot_upstart/providers.py create mode 100644 robot_upstart/uninstall_script.py create mode 100644 setup.cfg diff --git a/resource/robot_upstart b/resource/robot_upstart new file mode 100644 index 0000000..e69de29 diff --git a/robot_upstart/__init__.py b/robot_upstart/__init__.py new file mode 100644 index 0000000..68d82b0 --- /dev/null +++ b/robot_upstart/__init__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD) +# +# @author Mike Purvis +# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from robot_upstart.job import Job +import robot_upstart.providers diff --git a/robot_upstart/install_script.py b/robot_upstart/install_script.py new file mode 100644 index 0000000..5cfb42e --- /dev/null +++ b/robot_upstart/install_script.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD) +# +# @author Mike Purvis +# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import argparse +import os + +import robot_upstart +# from catkin.find_in_workspaces import find_in_workspaces +from ament_index_python.packages import get_package_share_directory + + +from . import providers + +DESC_PKGPATH = ("Make sure the path starts with the package name" + " (e.g. don't pass absolute path nor a path starting from" + " workspace top folder etc.)") + + +def get_argument_parser(): + p = argparse.ArgumentParser( + description="""Use this tool to quickly and easily create system startup jobs which run one or more + ROS launch files as a daemonized background process on your computer. More advanced users will prefer + to access the Python API from their own setup scripts, but this exists as a simple helper, an example, + and a compatibility shim for previous versions of robot_upstart which were bash-based.""") + + p.add_argument("pkgpath", type=str, nargs='+', metavar="pkg/path", + help="Package and path to install job launch files from. " + + DESC_PKGPATH) + p.add_argument("--job", type=str, + help="Specify job name. If unspecified, will be constructed from package name (first " + + "element before underscore is taken, e.g. 'myrobot' if the package name is 'myrobot_bringup').") + p.add_argument("--interface", type=str, metavar="ethN", + help="Specify network interface name to associate job with.") + p.add_argument("--user", type=str, metavar="NAME", + help="Specify user to launch job as.") + p.add_argument("--setup", type=str, metavar="path/to/setup.bash", + help="Specify workspace setup file for the job launch context.") + p.add_argument("--rosdistro", type=str, metavar="DISTRO", + help="Specify ROS distro this is for.") + p.add_argument("--master", type=str, metavar="http://MASTER:11311", + help="Specify an alternative ROS_MASTER_URI for the job launch context.") + p.add_argument("--logdir", type=str, metavar="path/to/logs", + help="Specify an a value for ROS_LOG_DIR in the job launch context.") + p.add_argument("--augment", action='store_true', + help="Bypass creating the job, and only copy user files. Assumes the job was previously created.") + p.add_argument("--provider", type=str, metavar="[upstart|systemd]", + help="Specify provider if the autodetect fails to identify the correct provider") + p.add_argument("--symlink", action='store_true', + help="Create symbolic link to job launch files instead of copying them.") + p.add_argument("--wait", action='store_true', + help="Pass a wait flag to roslaunch.") + p.add_argument("--systemd-after", type=str, metavar="After=", + help="Set the string of the After= section" + "of the generated Systemd service file") + + return p + + +def main(): + """ Implementation of the ``install`` script.""" + + args = get_argument_parser().parse_args() + + pkg, pkgpath = args.pkgpath[0].split('/', 1) + job_name = args.job or pkg.split('_', 1)[0] + + # Any unspecified arguments are on the args object as None. These are filled + # in by the Job constructor when passed as Nones. + j = robot_upstart.Job( + name=job_name, interface=args.interface, user=args.user, + workspace_setup=args.setup, rosdistro=args.rosdistro, + master_uri=args.master, log_path=args.logdir, + systemd_after=args.systemd_after) + + for this_pkgpath in args.pkgpath: + pkg, pkgpath = this_pkgpath.split('/', 1) + if not pkg: + print("Unable to locate package your job launch is in." + " Installation aborted. " + DESC_PKGPATH + + "\npkgpath passed: {}.".format(pkgpath)) + return 1 + + # found_path = find_in_workspaces(project=pkg, path=pkgpath, first_match_only=True) + found_path = get_package_share_directory(pkg)+"/"+pkgpath + if not found_path: + print("Unable to locate path %s in package %s. Installation aborted." % (pkgpath, pkg)) + return 1 + + # if os.path.isfile(found_path[0]): + print("found_path: %s" % found_path) + if os.path.isfile(found_path): + # Single file, install just that. + j.add(package=pkg, filename=pkgpath) + else: + # Directory found, install everything within. + j.add(package=pkg, glob=os.path.join(pkgpath, "*")) + + if args.augment: + j.generate_system_files = False + if args.wait: + j.roslaunch_wait = True + + provider = providers.detect_provider() + if args.provider == 'upstart': + provider = providers.Upstart + if args.provider == 'systemd': + provider = providers.Systemd + if args.symlink: + j.symlink = True + + j.install(Provider=provider) + + return 0 diff --git a/robot_upstart/job.py b/robot_upstart/job.py new file mode 100644 index 0000000..a47cce1 --- /dev/null +++ b/robot_upstart/job.py @@ -0,0 +1,233 @@ +# Software License Agreement (BSD) +# +# @author Mike Purvis +# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" +This file defines the Job class, which is the primary code API to robot_upstart. +""" + +import getpass +import os +import json +import subprocess +from glob import glob as glob_files + +# from catkin.find_in_workspaces import find_in_workspaces +from ament_index_python.packages import get_package_share_directory + +from . import providers + + +class Job(object): + """ Represents a ROS configuration to launch on machine startup. """ + + def __init__(self, name="ros", interface=None, user=None, workspace_setup=None, + rosdistro=None, master_uri=None, log_path=None, + systemd_after=None): + """Construct a new Job definition. + + :param name: Name of job to create. Defaults to "ros", but you might + prefer to use the name of your platform. + :type name: str + :param interface: Network interface to bring ROS up with. If specified, + the job will come up with that network interface, and ROS_IP will be set + to that interface's IP address. If unspecified, the job will come up + on system startup, and ROS_HOSTNAME will be set to the system's hostname. + :type interface: str + :param user: Unprivileged user to launch the job as. Defaults to the user + creating the job. + :type user: str + :param workspace_setup: Location of the workspace setup file to source for + the job's ROS context. Defaults to the current workspace. + :type workspace_setup: str + :param rosdistro: rosdistro to use for the /etc/ros/DISTRO path. Defaults + to $ROS_DISTRO from the current environment. + :type rosdistro: str + :param master_uri: For systems with multiple computers, you may want this + job to launch with ROS_MASTER_URI pointing to another machine. + :type master_uri: str + :param log_path: The location to set ROS_LOG_DIR to. If changed from the + default of using /tmp, it is the user's responsibility to manage log + rotation. + :type log_path: str + """ + + self.name = name + + self.interface = interface + + # Fall back on current user as the user to run ROS as. + self.user = user or getpass.getuser() + + # Fall back on current workspace setup file if not explicitly specified. + self.workspace_setup = workspace_setup or \ + os.environ['CMAKE_PREFIX_PATH'].split(':')[0] + '/../setup.bash' + + # Fall back on current distro if not otherwise specified. + self.rosdistro = rosdistro or os.environ['ROS_DISTRO'] + + self.master_uri = master_uri or "http://127.0.0.1:11311" + + self.log_path = log_path or "/tmp" + + # Override this to false if you want to bypass generating the + # upstart conf file. + self.generate_system_files = True + + # Override this to True if you want to create symbolic link for + # job launch files instead of copying them. + self.symlink = False + + # Override this to True is you want the --wait flag passed to roslaunch. + # This will be desired if the nodes spawned by this job are intended to + # connect to an existing master. + self.roslaunch_wait = False + + # Set the string of the "After=" section + # of the generated Systemd service file + self.systemd_after = systemd_after or "network.target" + + # Set of files to be installed for the job. This is only launchers + # and other user-specified configs--- nothing related to the system + # startup job itself. List of strs. + self.files = [] + + def add(self, package=None, filename=None, glob=None): + """ Add launch or other configuration files to Job. + + Files may be specified using relative, absolute, or package-relative + paths. Files may also be specified using shell globs. + + :param package: Optionally specify a package to search for the file + or glob relative-to. + :type package: str + :param filename: Name of a file to add to the job. Relative to the + package path, if specified. + :type filename: str + :param glob: Shell glob of files to add to the job. Relative to the + package path, if specified. + :type glob: str + """ + + if package: + # search_paths = reversed(find_in_workspaces(project=package)) + search_paths = (get_package_share_directory(package), ) + else: + search_paths = ('.', ) + + if glob and filename: + raise RuntimeError("You must specify only an exact filename or a glob, not both.") + + # See: https://docs.python.org/2/library/os.html#os.getlogin + if filename: + for path in search_paths: + candidate = os.path.join(path, filename) + if os.path.isfile(candidate): + print("candidate : %s" % candidate) + self.files.append(candidate) + + if glob: + for path in search_paths: + self.files.extend(glob_files(os.path.join(path, glob))) + + def install(self, root="/", sudo="/usr/bin/sudo", Provider=None): + """ Install the job definition to the system. + + :param root: Override the root to install to, useful for testing. + :type root: str + :param sudo: Override which sudo is used, useful for testing or for making + it use gksudo instead. + :type sudo: str + :param provider: Override to use your own generator function for the system + file preparation. + :type provider: Provider + """ + # This is a recipe of files and their contents which is pickled up and + # passed to a sudo process so that it can create the actual files, + # without needing a ROS workspace or any other environmental setup. + if Provider is None: + Provider = providers.detect_provider() + p = Provider(root, self) + installation_files = p.generate_install() + + print("Preparing to install files to the following paths:") + for filename in sorted(installation_files.keys()): + print(" %s" % filename) + + self._call_mutate(sudo, installation_files) + p.post_install() + + def uninstall(self, root="/", sudo="/usr/bin/sudo", Provider=None): + """ Uninstall the job definition from the system. + + :param root: Override the root to uninstall from, useful for testing. + :type root: str + :param sudo: Override which sudo is used, useful for testing or for making + it use gksudo instead. + :type sudo: str + :param provider: Override to use your own generator function for the system + file preparation. + :type provider: Provider + """ + if Provider is None: + Provider = providers.detect_provider() + p = Provider(root, self) + installation_files = p.generate_uninstall() + + if len(installation_files) == 0: + print("Job not found, nothing to remove.") + else: + print("Preparing to remove the following paths:") + for filename in sorted(installation_files.keys()): + print(" %s" % filename) + + self._call_mutate(sudo, installation_files) + + def _call_mutate(self, sudo, installation_files): + try: + # Installed script location + # mutate_files_exec = find_in_workspaces( + # project="robot_upstart", path="mutate_files", first_match_only=True)[0] + mutate_files_exec = get_package_share_directory("robot_upstart") + "/scripts/mutate_files" + except IndexError: + # Devel script location + # mutate_files_exec = find_in_workspaces( + # project="robot_upstart", path="scripts/mutate_files", first_match_only=True)[0] + mutate_files_exec = get_package_share_directory("robot_upstart") + "/scripts/mutate_files" + + + # If sudo is specified, then the user will be prompted at this point. + cmd = [mutate_files_exec] + if sudo: + cmd.insert(0, sudo) + print("Now calling: %s" % ' '.join(cmd)) + + # changed to use json, as pickle gives 0-bytes error + p = subprocess.Popen(cmd + [json.dumps(installation_files)]) + p.communicate() + + if p.returncode == 0: + print("Filesystem operation succeeded.") + else: + print("Error encountered; filesystem operation aborted.") + + return p.returncode diff --git a/robot_upstart/providers.py b/robot_upstart/providers.py new file mode 100644 index 0000000..b7e6a7e --- /dev/null +++ b/robot_upstart/providers.py @@ -0,0 +1,234 @@ +# Software License Agreement (BSD) +# +# @author Mike Purvis +# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" +These classes implement the translation from user-intended behaviours +as specified in the state of the Job class to the system-specific configuration +files. At present, there is only an upstart configuration, but similar providers +could be defined for systemd, supervisor, launchd, or other systems. +""" + +import em +import os +import io + +# from catkin.find_in_workspaces import find_in_workspaces +from ament_index_python.packages import get_package_share_directory + + +def detect_provider(): + cmd = open('/proc/1/cmdline', 'rb').read().split(b'\x00')[0] + print(os.path.realpath(cmd)) + if b'systemd' in os.path.realpath(cmd): + return Systemd + return Upstart + + +class Generic(object): + """ Provides only a common constructor for the moment, but as further + providers are implemented, may provide a place to store configuration + common to them. """ + + def __init__(self, root, job): + """ Construct a new Provider. + + :param root: The filesystem location to prefix all file-install + commands with. + :type root: str + :param job: The job definition to transform to a set of system files. + :type job: :py:class:robot_upstart.Job + """ + self.root = root + self.job = job + + # Recipe structure which is serialized to yaml and passed to the mutate_files script. + self.installation_files = {} + + # Bare list of files, stored in the .installed_files manifest file. + self.installed_files_set = set() + + def _add_job_files(self): + # Make up list of files to copy to system locations. + for filename in self.job.files: + dest_filename = os.path.join(self.job.job_path, os.path.basename(filename)) + if self.job.symlink: + self.installation_files[dest_filename] = {"symlink": filename} + else: + with open(filename) as f: + self.installation_files[dest_filename] = {"content": f.read()} + + def _load_installed_files_set(self): + self.installed_files_set_location = os.path.join(self.job.job_path, ".installed_files") + if os.path.exists(self.installed_files_set_location): + with open(self.installed_files_set_location) as f: + self.installed_files_set.update(f.read().split("\n")) + + +class Upstart(Generic): + """ The Upstart implementation places the user-specified files in ``/etc/ros/DISTRO/NAME.d``, + and creates an upstart job configuration in ``/etc/init/NAME.d``. Two additional + helper scripts are created for starting and stopping the job, places in + ``/usr/sbin``. + """ + + def generate_install(self): + # Default for Upstart is /etc/ros/DISTRO/JOBNAME.d + self._set_job_path() + + # User-specified launch files. + self._add_job_files() + + # This is optional to support the old --augment flag where a "job" only adds + # launch files to an existing configuration. + if (self.job.generate_system_files): + # Share a single instance of the empy interpreter. + self.interpreter = em.Interpreter(globals=self.job.__dict__.copy()) + + self.installation_files[os.path.join(self.root, "etc/init", self.job.name + ".conf")] = { + "content": self._fill_template("templates/job.conf.em"), "mode": 0o644} + self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-start")] = { + "content": self._fill_template("templates/job-start.em"), "mode": 0o755} + self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-stop")] = { + "content": self._fill_template("templates/job-stop.em"), "mode": 0o755} + self.interpreter.shutdown() + + # Add an annotation file listing what has been installed. This is a union of what's being + # installed now with what has been installed previously, so that an uninstall should remove + # all of it. A more sophisticated future implementation could track contents or hashes and + # thereby warn users when a new installation is stomping a change they have made. + self._load_installed_files_set() + self.installed_files_set.update(list(self.installation_files.keys())) + + # Remove the job directory. This will fail if it is not empty, and notify the user. + self.installed_files_set.add(self.job.job_path) + + # Remove the annotation file itself. + self.installed_files_set.add(self.installed_files_set_location) + + self.installation_files[self.installed_files_set_location] = { + "content": "\n".join(self.installed_files_set)} + + return self.installation_files + + def post_install(self): + return + + def generate_uninstall(self): + self._set_job_path() + self._load_installed_files_set() + + for filename in self.installed_files_set: + self.installation_files[filename] = {"remove": True} + + return self.installation_files + + def _set_job_path(self): + self.job.job_path = os.path.join( + self.root, "etc/ros", self.job.rosdistro, self.job.name + ".d") + + def _fill_template(self, template): + self.interpreter.output = io.StringIO() + self.interpreter.reset() + # with open(find_in_workspaces(project="robot_upstart", path=template)[0]) as f: + with open(get_package_share_directory("robot_upstart")+"/"+template) as f: + self.interpreter.file(f) + return self.interpreter.output.getvalue() + + +class Systemd(Generic): + """ The Systemd implementation places the user-specified files in ``/etc/ros/DISTRO/NAME.d``, + and creates an systemd job configuration in ``/lib/systemd/system/NAME.d``. Two additional + helper scripts are created for starting and stopping the job, places in + ``/usr/sbin``. + To detect which system you're using run: ps -p1 | grep systemd && echo systemd || echo upstart + """ + + def generate_install(self): + # Default is /etc/ros/DISTRO/JOBNAME.d + self._set_job_path() + + # User-specified launch files. + self._add_job_files() + + # This is optional to support the old --augment flag where a "job" only adds + # launch files to an existing configuration. + if self.job.generate_system_files: + # Share a single instance of the EmPy interpreter. + self.interpreter = em.Interpreter(globals=self.job.__dict__.copy()) + + self.installation_files[os.path.join(self.root, "lib/systemd/system", self.job.name + ".service")] = { + "content": self._fill_template("templates/systemd_job.conf.em"), "mode": 0o644} + self.installation_files[os.path.join(self.root, "etc/systemd/system/multi-user.target.wants", + self.job.name + ".service")] = { + "symlink": os.path.join(self.root, "lib/systemd/system/", self.job.name + ".service")} + self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-start")] = { + "content": self._fill_template("templates/job-start.em"), "mode": 0o755} + self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-stop")] = { + "content": self._fill_template("templates/job-stop.em"), "mode": 0o755} + self.interpreter.shutdown() + + # Add an annotation file listing what has been installed. This is a union of what's being + # installed now with what has been installed previously, so that an uninstall should remove + # all of it. A more sophisticated future implementation could track contents or hashes and + # thereby warn users when a new installation is stomping a change they have made. + self._load_installed_files_set() + self.installed_files_set.update(list(self.installation_files.keys())) + + # Remove the job directory. This will fail if it is not empty, and notify the user. + self.installed_files_set.add(self.job.job_path) + + # Remove the annotation file itself. + self.installed_files_set.add(self.installed_files_set_location) + + self.installation_files[self.installed_files_set_location] = { + "content": "\n".join(self.installed_files_set)} + + return self.installation_files + + def post_install(self): + print("** To complete installation please run the following command:") + print(" sudo systemctl daemon-reload" + + " && sudo systemctl start " + self.job.name) + + def generate_uninstall(self): + self._set_job_path() + self._load_installed_files_set() + + for filename in self.installed_files_set: + self.installation_files[filename] = {"remove": True} + + return self.installation_files + + def _set_job_path(self): + self.job.job_path = os.path.join( + self.root, "etc/ros", self.job.rosdistro, self.job.name + ".d") + + def _fill_template(self, template): + self.interpreter.output = io.StringIO() + self.interpreter.reset() + # with open(find_in_workspaces(project="robot_upstart", path=template)[0]) as f: + with open(get_package_share_directory("robot_upstart")+"/"+template) as f: + + self.interpreter.file(f) + return self.interpreter.output.getvalue() + self.set_job_path() diff --git a/robot_upstart/uninstall_script.py b/robot_upstart/uninstall_script.py new file mode 100644 index 0000000..7e68cdf --- /dev/null +++ b/robot_upstart/uninstall_script.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD) +# +# @author Mike Purvis +# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other materials provided with the distribution. +# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import argparse +import os + +import robot_upstart +# from catkin.find_in_workspaces import find_in_workspaces + + +def get_argument_parser(): + p = argparse.ArgumentParser( + description="""Use this script to remove upstart jobs created by the corresponding install script.""") + + p.add_argument("jobname", type=str, nargs=1, metavar=("JOBNAME", ), + help="Name of job to uninstall.") + p.add_argument("--rosdistro", type=str, metavar="DISTRO", + help="Specify ROS distro this is for.") + return p + + +def main(): + """ Implementation of the ``uninstall`` script.""" + + args = get_argument_parser().parse_args() + j = robot_upstart.Job(name=args.jobname[0], rosdistro=args.rosdistro) + j.uninstall() + + return 0 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..c00fbe3 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/robot_upstart +[install] +install-scripts=$base/lib/robot_upstart From a4cd13d461277f2b045e22896fd7a02895b94f53 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 16 Feb 2022 10:06:54 -0500 Subject: [PATCH 03/27] Removed src folder. --- src/robot_upstart/__init__.py | 25 --- src/robot_upstart/install_script.py | 129 --------------- src/robot_upstart/job.py | 227 ------------------------- src/robot_upstart/providers.py | 230 -------------------------- src/robot_upstart/uninstall_script.py | 50 ------ 5 files changed, 661 deletions(-) delete mode 100644 src/robot_upstart/__init__.py delete mode 100644 src/robot_upstart/install_script.py delete mode 100644 src/robot_upstart/job.py delete mode 100644 src/robot_upstart/providers.py delete mode 100644 src/robot_upstart/uninstall_script.py diff --git a/src/robot_upstart/__init__.py b/src/robot_upstart/__init__.py deleted file mode 100644 index 8de6c79..0000000 --- a/src/robot_upstart/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Software License Agreement (BSD) -# -# @author Mike Purvis -# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that -# the following conditions are met: -# * Redistributions of source code must retain the above copyright notice, this list of conditions and the -# following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other materials provided with the distribution. -# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or -# promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from robot_upstart.job import Job -import robot_upstart.providers diff --git a/src/robot_upstart/install_script.py b/src/robot_upstart/install_script.py deleted file mode 100644 index 29fbd77..0000000 --- a/src/robot_upstart/install_script.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python3 -# Software License Agreement (BSD) -# -# @author Mike Purvis -# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that -# the following conditions are met: -# * Redistributions of source code must retain the above copyright notice, this list of conditions and the -# following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other materials provided with the distribution. -# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or -# promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import argparse -import os - -import robot_upstart -from catkin.find_in_workspaces import find_in_workspaces - -from . import providers - -DESC_PKGPATH = ("Make sure the path starts with the package name" - " (e.g. don't pass absolute path nor a path starting from" - " workspace top folder etc.)") - - -def get_argument_parser(): - p = argparse.ArgumentParser( - description="""Use this tool to quickly and easily create system startup jobs which run one or more - ROS launch files as a daemonized background process on your computer. More advanced users will prefer - to access the Python API from their own setup scripts, but this exists as a simple helper, an example, - and a compatibility shim for previous versions of robot_upstart which were bash-based.""") - - p.add_argument("pkgpath", type=str, nargs='+', metavar="pkg/path", - help="Package and path to install job launch files from. " + - DESC_PKGPATH) - p.add_argument("--job", type=str, - help="Specify job name. If unspecified, will be constructed from package name (first " + - "element before underscore is taken, e.g. 'myrobot' if the package name is 'myrobot_bringup').") - p.add_argument("--interface", type=str, metavar="ethN", - help="Specify network interface name to associate job with.") - p.add_argument("--user", type=str, metavar="NAME", - help="Specify user to launch job as.") - p.add_argument("--setup", type=str, metavar="path/to/setup.bash", - help="Specify workspace setup file for the job launch context.") - p.add_argument("--rosdistro", type=str, metavar="DISTRO", - help="Specify ROS distro this is for.") - p.add_argument("--master", type=str, metavar="http://MASTER:11311", - help="Specify an alternative ROS_MASTER_URI for the job launch context.") - p.add_argument("--logdir", type=str, metavar="path/to/logs", - help="Specify an a value for ROS_LOG_DIR in the job launch context.") - p.add_argument("--augment", action='store_true', - help="Bypass creating the job, and only copy user files. Assumes the job was previously created.") - p.add_argument("--provider", type=str, metavar="[upstart|systemd]", - help="Specify provider if the autodetect fails to identify the correct provider") - p.add_argument("--symlink", action='store_true', - help="Create symbolic link to job launch files instead of copying them.") - p.add_argument("--wait", action='store_true', - help="Pass a wait flag to roslaunch.") - p.add_argument("--systemd-after", type=str, metavar="After=", - help="Set the string of the After= section" - "of the generated Systemd service file") - - return p - - -def main(): - """ Implementation of the ``install`` script.""" - - args = get_argument_parser().parse_args() - - pkg, pkgpath = args.pkgpath[0].split('/', 1) - job_name = args.job or pkg.split('_', 1)[0] - - # Any unspecified arguments are on the args object as None. These are filled - # in by the Job constructor when passed as Nones. - j = robot_upstart.Job( - name=job_name, interface=args.interface, user=args.user, - workspace_setup=args.setup, rosdistro=args.rosdistro, - master_uri=args.master, log_path=args.logdir, - systemd_after=args.systemd_after) - - for this_pkgpath in args.pkgpath: - pkg, pkgpath = this_pkgpath.split('/', 1) - if not pkg: - print("Unable to locate package your job launch is in." - " Installation aborted. " + DESC_PKGPATH + - "\npkgpath passed: {}.".format(pkgpath)) - return 1 - - found_path = find_in_workspaces(project=pkg, path=pkgpath, first_match_only=True) - if not found_path: - print("Unable to locate path %s in package %s. Installation aborted." % (pkgpath, pkg)) - return 1 - - if os.path.isfile(found_path[0]): - # Single file, install just that. - j.add(package=pkg, filename=pkgpath) - else: - # Directory found, install everything within. - j.add(package=pkg, glob=os.path.join(pkgpath, "*")) - - if args.augment: - j.generate_system_files = False - if args.wait: - j.roslaunch_wait = True - - provider = providers.detect_provider() - if args.provider == 'upstart': - provider = providers.Upstart - if args.provider == 'systemd': - provider = providers.Systemd - if args.symlink: - j.symlink = True - - j.install(Provider=provider) - - return 0 diff --git a/src/robot_upstart/job.py b/src/robot_upstart/job.py deleted file mode 100644 index 895525c..0000000 --- a/src/robot_upstart/job.py +++ /dev/null @@ -1,227 +0,0 @@ -# Software License Agreement (BSD) -# -# @author Mike Purvis -# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that -# the following conditions are met: -# * Redistributions of source code must retain the above copyright notice, this list of conditions and the -# following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other materials provided with the distribution. -# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or -# promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -This file defines the Job class, which is the primary code API to robot_upstart. -""" - -import getpass -import os -import json -import subprocess -from glob import glob as glob_files - -from catkin.find_in_workspaces import find_in_workspaces - -from . import providers - - -class Job(object): - """ Represents a ROS configuration to launch on machine startup. """ - - def __init__(self, name="ros", interface=None, user=None, workspace_setup=None, - rosdistro=None, master_uri=None, log_path=None, - systemd_after=None): - """Construct a new Job definition. - - :param name: Name of job to create. Defaults to "ros", but you might - prefer to use the name of your platform. - :type name: str - :param interface: Network interface to bring ROS up with. If specified, - the job will come up with that network interface, and ROS_IP will be set - to that interface's IP address. If unspecified, the job will come up - on system startup, and ROS_HOSTNAME will be set to the system's hostname. - :type interface: str - :param user: Unprivileged user to launch the job as. Defaults to the user - creating the job. - :type user: str - :param workspace_setup: Location of the workspace setup file to source for - the job's ROS context. Defaults to the current workspace. - :type workspace_setup: str - :param rosdistro: rosdistro to use for the /etc/ros/DISTRO path. Defaults - to $ROS_DISTRO from the current environment. - :type rosdistro: str - :param master_uri: For systems with multiple computers, you may want this - job to launch with ROS_MASTER_URI pointing to another machine. - :type master_uri: str - :param log_path: The location to set ROS_LOG_DIR to. If changed from the - default of using /tmp, it is the user's responsibility to manage log - rotation. - :type log_path: str - """ - - self.name = name - - self.interface = interface - - # Fall back on current user as the user to run ROS as. - self.user = user or getpass.getuser() - - # Fall back on current workspace setup file if not explicitly specified. - self.workspace_setup = workspace_setup or \ - os.environ['CMAKE_PREFIX_PATH'].split(':')[0] + '/setup.bash' - - # Fall back on current distro if not otherwise specified. - self.rosdistro = rosdistro or os.environ['ROS_DISTRO'] - - self.master_uri = master_uri or "http://127.0.0.1:11311" - - self.log_path = log_path or "/tmp" - - # Override this to false if you want to bypass generating the - # upstart conf file. - self.generate_system_files = True - - # Override this to True if you want to create symbolic link for - # job launch files instead of copying them. - self.symlink = False - - # Override this to True is you want the --wait flag passed to roslaunch. - # This will be desired if the nodes spawned by this job are intended to - # connect to an existing master. - self.roslaunch_wait = False - - # Set the string of the "After=" section - # of the generated Systemd service file - self.systemd_after = systemd_after or "network.target" - - # Set of files to be installed for the job. This is only launchers - # and other user-specified configs--- nothing related to the system - # startup job itself. List of strs. - self.files = [] - - def add(self, package=None, filename=None, glob=None): - """ Add launch or other configuration files to Job. - - Files may be specified using relative, absolute, or package-relative - paths. Files may also be specified using shell globs. - - :param package: Optionally specify a package to search for the file - or glob relative-to. - :type package: str - :param filename: Name of a file to add to the job. Relative to the - package path, if specified. - :type filename: str - :param glob: Shell glob of files to add to the job. Relative to the - package path, if specified. - :type glob: str - """ - - if package: - search_paths = reversed(find_in_workspaces(project=package)) - else: - search_paths = ('.', ) - - if glob and filename: - raise RuntimeError("You must specify only an exact filename or a glob, not both.") - - # See: https://docs.python.org/2/library/os.html#os.getlogin - if filename: - for path in search_paths: - candidate = os.path.join(path, filename) - if os.path.isfile(candidate): - self.files.append(candidate) - - if glob: - for path in search_paths: - self.files.extend(glob_files(os.path.join(path, glob))) - - def install(self, root="/", sudo="/usr/bin/sudo", Provider=None): - """ Install the job definition to the system. - - :param root: Override the root to install to, useful for testing. - :type root: str - :param sudo: Override which sudo is used, useful for testing or for making - it use gksudo instead. - :type sudo: str - :param provider: Override to use your own generator function for the system - file preparation. - :type provider: Provider - """ - # This is a recipe of files and their contents which is pickled up and - # passed to a sudo process so that it can create the actual files, - # without needing a ROS workspace or any other environmental setup. - if Provider is None: - Provider = providers.detect_provider() - p = Provider(root, self) - installation_files = p.generate_install() - - print("Preparing to install files to the following paths:") - for filename in sorted(installation_files.keys()): - print(" %s" % filename) - - self._call_mutate(sudo, installation_files) - p.post_install() - - def uninstall(self, root="/", sudo="/usr/bin/sudo", Provider=None): - """ Uninstall the job definition from the system. - - :param root: Override the root to uninstall from, useful for testing. - :type root: str - :param sudo: Override which sudo is used, useful for testing or for making - it use gksudo instead. - :type sudo: str - :param provider: Override to use your own generator function for the system - file preparation. - :type provider: Provider - """ - if Provider is None: - Provider = providers.detect_provider() - p = Provider(root, self) - installation_files = p.generate_uninstall() - - if len(installation_files) == 0: - print("Job not found, nothing to remove.") - else: - print("Preparing to remove the following paths:") - for filename in sorted(installation_files.keys()): - print(" %s" % filename) - - self._call_mutate(sudo, installation_files) - - def _call_mutate(self, sudo, installation_files): - try: - # Installed script location - mutate_files_exec = find_in_workspaces( - project="robot_upstart", path="mutate_files", first_match_only=True)[0] - except IndexError: - # Devel script location - mutate_files_exec = find_in_workspaces( - project="robot_upstart", path="scripts/mutate_files", first_match_only=True)[0] - - # If sudo is specified, then the user will be prompted at this point. - cmd = [mutate_files_exec] - if sudo: - cmd.insert(0, sudo) - print("Now calling: %s" % ' '.join(cmd)) - - # changed to use json, as pickle gives 0-bytes error - p = subprocess.Popen(cmd + [json.dumps(installation_files)]) - p.communicate() - - if p.returncode == 0: - print("Filesystem operation succeeded.") - else: - print("Error encountered; filesystem operation aborted.") - - return p.returncode diff --git a/src/robot_upstart/providers.py b/src/robot_upstart/providers.py deleted file mode 100644 index a91b6bd..0000000 --- a/src/robot_upstart/providers.py +++ /dev/null @@ -1,230 +0,0 @@ -# Software License Agreement (BSD) -# -# @author Mike Purvis -# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that -# the following conditions are met: -# * Redistributions of source code must retain the above copyright notice, this list of conditions and the -# following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other materials provided with the distribution. -# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or -# promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -These classes implement the translation from user-intended behaviours -as specified in the state of the Job class to the system-specific configuration -files. At present, there is only an upstart configuration, but similar providers -could be defined for systemd, supervisor, launchd, or other systems. -""" - -import em -import os -import io - -from catkin.find_in_workspaces import find_in_workspaces - - -def detect_provider(): - cmd = open('/proc/1/cmdline', 'rb').read().split(b'\x00')[0] - print(os.path.realpath(cmd)) - if b'systemd' in os.path.realpath(cmd): - return Systemd - return Upstart - - -class Generic(object): - """ Provides only a common constructor for the moment, but as further - providers are implemented, may provide a place to store configuration - common to them. """ - - def __init__(self, root, job): - """ Construct a new Provider. - - :param root: The filesystem location to prefix all file-install - commands with. - :type root: str - :param job: The job definition to transform to a set of system files. - :type job: :py:class:robot_upstart.Job - """ - self.root = root - self.job = job - - # Recipe structure which is serialized to yaml and passed to the mutate_files script. - self.installation_files = {} - - # Bare list of files, stored in the .installed_files manifest file. - self.installed_files_set = set() - - def _add_job_files(self): - # Make up list of files to copy to system locations. - for filename in self.job.files: - dest_filename = os.path.join(self.job.job_path, os.path.basename(filename)) - if self.job.symlink: - self.installation_files[dest_filename] = {"symlink": filename} - else: - with open(filename) as f: - self.installation_files[dest_filename] = {"content": f.read()} - - def _load_installed_files_set(self): - self.installed_files_set_location = os.path.join(self.job.job_path, ".installed_files") - if os.path.exists(self.installed_files_set_location): - with open(self.installed_files_set_location) as f: - self.installed_files_set.update(f.read().split("\n")) - - -class Upstart(Generic): - """ The Upstart implementation places the user-specified files in ``/etc/ros/DISTRO/NAME.d``, - and creates an upstart job configuration in ``/etc/init/NAME.d``. Two additional - helper scripts are created for starting and stopping the job, places in - ``/usr/sbin``. - """ - - def generate_install(self): - # Default for Upstart is /etc/ros/DISTRO/JOBNAME.d - self._set_job_path() - - # User-specified launch files. - self._add_job_files() - - # This is optional to support the old --augment flag where a "job" only adds - # launch files to an existing configuration. - if (self.job.generate_system_files): - # Share a single instance of the empy interpreter. - self.interpreter = em.Interpreter(globals=self.job.__dict__.copy()) - - self.installation_files[os.path.join(self.root, "etc/init", self.job.name + ".conf")] = { - "content": self._fill_template("templates/job.conf.em"), "mode": 0o644} - self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-start")] = { - "content": self._fill_template("templates/job-start.em"), "mode": 0o755} - self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-stop")] = { - "content": self._fill_template("templates/job-stop.em"), "mode": 0o755} - self.interpreter.shutdown() - - # Add an annotation file listing what has been installed. This is a union of what's being - # installed now with what has been installed previously, so that an uninstall should remove - # all of it. A more sophisticated future implementation could track contents or hashes and - # thereby warn users when a new installation is stomping a change they have made. - self._load_installed_files_set() - self.installed_files_set.update(list(self.installation_files.keys())) - - # Remove the job directory. This will fail if it is not empty, and notify the user. - self.installed_files_set.add(self.job.job_path) - - # Remove the annotation file itself. - self.installed_files_set.add(self.installed_files_set_location) - - self.installation_files[self.installed_files_set_location] = { - "content": "\n".join(self.installed_files_set)} - - return self.installation_files - - def post_install(self): - return - - def generate_uninstall(self): - self._set_job_path() - self._load_installed_files_set() - - for filename in self.installed_files_set: - self.installation_files[filename] = {"remove": True} - - return self.installation_files - - def _set_job_path(self): - self.job.job_path = os.path.join( - self.root, "etc/ros", self.job.rosdistro, self.job.name + ".d") - - def _fill_template(self, template): - self.interpreter.output = io.StringIO() - self.interpreter.reset() - with open(find_in_workspaces(project="robot_upstart", path=template)[0]) as f: - self.interpreter.file(f) - return self.interpreter.output.getvalue() - - -class Systemd(Generic): - """ The Systemd implementation places the user-specified files in ``/etc/ros/DISTRO/NAME.d``, - and creates an systemd job configuration in ``/lib/systemd/system/NAME.d``. Two additional - helper scripts are created for starting and stopping the job, places in - ``/usr/sbin``. - To detect which system you're using run: ps -p1 | grep systemd && echo systemd || echo upstart - """ - - def generate_install(self): - # Default is /etc/ros/DISTRO/JOBNAME.d - self._set_job_path() - - # User-specified launch files. - self._add_job_files() - - # This is optional to support the old --augment flag where a "job" only adds - # launch files to an existing configuration. - if self.job.generate_system_files: - # Share a single instance of the EmPy interpreter. - self.interpreter = em.Interpreter(globals=self.job.__dict__.copy()) - - self.installation_files[os.path.join(self.root, "lib/systemd/system", self.job.name + ".service")] = { - "content": self._fill_template("templates/systemd_job.conf.em"), "mode": 0o644} - self.installation_files[os.path.join(self.root, "etc/systemd/system/multi-user.target.wants", - self.job.name + ".service")] = { - "symlink": os.path.join(self.root, "lib/systemd/system/", self.job.name + ".service")} - self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-start")] = { - "content": self._fill_template("templates/job-start.em"), "mode": 0o755} - self.installation_files[os.path.join(self.root, "usr/sbin", self.job.name + "-stop")] = { - "content": self._fill_template("templates/job-stop.em"), "mode": 0o755} - self.interpreter.shutdown() - - # Add an annotation file listing what has been installed. This is a union of what's being - # installed now with what has been installed previously, so that an uninstall should remove - # all of it. A more sophisticated future implementation could track contents or hashes and - # thereby warn users when a new installation is stomping a change they have made. - self._load_installed_files_set() - self.installed_files_set.update(list(self.installation_files.keys())) - - # Remove the job directory. This will fail if it is not empty, and notify the user. - self.installed_files_set.add(self.job.job_path) - - # Remove the annotation file itself. - self.installed_files_set.add(self.installed_files_set_location) - - self.installation_files[self.installed_files_set_location] = { - "content": "\n".join(self.installed_files_set)} - - return self.installation_files - - def post_install(self): - print("** To complete installation please run the following command:") - print(" sudo systemctl daemon-reload" + - " && sudo systemctl start " + self.job.name) - - def generate_uninstall(self): - self._set_job_path() - self._load_installed_files_set() - - for filename in self.installed_files_set: - self.installation_files[filename] = {"remove": True} - - return self.installation_files - - def _set_job_path(self): - self.job.job_path = os.path.join( - self.root, "etc/ros", self.job.rosdistro, self.job.name + ".d") - - def _fill_template(self, template): - self.interpreter.output = io.StringIO() - self.interpreter.reset() - with open(find_in_workspaces(project="robot_upstart", path=template)[0]) as f: - self.interpreter.file(f) - return self.interpreter.output.getvalue() - self.set_job_path() diff --git a/src/robot_upstart/uninstall_script.py b/src/robot_upstart/uninstall_script.py deleted file mode 100644 index 3f28b09..0000000 --- a/src/robot_upstart/uninstall_script.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# Software License Agreement (BSD) -# -# @author Mike Purvis -# @copyright (c) 2015, Clearpath Robotics, Inc., All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that -# the following conditions are met: -# * Redistributions of source code must retain the above copyright notice, this list of conditions and the -# following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other materials provided with the distribution. -# * Neither the name of Clearpath Robotics nor the names of its contributors may be used to endorse or -# promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import argparse -import os - -import robot_upstart -from catkin.find_in_workspaces import find_in_workspaces - - -def get_argument_parser(): - p = argparse.ArgumentParser( - description="""Use this script to remove upstart jobs created by the corresponding install script.""") - - p.add_argument("jobname", type=str, nargs=1, metavar=("JOBNAME", ), - help="Name of job to uninstall.") - p.add_argument("--rosdistro", type=str, metavar="DISTRO", - help="Specify ROS distro this is for.") - return p - - -def main(): - """ Implementation of the ``uninstall`` script.""" - - args = get_argument_parser().parse_args() - j = robot_upstart.Job(name=args.jobname[0], rosdistro=args.rosdistro) - j.uninstall() - - return 0 From 7f3cfadb7ba93edf0497294284d5a3542b46a003 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 16 Feb 2022 10:07:23 -0500 Subject: [PATCH 04/27] Removed CMakeLists.txt. --- CMakeLists.txt | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 68811f2..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.0.2) -project(robot_upstart) - -find_package(catkin REQUIRED) - -catkin_package() -catkin_python_setup() - -file(GLOB SCRIPTS scripts/*) -install(PROGRAMS ${SCRIPTS} DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) -install(DIRECTORY templates DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) - -if (CATKIN_ENABLE_TESTING) - find_package(roslint REQUIRED) - roslint_python() - roslint_add_test() - - catkin_add_nosetests(test) -endif() From 96c219f854204d5ea9e272936967ae191f36ed69 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 16 Feb 2022 10:08:00 -0500 Subject: [PATCH 05/27] Fixed package.xml and setup.py information. --- package.xml | 6 ++++++ setup.py | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/package.xml b/package.xml index 8a0cfd1..2bf719e 100644 --- a/package.xml +++ b/package.xml @@ -8,6 +8,12 @@ and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. + Chris Iverach-Brereton + Tony Baltovski + Mike Purvis + + BSD + ament_copyright ament_flake8 ament_pep257 diff --git a/setup.py b/setup.py index ad26661..5854df5 100644 --- a/setup.py +++ b/setup.py @@ -2,21 +2,26 @@ from setuptools import setup from glob import glob -package_name = 'robot_upstart' +PACKAGE_NAME = 'robot_upstart' setup( - name=package_name, - packages=[package_name], + name=PACKAGE_NAME, + version='0.4.2', + packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', - ['resource/' + package_name]), - ('share/' + package_name, ['package.xml']), - (os.path.join('lib', package_name, 'scripts'), glob('scripts/*')), - (os.path.join('share', package_name, 'scripts'), glob('scripts/*')), - (os.path.join('share', package_name, 'templates'), glob('templates/*')), + ['resource/' + PACKAGE_NAME]), + ('share/' + PACKAGE_NAME, ['package.xml']), + (os.path.join('lib', PACKAGE_NAME, 'scripts'), glob('scripts/*')), + (os.path.join('share', PACKAGE_NAME, 'scripts'), glob('scripts/*')), + (os.path.join('share', PACKAGE_NAME, 'templates'), glob('templates/*')), ], install_requires=['setuptools'], zip_safe=True, + maintainer='Tony Baltovski', + maintainer_email='tbaltovski@clearpathrobotics.com', + description='The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files.', + license='BSD', tests_require=['pytest'], entry_points={ 'console_scripts': [ From 9b5469430dbac2e7900bb27aa0681cd617dca342 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 16 Feb 2022 10:15:47 -0500 Subject: [PATCH 06/27] Changes. --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8af8855..3ae664f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Fixed package.xml and setup.py information. +* Removed CMakeLists.txt. +* Removed src folder. +* ros2 foxy +* Contributors: Tony Baltovski, zifengqi123 + 0.4.2 (2022-02-16) ------------------ * Use setpriv instead of setuidgid From 6e5af3cd1b1ff0dc3bbbb7ad63ef89aec0005739 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 16 Feb 2022 10:24:02 -0500 Subject: [PATCH 07/27] 1.0.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3ae664f..505b03a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.0.0 (2022-02-16) +------------------ * Fixed package.xml and setup.py information. * Removed CMakeLists.txt. * Removed src folder. diff --git a/package.xml b/package.xml index 2bf719e..764669e 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ robot_upstart - 0.4.2 + 1.0.0 The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. From 30794660a8b07ad95f35978e5ba9d7f744f85080 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Mon, 21 Mar 2022 08:17:09 -0400 Subject: [PATCH 08/27] Updated setup.py to version 1.0.0. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5854df5..43e792b 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name=PACKAGE_NAME, - version='0.4.2', + version='1.0.0', packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', From e68886855ffd22d1dc95271ad7a457c01063a3e9 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 23 Mar 2022 09:42:13 -0400 Subject: [PATCH 09/27] Switched setup.cfg parameters to use underscores. --- setup.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index c00fbe3..3036db7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,4 @@ [develop] -script-dir=$base/lib/robot_upstart +script_dir=$base/lib/robot_upstart [install] -install-scripts=$base/lib/robot_upstart +install_scripts=$base/lib/robot_upstart From f7155631a4eb64d2585d87d0345eb6ea7e115c17 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 23 Mar 2022 09:42:39 -0400 Subject: [PATCH 10/27] Removed un-used import. --- test/test_basics.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_basics.py b/test/test_basics.py index 4e5531d..6c89723 100644 --- a/test/test_basics.py +++ b/test/test_basics.py @@ -4,7 +4,6 @@ import os import shutil import subprocess -import sys import tempfile import unittest From a945e5a2139f1ee5b38c94c5e9f86b66399a5012 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Wed, 6 Apr 2022 15:51:07 -0400 Subject: [PATCH 11/27] Added ament_index_python as run dep. --- package.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.xml b/package.xml index 764669e..dd04e14 100644 --- a/package.xml +++ b/package.xml @@ -14,6 +14,8 @@ BSD + ament_index_python + ament_copyright ament_flake8 ament_pep257 From cbd62799eb20836547d7a4ddd9d6d9d6c0926e62 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Thu, 7 Apr 2022 12:19:11 -0400 Subject: [PATCH 12/27] Changes. --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 505b03a..d9e0958 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Added ament_index_python as run dep. +* Removed un-used import. +* Switched setup.cfg parameters to use underscores. +* Updated setup.py to version 1.0.0. +* Contributors: Tony Baltovski + 1.0.0 (2022-02-16) ------------------ * Fixed package.xml and setup.py information. From 1bb9ecba7f899ad99acc08bf94f662d0c9706a16 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Thu, 7 Apr 2022 12:32:44 -0400 Subject: [PATCH 13/27] 1.0.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9e0958..dcda365 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.0.1 (2022-04-07) +------------------ * Added ament_index_python as run dep. * Removed un-used import. * Switched setup.cfg parameters to use underscores. diff --git a/package.xml b/package.xml index dd04e14..9b817f5 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ robot_upstart - 1.0.0 + 1.0.1 The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. diff --git a/setup.py b/setup.py index 43e792b..908bf2c 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name=PACKAGE_NAME, - version='1.0.0', + version='1.0.1', packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', From 699815624d17bcebae1799dcf0020eb3da5e0231 Mon Sep 17 00:00:00 2001 From: Roni Kreinin Date: Wed, 20 Apr 2022 12:39:01 -0400 Subject: [PATCH 14/27] Removed master_uri, added rmw, cyclonedds_config, and fastrtps_config --- robot_upstart/install_script.py | 14 +++++++++----- robot_upstart/job.py | 20 ++++++++++++++------ templates/job-start.em | 17 +++++++++++++---- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/robot_upstart/install_script.py b/robot_upstart/install_script.py index 5cfb42e..f6b7768 100644 --- a/robot_upstart/install_script.py +++ b/robot_upstart/install_script.py @@ -50,6 +50,12 @@ def get_argument_parser(): p.add_argument("--job", type=str, help="Specify job name. If unspecified, will be constructed from package name (first " + "element before underscore is taken, e.g. 'myrobot' if the package name is 'myrobot_bringup').") + p.add_argument("--rmw", type=str, metavar="rmw_fastrtps_cpp", + help="Specify RMW DDS being used. rmw_fastrtps_cpp or rmw_cyclonedds_cpp") + p.add_argument("--fastrtps_config", type=str, + help="FastRTPS configuration URI") + p.add_argument("--cyclonedds_config", type=str, + help="CycloneDDS configuration URI") p.add_argument("--interface", type=str, metavar="ethN", help="Specify network interface name to associate job with.") p.add_argument("--user", type=str, metavar="NAME", @@ -58,8 +64,6 @@ def get_argument_parser(): help="Specify workspace setup file for the job launch context.") p.add_argument("--rosdistro", type=str, metavar="DISTRO", help="Specify ROS distro this is for.") - p.add_argument("--master", type=str, metavar="http://MASTER:11311", - help="Specify an alternative ROS_MASTER_URI for the job launch context.") p.add_argument("--logdir", type=str, metavar="path/to/logs", help="Specify an a value for ROS_LOG_DIR in the job launch context.") p.add_argument("--augment", action='store_true', @@ -88,9 +92,9 @@ def main(): # Any unspecified arguments are on the args object as None. These are filled # in by the Job constructor when passed as Nones. j = robot_upstart.Job( - name=job_name, interface=args.interface, user=args.user, - workspace_setup=args.setup, rosdistro=args.rosdistro, - master_uri=args.master, log_path=args.logdir, + name=job_name, rmw=args.rmw, fastrtps_config=args.fastrtps_config, + cyclonedds_config=args.cyclonedds_config, interface=args.interface, user=args.user, + workspace_setup=args.setup, rosdistro=args.rosdistro, log_path=args.logdir, systemd_after=args.systemd_after) for this_pkgpath in args.pkgpath: diff --git a/robot_upstart/job.py b/robot_upstart/job.py index a47cce1..e1cdb7d 100644 --- a/robot_upstart/job.py +++ b/robot_upstart/job.py @@ -40,14 +40,21 @@ class Job(object): """ Represents a ROS configuration to launch on machine startup. """ - def __init__(self, name="ros", interface=None, user=None, workspace_setup=None, - rosdistro=None, master_uri=None, log_path=None, + def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config=None, + interface=None, user=None, workspace_setup=None, + rosdistro=None, log_path=None, systemd_after=None): """Construct a new Job definition. :param name: Name of job to create. Defaults to "ros", but you might prefer to use the name of your platform. :type name: str + :param rmw: RMW DDS being used. rmw_fastrtps_cpp or rmw_cyclonedds_cpp. + :type interface: str + :param fastrtps_config: Path to FastRTPS xml profile. + :type interface: str + :param cyclonedds_config: Path to CycloneDDS xml profile. + :type interface: str :param interface: Network interface to bring ROS up with. If specified, the job will come up with that network interface, and ROS_IP will be set to that interface's IP address. If unspecified, the job will come up @@ -62,9 +69,6 @@ def __init__(self, name="ros", interface=None, user=None, workspace_setup=None, :param rosdistro: rosdistro to use for the /etc/ros/DISTRO path. Defaults to $ROS_DISTRO from the current environment. :type rosdistro: str - :param master_uri: For systems with multiple computers, you may want this - job to launch with ROS_MASTER_URI pointing to another machine. - :type master_uri: str :param log_path: The location to set ROS_LOG_DIR to. If changed from the default of using /tmp, it is the user's responsibility to manage log rotation. @@ -85,7 +89,11 @@ def __init__(self, name="ros", interface=None, user=None, workspace_setup=None, # Fall back on current distro if not otherwise specified. self.rosdistro = rosdistro or os.environ['ROS_DISTRO'] - self.master_uri = master_uri or "http://127.0.0.1:11311" + self.rmw = rmw or "rmw_fastrtps_cpp" + + self.fastrtps_config = fastrtps_config or "" + + self.cyclonedds_config = cyclonedds_config or "" self.log_path = log_path or "/tmp" diff --git a/templates/job-start.em b/templates/job-start.em index 84ec7c2..becf072 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -62,14 +62,23 @@ fi export ROS_HOSTNAME=$(hostname) @[end if]@ -@[if master_uri]@ -export ROS_MASTER_URI=@(master_uri) +@[if rmw]@ +export RMW_IMPLEMENTATION=@(rmw) @[else]@ -export ROS_MASTER_URI=http://127.0.0.1:11311 +export RMW_IMPLEMENTATION=rmw_fastrtps_cpp @[end if]@ + +@[if fastrtps_config]@ +export FASTRTPS_DEFAULT_PROFILES_FILE=@(fastrtps_config) +@[end if]@ + +@[if cyclonedds_config]@ +export CYCLONEDDS_URI=@(cyclonedds_config) +@[end if]@ + export ROS_HOME=${ROS_HOME:=$(echo ~@(user))/.ros} export ROS_LOG_DIR=$log_path - + log info "@(name): Launching ROS_HOSTNAME=$ROS_HOSTNAME, ROS_IP=$ROS_IP, ROS_MASTER_URI=$ROS_MASTER_URI, ROS_HOME=$ROS_HOME, ROS_LOG_DIR=$log_path" # If xacro files are present in job folder, generate and expand an amalgamated urdf. From 780e2a5d2851eef8dd966a1d2a66124fb7671bab Mon Sep 17 00:00:00 2001 From: Roni Kreinin Date: Wed, 20 Apr 2022 13:11:54 -0400 Subject: [PATCH 15/27] Added ROS_DOMAIN_ID arg --- robot_upstart/install_script.py | 6 ++++-- robot_upstart/job.py | 12 ++++++++---- templates/job-start.em | 4 ++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/robot_upstart/install_script.py b/robot_upstart/install_script.py index f6b7768..1f15138 100644 --- a/robot_upstart/install_script.py +++ b/robot_upstart/install_script.py @@ -58,6 +58,8 @@ def get_argument_parser(): help="CycloneDDS configuration URI") p.add_argument("--interface", type=str, metavar="ethN", help="Specify network interface name to associate job with.") + p.add_argument("--ros_domain_id", type=str, + help="ROS_DOMAIN_ID value.") p.add_argument("--user", type=str, metavar="NAME", help="Specify user to launch job as.") p.add_argument("--setup", type=str, metavar="path/to/setup.bash", @@ -93,8 +95,8 @@ def main(): # in by the Job constructor when passed as Nones. j = robot_upstart.Job( name=job_name, rmw=args.rmw, fastrtps_config=args.fastrtps_config, - cyclonedds_config=args.cyclonedds_config, interface=args.interface, user=args.user, - workspace_setup=args.setup, rosdistro=args.rosdistro, log_path=args.logdir, + cyclonedds_config=args.cyclonedds_config, interface=args.interface, ros_domain_id=args.ros_domain_id, + user=args.user, workspace_setup=args.setup, rosdistro=args.rosdistro, log_path=args.logdir, systemd_after=args.systemd_after) for this_pkgpath in args.pkgpath: diff --git a/robot_upstart/job.py b/robot_upstart/job.py index e1cdb7d..366854d 100644 --- a/robot_upstart/job.py +++ b/robot_upstart/job.py @@ -41,7 +41,7 @@ class Job(object): """ Represents a ROS configuration to launch on machine startup. """ def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config=None, - interface=None, user=None, workspace_setup=None, + interface=None, ros_domain_id=None, user=None, workspace_setup=None, rosdistro=None, log_path=None, systemd_after=None): """Construct a new Job definition. @@ -50,16 +50,18 @@ def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config prefer to use the name of your platform. :type name: str :param rmw: RMW DDS being used. rmw_fastrtps_cpp or rmw_cyclonedds_cpp. - :type interface: str + :type rmw: str :param fastrtps_config: Path to FastRTPS xml profile. - :type interface: str + :type fastrtps_config: str :param cyclonedds_config: Path to CycloneDDS xml profile. - :type interface: str + :type cyclonedds_config: str :param interface: Network interface to bring ROS up with. If specified, the job will come up with that network interface, and ROS_IP will be set to that interface's IP address. If unspecified, the job will come up on system startup, and ROS_HOSTNAME will be set to the system's hostname. :type interface: str + :param ros_domain_id: ROS_DOMAIN_ID value. Defaults to 0. + :type ros_domain_id: str :param user: Unprivileged user to launch the job as. Defaults to the user creating the job. :type user: str @@ -95,6 +97,8 @@ def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config self.cyclonedds_config = cyclonedds_config or "" + self.ros_domain_id = ros_domain_id or "" + self.log_path = log_path or "/tmp" # Override this to false if you want to bypass generating the diff --git a/templates/job-start.em b/templates/job-start.em index becf072..5c594cb 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -76,6 +76,10 @@ export FASTRTPS_DEFAULT_PROFILES_FILE=@(fastrtps_config) export CYCLONEDDS_URI=@(cyclonedds_config) @[end if]@ +@[if ros_domain_id]@ +export ROS_DOMAIN_ID=@(ros_domain_id) +@[end if]@ + export ROS_HOME=${ROS_HOME:=$(echo ~@(user))/.ros} export ROS_LOG_DIR=$log_path From b97f047f65731badacb32f59f2ce63c50afffeef Mon Sep 17 00:00:00 2001 From: Roni Kreinin Date: Thu, 21 Apr 2022 10:48:35 -0400 Subject: [PATCH 16/27] Use a single rmw_config arg for both fastrtps and cyclonedds --- robot_upstart/install_script.py | 10 ++++------ robot_upstart/job.py | 14 +++++--------- templates/job-start.em | 21 +++++++++++++++------ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/robot_upstart/install_script.py b/robot_upstart/install_script.py index 1f15138..40fc96b 100644 --- a/robot_upstart/install_script.py +++ b/robot_upstart/install_script.py @@ -52,10 +52,8 @@ def get_argument_parser(): "element before underscore is taken, e.g. 'myrobot' if the package name is 'myrobot_bringup').") p.add_argument("--rmw", type=str, metavar="rmw_fastrtps_cpp", help="Specify RMW DDS being used. rmw_fastrtps_cpp or rmw_cyclonedds_cpp") - p.add_argument("--fastrtps_config", type=str, - help="FastRTPS configuration URI") - p.add_argument("--cyclonedds_config", type=str, - help="CycloneDDS configuration URI") + p.add_argument("--rmw_config", type=str, + help="RMW configuration URI") p.add_argument("--interface", type=str, metavar="ethN", help="Specify network interface name to associate job with.") p.add_argument("--ros_domain_id", type=str, @@ -94,8 +92,8 @@ def main(): # Any unspecified arguments are on the args object as None. These are filled # in by the Job constructor when passed as Nones. j = robot_upstart.Job( - name=job_name, rmw=args.rmw, fastrtps_config=args.fastrtps_config, - cyclonedds_config=args.cyclonedds_config, interface=args.interface, ros_domain_id=args.ros_domain_id, + name=job_name, rmw=args.rmw, rmw_config=args.rmw_config, + interface=args.interface, ros_domain_id=args.ros_domain_id, user=args.user, workspace_setup=args.setup, rosdistro=args.rosdistro, log_path=args.logdir, systemd_after=args.systemd_after) diff --git a/robot_upstart/job.py b/robot_upstart/job.py index 366854d..73b1e16 100644 --- a/robot_upstart/job.py +++ b/robot_upstart/job.py @@ -40,8 +40,8 @@ class Job(object): """ Represents a ROS configuration to launch on machine startup. """ - def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config=None, - interface=None, ros_domain_id=None, user=None, workspace_setup=None, + def __init__(self, name="ros", rmw=None, rmw_config=None, interface=None, + ros_domain_id=None, user=None, workspace_setup=None, rosdistro=None, log_path=None, systemd_after=None): """Construct a new Job definition. @@ -51,10 +51,8 @@ def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config :type name: str :param rmw: RMW DDS being used. rmw_fastrtps_cpp or rmw_cyclonedds_cpp. :type rmw: str - :param fastrtps_config: Path to FastRTPS xml profile. - :type fastrtps_config: str - :param cyclonedds_config: Path to CycloneDDS xml profile. - :type cyclonedds_config: str + :param rmw_config: Path to RMW xml profile. + :type rmw_config: str :param interface: Network interface to bring ROS up with. If specified, the job will come up with that network interface, and ROS_IP will be set to that interface's IP address. If unspecified, the job will come up @@ -93,9 +91,7 @@ def __init__(self, name="ros", rmw=None, fastrtps_config=None, cyclonedds_config self.rmw = rmw or "rmw_fastrtps_cpp" - self.fastrtps_config = fastrtps_config or "" - - self.cyclonedds_config = cyclonedds_config or "" + self.rmw_config = rmw_config or "" self.ros_domain_id = ros_domain_id or "" diff --git a/templates/job-start.em b/templates/job-start.em index 5c594cb..06b8bd4 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -68,13 +68,22 @@ export RMW_IMPLEMENTATION=@(rmw) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp @[end if]@ -@[if fastrtps_config]@ -export FASTRTPS_DEFAULT_PROFILES_FILE=@(fastrtps_config) -@[end if]@ +rmw="@(rmw)" +rmw_config="@(rmw_config)" -@[if cyclonedds_config]@ -export CYCLONEDDS_URI=@(cyclonedds_config) -@[end if]@ +if [[ "$rmw" == "rmw_fastrtps_cpp" ]] +then + if [[ ! -z $rmw_config ]] + then + export FASTRTPS_DEFAULT_PROFILES_FILE=$rmw_config + fi +elif [[ "$rmw" == "rmw_cyclonedds_cpp" ]] +then + if [[ ! -z $rmw_config ]] + then + export CYCLONEDDS_URI=$rmw_config + fi +fi @[if ros_domain_id]@ export ROS_DOMAIN_ID=@(ros_domain_id) From 7b5f6f0a23980d6fcf310e5f3578d226c6080292 Mon Sep 17 00:00:00 2001 From: Roni Kreinin Date: Thu, 21 Apr 2022 13:52:26 -0400 Subject: [PATCH 17/27] Removed whitespace --- templates/job-start.em | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/job-start.em b/templates/job-start.em index 06b8bd4..5b19912 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -91,7 +91,7 @@ export ROS_DOMAIN_ID=@(ros_domain_id) export ROS_HOME=${ROS_HOME:=$(echo ~@(user))/.ros} export ROS_LOG_DIR=$log_path - + log info "@(name): Launching ROS_HOSTNAME=$ROS_HOSTNAME, ROS_IP=$ROS_IP, ROS_MASTER_URI=$ROS_MASTER_URI, ROS_HOME=$ROS_HOME, ROS_LOG_DIR=$log_path" # If xacro files are present in job folder, generate and expand an amalgamated urdf. From f94e098ea52ca6b2455c54b486d07e0a8e36a9a3 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Thu, 21 Apr 2022 18:06:13 -0400 Subject: [PATCH 18/27] Changes. --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dcda365..2b16f4e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Removed whitespace +* Use a single rmw_config arg for both fastrtps and cyclonedds +* Added ROS_DOMAIN_ID arg +* Removed master_uri, added rmw, cyclonedds_config, and fastrtps_config +* Contributors: Roni Kreinin + 1.0.1 (2022-04-07) ------------------ * Added ament_index_python as run dep. From 271f0560068cc3f4e6dda6585191124a223d90c1 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Thu, 21 Apr 2022 18:07:14 -0400 Subject: [PATCH 19/27] 1.0.2 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b16f4e..1d274e5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.0.2 (2022-04-21) +------------------ * Removed whitespace * Use a single rmw_config arg for both fastrtps and cyclonedds * Added ROS_DOMAIN_ID arg diff --git a/package.xml b/package.xml index 9b817f5..0bebd78 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ robot_upstart - 1.0.1 + 1.0.2 The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. diff --git a/setup.py b/setup.py index 908bf2c..fc168b2 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name=PACKAGE_NAME, - version='1.0.1', + version='1.0.2', packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', From 58a6e016bd0538336d9228cdf9d79688803efaff Mon Sep 17 00:00:00 2001 From: Roni Kreinin Date: Thu, 13 Jul 2023 16:38:31 -0400 Subject: [PATCH 20/27] Source workspace after exporting domain ID and RMW --- templates/job-start.em | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/templates/job-start.em b/templates/job-start.em index 5b19912..bfaeb60 100644 --- a/templates/job-start.em +++ b/templates/job-start.em @@ -33,6 +33,34 @@ function log() { } log info "@(name): Using workspace setup file @(workspace_setup)" + +@[if rmw]@ +export RMW_IMPLEMENTATION=@(rmw) +@[else]@ +export RMW_IMPLEMENTATION=rmw_fastrtps_cpp +@[end if]@ + +rmw="@(rmw)" +rmw_config="@(rmw_config)" + +if [[ "$rmw" == "rmw_fastrtps_cpp" ]] +then + if [[ ! -z $rmw_config ]] + then + export FASTRTPS_DEFAULT_PROFILES_FILE=$rmw_config + fi +elif [[ "$rmw" == "rmw_cyclonedds_cpp" ]] +then + if [[ ! -z $rmw_config ]] + then + export CYCLONEDDS_URI=$rmw_config + fi +fi + +@[if ros_domain_id]@ +export ROS_DOMAIN_ID=@(ros_domain_id) +@[end if]@ + source @(workspace_setup) JOB_FOLDER=@(job_path) @@ -62,33 +90,6 @@ fi export ROS_HOSTNAME=$(hostname) @[end if]@ -@[if rmw]@ -export RMW_IMPLEMENTATION=@(rmw) -@[else]@ -export RMW_IMPLEMENTATION=rmw_fastrtps_cpp -@[end if]@ - -rmw="@(rmw)" -rmw_config="@(rmw_config)" - -if [[ "$rmw" == "rmw_fastrtps_cpp" ]] -then - if [[ ! -z $rmw_config ]] - then - export FASTRTPS_DEFAULT_PROFILES_FILE=$rmw_config - fi -elif [[ "$rmw" == "rmw_cyclonedds_cpp" ]] -then - if [[ ! -z $rmw_config ]] - then - export CYCLONEDDS_URI=$rmw_config - fi -fi - -@[if ros_domain_id]@ -export ROS_DOMAIN_ID=@(ros_domain_id) -@[end if]@ - export ROS_HOME=${ROS_HOME:=$(echo ~@(user))/.ros} export ROS_LOG_DIR=$log_path From c87146d21e75fd10acd5762263ef922d11070ba8 Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Fri, 14 Jul 2023 10:36:35 -0400 Subject: [PATCH 21/27] Changes. --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d274e5..ef56eeb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Source workspace after exporting domain ID and RMW +* Contributors: Roni Kreinin + 1.0.2 (2022-04-21) ------------------ * Removed whitespace From 12340f4c6835a9f455bb2fa81bded40bc069f78e Mon Sep 17 00:00:00 2001 From: Tony Baltovski Date: Fri, 14 Jul 2023 10:37:33 -0400 Subject: [PATCH 22/27] 1.0.3 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ef56eeb..d2ea023 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.0.3 (2023-07-14) +------------------ * Source workspace after exporting domain ID and RMW * Contributors: Roni Kreinin diff --git a/package.xml b/package.xml index 0bebd78..1f5e782 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ robot_upstart - 1.0.2 + 1.0.3 The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. diff --git a/setup.py b/setup.py index fc168b2..8d2278f 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name=PACKAGE_NAME, - version='1.0.2', + version='1.0.3', packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', From 67ffc023cbe5dff0e044a5bc51b73f19475c6dfb Mon Sep 17 00:00:00 2001 From: Chris Iverach-Brereton <59611394+civerachb-cpr@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:36:24 -0400 Subject: [PATCH 23/27] Make tests pass on ROS 2 (#124) * Install the test assets to the share directory; otherwise the tests cannot locate the files to install * Check for the systemd config file, not upstart. Upstart check left but commented-out for legacy & reference * Add github workflows * Modify CI to make sure tests are run * Specify container * Roll back to official template (https://github.com/marketplace/actions/ros-2-ci-action), explicitly set skip-tests to false * Add CI for other supported ROS distros * Remove Foxy * Improve workspace fallback * Fix build status in the README * Set branches for CI (this repo also has ROS 1 branches we don't care about testing with the new CI) --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++ README.md | 3 +-- robot_upstart/job.py | 13 +++++++++---- setup.py | 2 ++ test/test_basics.py | 7 ++++++- 5 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bce5d79 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: robot_upstart_ci + +on: + push: + branches: [foxy-devel] + pull_request: + branches: [foxy-devel] + +jobs: + jazzy_ci: + name: Jazzy + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v2.3.4 + - uses: ros-tooling/setup-ros@v0.7 + with: + required-ros-distributions: jazzy + - uses: ros-tooling/action-ros-ci@v0.3 + id: action_ros_ci_step + with: + target-ros2-distro: jazzy + import-token: ${{ secrets.GITHUB_TOKEN }} + skip-tests: false + package-name: + robot_upstart + + humble_ci: + name: Humble + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2.3.4 + - uses: ros-tooling/setup-ros@v0.7 + with: + required-ros-distributions: humble + - uses: ros-tooling/action-ros-ci@v0.3 + id: action_ros_ci_step + with: + target-ros2-distro: humble + import-token: ${{ secrets.GITHUB_TOKEN }} + skip-tests: false + package-name: + robot_upstart \ No newline at end of file diff --git a/README.md b/README.md index 4e2c290..08f74b8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -robot_upstart [![Build Status](https://travis-ci.org/clearpathrobotics/robot_upstart.svg?branch=jade-devel)](https://travis-ci.org/clearpathrobotics/robot_upstart) -============= +# robot_upstart [![robot_upstart_ci](https://github.com/clearpathrobotics/robot_upstart/actions/workflows/ci.yml/badge.svg?branch=foxy-devel)](https://github.com/clearpathrobotics/robot_upstart/actions/workflows/ci.yml) Clearpath Robotics presents a suite of scripts to assist with launching background ROS processes on Ubuntu Linux PCs. Please see the [generated documentation](http://docs.ros.org/latest-available/api/robot_upstart/html/) and [ROS Wiki](http://wiki.ros.org/robot_upstart). diff --git a/robot_upstart/job.py b/robot_upstart/job.py index 73b1e16..790aad2 100644 --- a/robot_upstart/job.py +++ b/robot_upstart/job.py @@ -82,13 +82,18 @@ def __init__(self, name="ros", rmw=None, rmw_config=None, interface=None, # Fall back on current user as the user to run ROS as. self.user = user or getpass.getuser() - # Fall back on current workspace setup file if not explicitly specified. - self.workspace_setup = workspace_setup or \ - os.environ['CMAKE_PREFIX_PATH'].split(':')[0] + '/../setup.bash' - # Fall back on current distro if not otherwise specified. self.rosdistro = rosdistro or os.environ['ROS_DISTRO'] + # Prioritize specified workspace, falling back to current workspace if possible, or + # system workspace as a last-resort + if workspace_setup: + self.workspace_setup = workspace_setup + elif 'CMAKE_PREFIX_PATH' in os.environ.keys(): + self.workspace_setup = os.environ['CMAKE_PREFIX_PATH'].split(':')[0] + '/../setup.bash' + else: + self.workspace_setup = f'/opt/ros/{self.rosdistro}/setup.bash' + self.rmw = rmw or "rmw_fastrtps_cpp" self.rmw_config = rmw_config or "" diff --git a/setup.py b/setup.py index 8d2278f..e859748 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,8 @@ (os.path.join('lib', PACKAGE_NAME, 'scripts'), glob('scripts/*')), (os.path.join('share', PACKAGE_NAME, 'scripts'), glob('scripts/*')), (os.path.join('share', PACKAGE_NAME, 'templates'), glob('templates/*')), + (os.path.join('share', PACKAGE_NAME, 'test'), glob('test/*.py')), + (os.path.join('share', PACKAGE_NAME, 'test/launch'), glob('test/launch/*.launch')), ], install_requires=['setuptools'], zip_safe=True, diff --git a/test/test_basics.py b/test/test_basics.py index 6c89723..21fcc69 100644 --- a/test/test_basics.py +++ b/test/test_basics.py @@ -32,7 +32,12 @@ def test_install(self): self.assertTrue(os.path.exists(self.pjoin("usr/sbin/foo-start")), "Start script not created.") self.assertTrue(os.path.exists(self.pjoin("usr/sbin/foo-stop")), "Stop script not created.") - self.assertTrue(os.path.exists(self.pjoin("etc/init/foo.conf")), "Upstart configuration file not created.") + + # Systemd config + self.assertTrue(os.path.exists(self.pjoin("etc/systemd/system/multi-user.target.wants/foo.service")), "Systemd service file not created.") + + # Upstart config + #self.assertTrue(os.path.exists(self.pjoin("etc/init/foo.conf")), "Upstart configuration file not created.") self.assertEqual(0, subprocess.call(["bash", "-n", self.pjoin("usr/sbin/foo-start")]), "Start script not valid bash syntax.") From a81f626af0838999761582e1fb27fcd3a0be922c Mon Sep 17 00:00:00 2001 From: Chris Iverach-Brereton Date: Mon, 9 Sep 2024 16:13:51 -0400 Subject: [PATCH 24/27] Changes --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d2ea023..68c895c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Make tests pass on ROS 2 (`#124 `_) +* Add Github CI +* Contributors: Chris Iverach-Brereton + 1.0.3 (2023-07-14) ------------------ * Source workspace after exporting domain ID and RMW From 49d52806bc017087ac6d5e0fcfccc4e01d06bb1e Mon Sep 17 00:00:00 2001 From: Chris Iverach-Brereton Date: Mon, 9 Sep 2024 16:13:59 -0400 Subject: [PATCH 25/27] 1.0.4 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 68c895c..677d2c6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package robot_upstart ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.0.4 (2024-09-09) +------------------ * Make tests pass on ROS 2 (`#124 `_) * Add Github CI * Contributors: Chris Iverach-Brereton diff --git a/package.xml b/package.xml index 1f5e782..dd5cadd 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ robot_upstart - 1.0.3 + 1.0.4 The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files. diff --git a/setup.py b/setup.py index e859748..6bf9b60 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name=PACKAGE_NAME, - version='1.0.3', + version='1.0.4', packages=[PACKAGE_NAME], data_files=[ ('share/ament_index/resource_index/packages', From 5e0ec3de50fb56a3bfdfd183d9ad046cd08eae94 Mon Sep 17 00:00:00 2001 From: Jeppy Date: Thu, 15 May 2025 14:22:13 +0900 Subject: [PATCH 26/27] Support multiple launch file patterns (py, xml, yaml) --- scripts/mklaunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mklaunch b/scripts/mklaunch index d1be78d..93d6ace 100755 --- a/scripts/mklaunch +++ b/scripts/mklaunch @@ -28,7 +28,7 @@ # Please send comments, questions, or patches to code@clearpathrobotics.com path=$1 -files=$(ls $path/*.launch.py) +files=$(ls $path/*launch.[pxy][yma]*) if [[ "$?" != "0" ]]; then echo "" exit 1 From f6b0d3e79234fd71d80d0afd1c4c6975f49905c5 Mon Sep 17 00:00:00 2001 From: Chris Iverach-Brereton <59611394+civerachb-cpr@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:15:51 -0400 Subject: [PATCH 27/27] Fix failing tests on buildfarm (#128) * Add a fallback for the ROS_DISTRO envar. Should resolve RPSW-1768 * Pass the ROS distro as a parameter to the jobs for testing --- test/test_basics.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/test/test_basics.py b/test/test_basics.py index 21fcc69..f230115 100644 --- a/test/test_basics.py +++ b/test/test_basics.py @@ -10,6 +10,8 @@ import robot_upstart +ROS_DISTRO = os.getenv("ROS_DISTRO", "jazzy") + class TestBasics(unittest.TestCase): def setUp(self): @@ -27,7 +29,7 @@ def pjoin(self, *p): return os.path.join(self.root_dir, *p) def test_install(self): - j = robot_upstart.Job(name="foo") + j = robot_upstart.Job(name="foo", rosdistro=ROS_DISTRO) j.install(sudo=None, root=self.root_dir) self.assertTrue(os.path.exists(self.pjoin("usr/sbin/foo-start")), "Start script not created.") @@ -45,45 +47,45 @@ def test_install(self): "Stop script not valid bash syntax.") def test_install_launcher(self): - j = robot_upstart.Job(name="bar") + j = robot_upstart.Job(name="bar", rosdistro=ROS_DISTRO) j.add('robot_upstart', 'test/launch/a.launch') j.install(sudo=None, root=self.root_dir) - self.assertTrue(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "bar.d/a.launch")), + self.assertTrue(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "bar.d/a.launch")), "Launch file not copied.") - self.assertFalse(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "bar.d/b.launch")), + self.assertFalse(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "bar.d/b.launch")), "Launch copied which shouldn't have been.") def test_install_glob(self): - j = robot_upstart.Job(name="baz") + j = robot_upstart.Job(name="baz", rosdistro=ROS_DISTRO) j.add('robot_upstart', glob='test/launch/*.launch') j.install(sudo=None, root=self.root_dir) - self.assertTrue(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "baz.d/a.launch")), + self.assertTrue(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "baz.d/a.launch")), "Launch file not copied.") - self.assertTrue(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "baz.d/b.launch")), + self.assertTrue(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "baz.d/b.launch")), "Launch file not copied.") def test_uninstall(self): - j = robot_upstart.Job(name="boo") + j = robot_upstart.Job(name="boo", rosdistro=ROS_DISTRO) j.add('robot_upstart', glob='test/launch/*.launch') j.install(sudo=None, root=self.root_dir) j.uninstall(sudo=None, root=self.root_dir) - self.assertFalse(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "boo.d")), + self.assertFalse(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "boo.d")), "Job dir not removed.") - self.assertFalse(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "usr/sbin/foo-start")), + self.assertFalse(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "usr/sbin/foo-start")), "Start script not removed.") def test_uninstall_user_file(self): - j = robot_upstart.Job(name="goo") + j = robot_upstart.Job(name="goo", rosdistro=ROS_DISTRO) j.add('robot_upstart', glob='test/launch/*.launch') j.install(sudo=None, root=self.root_dir) - with open(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "goo.d/c.launch"), "w") as f: + with open(self.pjoin("etc/ros", ROS_DISTRO, "goo.d/c.launch"), "w") as f: f.write("") j.uninstall(sudo=None, root=self.root_dir) - self.assertTrue(os.path.exists(self.pjoin("etc/ros", os.getenv("ROS_DISTRO"), "goo.d/c.launch")), + self.assertTrue(os.path.exists(self.pjoin("etc/ros", ROS_DISTRO, "goo.d/c.launch")), "User launch file wrongly removed.")