@ -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 QS tring CACHE_PATH = " /data/openpilot.cache " ;
const std : : s tring 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 : # 364 DEF ;
}
) " );
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 * 10 00 ) ;
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 QS tring & 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 ( ) ) ;
update Progress( 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 ( ) ) ;
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 ;
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 ;
}
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 ) ;
update Progress( 100 ) ;
render Progress( 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 ;
}