Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ env/
__pycache__/
.vscode/
.venv
*.egg*/
33 changes: 19 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
# `rovercli`
A multi-purpose CLI for UBC Rover operations. Add commands as needed
A command line interface and Textual TUI for UBC Rover operations.

# Installation
`rovercli` has no dependencies outside the Python standard library. To use it:
1. Clone this repo
2. From the root of the repo, run `python main.py [COMMAND] [ARGS]`
3. **[OPTIONAL BUT RECOMMENDED]** To install the CLI on the system root and run commands from anywhere using `rovercli [COMMAND] [ARGS]`:
1. Ensure you are in the root of the repo
2. `chmod +x main.py`
3. `ln -s "$(pwd)/main.py" ~/.local/bin/rovercli`
4. Verify that the symlink worked by running `rovercli`
From the repository root, install the package in a virtual environment:

```sh
python -m pip install -e .
```

This installs Textual and creates the `rovercli` terminal command. Running
`rovercli` without arguments opens the TUI.

# Commands
## TUI

```sh
rovercli
rovercli tui
```

## `sync`
Sync files between devices on the UBC Rover network, without unecessary copying of files that haven't changed.

### Usage

```
python main.py sync [SOURCE ROOT] [DEST ROOT] [DEST ADDRESS]
rovercli sync --src-root RoverFlake2 --dst-root RoverFlake2 --remote-host rv@192.168.1.4
```
For example:
```
python main.py sync ~/RoverFlake2 ~/RoverFlake2 rv@192.168.1.4
```

Other commands are `rovercli print-ip-table` and `rovercli time-sync`.
3 changes: 0 additions & 3 deletions cmds/__init__.py

This file was deleted.

24 changes: 0 additions & 24 deletions cmds/print_ip_table.py

This file was deleted.

101 changes: 0 additions & 101 deletions cmds/sync.py

This file was deleted.

13 changes: 0 additions & 13 deletions cmds/time_sync.py

This file was deleted.

1 change: 0 additions & 1 deletion jetson@192.168.1.5

This file was deleted.

54 changes: 1 addition & 53 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,7 @@
#!/usr/bin/env python3

import argparse
import cmds
from rovercli.cli import main

def main():
app = argparse.ArgumentParser(description="Rover Command Line Interface")
subparsers = app.add_subparsers(dest="command")

setup_sync(subparsers)
setup_print_ip_table(subparsers)
setup_time_sync(subparsers)
args = app.parse_args()
if hasattr(args, "func"):
args.func(args)
else:
app.print_help()

def setup_sync(subparsers):
def sync(args):
cmds.sync(
args.src_root,
args.dst_root,
remote_host=args.remote_host,
build=not args.no_build,
packages=args.packages,
external_pkgs=args.external_pkgs,
)

sync_parser = subparsers.add_parser("sync")
sync_parser.add_argument("--src-root", default="RoverFlake2", help="Sync source from home directory")
sync_parser.add_argument("--dst-root", default="RoverFlake2", help="Sync remote destination from home directory")
sync_parser.add_argument("--remote-host", default="rv@192.168.1.4", help="Remote host for syncing")
sync_parser.add_argument(
"--no-build",
action="store_true",
help="Disable building the project after syncing",
)
sync_parser.add_argument("--packages", nargs = "+", default=None, help="Space-separated list of packages to transfer and build (e.g., 'arm_control drive_control')")
sync_parser.add_argument("--external-pkgs", action="store_true", help="Include external packages in the sync process")
sync_parser.set_defaults(func=sync)

def setup_print_ip_table(subparsers):
def print_ip_table(args):
cmds.print_ip_table()

print_ip_table_parser = subparsers.add_parser("print-ip-table")
print_ip_table_parser.set_defaults(func=print_ip_table)

def setup_time_sync(subparsers):
def time_sync(args):
cmds.time_sync()

time_sync_parser = subparsers.add_parser("time-sync")
time_sync_parser.add_argument("--remote-host", default="rover", help="Remote host for time synchronization")
time_sync_parser.set_defaults(func=time_sync)

if __name__ == "__main__":
main()
23 changes: 23 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "rovercli"
version = "0.1.0"
description = "Command line tools and Textual TUI for UBC Rover operations"
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"textual>=0.50",
"PyYAML>=6.0",
]

[project.scripts]
rovercli = "rovercli.cli:main"

[tool.setuptools.packages.find]
include = ["rovercli*"]

[tool.setuptools.package-data]
rovercli = ["package_lists/*.yaml"]
3 changes: 3 additions & 0 deletions rovercli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Tools for operating the UBC Rover network."""

__version__ = "0.1.0"
60 changes: 60 additions & 0 deletions rovercli/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import argparse

from .commands import print_ip_table, sync, time_sync


def build_parser():
parser = argparse.ArgumentParser(description="Rover Command Line Interface")
subparsers = parser.add_subparsers(dest="command")

sync_parser = subparsers.add_parser("sync", help="Sync files to a rover computer")
sync_parser.add_argument("--src-root", default="RoverFlake2")
sync_parser.add_argument("--dst-root", default="RoverFlake2")
sync_parser.add_argument("--remote-host", default="rv@192.168.1.4")
sync_parser.add_argument("--no-build", action="store_true")
sync_parser.add_argument("--packages", nargs="+", default=None)
sync_parser.add_argument("--package-list", type=str, default=None)
sync_parser.add_argument("--no-external-pkgs", action="store_true")
sync_parser.set_defaults(func=_run_sync)

ip_parser = subparsers.add_parser("print-ip-table", help="Print rover network addresses")
ip_parser.set_defaults(func=lambda args: print_ip_table())

time_parser = subparsers.add_parser("time-sync", help="Synchronize time with a rover computer")
time_parser.add_argument("--remote-host", default="rover")
time_parser.set_defaults(func=lambda args: time_sync(remote_host=args.remote_host))

tui_parser = subparsers.add_parser("tui", help="Open the Textual interface")
tui_parser.set_defaults(func=lambda args: _run_tui())
return parser


def _run_sync(args):
sync(
args.src_root,
args.dst_root,
remote_host=args.remote_host,
build=not args.no_build,
packages=args.packages,
external_pkgs=not args.no_external_pkgs,
package_list=args.package_list,
)


def _run_tui():
from .tui import run_tui

run_tui()


def main():
parser = build_parser()
args = parser.parse_args()
if hasattr(args, "func"):
args.func(args)
else:
_run_tui()


if __name__ == "__main__":
main()
5 changes: 5 additions & 0 deletions rovercli/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .ip_table import print_ip_table
from .sync import sync
from .time_sync import time_sync

__all__ = ["print_ip_table", "sync", "time_sync"]
24 changes: 24 additions & 0 deletions rovercli/commands/ip_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
DEVICES = [
("Jetson", "192.168.1.5", "jet"),
("Rover Onboard Computer", "192.168.1.4", "rover"),
("Control Base Station", "192.168.1.50", "cbs"),
("Comms Pi", "192.168.1.51", "comms_pi"),
("Relay", "192.168.1.22", "relay"),
("Onboard Antenna", "192.168.1.21", "rv_bullet"),
("Dish", "192.168.1.20", "dish"),
("Ben's laptop", "192.168.1.55", "ben"),
("PTZ Camera", "192.168.1.88", "ptz"),
("Relay Pi", "192.168.1.52", "relay_pi"),
("Rowan's Laptop", "192.168.1.40", "rowan"),
]


def print_ip_table():
print("To create an alias, run sudo nano /etc/hosts and paste the following lines:")
for _, ip, alias in DEVICES:
print(f"{ip}\t{alias}")

print(f"\n\n{'Device':<25} {'IP Address':<15} {'Alias':<10}")
print("-" * 50)
for name, ip, alias in DEVICES:
print(f"{name:<25} {ip:<15} {alias:<10}")
Loading