10000 Reapply "ui: rewrite installer using raylib, remove qt (#33756)" by incognitojam · Pull Request #35308 · commaai/openpilot · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Reapply "ui: rewrite installer using raylib, remove qt (#33756)" #35308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 27, 2025
Merged
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
26 changes: 17 additions & 9 deletions selfdrive/ui/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os
import json
Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations')
Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations')

base_libs = [common, messaging, visionipc, transformations,
'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]
Expand Down Expand Up @@ -76,8 +75,15 @@ if GetOption('extras'):

if arch != "Darwin":
# build installers
senv = qt_env.Clone()
senv['LINKFLAGS'].append('-Wl,-strip-debug')
raylib_env = env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')

raylib_libs = common + ["raylib"]
if arch == "larch64":
raylib_libs += ["GLESv2", "wayland-client", "wayland-egl", "EGL"]
else:
raylib_libs += ["GL"]

release = "release3"
installers = [
Expand All @@ -87,17 +93,19 @@ if GetOption('extras'):
("openpilot_internal", "nightly-dev"),
]

cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE")
cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE")
inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
for name, branch in installers:
d = {'BRANCH': f"'\"{branch}\"'"}
if "internal" in name:
d['INTERNAL'] = "1"

obj = senv.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d)
f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs)
obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d)
f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs)
# keep installers small
assert f[0].get_size() < 370*1e3
assert f[0].get_size() < 1300*1e3, f[0].get_size()

# build watch3
if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'):
Expand Down
184 changes: 78 additions & 106 deletions selfdrive/ui/installer/installer.cc
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
#include <unistd.h>

#include <cstdlib>
#include <array>
#include <cassert>
#include <fstream>
#include <map>
#include <string>

#include <QDebug>
#include <QDir>
#include <QTimer>
#include <QVBoxLayout>

#include "common/swaglog.h"
#include "common/util.h"
#include "selfdrive/ui/installer/installer.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.h"
#include "third_party/raylib/include/raylib.h"

int freshClone();
int cachedFetch(const std::string &cache);
int executeGitCommand(const std::string &cmd);

std::string get_str(std::string const s) {
std::string::size_type pos = s.find('?');
Expand All @@ -28,136 +24,108 @@ const std::string BRANCH_STR = get_str(BRANCH "?
#define GIT_SSH_URL "git@github.com:commaai/openpilot.git"
#define CONTINUE_PATH "/data/continue.sh"

const QString CACHE_PATH = "/data/openpilot.cache";
const std::string CACHE_PATH = "/data/openpilot.cache";

#define INSTALL_PATH "/data/openpilot"
#define TMP_INSTALL_PATH "/data/tmppilot"

extern const uint8_t str_continue[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_start");
extern const uint8_t str_continue_end[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_end");
extern const uint8_t inter_ttf[] asm("_binary_selfdrive_ui_installer_inter_ascii_ttf_start");
extern const uint8_t inter_ttf_end[] asm("_binary_selfdrive_ui_installer_inter_ascii_ttf_end");

Font font;

void run(const char* cmd) {
int err = std::system(cmd);
assert(err == 0);
}

Installer::Installer(QWidget *parent) : QWidget(parent) {
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(150, 290, 150, 150);
layout->setSpacing(0);

QLabel *title = new QLabel(tr("Installing..."));
title->setStyleSheet("font-size: 90px; font-weight: 600;");
layout->addWidget(title, 0, Qt::AlignTop);

layout->addSpacing(170);

bar = new QProgressBar();
bar->setRange(0, 100);
bar->setTextVisible(false);
bar->setFixedHeight(72);
layout->addWidget(bar, 0, Qt::AlignTop);

layout->addSpacing(30);

val = new QLabel("0%");
val->setStyleSheet("font-size: 70px; font-weight: 300;");
layout->addWidget(val, 0, Qt::AlignTop);

layout->addStretch();

QObject::connect(&proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &Installer::cloneFinished);
QObject::connect(&proc, &QProcess::readyReadStandardError, this, &Installer::readProgress);

QTimer::singleShot(100, this, &Installer::doInstall);

setStyleSheet(R"(
* {
font-family: Inter;
color: white;
background-color: black;
}
QProgressBar {
border: none;
background-color: #292929;
}
QProgressBar::chunk {
background-color: #364DEF;
}
)");
void renderProgress(int progress) {
BeginDrawing();
ClearBackground(BLACK);
DrawTextEx(font, "Installing...", (Vector2){150, 290}, 110, 0, WHITE);
Rectangle bar = {150, 570, (float)GetScreenWidth() - 300, 72};
DrawRectangleRec(bar, (Color){41, 41, 41, 255});
progress = std::clamp(progress, 0, 100);
bar.width *= progress / 100.0f;
DrawRectangleRec(bar, (Color){70, 91, 234, 255});
DrawTextEx(font, (std::to_string(progress) + "%").c_str(), (Vector2){150, 670}, 85, 0, WHITE);
EndDrawing();
}

void Installer::updateProgress(int percent) {
bar->setValue(percent);
val->setText(QString("%1%").arg(percent));
update();
}

void Installer::doInstall() {
int doInstall() {
// wait for valid time
while (!util::system_time_valid()) {
usleep(500 * 1000);
qDebug() << "Waiting for valid time";
util::sleep_for(500);
LOGD("Waiting for valid time");
}

// cleanup previous install attempts
run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH);

// do the install
if (QDir(CACHE_PATH).exists()) {
cachedFetch(CACHE_PATH);
if (util::file_exists(CACHE_PATH)) {
return cachedFetch(CACHE_PATH);
} else {
freshClone();
return freshClone();
}
}

void Installer::freshClone() {
qDebug() << "Doing fresh clone";
proc.start("git", {"clone", "--progress", GIT_URL.c_str(), "-b", BRANCH_STR.c_str(),
"--depth=1", "--recurse-submodules", TMP_INSTALL_PATH});
int freshClone() {
LOGD("Doing fresh clone");
std::string cmd = util::string_format("git clone --progress %s -b %s --depth=1 --recurse-submodules %s 2>&1",
GIT_URL.c_str(), BRANCH_STR.c_str(), TMP_INSTALL_PATH);
return executeGitCommand(cmd);
}

void Installer::cachedFetch(const QString &cache) {
qDebug() << "Fetching with cache: " << cache;
int cachedFetch(const std::string &cache) {
8000 LOGD("Fetching with cache: %s", cache.c_str());

run(QString("cp -rp %1 %2").arg(cache, TMP_INSTALL_PATH).toStdString().c_str());
int err = chdir(TMP_INSTALL_PATH);
assert(err == 0);
run(("git remote set-branches --add origin " + BRANCH_STR).c_str());
run(util::string_format("cp -rp %s %s", cache.c_str(), TMP_INSTALL_PATH).c_str());
run(util::string_format("cd %s && git remote set-branches --add origin %s", TMP_INSTALL_PATH, BRANCH_STR.c_str()).c_str());

updateProgress(10);
renderProgress(10);

proc.setWorkingDirectory(TMP_INSTALL_PATH);
proc.start("git", {"fetch", "--progress", "origin", BRANCH_STR.c_str()});
return executeGitCommand(util::string_format("cd %s && git fetch --progress origin %s 2>&1", TMP_INSTALL_PATH, BRANCH_STR.c_str()));
}

void Installer::readProgress() {
const QVector<QPair<QString, int>> stages = {
int executeGitCommand(const std::string &cmd) {
static const std::array stages = {
// prefix, weight in percentage
{"Receiving objects: ", 91},
{"Resolving deltas: ", 2},
{"Updating files: ", 7},
std::pair{"Receiving objects: ", 91},
std::pair{"Resolving deltas: ", 2},
std::pair{"Updating files: ", 7},
};

auto line = QString(proc.readAllStandardError());

int base = 0;
for (const QPair kv : stages) {
if (line.startsWith(kv.first)) {
auto perc = line.split(kv.first)[1].split("%")[0];
int p = base + int(perc.toFloat() / 100. * kv.second);
updateProgress(p);
break;
FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe) return -1;

char buffer[512];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
std::string line(buffer);
int base = 0;
for (const auto &[text, weight] : stages) {
if (line.find(text) != std::string::npos) {
size_t percentPos = line.find("%");
if (percentPos != std::string::npos && percentPos >= 3) {
int percent = std::stoi(line.substr(percentPos - 3, 3));
int progress = base + int(percent / 100. * weight);
renderProgress(progress);
}
break;
}
base += weight;
}
base += kv.second;
}
return pclose(pipe);
}

void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << "git finished with " << exitCode;
void cloneFinished(int exitCode) {
LOGD("git finished with %d", exitCode);
assert(exitCode == 0);

updateProgress(100);
renderProgress(100);

// ensure correct branch is checked out
int err = chdir(TMP_INSTALL_PATH);
Expand Down Expand Up @@ -203,13 +171,17 @@ void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) {
run("mv /data/continue.sh.new " CONTINUE_PATH);

// wait for the installed software's UI to take over
QTimer::singleShot(60 * 1000, &QCoreApplication::quit);
util::sleep_for(60 * 1000);
}

int main(int argc, char *argv[]) {
initApp(argc, argv);
QApplication a(argc, argv);
Installer installer;
setMainWindow(&installer);
return a.exec();
InitWindow(2160, 1080, "Installer");
font = LoadFontFromMemory(".ttf", inter_ttf, inter_ttf_end - inter_ttf, 120, NULL, 0);
SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR);
renderProgress(0);
int result = doInstall();
cloneFinished(result);
CloseWindow();
UnloadFont(font);
return 0;
}
28 changes: 0 additions & 28 deletions selfdrive/ui/installer/installer.h

This file was deleted.

3 changes: 3 additions & 0 deletions selfdrive/ui/installer/inter-ascii.ttf
Git LFS file not shown
Loading
0