12#include "absl/strings/str_format.h"
18namespace fs = std::filesystem;
26 return fs::exists(git_dir);
30 if (!
project_)
return absl::InvalidArgumentError(
"No project context");
43 if (!
project_)
return absl::InvalidArgumentError(
"No project context");
51 if (!status.ok())
return status;
56 if (!add_status.ok())
return add_status;
59 if (!commit_status.ok()) {
62 LOG_INFO(
"VersionManager",
"Git commit skipped (no changes?)");
69 auto now = std::chrono::system_clock::now();
70 auto time_t = std::chrono::system_clock::to_time_t(now);
72 ss << std::put_time(std::localtime(&time_t),
"%Y%m%d_%H%M%S");
73 std::string timestamp = ss.str();
76 if (backup_status.ok()) {
79 LOG_ERROR(
"VersionManager",
"Failed to backup ROM: %s", backup_status.ToString().c_str());
83 result.
message =
"Snapshot created successfully.";
96 std::string cmd = absl::StrFormat(
"git log -n %d --pretty=format:\"%%h %%s\"", limit);
98 if (!output.ok())
return {};
101 std::vector<std::string> history;
102 std::istringstream stream(*output);
104 while (std::getline(stream, line)) {
105 if (!line.empty()) history.push_back(line);
125 std::string sanitized_msg = message;
127 std::replace(sanitized_msg.begin(), sanitized_msg.end(),
'"',
'\'');
129 return RunCommand(absl::StrFormat(
"git commit -m \"%s\"", sanitized_msg));
136 std::string hash = *res;
137 hash.erase(hash.find_last_not_of(
" \n\r\t") + 1);
149 return absl::FailedPreconditionError(
"Project output folder or build target not defined");
156 fs::path abs_rom_path = project_dir / rom_path;
158 if (!fs::exists(abs_rom_path)) {
159 return absl::NotFoundError(absl::StrFormat(
"Built ROM not found at %s", abs_rom_path.string()));
163 fs::path backup_dir = project_dir /
"backups" /
"snapshots";
165 fs::create_directories(backup_dir, ec);
166 if (ec)
return absl::InternalError(
"Could not create backup directory");
168 std::string filename = absl::StrFormat(
"rom_%s.sfc", timestamp_str);
169 fs::path backup_path = backup_dir / filename;
172 fs::copy_file(abs_rom_path, backup_path, fs::copy_options::overwrite_existing, ec);
174 return absl::InternalError(absl::StrFormat(
"Failed to copy ROM: %s", ec.message()));
177 return absl::OkStatus();
186 std::string full_cmd;
189 if (!project_dir.empty()) {
190 full_cmd = absl::StrFormat(
"cd \"%s\" && %s", project_dir.string(), cmd);
195 int ret = std::system(full_cmd.c_str());
197 return absl::InternalError(absl::StrFormat(
"Command failed: %s (Exit code %d)", cmd, ret));
199 return absl::OkStatus();
203 std::string full_cmd;
205 if (!project_dir.empty()) {
206 full_cmd = absl::StrFormat(
"cd \"%s\" && %s", project_dir.string(), cmd);
211 std::array<char, 128> buffer;
213 std::unique_ptr<FILE,
decltype(&pclose)> pipe(popen(full_cmd.c_str(),
"r"), pclose);
215 return absl::InternalError(
"popen() failed!");
217 while (fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr) {
218 result += buffer.data();
absl::Status BackupRomArtifact(const std::string ×tamp_str)
absl::Status GitCommit(const std::string &message)
std::vector< std::string > GetHistory(int limit=10) const
project::YazeProject * project_
VersionManager(project::YazeProject *project)
absl::StatusOr< std::string > RunCommandOutput(const std::string &cmd) const
absl::Status InitializeGit()
std::string GetCurrentHash() const
absl::StatusOr< SnapshotResult > CreateSnapshot(const std::string &message)
absl::Status RunCommand(const std::string &cmd)
std::string GitRevParseHead() const
bool IsGitInitialized() const
#define LOG_ERROR(category, format,...)
#define LOG_INFO(category, format,...)
std::string rom_backup_path
Modern project structure with comprehensive settings consolidation.
std::string git_repository
std::string output_folder
std::string last_build_hash