Skip to content

Commit

Permalink
Merge pull request #40 from gstavrinos/v1.7.0
Browse files Browse the repository at this point in the history
V1.7.0
  • Loading branch information
gstavrinos committed Jul 29, 2023
2 parents 6201c3e + 2586b4e commit bde1745
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 82 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ Docker 'n' rocker for quick and easy access to ROS2 (humble) and ROS1 (noetic) a

* `docker`
* `pip`
* `rocker` (automatically installed using pip in the installer script)
* `Linux` (not necessarily Debian-based)
* `dialog` (optionally for interactive terminal UI)

## Instructions
* Make sure your system satisfies all the requirements. The installer script tries to remain distro-agnostic, thus does not install anything apart from `rocker` through `pip`).
* Run the `ros_installer.bash` for ROS1 or `ros2_installer.bash` for ROS2 installation.
* Run the `installer.bash` script with a single argument with the rosez version you need to install. e.g. `./installer.bash ros2ez`. You can also run it interactively with no arguments. For ros-ez versions < `1.7.0`, you must use one of the `ros_*installer.bash` script. There are multiple, one for each supported ROS distribution.
* Run `. ~/.bashrc` or open a new terminal.
* Run `ros2ez` for ROS2 or `rosez` for ROS1 followed by the command you want to run else you will be thrown in a shell inside the image (useful if autocomplete is required).

Expand Down Expand Up @@ -39,6 +39,7 @@ or
* [For versions >= `v1.5.0`] The `sc` or `skip-compilation` flag is now supported, which completely bypasses rosdep and catkin/colcon builds for faster startup.
* [For versions >= `v1.6.0`] A ROS2 Foxy version is now available (with the `ros2ezf` command). Its image comes with built-in `ros1_bridge` support for *ez* ROS1-ROS2 integration.
* [For versions >= `v1.6.1`] A deletion script has been included inside the `internal/deeper/` folder. It takes the version-to-delete as an argument. For example, `bash delete_version.bash ros2ezf` deletes the Foxy version for rosez.
* [For versions >= `v1.7.0`] A new script to easily create systemd services was added. It can be used interactively using `dialog` or non-interactively by passing it 9 arguments. Running the `create_rosez_systemd_service.bash` with less than 9 args (but more than 0) will trigger a help message. Additionally the installation scripts have been merged into one, `installer.bash`. You can now use it interactively, or pass a single argument with the rosez version you need to install. e.g. `./installer.bash ros2ez`
## Tested platforms
* EndeavourOS
* Fedora 35
Expand Down
166 changes: 166 additions & 0 deletions create_rosez_systemd_service.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/bin/bash
sudo_service_location=$(systemctl show sudo.service -P FragmentPath)
if [ -z "$sudo_service_location" ]; then
systemd_system_service_dir=$(systemctl show default.target -P FragmentPath | xargs dirname)
else
systemd_system_service_dir=$(dirname $sudo_service_location)
fi
if [ "$#" -gt 0 ]; then
if [ "$#" -ne 9 ]; then
printf "9 arguments are needed.\n\
1st arg: rosez version.\n\
2nd arg: Systemd before field.\n\
3rd arg: Systemd after field.\n\
4th arg: rosez flags ('ni' and 'ns' are enabled by default and can't be disabled. Also 'fi' is recommended).\n\
5th arg: The ros command.\n\
6th arg: Systemd restart field.\n\
7th arg: Systemd wanted by field.\n\
8th arg: Systemd required by field.\n\
9th arg: Systemd service filename (without suffix).\n\
Fields that are not required should be passed an empty string (\"\")\n\n
Example 'roscore' command for ROS Melodic:\n\
create_rosez_systemd_service.bash \"rosezm\" \"\" \"network.target\" \"cl\" \"roscore\" \"always\" \"graphical.target\" \"\" \"noetic_roscore\"
"
exit
else
rosez_version=$1
before_field=$2
after_field=$3
rosez_flags=$4
command_input=$5
restart_field=$6
wanted_by_field=$7
required_by_field=$8
service_filename=$9
if [ -z "$command_input" ]; then
printf "The ROS command cannot be empty. Exiting..."
exit
fi
if [ -z "$service_filename" ]; then
printf "The systemd service filename cannot be empty. Exiting..."
exit
fi
service_filename="$service_filename.service"
exec_start_field="ExecStart=$(command -v $rosez_version) $rosez_flags ni ns $command_input"
if [ -n "$before_field" ]; then
before_field="Before=$before_field"
fi
if [ -n "$after_field" ]; then
after_field="After=$after_field"
fi
if [ -n "$restart_field" ]; then
restart_field="Restart=$restart_field"
fi
if [ -n "$wanted_by_field" ]; then
wanted_by_field="WantedBy=$wanted_by_field"
fi
if [ -n "$required_by_field" ]; then
required_by_field="RequiredBy=$required_by_field"
fi
fi
else
if ! type "dialog" > /dev/null 2>&1; then
echo "'dialog' (https://linux.die.net/man/1/dialog) is not installed, please install it and run the script again!"
exit -1
fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source $SCRIPT_DIR/internal/helpers.bash
get_supported_versions
# Welcome screen
run_dialog_command "--msgbox" "Welcome to the rosez systemd service creator!"
# rosez version
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
choices="$choices\"${rosezv[$i]}\" \"${distros[$i]}\" \"on\" "
done
run_dialog_command "--radiolist" "Select a rosez version" ${#distros[@]} "$choices"
selected_version=$choice
# rosez flags
choices=""
for i in $(seq 0 $(( ${#known_params[@]}-1 )) ); do
choices="$choices\"${known_params[$i]}\" \"${known_params_short[$i]}\" \"on\" "
done
run_dialog_command "--checklist" "Select rosez flags\n(non-interactive and no-sound are currently mandatory)" ${#known_params[@]} "$choices"
selected_flags=$choice
# ros command
choice=""
while [[ -z "${choice// }" ]]; do
run_dialog_command "--inputbox" "Enter the command you need to run on boot" 0 ""
command_input=$(printf '%q ' $choice)
done
IFS=$'\n' read -r -d '' -a systemd_targets < <(echo 'Skip' && systemctl show '*' --state=active --property=Id --value --no-pager | grep -E '+.target|+.service' | sort )
choices=""
for i in $(seq 0 $(( ${#systemd_targets[@]}-1 )) ); do
choices="$choices\"${systemd_targets[$i]}\" \"\" \"on\" "
done
# unit before field
before_field=""
run_dialog_command "--radiolist" "Select a systemd target for [Unit] Before" ${#systemd_targets[@]} "$choices"
selected_before=$choice
if [[ "$selected_before" != "Skip" ]]; then
before_field="Before=$selected_before"
fi
# unit after field
after_field=""
run_dialog_command "--radiolist" "Select a systemd target for [Unit] After" ${#systemd_targets[@]} "$choices"
selected_after=$choice
if [[ "$selected_after" != "Skip" ]]; then
after_field="After=$selected_after"
fi
# install wanted by field
wanted_by_field=""
run_dialog_command "--radiolist" "Select a systemd target for [Install] WantedBy" ${#systemd_targets[@]} "$choices"
selected_wanted_by=$choice
if [[ "$selected_wanted_by" != "Skip" ]]; then
wanted_by_field="WantedBy=$selected_wanted_by"
fi
# install required by field
required_by_field=""
run_dialog_command "--radiolist" "Select a systemd target for [Install] RequiredBy" ${#systemd_targets[@]} "$choices"
selected_required_by=$choice
if [[ "$selected_required_by" != "Skip" ]]; then
required_by_field="RequiredBy=$selected_required_by"
fi
# service exec start field
exec_start_field="ExecStart=$(command -v $selected_version) $selected_flags $command_input"
# service restart field
restart_options=("always" "on-success" "on-failure" "on-abnormal" "on-watchdog" "on-abort" "no")
choices=""
for i in $(seq 0 $(( ${#restart_options[@]}-1 )) ); do
choices="$choices\"${restart_options[$i]}\" \"\" \"on\" "
done
run_dialog_command "--radiolist" "Select a [Restart] strategy" ${#restart_options[@]} "$choices"
selected_restart=$choice
restart_field="Restart=$selected_restart"
fi
systemd_service="\
[Unit]\n\
Description=Auto-generated service file for rosez automation with command $command_input.\n\
$before_field\n\
$after_field\n\
\n\
[Service]\n\
Type=simple\n\
User=$(whoami)\n\
Group=$(id -gn)\n\
WorkingDirectory=$HOME\n\
# Environment=\"DISPLAY=$DISPLAY\"\n\
# Environment=\"XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR\"\n\
$exec_start_field\n\
$restart_field\n\
\n\
[Install]\n\
$wanted_by_field\n\
$required_by_field\n\
"
if [ "$#" -eq 0 ]; then
# Confirmation
run_dialog_command "--yesno" "Does the service look correct? ('No' will quit):\n$systemd_service"
# Installation process
run_dialog_command "--inputbox" "Enter the name of your service file. Do not incluce a suffix or any file-breaking characters. i.e. If you want to create a service file called 'rosez_roscore.service', simply input 'rosez_roscore'." 0 ""
service_filename=$choice.service
run_dialog_command "--msgbox" "The script will now exit and you will be prompted to enter your sudo password in order to install $service_filename in $systemd_system_service_dir..."
clear
fi
printf "$systemd_service"
printf "$systemd_service" | sudo tee $systemd_system_service_dir/$service_filename > /dev/null
sudo systemctl enable $service_filename
65 changes: 65 additions & 0 deletions installer.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash
original_dir=$(pwd)
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source $SCRIPT_DIR/internal/helpers.bash
image_name=""
dockerfile=""
executable_folder_name=""
get_supported_versions
selected_version=$1
if [[ -z "$1" ]] || [ "$1" == "--interactive" ]; then
if ! type "dialog" > /dev/null 2>&1; then
echo "'dialog' (https://linux.die.net/man/1/dialog) is not installed, please install it and run the script again!"
echo "You can alternatively use the non-interactive version by running the installer with one of the following parameters depending on the ROS version you need:"
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
echo "${rosezv[$i]} for ${distros[$i]}"
done
exit -1
else
echo "going interactive"
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
choices="$choices\"${rosezv[$i]}\" \"${distros[$i]}\" \"on\" "
done
run_dialog_command "--radiolist" "Select a rosez version to install" ${#distros[@]} "$choices"
clear
selected_version=$choice
fi
fi
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
if [ "$selected_version" == "${rosezv[$i]}" ]; then
image_name="${image_names[$i]}"
dockerfile="${dockerfiles[$i]}"
executable_folder_name="${executable_folder_names[$i]}"
break
fi
done
if [[ -z "$image_name" ]]; then
echo "Invalid argument passed. You can run the interactive version by using the --interactive flag (or no flags at all)."
echo "You can alternatively use the non-interactive version by running the installer with one of the following parameters depending on the ROS version you need:"
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
echo "${rosezv[$i]} for ${distros[$i]}"
done
exit -1
fi
sudo pip install rocker==0.2.10
cd $SCRIPT_DIR
need_rr=0
if ! id -nGz "$USER" | grep -qzxF "docker"
then
sudo usermod -aG docker $USER
need_rr=1
fi
sudo docker build --no-cache --pull -t $image_name -f $SCRIPT_DIR/internal/$dockerfile . --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)
string_for_bashrc='export PATH="$PATH:'$SCRIPT_DIR/internal/"${executable_folder_name}"'"'

if ! $( grep -Fx "$string_for_bashrc" ~/.bashrc )
then
echo $string_for_bashrc >> ~/.bashrc
. ~/.bashrc
fi
if [[ $need_rr -gt 0 ]]
then
echo "Please reboot your system, and then try using ros-ez!"
fi
cd $original_dir

23 changes: 9 additions & 14 deletions internal/entrypoint.bash
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
#!/bin/bash
source /home/rosez_user/helpers.bash
get_supported_versions
lock_file=$LOCKFILE
skip_compilation=$SKIPCOMPILATION
rosversion="unknown"
lockation=""
wstxt="ros2_ws.txt"
if [ -f /opt/ros/humble/setup.bash ]; then
rosversion="humble"
elif [ -f /opt/ros/foxy/setup.bash ]; then
rosversion="foxy"
wstxt="ros2f_ws.txt"
elif [ -f /opt/ros/noetic/setup.bash ]; then
rosversion="noetic"
wstxt="ros_ws.txt"
elif [ -f /opt/ros/melodic/setup.bash ]; then
rosversion="melodic"
wstxt="rosm_ws.txt"
fi
wstxt=""
for i in $(seq 0 $(( ${#distros[@]}-1 )) ); do
if [ -f /opt/ros/"${distros[$i]}"/setup.bash ]; then
rosversion="${distros[$i]}"
wstxt="${workspaces[$i]}"
fi
done
read -r lockdir</opt/ros/$wstxt
lockation="/opt/ros/$(basename $lockdir)"
source /home/rosez_user/helpers.bash
if [ "$ROSEZCLEARLOCKS" == "ros-ez-CL" ]; then
echo -e "${colour_orange}I was passed the clear-locks flag. Deleting all lock files...$colour_end"
sudo rm -f $lockation/$lock_prefix*$lock_suffix
Expand Down
53 changes: 53 additions & 0 deletions internal/helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Export everything in this file
set -a

known_params=("force-integrated" "clear-locks" "skip-compilation" "non-interactive" "no-sound")
known_params_short=("fi" "cl" "sc" "ni" "ns")
signal_list=(INT QUIT TSTP TERM HUP KILL)
colour_end='\033[0m'
colour_red='\033[0;31m'
Expand All @@ -11,12 +13,63 @@ colour_blue='\033[0;34m'
lock_prefix=".rosez-"
lock_suffix=".lock"

rosezv[0]=""
workspaces[0]=""
volumes[0]=""
distros[0]=""
image_names[0]=""
executable_folder_names[0]=""
dockerfiles[0]=""

title="rosez"
dialog_command="dialog --title \"$title\" --clear"
# Function that simpifies the process of creating dialog "screens"
function run_dialog_command {
tmpfile=`tempfile 2>/dev/null` || tmpfile=/tmp/test$$
trap "rm -f $tmpfile" $signal_list
if [ -n "$3" ] && [ $3 -eq 0 ]; then
eval "$dialog_command $1 \"$2\" 20 61 \"$4\" 2>$tmpfile"

else
eval "$dialog_command $1 \"$2\" 20 60 $3 $4 2>$tmpfile"
fi
retval=$?
if [ $retval -eq 0 ]; then
choice=$(cat $tmpfile)
else
clear
exit 0
fi
}
# This function read a txt file with all the supported ros versions along with their configuration
function get_supported_versions {
helper_script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
supported_versions_file=$helper_script_dir/supported_versions.txt
vnum=0
while read -r line; do
while IFS=',' read -ra line_arr; do
if [ $vnum -gt 0 ]; then
index=$(( $vnum-1 ))
rosezv[$index]="${line_arr[0]}"
workspaces[$index]="${line_arr[1]}"
volumes[$index]="${line_arr[2]}"
distros[$index]="${line_arr[3]}"
image_names[$index]="${line_arr[4]}"
executable_folder_names[$index]="${line_arr[5]}"
dockerfiles[$index]="${line_arr[6]}"
fi
vnum=$(( $vnum+1 ))
done <<< $line
done < $supported_versions_file
}

# This function is used to trap signals
function signal_handler() {
echo -e "${colour_red}Execution was aborted, deleting my lock_file ($lock_file)$colour_end"
rm -f $lockation/$lock_file
exit
}

# This function is used to check intermediate commands'
# exit codes and then terminate if there was an error
# This is a required behaviour, in order
Expand Down

0 comments on commit bde1745

Please sign in to comment.