47 auto status = project.
Open(
".");
52 return absl::PermissionDeniedError(
53 "Project builds are disabled by the project's read-only policy");
63 namespace fs = std::filesystem;
64 std::vector<std::string> bps_files;
67 for (
const auto& entry : fs::directory_iterator(project.
patches_folder)) {
68 if (entry.path().extension() ==
".bps") {
69 bps_files.push_back(entry.path().string());
72 }
catch (
const fs::filesystem_error& e) {
76 for (
const auto& patch_file : bps_files) {
77 std::ifstream patch_stream(patch_file, std::ios::binary);
78 if (!patch_stream.is_open()) {
79 return absl::InternalError(
"Failed to open BPS patch: " + patch_file);
82 std::vector<uint8_t> patch_data(
83 (std::istreambuf_iterator<char>(patch_stream)),
84 std::istreambuf_iterator<char>());
85 if (patch_data.empty()) {
86 return absl::InvalidArgumentError(
"BPS patch is empty: " + patch_file);
89 std::vector<uint8_t> patched_rom;
92 if (!apply_status.ok()) {
93 return absl::InternalError(
"Failed to apply BPS patch " + patch_file +
94 ": " + std::string(apply_status.message()));
97 auto load_patched_status = build_rom.
LoadFromData(patched_rom);
98 if (!load_patched_status.ok()) {
99 return absl::InternalError(
"Failed to load patched ROM after " +
101 std::string(load_patched_status.message()));
106 std::vector<std::string> asm_files;
108 for (
const auto& entry : fs::directory_iterator(project.
patches_folder)) {
109 if (entry.path().extension() ==
".asm") {
110 asm_files.push_back(entry.path().string());
113 }
catch (
const fs::filesystem_error& e) {
118 if (!asm_files.empty()) {
121 if (!init_status.ok()) {
123 "Asar not available, skipping ASM patches: " +
124 std::string(init_status.message()));
126 for (
const auto& asm_file : asm_files) {
127 auto rom_data = build_rom.
vector();
128 auto result = asar.
ApplyPatch(asm_file, rom_data);
131 return absl::InternalError(
"ASM patch failed for " + asm_file +
": " +
132 std::string(result.status().message()));
135 if (result->success) {
137 formatter.
AddField(
"asm_applied", asm_file);
140 if (!result->symbols.empty()) {
142 "symbols_" + fs::path(asm_file).stem().
string(),
143 std::to_string(result->symbols.size()) +
" symbols");
147 std::string error_msg =
"Errors in " + asm_file +
":";
148 for (
const auto& error : result->errors) {
149 error_msg +=
"\n " + error;
151 formatter.
AddField(
"error", error_msg);
152 return absl::InternalError(error_msg);
158 std::string output_file = project.
name +
".sfc";
159 status = build_rom.
SaveToFile({.save_new =
true, .filename = output_file});
164 formatter.
AddField(
"status",
"success");
165 formatter.
AddField(
"message",
"Successfully built project: " + project.
name);
167 formatter.
AddField(
"output_file", output_file);
169 return absl::OkStatus();