mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-13 13:22:22 +08:00
ui: rewrite installer using raylib, remove qt (#33756)
* update SConscript Co-authored-by: Dean Lee <deanlee3@gmail.com> * can't build on mac * raylib installer Co-authored-by: Dean Lee <deanlee3@gmail.com> * rm * debug pls * cleanup * quotes * libs? * bump * hmm * progress bar color * more * not rounded * hardcode a font path..? * embed (a subset of) inter into the installer * different in CI * closer font sizes * closer * add that back * unnecessary * closer to previous impl * prefix is at start of string, substr between prefix and % * Revert "prefix is at start of string, substr between prefix and %" This reverts commit bc53fe8e356ca642680e90682285bd5e8d98ecb5. * bigger on device? * rm --------- Co-authored-by: Cameron Clough <cameronjclough@gmail.com>
This commit is contained in:
+17
-9
@@ -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"]
|
||||
@@ -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 = [
|
||||
@@ -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'):
|
||||
|
||||
@@ -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('?');
|
||||
@@ -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) {
|
||||
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());
|
||||
FILE *pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe) return -1;
|
||||
|
||||
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;
|
||||
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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1ef26a4099ef867f3493389379d882381a2491cdbfa41a086be8899a2154dcb3
|
||||
size 26160
|
||||
Reference in New Issue
Block a user