From 472feefcfdf20a8f4823e28baf596868fd70391b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 21 May 2025 01:52:14 +0100 Subject: [PATCH] Revert "ui: rewrite installer using raylib, remove qt (#33756)" This reverts commit 9cd939d35497bc6d96607d4f5de3441501facd6f. --- selfdrive/ui/SConscript | 26 ++-- selfdrive/ui/installer/installer.cc | 184 ++++++++++++++----------- selfdrive/ui/installer/installer.h | 28 ++++ selfdrive/ui/installer/inter-ascii.ttf | 3 - 4 files changed, 143 insertions(+), 98 deletions(-) create mode 100644 selfdrive/ui/installer/installer.h delete mode 100644 selfdrive/ui/installer/inter-ascii.ttf diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 7199399d41..e63359da05 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,5 +1,6 @@ +import os import json -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') base_libs = [common, messaging, visionipc, transformations, 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] @@ -75,15 +76,8 @@ if GetOption('extras'): if arch != "Darwin": # build installers - 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"] + senv = qt_env.Clone() + senv['LINKFLAGS'].append('-Wl,-strip-debug') release = "release3" installers = [ @@ -93,19 +87,17 @@ if GetOption('extras'): ("openpilot_internal", "nightly-dev"), ] - 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") + cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh", + "ld -r -b binary -o $TARGET $SOURCE") for name, branch in installers: d = {'BRANCH': f"'\"{branch}\"'"} if "internal" in name: d['INTERNAL'] = "1" - 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) + 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) # keep installers small - assert f[0].get_size() < 1300*1e3, f[0].get_size() + assert f[0].get_size() < 370*1e3 # build watch3 if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): diff --git a/selfdrive/ui/installer/installer.cc b/selfdrive/ui/installer/installer.cc index 7326e089ab..84486e61be 100644 --- a/selfdrive/ui/installer/installer.cc +++ b/selfdrive/ui/installer/installer.cc @@ -1,15 +1,19 @@ -#include -#include +#include + +#include #include #include +#include -#include "common/swaglog.h" -#include "common/util.h" -#include "third_party/raylib/include/raylib.h" +#include +#include +#include +#include -int freshClone(); -int cachedFetch(const std::string &cache); -int executeGitCommand(const std::string &cmd); +#include "common/util.h" +#include "selfdrive/ui/installer/installer.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/qt_window.h" std::string get_str(std::string const s) { std::string::size_type pos = s.find('?'); @@ -24,108 +28,136 @@ 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 std::string CACHE_PATH = "/data/openpilot.cache"; +const QString 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); } -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(); +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::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; + } + )"); } -int doInstall() { +void Installer::updateProgress(int percent) { + bar->setValue(percent); + val->setText(QString("%1%").arg(percent)); + update(); +} + +void Installer::doInstall() { // wait for valid time while (!util::system_time_valid()) { - util::sleep_for(500); - LOGD("Waiting for valid time"); + usleep(500 * 1000); + qDebug() << "Waiting for valid time"; } // cleanup previous install attempts run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH); // do the install - if (util::file_exists(CACHE_PATH)) { - return cachedFetch(CACHE_PATH); + if (QDir(CACHE_PATH).exists()) { + cachedFetch(CACHE_PATH); } else { - return freshClone(); + freshClone(); } } -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::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 cachedFetch(const std::string &cache) { - LOGD("Fetching with cache: %s", cache.c_str()); +void Installer::cachedFetch(const QString &cache) { + qDebug() << "Fetching with cache: " << cache; - 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()); + 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()); - renderProgress(10); + updateProgress(10); - return executeGitCommand(util::string_format("cd %s && git fetch --progress origin %s 2>&1", TMP_INSTALL_PATH, BRANCH_STR.c_str())); + proc.setWorkingDirectory(TMP_INSTALL_PATH); + proc.start("git", {"fetch", "--progress", "origin", BRANCH_STR.c_str()}); } -int executeGitCommand(const std::string &cmd) { - static const std::array stages = { +void Installer::readProgress() { + const QVector> stages = { // prefix, weight in percentage - std::pair{"Receiving objects: ", 91}, - std::pair{"Resolving deltas: ", 2}, - std::pair{"Updating files: ", 7}, + {"Receiving objects: ", 91}, + {"Resolving deltas: ", 2}, + {"Updating files: ", 7}, }; - 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; + 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; } + base += kv.second; } - return pclose(pipe); } -void cloneFinished(int exitCode) { - LOGD("git finished with %d", exitCode); +void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) { + qDebug() << "git finished with " << exitCode; assert(exitCode == 0); - renderProgress(100); + updateProgress(100); // ensure correct branch is checked out int err = chdir(TMP_INSTALL_PATH); @@ -171,17 +203,13 @@ void cloneFinished(int exitCode) { run("mv /data/continue.sh.new " CONTINUE_PATH); // wait for the installed software's UI to take over - util::sleep_for(60 * 1000); + QTimer::singleShot(60 * 1000, &QCoreApplication::quit); } int main(int argc, char *argv[]) { - 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; + initApp(argc, argv); + QApplication a(argc, argv); + Installer installer; + setMainWindow(&installer); + return a.exec(); } diff --git a/selfdrive/ui/installer/installer.h b/selfdrive/ui/installer/installer.h new file mode 100644 index 0000000000..de3af0ff39 --- /dev/null +++ b/selfdrive/ui/installer/installer.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +class Installer : public QWidget { + Q_OBJECT + +public: + explicit Installer(QWidget *parent = 0); + +private slots: + void updateProgress(int percent); + + void readProgress(); + void cloneFinished(int exitCode, QProcess::ExitStatus exitStatus); + +private: + QLabel *val; + QProgressBar *bar; + QProcess proc; + + void doInstall(); + void freshClone(); + void cachedFetch(const QString &cache); +}; diff --git a/selfdrive/ui/installer/inter-ascii.ttf b/selfdrive/ui/installer/inter-ascii.ttf deleted file mode 100644 index 5d480c515a..0000000000 --- a/selfdrive/ui/installer/inter-ascii.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1ef26a4099ef867f3493389379d882381a2491cdbfa41a086be8899a2154dcb3 -size 26160