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

This reverts commit 9cd939d354.
reapply-raylib-installer
Cameron Clough 5 days ago
parent 6d0cac5305
commit 472feefcfd
  1. 26
      selfdrive/ui/SConscript
  2. 184
      selfdrive/ui/installer/installer.cc
  3. 28
      selfdrive/ui/installer/installer.h
  4. 3
      selfdrive/ui/installer/inter-ascii.ttf

@ -1,5 +1,6 @@
import os
import json 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, base_libs = [common, messaging, visionipc, transformations,
'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]
@ -75,15 +76,8 @@ if GetOption('extras'):
if arch != "Darwin": if arch != "Darwin":
# build installers # build installers
raylib_env = env.Clone() senv = qt_env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/'] senv['LINKFLAGS'].append('-Wl,-strip-debug')
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" release = "release3"
installers = [ installers = [
@ -93,19 +87,17 @@ if GetOption('extras'):
("openpilot_internal", "nightly-dev"), ("openpilot_internal", "nightly-dev"),
] ]
cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh", cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE") "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: for name, branch in installers:
d = {'BRANCH': f"'\"{branch}\"'"} d = {'BRANCH': f"'\"{branch}\"'"}
if "internal" in name: if "internal" in name:
d['INTERNAL'] = "1" d['INTERNAL'] = "1"
obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) obj = senv.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) f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs)
# keep installers small # keep installers small
assert f[0].get_size() < 1300*1e3, f[0].get_size() assert f[0].get_size() < 370*1e3
# build watch3 # build watch3
if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'):

@ -1,15 +1,19 @@
#include <array> #include <unistd.h>
#include <cassert>
#include <cstdlib>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <string>
#include "common/swaglog.h" #include <QDebug>
#include "common/util.h" #include <QDir>
#include "third_party/raylib/include/raylib.h" #include <QTimer>
#include <QVBoxLayout>
int freshClone(); #include "common/util.h"
int cachedFetch(const std::string &cache); #include "selfdrive/ui/installer/installer.h"
int executeGitCommand(const std::string &cmd); #include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.h"
std::string get_str(std::string const s) { std::string get_str(std::string const s) {
std::string::size_type pos = s.find('?'); 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 GIT_SSH_URL "git@github.com:commaai/openpilot.git"
#define CONTINUE_PATH "/data/continue.sh" #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 INSTALL_PATH "/data/openpilot"
#define TMP_INSTALL_PATH "/data/tmppilot" #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[] 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 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) { void run(const char* cmd) {
int err = std::system(cmd); int err = std::system(cmd);
assert(err == 0); assert(err == 0);
} }
void renderProgress(int progress) { Installer::Installer(QWidget *parent) : QWidget(parent) {
BeginDrawing(); QVBoxLayout *layout = new QVBoxLayout(this);
ClearBackground(BLACK); layout->setContentsMargins(150, 290, 150, 150);
DrawTextEx(font, "Installing...", (Vector2){150, 290}, 110, 0, WHITE); layout->setSpacing(0);
Rectangle bar = {150, 570, (float)GetScreenWidth() - 300, 72};
DrawRectangleRec(bar, (Color){41, 41, 41, 255}); QLabel *title = new QLabel(tr("Installing..."));
progress = std::clamp(progress, 0, 100); title->setStyleSheet("font-size: 90px; font-weight: 600;");
bar.width *= progress / 100.0f; layout->addWidget(title, 0, Qt::AlignTop);
DrawRectangleRec(bar, (Color){70, 91, 234, 255});
DrawTextEx(font, (std::to_string(progress) + "%").c_str(), (Vector2){150, 670}, 85, 0, WHITE); layout->addSpacing(170);
EndDrawing();
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;
}
)");
} }
int doInstall() { void Installer::updateProgress(int percent) {
bar->setValue(percent);
val->setText(QString("%1%").arg(percent));
update();
}
void Installer::doInstall() {
// wait for valid time // wait for valid time
while (!util::system_time_valid()) { while (!util::system_time_valid()) {
util::sleep_for(500); usleep(500 * 1000);
LOGD("Waiting for valid time"); qDebug() << "Waiting for valid time";
} }
// cleanup previous install attempts // cleanup previous install attempts
run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH); run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH);
// do the install // do the install
if (util::file_exists(CACHE_PATH)) { if (QDir(CACHE_PATH).exists()) {
return cachedFetch(CACHE_PATH); cachedFetch(CACHE_PATH);
} else { } else {
return freshClone(); freshClone();
} }
} }
int freshClone() { void Installer::freshClone() {
LOGD("Doing fresh clone"); qDebug() << "Doing fresh clone";
std::string cmd = util::string_format("git clone --progress %s -b %s --depth=1 --recurse-submodules %s 2>&1", proc.start("git", {"clone", "--progress", GIT_URL.c_str(), "-b", BRANCH_STR.c_str(),
GIT_URL.c_str(), BRANCH_STR.c_str(), TMP_INSTALL_PATH); "--depth=1", "--recurse-submodules", TMP_INSTALL_PATH});
return executeGitCommand(cmd);
} }
int cachedFetch(const std::string &cache) { void Installer::cachedFetch(const QString &cache) {
LOGD("Fetching with cache: %s", cache.c_str()); qDebug() << "Fetching with cache: " << cache;
run(util::string_format("cp -rp %s %s", cache.c_str(), TMP_INSTALL_PATH).c_str()); run(QString("cp -rp %1 %2").arg(cache, TMP_INSTALL_PATH).toStdString().c_str());
run(util::string_format("cd %s && git remote set-branches --add origin %s", TMP_INSTALL_PATH, BRANCH_STR.c_str()).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) { void Installer::readProgress() {
static const std::array stages = { const QVector<QPair<QString, int>> stages = {
// prefix, weight in percentage // prefix, weight in percentage
std::pair{"Receiving objects: ", 91}, {"Receiving objects: ", 91},
std::pair{"Resolving deltas: ", 2}, {"Resolving deltas: ", 2},
std::pair{"Updating files: ", 7}, {"Updating files: ", 7},
}; };
FILE *pipe = popen(cmd.c_str(), "r"); auto line = QString(proc.readAllStandardError());
if (!pipe) return -1;
int base = 0;
char buffer[512]; for (const QPair kv : stages) {
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { if (line.startsWith(kv.first)) {
std::string line(buffer); auto perc = line.split(kv.first)[1].split("%")[0];
int base = 0; int p = base + int(perc.toFloat() / 100. * kv.second);
for (const auto &[text, weight] : stages) { updateProgress(p);
if (line.find(text) != std::string::npos) { break;
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 cloneFinished(int exitCode) { void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) {
LOGD("git finished with %d", exitCode); qDebug() << "git finished with " << exitCode;
assert(exitCode == 0); assert(exitCode == 0);
renderProgress(100); updateProgress(100);
// ensure correct branch is checked out // ensure correct branch is checked out
int err = chdir(TMP_INSTALL_PATH); int err = chdir(TMP_INSTALL_PATH);
@ -171,17 +203,13 @@ void cloneFinished(int exitCode) {
run("mv /data/continue.sh.new " CONTINUE_PATH); run("mv /data/continue.sh.new " CONTINUE_PATH);
// wait for the installed software's UI to take over // 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[]) { int main(int argc, char *argv[]) {
InitWindow(2160, 1080, "Installer"); initApp(argc, argv);
font = LoadFontFromMemory(".ttf", inter_ttf, inter_ttf_end - inter_ttf, 120, NULL, 0); QApplication a(argc, argv);
SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR); Installer installer;
renderProgress(0); setMainWindow(&installer);
int result = doInstall(); return a.exec();
cloneFinished(result);
CloseWindow();
UnloadFont(font);
return 0;
} }

@ -0,0 +1,28 @@
#pragma once
#include <QLabel>
#include <QProcess>
#include <QProgressBar>
#include <QWidget>
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);
};

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1ef26a4099ef867f3493389379d882381a2491cdbfa41a086be8899a2154dcb3
size 26160
Loading…
Cancel
Save