binpack/MainWidget.cpp
2025-02-07 10:44:02 +08:00

316 lines
9.3 KiB
C++

#include "MainWidget.h"
#include "./ui_MainWidget.h"
#include "adddesktop.h"
#include <QTextStream>
#include <fstream>
#include <of_path.h>
#include <of_str.h>
using namespace ofen;
MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
{
ui->setupUi(this);
setWindowTitle("binpack v1.0.5");
connect_operator();
control_init();
}
MainWidget::~MainWidget()
{
delete ui;
}
void MainWidget::connect_operator()
{
connect(ui->btnSelcetBinary, &QPushButton::clicked, this,
[=]() { SelectFile(this, ui->edBinary, "请选择二进制文件", "所有文件 (*)"); });
connect(ui->btnSelectOut, &QPushButton::clicked, this, [=]() { SelectDirectory(this, ui->edOutDir); });
connect(ui->btnAddEnv, &QPushButton::clicked, this, [=]() { add_env_btn(); });
connect(ui->btnDelEnv, &QPushButton::clicked, this, [=]() { del_env_btn(); });
connect(ui->btnGenerate, &QPushButton::clicked, this, [=]() { generate(); });
connect(ui->btnInstall, &QPushButton::clicked, this, [=]() { install_bin2menu(); });
connect(ui->btnExit, &QPushButton::clicked, this, [=]() { QApplication::exit(); });
}
void MainWidget::control_init()
{
ui->plainTextEdit->setReadOnly(true);
ui->edOutDir->setText(QDir::homePath() + "/program");
#if !defined(NDEBUG)
#endif
}
void MainWidget::add_env_btn()
{
QString env = SelectDirectory(this, nullptr);
if (env.isEmpty()) {
return;
}
ui->listWidget->addItem(env);
}
void MainWidget::simple_log(const QString& info, bool enter)
{
// dd
if (enter) {
ui->plainTextEdit->appendPlainText(info + "\n");
} else {
ui->plainTextEdit->appendPlainText(info);
}
}
// 将二进制文件安装到菜单栏
void MainWidget::install_bin2menu()
{
// QString bin = SelectFile(this, ui->edBinary, "请选择二进制可执行文件", "所有文件 (*)");
// if (bin.isEmpty()) {
// return;
// }
AddDesktop add(this);
add.exec();
}
// 将某个文件夹拷贝到制定目录下
bool MainWidget::copy_dir(const std::string& source_dir, const std::string& des_dir)
{
if (!fs::exists(source_dir) || !fs::exists(des_dir)) {
return false;
}
fs::path des_parent_dir = fs::path(des_dir).append(fs::path(source_dir).filename().string());
if (!fs::exists(des_parent_dir)) {
fs::create_directories(des_parent_dir);
}
std::list<fs::path> paths{};
for (const auto& entry : fs::directory_iterator(source_dir)) {
paths.push_back(entry);
}
while (!paths.empty()) {
fs::path path = paths.front();
paths.pop_front();
fs::path destination(COfStr::replace(path.string(), source_dir, des_parent_dir.string()));
if (fs::is_directory(path)) {
if (!fs::exists(destination)) {
fs::create_directories(destination);
}
for (const auto& entry : fs::directory_iterator(path)) {
paths.push_back(entry);
}
continue;
}
fs::copy_file(path, destination, fs::copy_options::overwrite_existing);
}
return true;
}
std::vector<std::string> MainWidget::get_depend_on(const std::string& name,
const std::vector<std::string>& env)
{
std::vector<std::string> vec;
std::string cmd{};
if (!env.empty()) {
cmd.append("export LD_LIBRARY_PATH=$LD_LIBRARY_PATH");
for (const auto& data : env) {
cmd.append(":" + data);
}
}
cmd.append(" && ldd " + name);
char buffer[1024]{};
FILE* pf = nullptr;
if ((pf = popen(cmd.c_str(), "r")) == nullptr) {
return vec;
}
std::string result{};
while (std::fgets(buffer, sizeof(buffer), pf)) {
result.append(buffer);
}
vec = COfStr::split(result, "\t");
return vec;
}
std::list<std::string> MainWidget::handle_result(const std::vector<std::string>& vec)
{
std::list<std::string> ret;
for (const auto& data : vec) {
if (data.empty()) {
continue;
}
if (data.find("not found") == 0) {
simple_log(QString::fromStdString("未找到依赖:" + data), false);
continue;
}
std::string tdata = COfStr::replace(data, "=>", "");
std::vector<std::string> vt = COfStr::split(tdata, " ");
if (vt.size() != 4) {
// QString info = "原始数据:" + QString::fromStdString(data);
// simple_log(info, false);
continue;
}
if (vt[2].find("/lib") == 0) {
continue;
}
ret.push_back(vt[2]);
// simple_log(QString::fromStdString(vt[2]), false);
}
return ret;
}
void MainWidget::del_env_btn()
{
QListWidgetItem* item = ui->listWidget->currentItem();
if (!item) {
return;
}
delete ui->listWidget->takeItem(ui->listWidget->currentRow());
}
QString MainWidget::SelectDirectory(QWidget* parent, QLineEdit* pEdit, const QString& pre_path)
{
QString start_path = pre_path;
QDir folder(start_path);
if (start_path.isEmpty() || !folder.exists()) {
start_path = QDir::homePath();
}
QString selectedDirectory = QFileDialog::getExistingDirectory(parent, u8"选择文件夹", start_path);
if (selectedDirectory.isEmpty()) {
return "";
}
if (pEdit) {
pEdit->setText(selectedDirectory);
}
return selectedDirectory;
}
QString MainWidget::SelectFile(QWidget* parent, QLineEdit* pEdit, const QString& info, const QString& filter)
{
QString filePath = QFileDialog::getOpenFileName(parent, info, QDir::homePath(), filter);
if (!filePath.isEmpty() && pEdit) {
pEdit->setText(filePath);
}
return filePath;
}
bool MainWidget::isOk(QWidget* parent, const QString& title, const QString& content)
{
QMessageBox questionBox(parent);
questionBox.setText(content);
questionBox.setWindowTitle(title);
questionBox.setIcon(QMessageBox::Question);
questionBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
int result = questionBox.exec();
if (result != QMessageBox::Yes) {
return false;
} else {
return true;
}
}
void MainWidget::message(QWidget* parent, const QString& content)
{
QMessageBox::information(parent, "提示", content);
}
void MainWidget::cmd_exec(const std::string& cmd)
{
int r = system(cmd.c_str());
(void)r;
}
void MainWidget::generate()
{
ui->plainTextEdit->clear();
envs_.clear();
sos_.clear();
binary_ = ui->edBinary->text().trimmed();
fs::path binary_dir = fs::path(binary_.toStdString()).parent_path();
envs_.push_back(binary_dir.string());
std::string filename = fs::path(binary_.toStdString()).filename().string();
int env_cnt = ui->listWidget->count();
for (int i = 0; i < env_cnt; ++i) {
envs_.push_back(ui->listWidget->item(i)->text().toStdString());
}
auto retPrevious = get_depend_on(binary_.toStdString(), envs_);
auto result = handle_result(retPrevious);
std::vector<std::string> dynamic_so{};
std::copy(result.begin(), result.end(), std::back_inserter(dynamic_so));
while (!result.empty()) {
std::string bin = result.front();
result.pop_front();
auto tmp_retPrevious = get_depend_on(bin, envs_);
auto tmp_result = handle_result(tmp_retPrevious);
for (const auto& data : tmp_result) {
auto iter = std::find(dynamic_so.begin(), dynamic_so.end(), data);
if (iter != dynamic_so.end()) {
continue;
}
dynamic_so.push_back(data);
result.push_back(data);
}
}
fs::path out_dir(ui->edOutDir->text().trimmed().toStdString());
out_dir.append(filename);
if (!fs::exists(out_dir)) {
fs::create_directories(out_dir);
}
for (const auto& data : dynamic_so) {
std::string purpose = fs::path(out_dir).append(fs::path(data).filename().string()).string();
fs::copy_file(data, purpose, fs::copy_options::overwrite_existing);
}
// 复制主体文件
fs::path out_binary = fs::path(out_dir).append(fs::path(binary_.toStdString()).filename().string());
fs::copy_file(binary_.toStdString(), out_binary, fs::copy_options::overwrite_existing);
if (!add_run_sh(out_dir.string(), filename, std::vector<std::string>())) {
return;
}
message(this, "完成");
}
bool MainWidget::add_run_sh(const std::string& out_dir, const std::string& exe_name, const std::vector<std::string>& exports)
{
// 生成一个启动文件夹
QFile file("://resource/run.sh");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return false;
}
QTextStream in(&file);
// 读取文件内容
QString content = in.readAll();
file.close();
std::string run_sh = content.toStdString();
run_sh = COfStr::replace(run_sh, "replace_string", exe_name);
// REPLACE_EXPORT
std::string outs{};
for (const auto& item : exports) {
outs = outs + "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:" + item + "\n";
}
run_sh = COfStr::replace(run_sh, "REPLACE_EXPORT", outs);
std::string out_sh = fs::path(out_dir).append(exe_name + ".sh").string();
std::ofstream out(out_sh, std::ios::out);
if (!out.is_open()) {
return false;
}
out << run_sh;
out.close();
cmd_exec(std::string("chmod +x " + out_sh));
return true;
}