Browse Source

Fixes #431: can now cancel creating/updating build folder

pipelines/235045657
eidheim 5 years ago
parent
commit
727d9c1c0c
  1. 40
      src/cmake.cpp
  2. 40
      src/meson.cpp
  3. 97
      src/terminal.cpp
  4. 4
      src/terminal.hpp

40
src/cmake.cpp

@ -60,15 +60,23 @@ bool CMake::update_default_build(const boost::filesystem::path &default_build_pa
return true; return true;
auto compile_commands_path = default_build_path / "compile_commands.json"; auto compile_commands_path = default_build_path / "compile_commands.json";
Dialog::Message message("Creating/updating default build"); bool canceled = false;
Dialog::Message message("Creating/updating default build", [&canceled] {
canceled = true;
});
std::promise<int> promise; std::promise<int> promise;
Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", auto process = Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
default_build_path, default_build_path,
[&promise](int exit_status) { [&promise](int exit_status) {
promise.set_value(exit_status); promise.set_value(exit_status);
}); });
auto future = promise.get_future(); auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) { while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending()) while(Gtk::Main::events_pending())
Gtk::Main::iteration(); Gtk::Main::iteration();
} }
@ -112,15 +120,23 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
if(!force && boost::filesystem::exists(debug_build_path / "CMakeCache.txt", ec)) if(!force && boost::filesystem::exists(debug_build_path / "CMakeCache.txt", ec))
return true; return true;
Dialog::Message message("Creating/updating debug build"); bool canceled = false;
Dialog::Message message("Creating/updating debug build", [&canceled] {
canceled = true;
});
std::promise<int> promise; std::promise<int> promise;
Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_BUILD_TYPE=Debug", auto process = Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_BUILD_TYPE=Debug",
debug_build_path, debug_build_path,
[&promise](int exit_status) { [&promise](int exit_status) {
promise.set_value(exit_status); promise.set_value(exit_status);
}); });
auto future = promise.get_future(); auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) { while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending()) while(Gtk::Main::events_pending())
Gtk::Main::iteration(); Gtk::Main::iteration();
} }

40
src/meson.cpp

@ -60,15 +60,23 @@ bool Meson::update_default_build(const boost::filesystem::path &default_build_pa
if(!force && compile_commands_exists) if(!force && compile_commands_exists)
return true; return true;
Dialog::Message message("Creating/updating default build"); bool canceled = false;
Dialog::Message message("Creating/updating default build", [&canceled] {
canceled = true;
});
std::promise<int> promise; std::promise<int> promise;
Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype plain " + filesystem::escape_argument(project_path.string()), auto process = Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype plain " + filesystem::escape_argument(project_path.string()),
default_build_path, default_build_path,
[&promise](int exit_status) { [&promise](int exit_status) {
promise.set_value(exit_status); promise.set_value(exit_status);
}); });
auto future = promise.get_future(); auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) { while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending()) while(Gtk::Main::events_pending())
Gtk::Main::iteration(); Gtk::Main::iteration();
} }
@ -94,15 +102,23 @@ bool Meson::update_debug_build(const boost::filesystem::path &debug_build_path,
if(!force && compile_commands_exists) if(!force && compile_commands_exists)
return true; return true;
Dialog::Message message("Creating/updating debug build"); bool canceled = false;
Dialog::Message message("Creating/updating debug build", [&canceled] {
canceled = true;
});
std::promise<int> promise; std::promise<int> promise;
Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype debug " + filesystem::escape_argument(project_path.string()), auto process = Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype debug " + filesystem::escape_argument(project_path.string()),
debug_build_path, debug_build_path,
[&promise](int exit_status) { [&promise](int exit_status) {
promise.set_value(exit_status); promise.set_value(exit_status);
}); });
auto future = promise.get_future(); auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) { while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending()) while(Gtk::Main::events_pending())
Gtk::Main::iteration(); Gtk::Main::iteration();
} }

97
src/terminal.cpp

@ -254,61 +254,61 @@ int Terminal::process(std::istream &stdin_stream, std::ostream &stdout_stream, c
return process.get_exit_status(); return process.get_exit_status();
} }
void Terminal::async_process(const std::string &command, const boost::filesystem::path &path, const std::function<void(int exit_status)> &callback, bool quiet) { std::shared_ptr<TinyProcessLib::Process> Terminal::async_process(const std::string &command, const boost::filesystem::path &path, std::function<void(int exit_status)> callback, bool quiet) {
std::thread async_execute_thread([this, command, path, callback, quiet]() { stdin_buffer.clear();
perform_scroll_to_bottom = true; perform_scroll_to_bottom = true;
LockGuard lock(processes_mutex);
stdin_buffer.clear(); auto process = std::make_shared<TinyProcessLib::Process>(command, path.string(), [this, quiet](const char *bytes, size_t n) {
auto process = std::make_shared<TinyProcessLib::Process>(command, path.string(), [this, quiet](const char *bytes, size_t n) { if(!quiet) {
if(!quiet) { // Print stdout message sequentially to avoid the GUI becoming unresponsive
// Print stdout message sequentially to avoid the GUI becoming unresponsive std::promise<void> message_printed;
std::promise<void> message_printed; dispatcher.post([message = std::string(bytes, n), &message_printed]() mutable {
dispatcher.post([message = std::string(bytes, n), &message_printed]() mutable { Terminal::get().print(std::move(message));
Terminal::get().print(std::move(message)); message_printed.set_value();
message_printed.set_value(); });
}); message_printed.get_future().get();
message_printed.get_future().get();
}
}, [this, quiet](const char *bytes, size_t n) {
if(!quiet) {
// Print stderr message sequentially to avoid the GUI becoming unresponsive
std::promise<void> message_printed;
dispatcher.post([message = std::string(bytes, n), &message_printed]() mutable {
Terminal::get().print(std::move(message), true);
message_printed.set_value();
});
message_printed.get_future().get();
}
}, true);
auto pid = process->get_id();
if(pid <= 0) {
lock.unlock();
async_print("Error: failed to run command: " + command + "\n", true);
if(callback)
callback(-1);
return;
} }
else { }, [this, quiet](const char *bytes, size_t n) {
processes.emplace_back(process); if(!quiet) {
lock.unlock(); // Print stderr message sequentially to avoid the GUI becoming unresponsive
std::promise<void> message_printed;
dispatcher.post([message = std::string(bytes, n), &message_printed]() mutable {
Terminal::get().print(std::move(message), true);
message_printed.set_value();
});
message_printed.get_future().get();
} }
}, true);
auto exit_status = process->get_exit_status(); auto pid = process->get_id();
if(pid <= 0) {
async_print("Error: failed to run command: " + command + "\n", true);
if(callback)
callback(-1);
return process;
}
else {
LockGuard lock(processes_mutex);
processes.emplace_back(process);
}
lock.lock(); std::thread exit_status_thread([this, process, pid, callback = std::move(callback)]() {
for(auto it = processes.begin(); it != processes.end(); it++) { auto exit_status = process->get_exit_status();
if((*it)->get_id() == pid) { {
processes.erase(it); LockGuard lock(processes_mutex);
break; for(auto it = processes.begin(); it != processes.end(); it++) {
if((*it)->get_id() == pid) {
processes.erase(it);
break;
}
} }
} }
stdin_buffer.clear();
lock.unlock();
if(callback) if(callback)
callback(exit_status); callback(exit_status);
}); });
async_execute_thread.detach(); exit_status_thread.detach();
return process;
} }
void Terminal::kill_last_async_process(bool force) { void Terminal::kill_last_async_process(bool force) {
@ -410,9 +410,10 @@ void Terminal::print(std::string message, bool bold) {
if(!parent->is_visible()) if(!parent->is_visible())
parent->show(); parent->show();
bool expected = true; if(perform_scroll_to_bottom == true && scroll_to_bottom) {
if(perform_scroll_to_bottom.compare_exchange_strong(expected, false) && scroll_to_bottom) perform_scroll_to_bottom = false;
scroll_to_bottom(); scroll_to_bottom();
}
} }
Glib::ustring umessage = std::move(message); Glib::ustring umessage = std::move(message);

4
src/terminal.hpp

@ -21,7 +21,7 @@ public:
int process(const std::string &command, const boost::filesystem::path &path = "", bool use_pipes = true); int process(const std::string &command, const boost::filesystem::path &path = "", bool use_pipes = true);
int process(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path = "", std::ostream *stderr_stream = nullptr); int process(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path = "", std::ostream *stderr_stream = nullptr);
void async_process(const std::string &command, const boost::filesystem::path &path = "", const std::function<void(int exit_status)> &callback = nullptr, bool quiet = false); std::shared_ptr<TinyProcessLib::Process> async_process(const std::string &command, const boost::filesystem::path &path = "", std::function<void(int exit_status)> callback = nullptr, bool quiet = false);
void kill_last_async_process(bool force = false); void kill_last_async_process(bool force = false);
void kill_async_processes(bool force = false); void kill_async_processes(bool force = false);
@ -61,5 +61,5 @@ private:
std::vector<std::shared_ptr<TinyProcessLib::Process>> processes GUARDED_BY(processes_mutex); std::vector<std::shared_ptr<TinyProcessLib::Process>> processes GUARDED_BY(processes_mutex);
Glib::ustring stdin_buffer; Glib::ustring stdin_buffer;
std::atomic<bool> perform_scroll_to_bottom = {false}; bool perform_scroll_to_bottom = false;
}; };

Loading…
Cancel
Save