Commit 3d91b436 authored by heretik's avatar heretik
Browse files

construct a clean execution engine

parent f68abfc9
......@@ -13,101 +13,63 @@ MainWindow::MainWindow( QWidget *parent )
, directory_{ fs::temp_directory_path() / "prototypator" }
, process_{ parent }
, plain_text_{ nullptr }
, commands_{}
{
// prepare qt things
ui_ptr_->setupUi( this );
plain_text_.reset( ui_ptr_->plainTextEdit_compilation );
connect( &process_, &QProcess::readyReadStandardOutput, this, &MainWindow::update_std_out );
connect( &process_, &QProcess::readyReadStandardError, this, &MainWindow::update_std_err );
connect( &process_, SIGNAL(finished(int)), this, SLOT(finished(int)));
restore_settings();
}
// TODO c'est de la merde.
// C'est juste pour le prototype.
// Il faut passer par QProcess et pas par std::system pour récupérer correctement
// les messages d'erreurs et les passer dans la zone de texte.
// TODO aussi dégager CMake et utiliser directement gcc ???
void MainWindow::prepare()
{
// check cmake executable
auto errc = std::system( "cmake --version" );
if( errc ) {
throw std::runtime_error( "The program 'cmake' can't be found in the system." );
}
// erase directory
fs::remove_all( directory_ );
// create directory
const auto build_directory = directory_ / "build";
fs::create_directories( build_directory );
// copy files
QFile::copy( ":/resources/CMakeLists.txt", QString::fromStdString( directory_ / "CMakeLists.txt" ) );
QFile::copy( ":/resources/main.cpp", QString::fromStdString( directory_ / "main.cpp" ) );
fs::permissions( directory_ / "main.cpp", fs::perms::owner_write, fs::perm_options::add );
// run cmake
auto os = std::ostringstream{};
os << "cd " << build_directory << " && cmake ..";
errc = std::system( os.str().c_str() );
if( errc ) {
// TODO gestion des erreurs correctes
throw std::runtime_error( "The program"
" 'cmake' failes" );
}
// restore settings
restore_settings();
// Great success !!
is_prepared_ = true;
// prepare context
prepare_directory();
// prepare commands
using namespace std::string_literals;
const auto build_dir = (directory_ / "build").string();
commands_ = {
{
tr( "testing presence of cmake...\n" ).toStdString(),
"cmake --version"
},
{
tr( "running 'cmake'...\n" ).toStdString(),
"cmake -B"s + build_dir + " -H" + directory_.string()
},
{
tr( "running 'make'...\n" ).toStdString(),
"make -C "s + build_dir
},
{
tr( "running application...\n" ).toStdString(),
build_dir + "/prototypator"
},
};
}
// pareil pour ici, il faut virer les access a std::system
// et faire la remontee d'erreur via QProcess
void MainWindow::run()
{
// show compilation tab
// preparation
ui_ptr_->tabWidget->setCurrentIndex( 0 );
const auto build_directory = directory_ / "build";
try {
// ensure preparation has been done
if( not is_prepared_ ) {
prepare();
}
// set plain text
plain_text_.reset( ui_ptr_->plainTextEdit_io );
// copy code
auto fos = std::ofstream{};
fos.exceptions( std::ifstream::failbit );
fos.open( directory_ / "main.cpp", std::fstream::trunc );
fos << ui_ptr_->textEdit_code->toPlainText().toStdString();
fos.close();
// compile
auto os = std::ostringstream{};
os << "cd " << build_directory << " && make";
auto errc = std::system( os.str().c_str() );
if( errc ) {
// TODO gestion des erreurs correctes
throw std::runtime_error( "The program failed to compile." );
}
} catch( const std::exception &e ) {
ui_ptr_->plainTextEdit_compilation->setPlainText( QString{ e.what() } );
return;
}
QApplication::setOverrideCursor( Qt::WaitCursor );
setEnabled( false );
ui_ptr_->plainTextEdit_compilation->clear();
ui_ptr_->plainTextEdit_io->clear();
plain_text_.reset( ui_ptr_->plainTextEdit_compilation );
// show io tab
ui_ptr_->tabWidget->setCurrentIndex( 1 );
// copy code
auto fos = std::ofstream{};
fos.exceptions( std::ifstream::failbit );
fos.open( directory_ / "main.cpp", std::fstream::trunc );
fos << ui_ptr_->textEdit_code->toPlainText().toStdString();
fos.close();
// write output
ui_ptr_->plainTextEdit_io->clear();
process_.start( QString::fromStdString( build_directory / "prototypator" ) );
bool started = process_.waitForStarted();
if( not started ) {
throw std::runtime_error( "Unable to start program." );
}
// go !
current_command_index_ = is_prepared_ ? 2 : 0;
execute_next_command();
}
void MainWindow::update_std_out()
......@@ -122,9 +84,34 @@ void MainWindow::update_std_err()
void MainWindow::finished( int exit_code )
{
auto os = std::ostringstream{};
os << tr( "exited with code " ).toStdString() << exit_code;
append_text( os.str(), Qt::darkGreen );
// execute next command
++current_command_index_;
// check if prepation or compilation is finished
if( exit_code == 0 ) {
if( current_command_index_ == 2 ) {
is_prepared_ = true;
} else if( current_command_index_ == 3 ) {
plain_text_.reset( ui_ptr_->plainTextEdit_io );
ui_ptr_->tabWidget->setCurrentIndex( 1 );
}
}
// if failed or everything finished
if( exit_code != 0 or current_command_index_ == commands_.size() ) {
auto os = std::ostringstream{};
os << process_.program().toStdString()
<< tr( " exited with code " ).toStdString() << exit_code;
append_text( os.str(), exit_code == 0 ? Qt::darkRed : Qt::darkGreen );
// enable
enable();
return;
}
// go next
execute_next_command();
}
MainWindow::~MainWindow() = default;
......@@ -140,6 +127,23 @@ void MainWindow::closeEvent( QCloseEvent *event )
QMainWindow::closeEvent( event );
}
void MainWindow::prepare_directory()
{
// TODO revoir la gestion des repertoires temporaires
// pour pouvoir gérer la gestion de plusieurs applications lancees en meme temps
// erase directory
fs::remove_all( directory_ );
// create directory
fs::create_directories( directory_ / "build" );
// copy files
QFile::copy( ":/resources/CMakeLists.txt", QString::fromStdString( directory_ / "CMakeLists.txt" ) );
QFile::copy( ":/resources/main.cpp", QString::fromStdString( directory_ / "main.cpp" ) );
fs::permissions( directory_ / "main.cpp", fs::perms::owner_write, fs::perm_options::add );
}
void MainWindow::restore_settings()
{
auto settings = QSettings{};
......@@ -150,11 +154,31 @@ void MainWindow::restore_settings()
settings.endGroup();
}
void MainWindow::execute_next_command()
{
const Command &command = commands_.at( current_command_index_ );
append_text( command.introduction, Qt::darkGreen );
process_.start( QString::fromStdString( command.command ) );
bool started = process_.waitForStarted();
if( not started ) {
const auto msg = tr( "failed to start '" ) + process_.program() + '\'';
append_text( msg.toStdString(), Qt::darkRed );
enable();
}
}
void MainWindow::enable()
{
QApplication::restoreOverrideCursor();
setEnabled( true );
}
void MainWindow::append_text( std::string_view text, const QColor &color )
{
auto format = QTextCharFormat{};
format.setForeground( QBrush{ color } );
auto cursor = plain_text_->textCursor();
cursor.movePosition( QTextCursor::End );
auto format = QTextCharFormat{};
format.setForeground( QBrush{ color } );
cursor.insertText( text.data(), format );
plain_text_->moveCursor( QTextCursor::End );
}
......@@ -7,12 +7,17 @@
#include <filesystem>
#include <memory>
// forward declarations
namespace Ui {
class MainWindow;
}
class QPlainTextEdit;
struct Command {
std::string introduction;
std::string command;
};
class MainWindow
: public QMainWindow
{
......@@ -23,18 +28,20 @@ public:
~MainWindow() override;
public slots:
void prepare();
void finished( int exit_code );
void run();
void update_std_out();
void update_std_err();
void finished( int exit_code );
void update_std_out();
protected:
void closeEvent( QCloseEvent *event ) override;
private:
void restore_settings();
void append_text( std::string_view text, const QColor &color );
void enable();
void execute_next_command();
void prepare_directory();
void restore_settings();
private:
std::unique_ptr<Ui::MainWindow> ui_ptr_;
......@@ -42,6 +49,8 @@ private:
std::filesystem::path directory_;
QProcess process_;
std::experimental::observer_ptr<QPlainTextEdit> plain_text_;
std::vector<Command> commands_;
unsigned current_command_index_ = 0;
};
#endif // MAINWINDOW_HPP
......@@ -129,6 +129,9 @@
<property name="readOnly">
<bool>true</bool>
</property>
<property name="centerOnScroll">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
......
......@@ -29,13 +29,42 @@
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.ui" line="138"/>
<location filename="../src/prototypator/mainwindow.ui" line="141"/>
<source>Input/output</source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="126"/>
<source>exited with code </source>
<location filename="../src/prototypator/mainwindow.cpp" line="35"/>
<source>testing presence of cmake...
</source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="39"/>
<source>running &apos;cmake&apos;...
</source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="43"/>
<source>running &apos;make&apos;...
</source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="47"/>
<source>running application...
</source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="104"/>
<source> exited with code </source>
<translation></translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="164"/>
<source>failed to start &apos;</source>
<translation></translation>
</message>
</context>
......
......@@ -29,14 +29,47 @@
<translation>Compilation</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.ui" line="138"/>
<location filename="../src/prototypator/mainwindow.ui" line="141"/>
<source>Input/output</source>
<translation>Entrée/sortie</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="126"/>
<source>exited with code </source>
<translation>terminé avec le code </translation>
<location filename="../src/prototypator/mainwindow.cpp" line="35"/>
<source>testing presence of cmake...
</source>
<translation>test de la présence de cmake...
</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="39"/>
<source>running &apos;cmake&apos;...
</source>
<translation>démarrage de &apos;cmake&apos;...
</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="43"/>
<source>running &apos;make&apos;...
</source>
<translation>démarrage de &apos;make&apos;...
</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="47"/>
<source>running application...
</source>
<translation>démarrage de l&apos;application...
</translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="104"/>
<source> exited with code </source>
<translation> s&apos;est terminé avec le code </translation>
</message>
<message>
<location filename="../src/prototypator/mainwindow.cpp" line="164"/>
<source>failed to start &apos;</source>
<translation>impossible de démarrer &apos;</translation>
</message>
</context>
</TS>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment