Skip to content

Commit

Permalink
raylib installer
Browse files Browse the repository at this point in the history
  • Loading branch information
deanlee committed Oct 9, 2024
1 parent 596d8b1 commit cfe10cd
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 168 deletions.
14 changes: 8 additions & 6 deletions selfdrive/ui/SConscript
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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 @@ -84,8 +84,10 @@ if GetOption('extras') and arch != "Darwin":
qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs)

# 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_frameworks = ['CoreVideo', 'Cocoa', 'GLUT', 'CoreFoundation', 'OpenGL', 'IOKit'] if arch == 'Darwin' else []
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')

release = "release3"
installers = [
Expand All @@ -95,15 +97,15 @@ if GetOption('extras') and arch != "Darwin":
("openpilot_internal", "master"),
]

cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh",
cont = raylib_env.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 = 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], LIBS=['raylib', common], FRAMEWORKS=raylib_frameworks)
# keep installers small
assert f[0].get_size() < 370*1e3

Expand Down
207 changes: 73 additions & 134 deletions selfdrive/ui/installer/installer.cc
Original file line number Diff line number Diff line change
@@ -1,34 +1,21 @@
#include <time.h>
#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 "third_party/raylib/include/raylib.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('?');
assert(pos != std::string::npos);
return s.substr(0, pos);
}

// Leave some extra space for the fork installer
const std::string GIT_URL = get_str("https://github.com/commaai/openpilot.git" "? ");
const std::string BRANCH_STR = get_str(BRANCH "? ");
const std::string GIT_URL = "https://github.com/commaai/openpilot.git";
const std::string BRANCH_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"
Expand All @@ -39,7 +26,6 @@ extern const uint8_t str_continue_end[] asm("_binary_selfdrive_ui_installer_cont
bool time_valid() {
time_t rawtime;
time(&rawtime);

struct tm * sys_time = gmtime(&rawtime);
return (1900 + sys_time->tm_year) >= 2020;
}
Expand All @@ -49,124 +35,68 @@ void run(const char* 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);
DrawText("Installing...", 150, 290, 90, WHITE);
Rectangle bar = {150, 500, (float)GetScreenWidth() - 300, 72};
DrawRectangleRounded(bar, 0.5f, 10, GRAY);
progress = std::clamp(progress, 0, 100);
bar.width *= progress / 100.0f;
DrawRectangleRounded(bar, 0.5f, 10, RAYWHITE);
DrawText((std::to_string(progress) + "%").c_str(), 150, 600, 70, WHITE);
EndDrawing();
}

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

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

// cleanup previous install attempts
run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH);
int executeGitCommand(const std::string &cmd) {
static const std::array stages = {
std::pair{"Receiving objects: ", 91},
std::pair{"Resolving deltas: ", 2},
std::pair{"Updating files: ", 7},
};

// do the install
if (QDir(CACHE_PATH).exists()) {
cachedFetch(CACHE_PATH);
} else {
freshClone();
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 + (percent / 100.0f) * weight;
renderProgress(progress);
}
break;
}
base += weight;
}
}
return pclose(pipe);
}

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});
}

void Installer::cachedFetch(const QString &cache) {
qDebug() << "Fetching with cache: " << cache;

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());

updateProgress(10);

proc.setWorkingDirectory(TMP_INSTALL_PATH);
proc.start("git", {"fetch", "--progress", "origin", BRANCH_STR.c_str()});
int freshClone() {
LOGD("Doing fresh clone");
// Create the git command with redirection of stderr to stdout (2>&1)
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::readProgress() {
const QVector<QPair<QString, int>> stages = {
// prefix, weight in percentage
{"Receiving objects: ", 91},
{"Resolving deltas: ", 2},
{"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;
}
base += kv.second;
}
int cachedFetch(const std::string &cache) {
LOGD("Fetching with cache: %s", cache.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()));
return executeGitCommand(util::string_format("cd %s && git fetch --progress origin %s 2>&1", TMP_INSTALL_PATH, BRANCH_STR.c_str()));
}

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);

// ensure correct branch is checked out
int err = chdir(TMP_INSTALL_PATH);
assert(err == 0);
Expand Down Expand Up @@ -211,13 +141,22 @@ 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(0, 0, "Installer");

renderProgress(0);
while (!time_valid()) {
util::sleep_for(1000);
}

run("rm -rf " TMP_INSTALL_PATH " " INSTALL_PATH); // cleanup previous install attempts
int result = util::file_exists(CACHE_PATH) ? cachedFetch(CACHE_PATH) : freshClone();
cloneFinished(result);
renderProgress(100);

CloseWindow();
return 0;
}
28 changes: 0 additions & 28 deletions selfdrive/ui/installer/installer.h

This file was deleted.

0 comments on commit cfe10cd

Please sign in to comment.