Skip to content

Commit

Permalink
[BUILD] Merge pull request #263 from pioneers/github_workflows
Browse files Browse the repository at this point in the history
[BUILD] Replace Travis + Docker with Github Actions for CI
  • Loading branch information
benliao1 authored Jun 18, 2023
2 parents 4b24cee + 33eb623 commit e36f4ae
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 264 deletions.
10 changes: 0 additions & 10 deletions .dockerignore

This file was deleted.

103 changes: 103 additions & 0 deletions .github/workflows/pull_request_ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# This configures the Continuous Integration builds on every PR,
# as well as every commit on master.

# This is the name of this workflow
name: CI

# Under what conditions do we run this workflow? Either
# a) It is a commit on a pull request on a branch to be merged into master
# b) It is a push to master (which only happens when we close a pull request)
# c) It's 10:45 UTC on the 1st, 8th, 15th, 22nd, or 29th of a month (to prevent the cache from expiring)
on:
pull_request:
branches: [master]
types: [opened, synchronize]
push:
branches: [master]
schedule:
- cron: '45 10 1,8,15,22,29 * *'

# Here is the list of jobs that this workflow will run. There is only one job.
jobs:
# The name of the job: "build-and-test"
build-and-test:
# This specifies the OS that we are running the workflow on: the latest version of Ubuntu
runs-on: ubuntu-latest

# Here is the list of specific commands this job will run. They are run in order
steps:
# First, we check out the repository's code using the Github Actions' "Checkout" tool.
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: 'recursive'

# Next, we install dev packages needed for Runtime
- name: Install dev packages
run: |
sudo apt-get install -y \
python3-dev \
clang-format \
protobuf-compiler \
libprotoc-dev
# Next, we install Cython
- name: Install Cython
run: |
python3 -m pip install Cython
# The next steps steps do the following:
#
# 1) Give the program "tar" root permissions
# 2) Retrieve cached files associated with the protobuf-c library, if they exist
# 3) Take away root permission from the "tar" program
#
# We need to do this because the Cache Action uses "tar" to restore cached files
# into the runner. However, the cached files need root permission to get restored.
# Thus, we need to give tar root permissions to do the cache restoration, then
# take it away once we're done (since if the caching step fails and we do the
# insallation of protobuf-c with root permissions, we will get permission errors)
- name: Give tar root permissions
run: |
sudo chown root:root /usr/bin/tar && sudo chmod u+s /usr/bin/tar
- name: Cache protobuf-c
id: cache-protobuf-c
uses: actions/cache@v3 # Uses the Github Actions' "Cache" tool
with:
# These are the files we cache
path: |
/usr/local/lib/libprotobuf-c.*
/usr/local/lib/pkgconfig
/usr/local/bin/protoc-*
/usr/local/include/protobuf-c
/usr/local/include/google
# This is the name (key) of the cache that we look for each time
key: libprotobuf-c
- name: Take away tar root permissions
run: |
sudo chown runner:runner /usr/bin/tar && sudo chmod u+x /usr/bin/tar
# This if statement determine whether the cache lookup was a hit (true) or miss (not true--idk, false doesn't work)
# If the cache lookup hit, we just run "sudo ldconfig" to tell the linker where to look for
# protobuf-c files. If the cache lookup missed, we have to install protobuf-c from scratch
# See https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#using-the-output-of-the-cache-action
- if: ${{ steps.cache-protobuf-c.outputs.cache-hit == 'true' }}
name: Run ldconfig
run: |
sudo ldconfig
- if: ${{ steps.cache-protobuf-c.outputs.cache-hit != 'true' }}
name: Install protobuf-c
run: |
wget https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.1/protobuf-c-1.4.1.tar.gz
tar -xzf protobuf-c-1.4.1.tar.gz
cd protobuf-c-1.4.1 && ./configure && make && sudo make install && sudo ldconfig
# Now that we are done installing Runtime's dependencies, we build Runtime
- name: Build
run: |
./runtime build
# And finally, we test Runtime
- name: Test
run: |
./runtime test
46 changes: 0 additions & 46 deletions .travis.yml

This file was deleted.

47 changes: 20 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PiE Runtime [![Build Status](https://travis-ci.org/pioneers/runtime.svg?branch=master)](https://travis-ci.org/pioneers/runtime)
# PiE Runtime [![Build](https://github.com/pioneers/runtime/actions/workflows/pull_request_ci.yml/badge.svg)](https://github.com/pioneers/runtime/actions/workflows/pull_request_ci.yml)

Welcome to the PiE Runtime repo! This README will only cover how to install, build, and run Runtime. If you want to learn more info about how Runtime works, or are a new member, please check out our wiki https://github.com/pioneers/runtime/wiki.

Expand All @@ -23,18 +23,16 @@ Runtime can be divided into a few neatly containerized parts:

In addition to these parts, there are a number of configuration files for Runtime to manage the various tools that we use. They are listed here, with a brief explanation about what they do:

* `.dockerignore`: this file lists out all of the directories, files, and other information that we do not want to include when building Runtime's Docker image.
* `.gitignore`: this file lists out all of the directories and files that we don't want in our Git repository. This includes things like executables, build files, and `.DS_Store`.
* `.gitattributes`: this file is purely for aesthetic purposes. It tells Github which files to exclude when calculating the repository language makeup you see in the repo (below the "Contributors" section in the sidebar on the web page that you're probably looking at right now).
* `.travis.yml`: this file tells Travis (the continuous integration tool that we use) what to run when checking if Runtime is working properly before a new feature is merged into the master branch. It is essentially responsible for running the integration tests and for updating Runtime's Docker image.
* `docker-compose.yml`: this file is used to describe to the `docker-compose` command what to run.
* `.github/workflows/pull_request_ci.yml`: this file outlines the steps taken by the Github Action that we use to test our code before we release Runtime. See our most recent CI builds [here](https://github.com/pioneers/runtime/actions/workflows/pull_request_ci.yml)!
* `runtime`: this file is a convenience shell script that makes it easy to call the various other shell scripts in our directory, which you will read more about later.

This README will not go into each of these parts into exhaustive detail; explanations for each part can be found in the corresponding folder's README in the repo as well as [our wiki.](https://github.com/pioneers/runtime/wiki)

## Dependencies

Runtime is designed to be used on the Raspberry Pi, and with a distribution of Linux called Raspbian, a slight variant of the extremely popular Debian. We tested Runtime to work well on Linux systems. If you do not have a Linux system, please instead use Docker (which might even be easier than using Linux). The major benefit of using Docker is you can skip this entire dependency section. To learn more about it, check out the README in the `docker/` folder.
Runtime is designed to be used on the Raspberry Pi, and with a distribution of Linux called Raspbian, a slight variant of the extremely popular Debian. We tested Runtime to work well on Linux systems. Only some parts of Runtime work on macOS and may require different commands to compile; no parts of Runtime can operate on Windows. Please use a Linux machine or (preferably) a Raspberry Pi to run Runtime!

### Commonly Used Tools

Expand All @@ -60,21 +58,19 @@ Runtime has the following third-party library dependencies:

#### Installing Google Protobufs and `protobuf-c`

1. From `https://github.com/protocolbuffers/protobuf/releases`, download the latest `protobuf-cpp-<release>.tar.gz` and extract it (for help, click [here](#extract))
2. From `https://github.com/protobuf-c/protobuf-c/releases` download the latest `protobuf-c-<release>.tar.gz` and extract it (for help, click [here](#extract))
3. You may need to install some tools (`libtool`, `pkg-config`, `g++`). To install a tool you don't have, run `sudo apt-get -y install <tool-name>`, replace `<tool-name>` with what you want to install.

4. `cd` into the folder for `protobuf-cpp-<release>.tar.gz` and run:
1. `./configure`
2. `make` (this takes a long time)
3. `sudo make install`
4. `sudo ldconfig`
5. `cd` into the folder for `protobuf-c-<release>.tar.gz` and run:
1. From `https://github.com/protobuf-c/protobuf-c/releases` download version 1.4.1, i.e. [`protobuf-c-1.4.1.tar.gz`](https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.1/protobuf-c-1.4.1.tar.gz) and extract it (for help, click [here](#extract))
2. You may need to install some tools (`libtool`, `pkg-config`, `g++`). To install a tool you don't have, run `sudo apt-get -y install <tool-name>`, replace `<tool-name>` with what you want to install.

3. To install Google Protobuf, run:
1. `sudo apt-get -y install protobuf-compiler`
2. `sudo apt-get -y install libprotoc-dev`
4. To install `protobuf-c`, first `cd` into the folder for `protobuf-c-<release>.tar.gz` and run:
1. `./configure`
2. `make`
3. `sudo make install`
4. `sudo ldconfig`
6. (optional) To view `protobuf-c` documentation:
5. (optional) To view `protobuf-c` documentation:
1. Install `doxygen`: `sudo apt-get -y install doxygen`
2. Repeat steps 5.i and 5.ii from above in the `protobuf-c` directory, then do `make html`
3. Then navigate to that directory in Explorer/Finder and open the `html/index.html` file by double clicking on it
Expand All @@ -90,26 +86,22 @@ Then, extract the files with

You might need to install `wget` and `tar` with `sudo apt-get -y install wget tar`.

### Installing ncurses for Shared Memory UI
The Shared Memory UI allows the user to have a real-time view of data flowing in and out of shared memory.
This is analogous to the "shm_cli" among dev_handler_cli, executor_cli, and net_handler_cli.
Note that the UI is used in development only as a debugging tool and should not be used in production.
The command below will install ncurses on Raspbian / Debian machines:
### Installing `ncurses` for Shared Memory UI

The Shared Memory UI allows the user to have a real-time view of data flowing in and out of shared memory. This is analogous to the "`shm_cli`" among `dev_handler_cli`, `executor_cli`, and `net_handler_cli`. Note that the UI is used in development only as a debugging tool and should not be used in production. The command below will install `ncurses` on Linux machines:

sudo apt-get -y install libncurses5-dev libncursesw5-dev

### Installing Clang Format
Clang Format is used to format code to comply with our [code style](https://github.com/pioneers/runtime/wiki/Project-Conventions). Code that is not formatted with Clang cannot be merged into master. After installing, use the runtime script to format code. (See `runtime format`)
```
sudo apt-get -y install clang-format
```
Clang Format is used to format code to comply with our [code style](https://github.com/pioneers/runtime/wiki/Project-Conventions). Code that is not formatted with Clang cannot be merged into `master`. After installing, use the runtime script to format code. (See `runtime format`)

sudo apt-get -y install clang-format

## Runtime Script and Usage

We use the bash script `runtime` in this root directory as the entrypoint to our code. You can call it with `./runtime <args>` in this folder. However, you can also have it be callable from any directory by adding it to your `PATH` variable. This can be done automatically adding the following line to your `~/.bashrc` file:

```
export PATH="$PATH:<path to runtime folder>"
```
export PATH="$PATH:<path to runtime folder>"

Then either close and reopen the terminal, or do `source ~/.bashrc`.

Expand All @@ -122,6 +114,7 @@ If you now type `runtime` it will list all the possible subcommands you can run.
* `flash`: will flash an Arduino as a Lowcar device
* `clean`: will remove all artifacts generated when building or running Runtime
* `update`: waits for new `runtime.zip` to appear in `/tmp` and then will unzip it and reboot the robot
* `status`: will display the currently running processes under the `ubuntu` user (to list active Runtime processes)

## Authors

Expand Down
15 changes: 10 additions & 5 deletions dev_handler/dev_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
* a file with path "/dev/ttyACM0". A second device connected will appear as
* "/dev/ttyACM1".
* Virtual devices (not Arduinos) on the other hand are UNIX sockets that appear as
* "/tmp/ttyACM0"
* "/var/ttyACM0"
* In the code, the number is referred to as "port_num"
* Depending on whether a device is an Arduino ("lowcar") or a virtual device,
* dev handler has to open a connection with it differently.
*
* These file paths may also be referred to as "port_prefix" in the code.
*/
#define LOWCAR_FILE_PATH "/dev/ttyACM"
#define VIRTUAL_FILE_PATH "/tmp/ttyACM"
#define VIRTUAL_FILE_PATH "ttyACM" // will be created in the home directory
#define LOWCAR_USB_FILE_PATH "/dev/ttyUSB"

// **************************** PRIVATE STRUCT ****************************** //
Expand Down Expand Up @@ -92,7 +92,10 @@ uint32_t used_virtual_ports = 0;
uint32_t used_lowcar_usb_ports = 0;
pthread_mutex_t used_ports_lock; // poll_connected_devices() and relay_clean_up() shouldn't access used_ports at the same time

#define MAX_PORT_NAME_SIZE 16
// String to hold the home directory path (for looking for virtual device sockets)
const char *home_dir;

#define MAX_PORT_NAME_SIZE 64

// ***************************** MAIN FUNCTIONS ***************************** //

Expand Down Expand Up @@ -312,7 +315,7 @@ void* relayer(void* relay_cast) {

// If the device disconnects or times out, clean up
log_printf(DEBUG, "Monitoring %s (0x%016llX)", get_device_name(relay->dev_id.type), relay->dev_id.uid);
char port_name[14];
char port_name[MAX_PORT_NAME_SIZE];
construct_port_name(port_name, relay->is_virtual, relay->is_usb, relay->port_num);
while (1) {
// If Arduino port file doesn't exist, it disconnected
Expand Down Expand Up @@ -829,7 +832,8 @@ void cleanup_handler(void* args) {

void construct_port_name(char* port_name, bool is_virtual, bool is_usb, int port_num) {
if (is_virtual) {
sprintf(port_name, "%s%d", VIRTUAL_FILE_PATH, port_num);
// append home directory in front of the socket name
sprintf(port_name, "%s/%s%d", home_dir, VIRTUAL_FILE_PATH, port_num);
} else if (is_usb) {
sprintf(port_name, "%s%d", LOWCAR_USB_FILE_PATH, port_num);
} else {
Expand All @@ -853,6 +857,7 @@ int main(int argc, char* argv[]) {
// If SIGINT (Ctrl+C) is received, call stop() to clean up
signal(SIGINT, stop);
init();
home_dir = getenv("HOME"); // set the home directory
log_printf(INFO, "DEV_HANDLER initialized.");
poll_connected_devices();
return 0;
Expand Down
15 changes: 0 additions & 15 deletions docker-compose.yml

This file was deleted.

16 changes: 0 additions & 16 deletions docker/Dockerfile

This file was deleted.

Loading

0 comments on commit e36f4ae

Please sign in to comment.