12#include "absl/strings/str_format.h"
18namespace fs = std::filesystem;
21 : project_(project) {}
28 return fs::exists(git_dir);
33 return absl::InvalidArgumentError(
"No project context");
41 return absl::OkStatus();
47 const std::string& message) {
49 return absl::InvalidArgumentError(
"No project context");
67 if (!commit_status.ok()) {
70 LOG_INFO(
"VersionManager",
"Git commit skipped (no changes?)");
77 auto now = std::chrono::system_clock::now();
78 auto time_t = std::chrono::system_clock::to_time_t(now);
80 ss << std::put_time(std::localtime(&time_t),
"%Y%m%d_%H%M%S");
81 std::string timestamp = ss.str();
84 if (backup_status.ok()) {
87 LOG_ERROR(
"VersionManager",
"Failed to backup ROM: %s",
88 backup_status.ToString().c_str());
92 result.
message =
"Snapshot created successfully.";
106 absl::StrFormat(
"git log -n %d --pretty=format:\"%%h %%s\"", limit);
112 std::vector<std::string> history;
113 std::istringstream stream(*output);
115 while (std::getline(stream, line)) {
117 history.push_back(line);
137 std::string sanitized_msg = message;
139 std::replace(sanitized_msg.begin(), sanitized_msg.end(),
'"',
'\'');
141 return RunCommand(absl::StrFormat(
"git commit -m \"%s\"", sanitized_msg));
148 std::string hash = *res;
149 hash.erase(hash.find_last_not_of(
" \n\r\t") + 1);
160 const std::string& timestamp_str) {
162 return absl::FailedPreconditionError(
163 "Project output folder or build target not defined");
170 fs::path abs_rom_path = project_dir / rom_path;
172 if (!fs::exists(abs_rom_path)) {
173 return absl::NotFoundError(
174 absl::StrFormat(
"Built ROM not found at %s", abs_rom_path.string()));
178 fs::path backup_dir = project_dir /
"backups" /
"snapshots";
180 fs::create_directories(backup_dir, ec);
182 return absl::InternalError(
"Could not create backup directory");
184 std::string filename = absl::StrFormat(
"rom_%s.sfc", timestamp_str);
185 fs::path backup_path = backup_dir / filename;
188 fs::copy_file(abs_rom_path, backup_path, fs::copy_options::overwrite_existing,
191 return absl::InternalError(
192 absl::StrFormat(
"Failed to copy ROM: %s", ec.message()));
195 return absl::OkStatus();
205 return absl::FailedPreconditionError(
206 "Command execution is not available on iOS");
209 std::string full_cmd;
212 if (!project_dir.empty()) {
213 full_cmd = absl::StrFormat(
"cd \"%s\" && %s", project_dir.string(), cmd);
218 int ret = std::system(full_cmd.c_str());
220 return absl::InternalError(
221 absl::StrFormat(
"Command failed: %s (Exit code %d)", cmd, ret));
223 return absl::OkStatus();
228 const std::string& cmd)
const {
231 return absl::FailedPreconditionError(
232 "Command execution is not available on iOS");
234 std::string full_cmd;
236 if (!project_dir.empty()) {
237 full_cmd = absl::StrFormat(
"cd \"%s\" && %s", project_dir.string(), cmd);
242 std::array<char, 128> buffer;
245 std::unique_ptr<FILE,
decltype(&_pclose)> pipe(_popen(full_cmd.c_str(),
"r"),
248 std::unique_ptr<FILE,
decltype(&pclose)> pipe(popen(full_cmd.c_str(),
"r"),
252 return absl::InternalError(
"popen() failed!");
254 while (fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr) {
255 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