raylib installer

Co-authored-by: Dean Lee <deanlee3@gmail.com>
pull/33756/head
Cameron Clough 3 weeks ago
parent 5053947991
commit f0a8c2bf15
  1. 179
      selfdrive/ui/installer/installer.cc
  2. 28
      selfdrive/ui/installer/installer.h

@ -1,19 +1,17 @@
#include <unistd.h> #include <time.h>
#include <cstdlib> #include <array>
#include <cassert>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <string>
#include <QDebug>
#include <QDir>
#include <QTimer>
#include <QVBoxLayout>
#include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/ui/installer/installer.h" #include "third_party/raylib/include/raylib.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.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 get_str(std::string const s) {
std::string::size_type pos = s.find('?'); std::string::size_type pos = s.find('?');
@ -28,7 +26,7 @@ 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 QString CACHE_PATH = "/data/openpilot.cache"; const std::string 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"
@ -41,123 +39,91 @@ void run(const char* cmd) {
assert(err == 0); assert(err == 0);
} }
Installer::Installer(QWidget *parent) : QWidget(parent) { void renderProgress(int progress) {
QVBoxLayout *layout = new QVBoxLayout(this); BeginDrawing();
layout->setContentsMargins(150, 290, 150, 150); ClearBackground(BLACK);
layout->setSpacing(0); DrawText("Installing...", 150, 290, 90, WHITE);
Rectangle bar = {150, 500, (float)GetScreenWidth() - 300, 72};
QLabel *title = new QLabel(tr("Installing...")); DrawRectangleRounded(bar, 0.5f, 10, GRAY);
title->setStyleSheet("font-size: 90px; font-weight: 600;"); progress = std::clamp(progress, 0, 100);
layout->addWidget(title, 0, Qt::AlignTop); bar.width *= progress / 100.0f;
DrawRectangleRounded(bar, 0.5f, 10, RAYWHITE);
layout->addSpacing(170); DrawText((std::to_string(progress) + "%").c_str(), 150, 600, 70, WHITE);
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;
}
)");
} }
void Installer::updateProgress(int percent) { int doInstall() {
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()) {
usleep(500 * 1000); util::sleep_for(500);
qDebug() << "Waiting for valid time"; LOGD("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 (QDir(CACHE_PATH).exists()) { if (util::file_exists(CACHE_PATH)) {
cachedFetch(CACHE_PATH); return cachedFetch(CACHE_PATH);
} else { } else {
freshClone(); return freshClone();
} }
} }
void Installer::freshClone() { int freshClone() {
qDebug() << "Doing fresh clone"; LOGD("Doing fresh clone");
proc.start("git", {"clone", "--progress", GIT_URL.c_str(), "-b", BRANCH_STR.c_str(), // Create the git command with redirection of stderr to stdout (2>&1)
"--depth=1", "--recurse-submodules", TMP_INSTALL_PATH}); 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) { int cachedFetch(const std::string &cache) {
qDebug() << "Fetching with cache: " << cache; LOGD("Fetching with cache: %s", cache.c_str());
run(QString("cp -rp %1 %2").arg(cache, TMP_INSTALL_PATH).toStdString().c_str()); run(util::string_format("cp -rp %s %s", cache.c_str(), TMP_INSTALL_PATH).c_str());
int err = chdir(TMP_INSTALL_PATH); run((util::string_format("cd %s && git remote set-branches --add origin %s", TMP_INSTALL_PATH, BRANCH_STR.c_str()).c_str()));
assert(err == 0);
run(("git remote set-branches --add origin " + BRANCH_STR).c_str());
updateProgress(10); renderProgress(10);
proc.setWorkingDirectory(TMP_INSTALL_PATH); return executeGitCommand(util::string_format("cd %s && git fetch --progress origin %s 2>&1", TMP_INSTALL_PATH, BRANCH_STR.c_str()));
proc.start("git", {"fetch", "--progress", "origin", BRANCH_STR.c_str()});
} }
void Installer::readProgress() { int executeGitCommand(const std::string &cmd) {
const QVector<QPair<QString, int>> stages = { static const std::array stages = {
// 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},
}; };
auto line = QString(proc.readAllStandardError()); FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe) return -1;
int base = 0;
for (const QPair kv : stages) { char buffer[512];
if (line.startsWith(kv.first)) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
auto perc = line.split(kv.first)[1].split("%")[0]; std::string line(buffer);
int p = base + int(perc.toFloat() / 100. * kv.second); int base = 0;
updateProgress(p); for (const auto &[text, weight] : stages) {
break; 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 + (percent / 100.0f) * weight;
renderProgress(progress);
}
break;
}
base += weight;
} }
base += kv.second;
} }
return pclose(pipe);
} }
void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) { void cloneFinished(int exitCode) {
qDebug() << "git finished with " << exitCode; LOGD("git finished with %d", exitCode);
assert(exitCode == 0); assert(exitCode == 0);
updateProgress(100); renderProgress(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);
@ -203,13 +169,14 @@ void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) {
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
QTimer::singleShot(60 * 1000, &QCoreApplication::quit); util::sleep_for(60 * 1000);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
initApp(argc, argv); InitWindow(2160, 1080, "Installer");
QApplication a(argc, argv); renderProgress(0);
Installer installer; int result = doInstall();
setMainWindow(&installer); cloneFinished(result);
return a.exec(); CloseWindow();
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);
};
Loading…
Cancel
Save