多线程
This commit is contained in:
@@ -19,25 +19,28 @@ BranchSelector::BranchSelector(wxWindow* parent, std::shared_ptr<git::Repository
|
||||
// 创建下拉列表
|
||||
branch_combo_ = new wxComboBox(this, wxID_ANY);
|
||||
|
||||
// 填充分支列表
|
||||
const auto& branches = repo->GetAllBranches();
|
||||
for (const auto& branch : branches.value()) {
|
||||
branch_combo_->Append(branch);
|
||||
}
|
||||
|
||||
auto result = repo->GetCurrentBranchName();
|
||||
// 选择当前分支
|
||||
if (!result.has_value()) {
|
||||
ProcessResult(result);
|
||||
return;
|
||||
}
|
||||
branch_combo_->SetStringSelection(result.value());
|
||||
|
||||
// 布局
|
||||
hbox->Add(label_ctrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
|
||||
hbox->Add(branch_combo_, 1);
|
||||
|
||||
SetSizerAndFit(hbox);
|
||||
|
||||
// 填充分支列表
|
||||
repo->GetAllBranches([this](const std::expected<std::vector<std::string>, std::string>& branches) {
|
||||
for (const auto& branch : branches.value()) {
|
||||
branch_combo_->Append(branch);
|
||||
}
|
||||
});
|
||||
|
||||
repo->GetCurrentBranchName([this](const std::expected<std::string, std::string>& result) {
|
||||
// 选择当前分支
|
||||
if (!result.has_value()) {
|
||||
ProcessResult(result);
|
||||
}
|
||||
else {
|
||||
branch_combo_->SetStringSelection(result.value());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool BranchSelector::SelectBranch(const wxString& branch_name) {
|
||||
@@ -81,22 +84,55 @@ std::string BranchSelector::GetSelectedBranchName() const {
|
||||
return branch_combo_->GetStringSelection().ToStdString();
|
||||
}
|
||||
|
||||
std::expected<std::string, std::string> BranchSelector::ApplyBranchChange() {
|
||||
void BranchSelector::ApplyBranchChange() {
|
||||
const std::string selected_branch = GetSelectedBranchName();
|
||||
if (selected_branch.empty()) {
|
||||
return std::unexpected("No branch selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// 先切换分支
|
||||
if (auto switch_result = repo_->SwitchBranch(selected_branch); !switch_result.has_value()) { return switch_result; }
|
||||
repo_->SwitchBranch(selected_branch, [this](const git::result_t& result) {
|
||||
ProcessResult(result);
|
||||
if (!result.has_value()) {
|
||||
wxLogError("%s SwitchBranch: %s", repo_->GetName(), result.error());
|
||||
return;
|
||||
}
|
||||
wxLogInfo("%s SwitchBranch: %s", repo_->GetName(), result.value());
|
||||
// 分支切换成功后,更新当前分支名称
|
||||
branch_combo_->SetStringSelection(result.value());
|
||||
|
||||
// 如果需要硬重置
|
||||
if (ConfigManager::Instance().GetHardReset()) {
|
||||
if (auto reset_result = repo_->HardReset(); !reset_result) { return reset_result; }
|
||||
}
|
||||
// 如果需要硬重置
|
||||
if (ConfigManager::Instance().GetHardReset()) {
|
||||
repo_->HardReset([this](const git::result_t& reset_result) {
|
||||
ProcessResult(reset_result);
|
||||
if (!reset_result.has_value()) {
|
||||
wxLogError("%s HardReset: %s", repo_->GetName(), reset_result.error());
|
||||
return;
|
||||
}
|
||||
|
||||
// 拉取更新
|
||||
return repo_->Pull();
|
||||
wxLogInfo("%s HardReset: %s", repo_->GetName(), reset_result.value());
|
||||
// 拉取更新
|
||||
repo_->Pull([this](const git::result_t& pull_result) {
|
||||
ProcessResult(pull_result);
|
||||
if (!pull_result.has_value()) {
|
||||
wxLogError("%s Pull: %s", repo_->GetName(), pull_result.error());
|
||||
} else {
|
||||
wxLogInfo("%s Pull: %s", repo_->GetName(), pull_result.value());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
// 拉取更新
|
||||
repo_->Pull([this](const git::result_t& pull_result) {
|
||||
ProcessResult(pull_result);
|
||||
if (!pull_result.has_value()) {
|
||||
wxLogError("%s Pull: %s", repo_->GetName(), pull_result.error());
|
||||
} else {
|
||||
wxLogInfo("%s Pull: %s", repo_->GetName(), pull_result.value());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BranchSelector::OnBranchSelected(wxCommandEvent& event) {
|
||||
|
||||
@@ -12,8 +12,7 @@ public:
|
||||
bool SelectGroupBranch(const wxString& group_name);
|
||||
std::string GetSelectedBranchName() const;
|
||||
|
||||
std::expected<std::string, std::string> ApplyBranchChange();
|
||||
bool HardReset() const { return repo_->HardReset().has_value(); }
|
||||
void ApplyBranchChange();
|
||||
|
||||
std::shared_ptr<git::Repository> GetRepo() const { return repo_; }
|
||||
|
||||
@@ -21,10 +20,10 @@ public:
|
||||
void ProcessResult(const std::expected<Value, ErrMsg>& in_expected) {
|
||||
if (in_expected.has_value()) {
|
||||
label_ctrl->SetForegroundColour(*wxGREEN);
|
||||
label_ctrl->SetToolTip(in_expected.value());
|
||||
label_ctrl->SetToolTip(wxString::FromUTF8(in_expected.value()));
|
||||
} else {
|
||||
label_ctrl->SetForegroundColour(*wxRED);
|
||||
label_ctrl->SetToolTip(in_expected.error());
|
||||
label_ctrl->SetToolTip(wxString::FromUTF8(in_expected.error()));
|
||||
}
|
||||
label_ctrl->Refresh(true);
|
||||
}
|
||||
|
||||
@@ -2,24 +2,32 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <direct.h>
|
||||
#include <bits/this_thread_sleep.h>
|
||||
#include <wx/process.h>
|
||||
#include <wx/txtstrm.h>
|
||||
|
||||
#include "git_command.h"
|
||||
#include "task_manager.h"
|
||||
|
||||
std::expected<std::string, std::string> ExecGitCommand(
|
||||
const std::string& cmd,
|
||||
const std::filesystem::path& path) {
|
||||
wxProcess* CreateGitProcess(const std::string& cmd, const std::filesystem::path& path) {
|
||||
// 使用完整路径执行命令,避免改变工作目录
|
||||
std::string fullCmd = "git -C \"" + path.string() + "\" " + cmd;
|
||||
std::string full_cmd = "git -C \"" + path.string() + "\" " + cmd;
|
||||
|
||||
wxProcess process;
|
||||
process.Redirect();
|
||||
long exit_code = wxExecute(fullCmd, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE, &process);
|
||||
// ReSharper disable once CppDFAMemoryLeak
|
||||
wxProcess* process = new wxProcess();
|
||||
process->Redirect();
|
||||
wxExecute(full_cmd, wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxUSE_STREAMS, process);
|
||||
return process;
|
||||
}
|
||||
|
||||
git::result_t ExecGitCommand(wxProcess* process) {
|
||||
while (wxProcess::Exists(process->GetPid())) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
// 读取输出
|
||||
wxString process_result;
|
||||
if (wxInputStream* stream = process.GetInputStream()) {
|
||||
if (wxInputStream* stream = process->GetInputStream(); process->IsInputAvailable()) {
|
||||
wxTextInputStream tis(*stream);
|
||||
while (!stream->Eof()) {
|
||||
process_result += tis.ReadLine() + "\n";
|
||||
@@ -28,100 +36,179 @@ std::expected<std::string, std::string> ExecGitCommand(
|
||||
|
||||
// 读取错误输出
|
||||
wxString error_result;
|
||||
if (wxInputStream* errorStream = process.GetErrorStream()) {
|
||||
if (wxInputStream* errorStream = process->GetErrorStream(); process->IsErrorAvailable()) {
|
||||
wxTextInputStream tis(*errorStream, wxT("\n"), wxConvUTF8);
|
||||
while (!errorStream->Eof()) {
|
||||
error_result += tis.ReadLine() + "\n";
|
||||
const auto& line = tis.ReadLine();
|
||||
if (!line.empty())
|
||||
error_result += line + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 检查命令是否成功
|
||||
if (!error_result.empty() && exit_code != 0) {
|
||||
return std::unexpected("Git command failed: " + error_result.ToStdString());
|
||||
while (!error_result.empty()) {
|
||||
if (error_result.Contains("Switched to branch"))
|
||||
break;
|
||||
if (error_result.Contains("Already on"))
|
||||
break;
|
||||
if (error_result.Contains("Updating files"))
|
||||
break;
|
||||
return std::unexpected("git命令失败: " + error_result.ToStdString());
|
||||
}
|
||||
|
||||
return process_result.ToStdString();
|
||||
}
|
||||
|
||||
void GitCommandTask(const std::string& cmd, const std::filesystem::path& path, std::function<void(git::result_t)> callback) {
|
||||
wxASSERT_MSG(wxIsMainThread(), "GitCommandTask must be called from the main thread");
|
||||
const auto process = CreateGitProcess(cmd, path);
|
||||
|
||||
if (!process) {
|
||||
callback(std::unexpected("无法启动git进程: " + cmd));
|
||||
return;
|
||||
}
|
||||
|
||||
TaskManager::Get().PushTask([process] {
|
||||
return ExecGitCommand(process);
|
||||
}, callback);
|
||||
// ReSharper disable once CppDFAMemoryLeak
|
||||
}
|
||||
|
||||
git::Repository::Repository(const std::filesystem::path& in_path) {
|
||||
path_ = in_path;
|
||||
name_ = path_.filename().string();
|
||||
}
|
||||
|
||||
std::expected<std::string, std::string> git::Repository::SwitchBranch(const std::string& in_branch) {
|
||||
void git::Repository::SwitchBranch(const std::string& in_branch, const std::function<void(result_t)>& in_callback) {
|
||||
const std::string cmd = "checkout " + in_branch;
|
||||
auto result = ExecGitCommand(cmd, path_);
|
||||
if (result)
|
||||
branch_ = in_branch;
|
||||
return result;
|
||||
GitCommandTask(cmd, path_, [this, in_branch, in_callback](result_t result) {
|
||||
if (result.has_value()) {
|
||||
const std::unique_lock u_lock(branch_name_mutex_);
|
||||
branch_ = in_branch;
|
||||
}
|
||||
in_callback(result);
|
||||
});
|
||||
}
|
||||
|
||||
std::expected<std::string, std::string> git::Repository::HardReset() {
|
||||
return ExecGitCommand("reset --hard", path_);
|
||||
void git::Repository::HardReset(const std::function<void(result_t)>& in_callback) {
|
||||
GitCommandTask("reset --hard", path_, [in_callback](result_t result) {
|
||||
in_callback(result);
|
||||
});
|
||||
}
|
||||
|
||||
std::expected<std::string, std::string> git::Repository::Pull() {
|
||||
return ExecGitCommand("pull", path_);
|
||||
void git::Repository::Pull(const std::function<void(result_t)>& in_callback) {
|
||||
GitCommandTask("pull", path_, [in_callback](result_t result) {
|
||||
in_callback(result);
|
||||
});
|
||||
}
|
||||
|
||||
void git::Repository::GetSubmodules(const std::function<void(submodules_t)>& in_callback) const {
|
||||
{
|
||||
std::shared_lock s_lock(submodules_mutex_);
|
||||
if (!submodules_.empty()) {
|
||||
in_callback(submodules_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GitCommandTask("submodule", path_, [this, in_callback](result_t result) {
|
||||
if (!result.has_value()) {
|
||||
in_callback(std::unexpected(result.error()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<git::Repository>> submodules;
|
||||
std::istringstream iss(result.value());
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
// 截取第一个空格到第二个空格之间的内容
|
||||
const size_t first_space = line.find(' ', 1);
|
||||
const size_t second_space = line.find(' ', first_space + 1);
|
||||
if (first_space != std::string::npos && second_space != std::string::npos) {
|
||||
std::string submodule_path = line.substr(first_space + 1, second_space - first_space - 1);
|
||||
std::filesystem::path submodule_full_path = path_ / submodule_path;
|
||||
auto submodule_repo = std::make_shared<Repository>(submodule_full_path);
|
||||
submodules.push_back(submodule_repo);
|
||||
}
|
||||
}
|
||||
const std::unique_lock u_lock(submodules_mutex_);
|
||||
submodules_ = submodules;
|
||||
in_callback(submodules);
|
||||
});
|
||||
}
|
||||
|
||||
void git::Repository::GetCurrentBranchName(const std::function<void(result_t)>& in_callback) const {
|
||||
std::shared_lock s_lock(branch_name_mutex_);
|
||||
if (branch_) {
|
||||
in_callback(branch_.value());
|
||||
return;
|
||||
}
|
||||
|
||||
GitCommandTask("rev-parse --abbrev-ref HEAD", path_, [this, in_callback](result_t result) {
|
||||
if (!result.has_value()) {
|
||||
in_callback(std::unexpected(result.error()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string branch_name = result.value();
|
||||
std::erase(branch_name, '\n'); // Remove trailing newline
|
||||
const std::unique_lock u_lock(branch_name_mutex_);
|
||||
branch_ = branch_name;
|
||||
in_callback(branch_name);
|
||||
});
|
||||
}
|
||||
|
||||
void git::Repository::GetAllBranches(
|
||||
const std::function<void(branches_t)>& in_callback) const {
|
||||
{
|
||||
std::shared_lock s_lock(all_branches_mutex_);
|
||||
if (!all_branches_.empty()) {
|
||||
in_callback(all_branches_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GitCommandTask("branch", path_, [this, in_callback](result_t result) {
|
||||
if (!result.has_value()) {
|
||||
in_callback(std::unexpected(result.error()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> branches;
|
||||
std::istringstream iss(result.value());
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
if (!line.empty()) {
|
||||
branches.push_back(line.substr(2)); // Remove the leading "* " or " "
|
||||
}
|
||||
}
|
||||
const std::unique_lock u_lock(all_branches_mutex_);
|
||||
all_branches_ = branches;
|
||||
in_callback(branches);
|
||||
});
|
||||
}
|
||||
|
||||
std::expected<std::vector<std::shared_ptr<git::Repository>>, std::string> git::Repository::GetSubmodules() const {
|
||||
if (!submodules_.empty())
|
||||
std::shared_lock s_lock(submodules_mutex_);
|
||||
if (!submodules_.empty()) {
|
||||
return submodules_;
|
||||
|
||||
std::vector<std::shared_ptr<git::Repository>> submodules;
|
||||
std::string cmd = "submodule";
|
||||
auto result = ExecGitCommand(cmd, path_);
|
||||
if (!result.has_value())
|
||||
return std::unexpected(result.error());
|
||||
|
||||
std::istringstream iss(result.value());
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
// 截取第一个空格到第二个空格之间的内容
|
||||
const size_t first_space = line.find(' ', 1);
|
||||
const size_t second_space = line.find(' ', first_space + 1);
|
||||
if (first_space != std::string::npos && second_space != std::string::npos) {
|
||||
std::string submodule_path = line.substr(first_space + 1, second_space - first_space - 1);
|
||||
std::filesystem::path submodule_full_path = path_ / submodule_path;
|
||||
auto submodule_repo = std::make_shared<Repository>(submodule_full_path);
|
||||
submodules.push_back(submodule_repo);
|
||||
}
|
||||
}
|
||||
submodules_ = submodules;
|
||||
return submodules;
|
||||
return std::unexpected("No submodules available");
|
||||
}
|
||||
|
||||
std::expected<std::string, std::string> git::Repository::GetCurrentBranchName() const {
|
||||
if (branch_)
|
||||
return branch_.value();
|
||||
const std::string cmd = "rev-parse --abbrev-ref HEAD";
|
||||
auto result = ExecGitCommand(cmd, path_);
|
||||
if (!result.has_value())
|
||||
return result;
|
||||
auto& str = result.value();
|
||||
str.replace(str.find('\n'), 2, ""); // Remove trailing newline
|
||||
branch_ = str;
|
||||
return result;
|
||||
std::shared_lock s_lock(branch_name_mutex_);
|
||||
if (branch_) {
|
||||
return *branch_;
|
||||
}
|
||||
return std::unexpected("No current branch set");
|
||||
}
|
||||
|
||||
std::expected<std::vector<std::string>, std::string> git::Repository::GetAllBranches() const {
|
||||
std::shared_lock s_lock(all_branches_mutex_);
|
||||
if (!all_branches_.empty())
|
||||
return all_branches_;
|
||||
std::vector<std::string> branches;
|
||||
const std::string cmd = "branch";
|
||||
auto result = ExecGitCommand(cmd, path_);
|
||||
if (!result.has_value())
|
||||
return std::unexpected(result.error());
|
||||
|
||||
std::istringstream iss(result.value());
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
if (!line.empty()) {
|
||||
branches.push_back(line.substr(2)); // Remove the leading "* " or " "
|
||||
}
|
||||
}
|
||||
all_branches_ = branches;
|
||||
return branches;
|
||||
return std::unexpected("No branches available");
|
||||
}
|
||||
|
||||
bool git::Repository::IsValid() const {
|
||||
|
||||
@@ -4,21 +4,37 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <shared_mutex>
|
||||
|
||||
|
||||
namespace git {
|
||||
class Repository;
|
||||
|
||||
using result_t = std::expected<std::string, std::string>;
|
||||
using submodules_t = std::expected<std::vector<std::shared_ptr<Repository>>, std::string>;
|
||||
using branches_t = std::expected<std::vector<std::string>, std::string>;
|
||||
|
||||
class Repository {
|
||||
public:
|
||||
|
||||
explicit Repository(const std::filesystem::path& in_path);
|
||||
|
||||
std::expected<std::string, std::string> SwitchBranch(const std::string& in_branch);
|
||||
std::expected<std::string, std::string> HardReset();
|
||||
std::expected<std::string, std::string> Pull();
|
||||
void SwitchBranch(const std::string& in_branch, const std::function<void(result_t)>& in_callback);
|
||||
void HardReset(const std::function<void(result_t)>& in_callback);
|
||||
void Pull(const std::function<void(result_t)>& in_callback);
|
||||
|
||||
void GetSubmodules(const std::function<void(submodules_t)>& in_callback) const;
|
||||
void GetCurrentBranchName(const std::function<void(result_t)>& in_callback) const;
|
||||
void GetAllBranches(const std::function<void(branches_t)>& in_callback) const;
|
||||
|
||||
[[nodiscard]] std::expected<std::vector<std::shared_ptr<Repository>>, std::string> GetSubmodules() const;
|
||||
[[nodiscard]] std::expected<std::string, std::string> GetCurrentBranchName() const;
|
||||
[[nodiscard]] std::expected<std::vector<std::string>, std::string> GetAllBranches() const;
|
||||
[[nodiscard]] auto GetName() const { return name_; }
|
||||
|
||||
[[nodiscard]] std::expected<std::string, std::string> GetCurrentBranchName() const;
|
||||
|
||||
[[nodiscard]] std::expected<std::vector<std::string>, std::string> GetAllBranches() const;
|
||||
|
||||
[[nodiscard]] auto GetName() const { return name_; }
|
||||
[[nodiscard]] bool IsValid() const;
|
||||
private:
|
||||
std::string name_;
|
||||
@@ -26,6 +42,10 @@ namespace git {
|
||||
mutable std::vector<std::shared_ptr<Repository>> submodules_;
|
||||
mutable std::optional<std::string> branch_;
|
||||
mutable std::vector<std::string> all_branches_;
|
||||
// mutable std::shared_mutex mutex_;
|
||||
mutable std::shared_mutex branch_name_mutex_;
|
||||
mutable std::shared_mutex all_branches_mutex_;
|
||||
mutable std::shared_mutex submodules_mutex_;
|
||||
};
|
||||
|
||||
std::shared_ptr<Repository> OpenRepository(const std::filesystem::path& in_path);
|
||||
|
||||
@@ -17,14 +17,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 打开主仓库
|
||||
std::string repo_path = config.GetRepositoryPath();
|
||||
auto repo = git::OpenRepository(repo_path);
|
||||
if (!repo) {
|
||||
wxMessageBox("Failed to open repository: " + repo_path, "Error", wxICON_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建并显示主窗口
|
||||
auto* frame = new MainFrame("Git Branch Manager");
|
||||
frame->Show(true);
|
||||
|
||||
@@ -37,69 +37,69 @@ MainFrame::MainFrame(const wxString& title)
|
||||
|
||||
// 初始化UI
|
||||
InitializeUI();
|
||||
|
||||
// 设置分支组
|
||||
PopulateBranchGroups();
|
||||
}
|
||||
|
||||
void MainFrame::InitializeUI() {
|
||||
// 创建主布局
|
||||
main_sizer_ = new wxBoxSizer(wxVERTICAL);
|
||||
// 创建日志控件
|
||||
log_ctrl_ = new ColoredLogCtrl(this);
|
||||
// 创建分支组选择器
|
||||
group_combo_ = new wxComboBox(this, wxID_ANY);
|
||||
main_repo_->GetSubmodules([this](const git::submodules_t& submodules){
|
||||
if (!submodules) {
|
||||
// 弹出窗口报错
|
||||
wxMessageBox(wxString::Format(wxString::FromUTF8("获取子模块失败: %s"), submodules.error()), "Error", wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
// 创建主布局
|
||||
main_sizer_ = new wxBoxSizer(wxVERTICAL);
|
||||
// 创建日志控件
|
||||
log_ctrl_ = new ColoredLogCtrl(this);
|
||||
// 创建分支组选择器
|
||||
group_combo_ = new wxComboBox(this, wxID_ANY);
|
||||
|
||||
// 创建主仓库分支选择器
|
||||
branch_selectors_.push_back(new BranchSelector(this, main_repo_, wxString::FromUTF8("主仓库")));
|
||||
// 创建子模块分支选择器
|
||||
auto submodules = main_repo_->GetSubmodules();
|
||||
for (const auto& submodule: submodules.value()) {
|
||||
branch_selectors_.push_back(new BranchSelector(this, submodule));
|
||||
}
|
||||
// 创建主仓库分支选择器
|
||||
branch_selectors_.push_back(new BranchSelector(this, main_repo_, wxString::FromUTF8("主仓库")));
|
||||
// 创建子模块分支选择器
|
||||
for (const auto& submodule: submodules.value()) {
|
||||
branch_selectors_.push_back(new BranchSelector(this, submodule));
|
||||
}
|
||||
|
||||
// 创建硬重置选项
|
||||
hard_reset_checkbox_ = new wxCheckBox(this, wxID_ANY, "Hard reset");
|
||||
hard_reset_checkbox_->SetValue(is_hard_reset_);
|
||||
// 创建硬重置选项
|
||||
hard_reset_checkbox_ = new wxCheckBox(this, wxID_ANY, "Hard reset");
|
||||
hard_reset_checkbox_->SetValue(is_hard_reset_);
|
||||
|
||||
// 创建应用按钮
|
||||
apply_button_ = new wxButton(this, wxID_APPLY, "Apply");
|
||||
// 创建应用按钮
|
||||
apply_button_ = new wxButton(this, wxID_APPLY, "Apply");
|
||||
|
||||
// 添加分支组选择器
|
||||
main_sizer_->Add(group_combo_, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
// 添加分支组选择器
|
||||
main_sizer_->Add(group_combo_, 0, wxEXPAND | wxALL, 5);
|
||||
// 添加所有分支选择器到布局
|
||||
for (auto selector: branch_selectors_) { main_sizer_->Add(selector, 0, wxEXPAND | wxALL, 5); }
|
||||
|
||||
// 添加所有分支选择器到布局
|
||||
for (auto selector: branch_selectors_) {
|
||||
main_sizer_->Add(selector, 0, wxEXPAND | wxALL, 5);
|
||||
}
|
||||
main_sizer_->Add(hard_reset_checkbox_, 0, wxALL, 5);
|
||||
main_sizer_->Add(apply_button_, 0, wxALL, 5);
|
||||
|
||||
main_sizer_->Add(hard_reset_checkbox_, 0, wxALL, 5);
|
||||
main_sizer_->Add(apply_button_, 0, wxALL, 5);
|
||||
// 添加日志控件
|
||||
main_sizer_->Add(log_ctrl_, 1, wxEXPAND | wxALL, 5);
|
||||
|
||||
// 添加日志控件
|
||||
main_sizer_->Add(log_ctrl_, 1, wxEXPAND | wxALL, 5);
|
||||
SetSizerAndFit(main_sizer_);
|
||||
SetSize(wxSize(600, 400));
|
||||
SetMinSize(wxSize(600, 400));
|
||||
|
||||
|
||||
SetSizerAndFit(main_sizer_);
|
||||
SetSize(wxSize(600, 400));
|
||||
SetMinSize(wxSize(600, 400));
|
||||
// 设置分支组
|
||||
CallAfter([this] { PopulateBranchGroups(); });
|
||||
});
|
||||
}
|
||||
|
||||
void MainFrame::PopulateBranchGroups() {
|
||||
apply_button_->Enable(false); // 初始时禁用应用按钮
|
||||
|
||||
auto task = [this] -> std::vector<std::string> {
|
||||
main_repo_->GetAllBranches([this](const std::expected<std::vector<std::string>, std::string>& branches) {
|
||||
// 获取所有分支组
|
||||
std::vector<std::string> branch_groups;
|
||||
auto result = main_repo_->GetAllBranches();
|
||||
if (!result.has_value()) {
|
||||
log_ctrl_->LogError(wxString::Format(wxString::FromUTF8("获取主仓库分支失败: %s"),
|
||||
result.error()));
|
||||
return {};
|
||||
if (!branches.has_value()) {
|
||||
log_ctrl_->LogError(wxString::Format(wxString::FromUTF8("获取主仓库分支失败: %s"), branches.error()));
|
||||
return;
|
||||
}
|
||||
// 获取主仓库的所有分支
|
||||
for (const auto& branch: result.value()) { branch_groups.push_back(branch); }
|
||||
for (const auto& branch: branches.value()) { branch_groups.push_back(branch); }
|
||||
|
||||
// 获取子模块的所有分支
|
||||
auto submodules = main_repo_->GetSubmodules();
|
||||
@@ -107,8 +107,8 @@ void MainFrame::PopulateBranchGroups() {
|
||||
auto r = submodule->GetAllBranches();
|
||||
if (!r.has_value()) {
|
||||
log_ctrl_->LogError(wxString::Format(wxString::FromUTF8("获取子模块 %s 的分支失败: %s"),
|
||||
submodule->GetName(),
|
||||
r.error()));
|
||||
submodule->GetName(),
|
||||
r.error()));
|
||||
continue;
|
||||
}
|
||||
for (const auto& branch: r.value()) { branch_groups.push_back(branch); }
|
||||
@@ -116,23 +116,20 @@ void MainFrame::PopulateBranchGroups() {
|
||||
|
||||
// 去重
|
||||
std::ranges::sort(branch_groups);
|
||||
branch_groups.erase(std::ranges::unique(branch_groups).begin(),
|
||||
branch_groups.end());
|
||||
return branch_groups;
|
||||
};
|
||||
auto callback = [this](std::vector<std::string> branch_groups) {
|
||||
branch_groups.erase(std::ranges::unique(branch_groups).begin(), branch_groups.end());
|
||||
|
||||
// 填充分支组
|
||||
for (const auto& group: branch_groups) { group_combo_->Append(group); }
|
||||
apply_button_->Enable(true);
|
||||
|
||||
if (group_combo_->GetCount() > 0) {
|
||||
if (auto result = main_repo_->GetCurrentBranchName()) {
|
||||
log_ctrl_->LogInfo(wxString::Format(wxString::FromUTF8("当前分支: %s"), result.value()));
|
||||
group_combo_->SetStringSelection(result.value());
|
||||
if (auto branch_name = main_repo_->GetCurrentBranchName()) {
|
||||
log_ctrl_->LogInfo(wxString::Format(wxString::FromUTF8("当前分支: %s"), branch_name.value()));
|
||||
group_combo_->SetStringSelection(branch_name.value());
|
||||
}
|
||||
else {
|
||||
log_ctrl_->LogError(wxString::Format(wxString::FromUTF8("获取当前分支失败: %s, 将使用默认分支 Develop"),
|
||||
result.error()));
|
||||
branch_name.error()));
|
||||
group_combo_->SetStringSelection("Develop");
|
||||
}
|
||||
wxCommandEvent event(wxEVT_COMBOBOX);
|
||||
@@ -141,68 +138,57 @@ void MainFrame::PopulateBranchGroups() {
|
||||
else { log_ctrl_->LogError(wxString::FromUTF8("没有可用的分支")); }
|
||||
// 置顶窗口
|
||||
Raise();
|
||||
};
|
||||
TaskManager::Get().PushTask(task, callback);
|
||||
});
|
||||
}
|
||||
|
||||
void MainFrame::OnApply(wxCommandEvent& event) {
|
||||
// 禁用按钮防止重复点击
|
||||
wxButton* apply_button = wxDynamicCast(event.GetEventObject(), wxButton);
|
||||
if (apply_button) { apply_button->Enable(false); }
|
||||
|
||||
// 创建进度对话框
|
||||
auto* progress = new wxProgressDialog(wxString::FromUTF8("应用修改"),
|
||||
wxString::FromUTF8("处理中..."),
|
||||
branch_selectors_.size(),
|
||||
this,
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL);
|
||||
|
||||
log_ctrl_->LogInfo(wxString::FromUTF8("...开始应用修改..."));
|
||||
|
||||
for (auto branch_selector : branch_selectors_) {
|
||||
auto selector = branch_selector;
|
||||
selector->ApplyBranchChange();
|
||||
|
||||
TaskManager::Get().PushTask(
|
||||
[selector, this]() -> std::expected<std::string, std::string> {
|
||||
return selector->ApplyBranchChange();
|
||||
},
|
||||
[this, progress, selector, apply_button]
|
||||
(const std::expected<std::string, std::string>& result) {
|
||||
const auto& log_str = wxString::Format(wxString::FromUTF8("%s => %s"), selector->GetRepo()->GetName(), result ? result.value() : result.error());
|
||||
if (result) {
|
||||
log_ctrl_->LogSuccess(TrimTrailingNewline(log_str));
|
||||
} else {
|
||||
log_ctrl_->LogError(TrimTrailingNewline(log_str));
|
||||
}
|
||||
|
||||
selector->ProcessResult(result);
|
||||
if (!result.has_value()) {
|
||||
has_errors = true;
|
||||
log_ctrl_->LogError(selector->GetRepo()->GetName() + wxString::FromUTF8(" 操作失败: ") + result.error());
|
||||
}
|
||||
|
||||
++completed;
|
||||
progress->Update(completed);
|
||||
|
||||
// 所有任务完成
|
||||
if (completed == branch_selectors_.size()) {
|
||||
if (apply_button) {
|
||||
apply_button->Enable(true);
|
||||
}
|
||||
|
||||
if (has_errors) {
|
||||
wxMessageBox(wxString::FromUTF8("某些操作失败,请检查日志。"),
|
||||
"Warning", wxICON_WARNING);
|
||||
} else {
|
||||
log_ctrl_->LogInfo(wxString::FromUTF8("所有操作已成功完成。"));
|
||||
}
|
||||
|
||||
completed = 0; // 重置计数器
|
||||
has_errors = false; // 重置错误状态
|
||||
delete progress;
|
||||
}
|
||||
}
|
||||
);
|
||||
// TaskManager::Get().PushTask(
|
||||
// [selector, this] {
|
||||
// return selector->ApplyBranchChange();
|
||||
// },
|
||||
// [this, progress, selector, apply_button]
|
||||
// (const git::result_t& result) {
|
||||
// const auto& log_str = wxString::Format(wxString::FromUTF8("%s => %s"), selector->GetRepo()->GetName(), result ? result.value() : result.error());
|
||||
// if (result) {
|
||||
// log_ctrl_->LogSuccess(TrimTrailingNewline(log_str));
|
||||
// } else {
|
||||
// log_ctrl_->LogError(TrimTrailingNewline(log_str));
|
||||
// }
|
||||
//
|
||||
// selector->ProcessResult(result);
|
||||
// if (!result.has_value()) {
|
||||
// has_errors = true;
|
||||
// log_ctrl_->LogError(selector->GetRepo()->GetName() + wxString::FromUTF8(" 操作失败: ") + result.error());
|
||||
// }
|
||||
//
|
||||
// ++completed;
|
||||
// progress->Update(completed);
|
||||
//
|
||||
// // 所有任务完成
|
||||
// if (completed == branch_selectors_.size()) {
|
||||
// if (apply_button) {
|
||||
// apply_button->Enable(true);
|
||||
// }
|
||||
//
|
||||
// if (has_errors) {
|
||||
// wxMessageBox(wxString::FromUTF8("某些操作失败,请检查日志。"),
|
||||
// "Warning", wxICON_WARNING);
|
||||
// } else {
|
||||
// log_ctrl_->LogInfo(wxString::FromUTF8("所有操作已成功完成。"));
|
||||
// }
|
||||
//
|
||||
// completed = 0; // 重置计数器
|
||||
// has_errors = false; // 重置错误状态
|
||||
// delete progress;
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
private:
|
||||
TaskManager() : shutdown_(false) {
|
||||
// 创建工作线程池
|
||||
const size_t num_threads = std::thread::hardware_concurrency();
|
||||
const size_t num_threads = 4;
|
||||
for (size_t i = 0; i < num_threads; ++i) {
|
||||
workers_.emplace_back(&TaskManager::WorkerThread, this);
|
||||
}
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
while (true) {
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
std::unique_lock lock(queue_mutex_);
|
||||
cv_.wait(lock, [this] { return shutdown_ || !tasks_.empty(); });
|
||||
|
||||
if (shutdown_ && tasks_.empty()) {
|
||||
|
||||
Reference in New Issue
Block a user