-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TgBot++: Initial C++/Python based Android ROM builder
- Loading branch information
Showing
27 changed files
with
1,331 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include "ArgumentBuilder.hpp" | ||
|
||
#include <absl/log/check.h> | ||
#include <absl/log/log.h> | ||
|
||
ArgumentBuilder::ArgumentBuilder(Py_ssize_t argument_count) | ||
: argument_count(argument_count) { | ||
arguments.reserve(argument_count); | ||
} | ||
|
||
ArgumentBuilder& ArgumentBuilder::add_argument(Variants value) { | ||
arguments.emplace_back(value); | ||
CHECK(argument_count >= arguments.size()) | ||
<< "Too many arguments, expected " << argument_count; | ||
return *this; | ||
} | ||
|
||
PyObject* ArgumentBuilder::build() { | ||
if (arguments.size() != argument_count) { | ||
LOG(ERROR) << "Too few arguments, expected " << argument_count; | ||
return nullptr; | ||
} | ||
PyObject* result = PyTuple_New(argument_count); | ||
std::vector<PyObject*> arguments_ref; | ||
|
||
if (result == nullptr) { | ||
LOG(ERROR) << "Failed to create tuple"; | ||
PyErr_Print(); | ||
return nullptr; | ||
} | ||
arguments_ref.reserve(argument_count); | ||
for (Py_ssize_t i = 0; i < argument_count; ++i) { | ||
PyObject* value = nullptr; | ||
std::visit( | ||
[&value, &arguments_ref](auto&& arg) { | ||
using T = std::decay_t<decltype(arg)>; | ||
if constexpr (std::is_same_v<T, long>) { | ||
value = PyLong_FromLong(arg); | ||
arguments_ref.emplace_back(value); | ||
} else if constexpr (std::is_same_v<T, std::string>) { | ||
value = PyUnicode_FromString(arg.c_str()); | ||
arguments_ref.emplace_back(value); | ||
} | ||
}, | ||
arguments[i]); | ||
if (value == nullptr) { | ||
LOG(ERROR) << "Failed to convert argument to Python object"; | ||
Py_DECREF(result); | ||
PyErr_Print(); | ||
for (const auto& obj : arguments_ref) { | ||
Py_XDECREF(obj); | ||
} | ||
return nullptr; | ||
} | ||
PyTuple_SetItem(result, i, value); | ||
} | ||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include <Python.h> | ||
#include <string> | ||
#include <variant> | ||
#include <vector> | ||
|
||
class ArgumentBuilder { | ||
public: | ||
using Variants = std::variant<long, std::string>; | ||
|
||
/** | ||
* @brief Constructs an ArgumentBuilder | ||
* object with the specified argument count. | ||
* | ||
* @param argument_count The number of | ||
* arguments to be added to the builder. | ||
*/ | ||
explicit ArgumentBuilder(Py_ssize_t argument_count); | ||
|
||
/** | ||
* @brief Adds a variant argument to the builder. | ||
* | ||
* @param value The variant argument to be added. | ||
* | ||
* @return Reference to the builder for method chaining. | ||
*/ | ||
ArgumentBuilder& add_argument(Variants value); | ||
|
||
/** | ||
* @brief Builds and returns the constructed arguments as a Python object. | ||
* | ||
* @return A Python object containing the constructed arguments. | ||
*/ | ||
PyObject* build(); | ||
|
||
private: | ||
std::vector<Variants> arguments; | ||
Py_ssize_t argument_count = 0; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "ConfigParsers.hpp" | ||
|
||
#include <absl/log/log.h> | ||
|
||
constexpr bool parserDebug = true; | ||
|
||
// Name RomName LocalManifestUrl LocalManifestBranch device variant | ||
template <> | ||
std::vector<BuildConfig> parse(std::ifstream data) { | ||
std::vector<BuildConfig> configs; | ||
std::string line; | ||
while (std::getline(data, line)) { | ||
if (line.empty() || line[0] == '#') { | ||
continue; | ||
} | ||
BuildConfig config; | ||
std::vector<std::string> items; | ||
splitWithSpaces(line, items); | ||
if (items.size() != BuildConfig::elem_size) { | ||
LOG(WARNING) << "Skipping invalid line: " << line; | ||
continue; | ||
} | ||
config.name = items[BuildConfig::indexOf_name]; | ||
config.romName = items[BuildConfig::indexOf_romName]; | ||
config.local_manifest.url = items[BuildConfig::indexOf_localManifestUrl]; | ||
config.local_manifest.branch = items[BuildConfig::indexOf_localManifestBranch]; | ||
config.device = items[BuildConfig::indexOf_device]; | ||
if (items[BuildConfig::indexOf_variant] == "user") { | ||
config.variant = BuildConfig::Variant::kUser; | ||
} else if (items[BuildConfig::indexOf_variant] == "userdebug") { | ||
config.variant = BuildConfig::Variant::kUserDebug; | ||
} else if (items[BuildConfig::indexOf_variant] == "eng") { | ||
config.variant = BuildConfig::Variant::kEng; | ||
} else { | ||
LOG(WARNING) << "Skipping invalid variant: " << items[BuildConfig::indexOf_variant]; | ||
continue; | ||
} | ||
if (parserDebug) { | ||
LOG(INFO) << "---------------------------"; | ||
LOG(INFO) << "Parsed config"; | ||
LOG(INFO) << "Name: " << config.name; | ||
LOG(INFO) << "RomName: " << config.romName; | ||
LOG(INFO) << "LocalManifestUrl: " << config.local_manifest.url; | ||
LOG(INFO) << "LocalManifestBranch: " | ||
<< config.local_manifest.branch; | ||
LOG(INFO) << "Device: " << config.device; | ||
LOG(INFO) << "Variant: " | ||
<< (config.variant == BuildConfig::Variant::kUser | ||
? "User" | ||
: (config.variant == | ||
BuildConfig::Variant::kUserDebug | ||
? "UserDebug" | ||
: "Eng")); | ||
LOG(INFO) << "---------------------------"; | ||
LOG(INFO) << "---------------------------"; | ||
} | ||
configs.emplace_back(config); | ||
} | ||
return configs; | ||
} | ||
|
||
template <> | ||
std::vector<RomConfig> parse(std::ifstream data) { | ||
std::vector<RomConfig> roms; | ||
std::string line; | ||
while (std::getline(data, line)) { | ||
if (line.empty() || line[0] == '#') { | ||
continue; | ||
} | ||
RomConfig rom; | ||
std::vector<std::string> items; | ||
splitWithSpaces(line, items); | ||
if (items.size() != RomConfig::elem_size) { | ||
LOG(WARNING) << "Skipping invalid line: " << line; | ||
continue; | ||
} | ||
rom.name = items[RomConfig::indexOf_name]; | ||
rom.url = items[RomConfig::indexOf_url]; | ||
rom.branch = items[RomConfig::indexOf_branch]; | ||
rom.target = items[RomConfig::indexOf_target]; | ||
if (parserDebug) { | ||
LOG(INFO) << "---------------------------"; | ||
LOG(INFO) << "Parsed rom"; | ||
LOG(INFO) << "Name: " << rom.name; | ||
LOG(INFO) << "Url: " << rom.url; | ||
LOG(INFO) << "Branch: " << rom.branch; | ||
LOG(INFO) << "Target: " << rom.target; | ||
LOG(INFO) << "---------------------------"; | ||
} | ||
roms.emplace_back(rom); | ||
} | ||
return roms; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#pragma once | ||
|
||
#include <fstream> | ||
#include <StringToolsExt.hpp> | ||
#include <string> | ||
#include <vector> | ||
#include <absl/log/log.h> | ||
#include "RepoUtils.hpp" | ||
|
||
struct BuildConfig { | ||
static constexpr int elem_size = 6; | ||
static constexpr int indexOf_name = 0; | ||
static constexpr int indexOf_romName = 1; | ||
static constexpr int indexOf_localManifestUrl = 2; | ||
static constexpr int indexOf_localManifestBranch = 3; | ||
static constexpr int indexOf_device = 4; | ||
static constexpr int indexOf_variant = 5; | ||
|
||
std::string name; // name of the build | ||
std::string romName; // name of the ROM | ||
RepoUtils::CloneOptions local_manifest; // local manifest information | ||
std::string device; // codename of the device | ||
enum class Variant { | ||
kUser, | ||
kUserDebug, | ||
kEng | ||
} variant; // Target build variant | ||
}; | ||
|
||
struct RomConfig { | ||
static constexpr int elem_size = 4; | ||
static constexpr int indexOf_name = 0; | ||
static constexpr int indexOf_url = 1; | ||
static constexpr int indexOf_branch = 2; | ||
static constexpr int indexOf_target = 3; | ||
|
||
std::string name; // name of the ROM | ||
std::string url; // URL of the ROM repo | ||
std::string branch; // branch of the repo | ||
std::string target; // build target to build a ROM | ||
}; | ||
|
||
template <typename Data> | ||
std::vector<Data> parse(std::ifstream data) = delete; | ||
|
||
// Name RomName LocalManifestUrl LocalManifestBranch device variant | ||
template <> | ||
std::vector<BuildConfig> parse(std::ifstream data); | ||
|
||
// Name RepoUrl RepoBranch TargetName | ||
template <> | ||
std::vector<RomConfig> parse(std::ifstream data); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include "ForkAndRun.hpp" | ||
|
||
#include <absl/log/log.h> | ||
#include <internal/_FileDescriptor_posix.h> | ||
#include <sys/wait.h> | ||
|
||
#include <cstdlib> | ||
#include <thread> | ||
#include "libos/libsighandler.h" | ||
|
||
bool ForkAndRun::execute() { | ||
Pipe stdout_pipe{}; | ||
Pipe stderr_pipe{}; | ||
|
||
if (!stderr_pipe.pipe() || !stdout_pipe.pipe()) { | ||
PLOG(ERROR) << "Failed to create pipes"; | ||
return false; | ||
} | ||
pid_t pid = fork(); | ||
if (pid == 0) { | ||
dup2(stdout_pipe.writeEnd(), STDOUT_FILENO); | ||
dup2(stderr_pipe.writeEnd(), STDERR_FILENO); | ||
close(stdout_pipe.readEnd()); | ||
close(stderr_pipe.readEnd()); | ||
if (runFunction()) { | ||
_exit(EXIT_SUCCESS); | ||
} else { | ||
_exit(EXIT_FAILURE); | ||
} | ||
} else if (pid > 0) { | ||
Pipe program_termination_pipe{}; | ||
bool breakIt = false; | ||
int status = 0; | ||
|
||
close(stdout_pipe.writeEnd()); | ||
close(stderr_pipe.writeEnd()); | ||
program_termination_pipe.pipe(); | ||
|
||
selector.add( | ||
stdout_pipe.readEnd(), | ||
[stdout_pipe, this]() { | ||
BufferType buf{}; | ||
ssize_t bytes_read = | ||
read(stdout_pipe.readEnd(), buf.data(), buf.size() - 1); | ||
if (bytes_read >= 0) { | ||
onNewStdoutBuffer(buf); | ||
buf.fill(0); | ||
} | ||
}, | ||
Selector::Mode::READ); | ||
selector.add( | ||
stderr_pipe.readEnd(), | ||
[stderr_pipe, this]() { | ||
BufferType buf{}; | ||
ssize_t bytes_read = | ||
read(stderr_pipe.readEnd(), buf.data(), buf.size() - 1); | ||
if (bytes_read >= 0) { | ||
onNewStderrBuffer(buf); | ||
buf.fill(0); | ||
} | ||
}, | ||
Selector::Mode::READ); | ||
selector.add( | ||
program_termination_pipe.readEnd(), | ||
[program_termination_pipe, &breakIt]() { breakIt = true; }, | ||
Selector::Mode::READ); | ||
std::thread pollThread([&breakIt, this]() { | ||
while (!breakIt) { | ||
switch (selector.poll()) { | ||
case Selector::PollResult::OK: | ||
break; | ||
case Selector::PollResult::FAILED: | ||
case Selector::PollResult::TIMEOUT: | ||
breakIt = true; | ||
break; | ||
} | ||
} | ||
}); | ||
waitpid(pid, &status, 0); | ||
if (WIFEXITED(status)) { | ||
onExit(WEXITSTATUS(status)); | ||
} else if (WIFSIGNALED(status)) { | ||
onSignal(WTERMSIG(status)); | ||
} else { | ||
LOG(WARNING) << "Unknown program termination: " << status; | ||
onExit(0); | ||
} | ||
// Notify the polling thread that program has ended. | ||
write(program_termination_pipe.writeEnd(), &status, sizeof(status)); | ||
pollThread.join(); | ||
|
||
// Cleanup | ||
program_termination_pipe.close(); | ||
stderr_pipe.close(); | ||
stdout_pipe.close(); | ||
} else { | ||
PLOG(ERROR) << "Unable to fork"; | ||
} | ||
return true; | ||
} |
Oops, something went wrong.