Skip to content
Closed

Dev #14

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
123 changes: 117 additions & 6 deletions .github/workflows/install-and-launch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,95 @@ jobs:
- name: Launch smoke test (headless, no TTY)
run: ./launch_lucy.sh --headless ros2 doctor --report

# Windows-specific CI. NOTE: GitHub-hosted Windows runners cannot run Linux
# containers (no Hyper-V/nested virtualization, no WSL2), so the heavy install
# step (docker build of the ROS image + colcon) CANNOT run here — that is
# covered for both amd64/arm64 by the Linux `install-and-launch` job above.
# This job verifies the Windows-only pieces on real x64 AND arm64 hardware:
# - host CPU -> Docker platform detection (install_ops.host_container_platform)
# - Lucy.exe builds (PyInstaller) and its bundled --cli imports work
# - the NSIS installer compiles
windows-build-test:
name: Windows build & installer test (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
include:
- arch: x64
runner: windows-latest
expected_platform: linux/amd64
- arch: arm64
runner: windows-11-arm
expected_platform: linux/arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Generate releases manifest
run: python windows/generate_releases.py

- name: Verify host architecture detection
shell: pwsh
run: |
$expected = "${{ matrix.expected_platform }}"
$got = (python -c "import sys; sys.path.insert(0,'windows'); import install_ops; print(install_ops.host_container_platform())").Trim()
Write-Host "host_container_platform() -> $got (expected $expected)"
if ($got -ne $expected) {
Write-Error "Arch detection mismatch: got '$got', expected '$expected'"
exit 1
}

- name: Install PyInstaller
run: python -m pip install pyinstaller

- name: Build Lucy.exe
shell: pwsh
run: |
python -m PyInstaller --noconfirm --onefile --name Lucy `
--icon windows/assets/lucy-icon.ico `
--hidden-import install_ops `
--hidden-import install_runner `
--paths windows `
windows/Lucy.py
if (-not (Test-Path "dist/Lucy.exe")) { Write-Error "Lucy.exe not produced"; exit 1 }

- name: Smoke-test Lucy.exe CLI (bundled imports + prereq report)
shell: pwsh
run: |
dist\Lucy.exe --cli check-prereqs
$code = $LASTEXITCODE
Write-Host "check-prereqs exit code: $code"
# 0 (all present) or 1 (a prereq missing, e.g. no Docker on CI) both mean
# the exe ran fine; >1 = crash. Reset the propagated exit code explicitly.
if ($code -gt 1) { Write-Error "Lucy.exe --cli check-prereqs crashed (exit $code)"; exit 1 }
exit 0

- name: Install NSIS
run: choco install nsis -y --no-progress

- name: Build Lucy-Setup.exe (NSIS)
shell: pwsh
run: |
$makensis = "${env:ProgramFiles(x86)}\NSIS\makensis.exe"
& $makensis "/DMyAppVersion=0.0.0-ci" windows/installer/Lucy.nsi
if (-not (Test-Path "dist/Lucy-Setup-0.0.0-ci.exe")) { Write-Error "Installer not produced"; exit 1 }

- name: Upload Windows artifacts
uses: actions/upload-artifact@v4
with:
name: lucy-windows-${{ matrix.arch }}
path: |
dist/Lucy.exe
dist/Lucy-Setup-0.0.0-ci.exe
if-no-files-found: error

build-and-release-windows-exe:
name: Build and Release Windows Executable
# Only run this job when a new tag is pushed
Expand All @@ -115,15 +204,37 @@ jobs:
with:
python-version: '3.x'

- name: Generate releases manifest
run: python windows/generate_releases.py

- name: Install PyInstaller
run: pip install pyinstaller
run: python -m pip install pyinstaller

- name: Build the executable
run: pyinstaller --onefile --name Lucy windows/Lucy.py
- name: Build Lucy.exe
shell: pwsh
run: |
python -m PyInstaller --noconfirm --onefile --name Lucy `
--icon windows/assets/lucy-icon.ico `
--hidden-import install_ops `
--hidden-import install_runner `
--paths windows `
windows/Lucy.py

- name: Install NSIS
run: choco install nsis -y

- name: Build Lucy-Setup.exe
shell: pwsh
run: |
$version = "${{ github.ref_name }}" -replace '^v',''
if (-not $version) { $version = "0.0.0" }
$makensis = "${env:ProgramFiles(x86)}\NSIS\makensis.exe"
& $makensis "/DMyAppVersion=$version" windows/installer/Lucy.nsi

- name: Create Release and Upload Asset
- name: Create Release and Upload Assets
uses: softprops/action-gh-release@v2
with:
files: dist/Lucy.exe
# This creates a draft release. Remove `draft: true` to publish it automatically.
files: |
dist/Lucy.exe
dist/Lucy-Setup-*.exe
draft: true
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Trigger Release

on:
workflow_dispatch:
inputs:
version:
description: 'Version number'
required: true
type: string

jobs:
create-release:
uses: Sentience-Robotics/.github/.github/workflows/release.yaml@master
with:
version: ${{ inputs.version }}

7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ __pycache__/

# Local repo override (forks/branches; takes precedence over config/repos.json)
config/repos.json.local

# End-user install profile (written by installer / Lucy.exe)
config/install.profile.json

# Windows executable files
dist/
*.spec
8 changes: 4 additions & 4 deletions Lucy.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def set_dev_mode(is_enabled):

def run_command(command, interactive=False):
"""Runs a command.

If interactive is True, runs natively in the terminal.
"""
print(f"--- Running: {' '.join(command)} ---")
try:
if interactive:
# Inherit standard IO to maintain terminal size and TTY functionality
# Inherit standard IO to maintain terminal size and TTY functionality
return subprocess.run(command).returncode
else:
# Popen is fine for non-interactive scripts like install/build
Expand Down Expand Up @@ -91,7 +91,7 @@ def main_tui(stdscr):
continue

prefix = "> " if current_idx == i else " "

if option == "Developer Mode":
checkbox = "[x]" if is_dev_mode else "[ ]"
stdscr.addstr(2 + i, 4, f"{prefix}{checkbox} {option}")
Expand Down Expand Up @@ -167,7 +167,7 @@ def check_initial_size():
if task.get("interactive", False):
print(f"--- Session finished with exit code {rc} ---")
break

task_name = task.get("name")
if task_name in ["Install", "Rebuild"] and rc == 0:
print(f"\n--- Task '{task_name}' finished successfully. ---")
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Workspace bringup for the Lucy / InMoov humanoid. Everything (ROS 2 Humble, Gaze

<sub>Linux GUI forwarding uses `xhost` (preinstalled). On Wayland run `xhost +local:docker` if windows don't open — see [GUI](#gui-rviz-and-gazebo).</sub>

> **Windows users:** see the [Windows README](windows/README.md) for step-by-step install instructions (including the Docker Desktop "uncheck WSL 2" note) and the native `windows/Lucy.py` manager.
> **Windows users:** see the [Windows README](windows/README.md) — **`Lucy-Setup.exe`** to install/update, **`Lucy.exe`** to launch.

## Get the repository

Expand Down Expand Up @@ -48,13 +48,16 @@ python3 Lucy.py

### Windows

**Installer (recommended):** download `Lucy-Setup.exe` from [GitHub Releases](https://github.com/Sentience-Robotics/lucy_ws/releases), then see the [Windows README](windows/README.md).

**From source (developers):**

```bash
python windows/Lucy.py
python windows/Lucy.py --cli install # first time
python windows/Lucy.py # launch
```

> **Windows** additionally needs a third-party X Server — see the [Windows README](windows/README.md).

> **First run:** in the TUI, choose **`Install / Update`** before anything else. It clones the sub-repositories, builds the Docker image and the workspace (this can take a while). Only once it finishes should you use **`Launch`**.
> **Windows** additionally needs a third-party X Server for RViz/Gazebo — see the [Windows README](windows/README.md). End users should use **`Lucy-Setup.exe`** instead of manual install.

### Opening the Control Panel

Expand Down
2 changes: 2 additions & 0 deletions config/launcher_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
"dependencies": ["core"],
"conflicts": [],
"command": "ros2 run lucy_cli tui",
"readiness_check": "test -f /tmp/lucy_cli.ready",
"nav_hint": "Ctrl-B W",
"default_on": false
},
{
Expand Down
12 changes: 12 additions & 0 deletions docs/developer_lucy_packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ Use the same structure as `repos.json` — list only the repos you want to overr

Delete the file to fall back to the tracked `repos.json`.

### Windows install profile (`config/install.profile.json`)

On Windows, **`Lucy-Setup.exe`** (or `Lucy.exe --cli …`) writes **`config/install.profile.json`** (gitignored) to record install choices: `lucy_ws` version, `repos_branch` (default `master`), `fetch_method` (`git` or `zip`), and whether **developer install** was selected. The file is created automatically on first install.

| Windows | Linux/macOS equivalent |
|---------|------------------------|
| `Lucy-Setup.exe` → Fresh install | `./install.sh` |
| `Lucy-Setup.exe` → Update | `./install.sh` / `./install.sh --update` |
| `Lucy-Setup.exe` → Repair | `./install.sh --repair` |
| `Lucy.exe` (no args) | `./launch_lucy.sh` / **Launch** in `Lucy.py` |
| `Lucy.exe --cli build-only` | `./install.sh --build-only` |

## `launch_lucy.sh`

Builds the Docker image if needed, mounts the workspace at `/workspace`, sources the built ROS overlay, then:
Expand Down
Loading
Loading