Try to also grab submodules
This commit is contained in:
parent
f5bb145add
commit
5765fe829b
@ -197,21 +197,20 @@ static void git_init_once() {
|
||||
});
|
||||
}
|
||||
|
||||
static void git_fetch_and_checkout(const fs::path &repo_path, const std::string &repo_url, const std::optional<std::string> &branch) {
|
||||
static void git_fetch_and_checkout(const fs::path& repo_path, const std::string& repo_url, const std::optional<std::string>& branch) {
|
||||
log_info("Fetching and checking out repository: " + repo_url + " into " + repo_path.string());
|
||||
git_init_once();
|
||||
|
||||
// Define unique_ptrs with lambda-based deleters for libgit2 resources
|
||||
auto repo_deleter = [](git_repository* r) { if (r) git_repository_free(r); };
|
||||
std::unique_ptr<git_repository, decltype(repo_deleter)> repo(nullptr, repo_deleter);
|
||||
|
||||
bool need_clone = false;
|
||||
|
||||
if(fs::exists(repo_path)) {
|
||||
if (fs::exists(repo_path)) {
|
||||
log_verbose("Repository path exists. Attempting to open repository.");
|
||||
git_repository* raw_repo = nullptr;
|
||||
int err = git_repository_open(&raw_repo, repo_path.string().c_str());
|
||||
if(err < 0) {
|
||||
if (err < 0) {
|
||||
log_warning("Cannot open repo at " + repo_path.string() + ", recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
need_clone = true;
|
||||
@ -224,139 +223,130 @@ static void git_fetch_and_checkout(const fs::path &repo_path, const std::string
|
||||
need_clone = true;
|
||||
}
|
||||
|
||||
if(!need_clone && repo) {
|
||||
// Define unique_ptr for git_remote with lambda-based deleter
|
||||
auto remote_deleter = [](git_remote* r) { if (r) git_remote_free(r); };
|
||||
std::unique_ptr<git_remote, decltype(remote_deleter)> remote(nullptr, remote_deleter);
|
||||
git_remote* raw_remote = nullptr;
|
||||
int err = git_remote_lookup(&raw_remote, repo.get(), "origin");
|
||||
if(err < 0) {
|
||||
log_warning("No origin remote found. Recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
need_clone = true;
|
||||
} else {
|
||||
remote.reset(raw_remote);
|
||||
const char* url = git_remote_url(remote.get());
|
||||
if(!url || repo_url != url) {
|
||||
log_warning("Remote URL differs. Recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
need_clone = true;
|
||||
} else {
|
||||
log_verbose("Remote URL matches. Fetching latest changes.");
|
||||
// Fetch
|
||||
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
|
||||
err = git_remote_fetch(remote.get(), nullptr, &fetch_opts, nullptr);
|
||||
if(err < 0){
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Git fetch failed: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Git fetch failed");
|
||||
}
|
||||
log_verbose("Fetch completed.");
|
||||
|
||||
if(branch) {
|
||||
// Define unique_ptr for git_reference with lambda-based deleter
|
||||
auto ref_deleter = [](git_reference* r) { if (r) git_reference_free(r); };
|
||||
std::unique_ptr<git_reference, decltype(ref_deleter)> ref(nullptr, ref_deleter);
|
||||
std::string fullbranch = "refs/remotes/origin/" + *branch;
|
||||
git_reference* raw_ref = nullptr;
|
||||
int ref_err = git_reference_lookup(&raw_ref, repo.get(), fullbranch.c_str());
|
||||
if(ref_err == 0){
|
||||
ref.reset(raw_ref);
|
||||
|
||||
// Define unique_ptr for git_object with lambda-based deleter
|
||||
auto target_deleter = [](git_object* o) { if (o) git_object_free(o); };
|
||||
std::unique_ptr<git_object, decltype(target_deleter)> target(nullptr, target_deleter);
|
||||
git_object* raw_target = nullptr;
|
||||
git_reference_peel(&raw_target, ref.get(), GIT_OBJECT_COMMIT);
|
||||
if(raw_target == nullptr) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to peel reference: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Failed to peel reference");
|
||||
}
|
||||
target.reset(raw_target);
|
||||
|
||||
git_checkout_options co_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
co_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
int checkout_err = git_checkout_tree(repo.get(), target.get(), &co_opts);
|
||||
if(checkout_err != 0){
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to checkout tree: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Git checkout failed");
|
||||
}
|
||||
|
||||
git_repository_set_head_detached(repo.get(), git_object_id(target.get()));
|
||||
log_info("Checked out branch: " + *branch);
|
||||
} else {
|
||||
log_warning("Branch " + *branch + " not found, recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
need_clone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(need_clone) {
|
||||
// Define unique_ptr for new repository with lambda-based deleter
|
||||
auto newrepo_deleter = [](git_repository* r) { if (r) git_repository_free(r); };
|
||||
std::unique_ptr<git_repository, decltype(newrepo_deleter)> newrepo(nullptr, newrepo_deleter);
|
||||
|
||||
git_repository* raw_newrepo = nullptr;
|
||||
if (need_clone) {
|
||||
log_info("Cloning repository from " + repo_url + " to " + repo_path.string());
|
||||
git_repository* raw_newrepo = nullptr;
|
||||
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
|
||||
git_checkout_options co_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
co_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
clone_opts.checkout_opts = co_opts;
|
||||
int err = git_clone(&raw_newrepo, repo_url.c_str(), repo_path.string().c_str(), &clone_opts);
|
||||
if(err < 0) {
|
||||
clone_opts.fetch_opts = GIT_FETCH_OPTIONS_INIT;
|
||||
|
||||
if (git_clone(&raw_newrepo, repo_url.c_str(), repo_path.string().c_str(), &clone_opts) != 0) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Git clone failed: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Git clone failed");
|
||||
}
|
||||
newrepo.reset(raw_newrepo);
|
||||
repo.reset(raw_newrepo);
|
||||
log_info("Repository cloned successfully.");
|
||||
|
||||
if(branch) {
|
||||
// Define unique_ptr for git_reference with lambda-based deleter
|
||||
auto ref_deleter = [](git_reference* r) { if (r) git_reference_free(r); };
|
||||
std::unique_ptr<git_reference, decltype(ref_deleter)> ref(nullptr, ref_deleter);
|
||||
// Checkout branch if specified
|
||||
if (branch) {
|
||||
std::string fullbranch = "refs/remotes/origin/" + *branch;
|
||||
git_reference* raw_ref = nullptr;
|
||||
int ref_err = git_reference_lookup(&raw_ref, newrepo.get(), fullbranch.c_str());
|
||||
if(ref_err == 0) {
|
||||
ref.reset(raw_ref);
|
||||
|
||||
// Define unique_ptr for git_object with lambda-based deleter
|
||||
auto target_deleter = [](git_object* o) { if (o) git_object_free(o); };
|
||||
std::unique_ptr<git_object, decltype(target_deleter)> target(nullptr, target_deleter);
|
||||
git_object* raw_target = nullptr;
|
||||
git_reference_peel(&raw_target, ref.get(), GIT_OBJECT_COMMIT);
|
||||
if(raw_target == nullptr) {
|
||||
git_object* target = nullptr;
|
||||
if (git_revparse_single(&target, repo.get(), fullbranch.c_str()) == 0) {
|
||||
git_checkout_options co_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
co_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
if (git_checkout_tree(repo.get(), target, &co_opts) != 0) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to peel reference after clone: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Failed to peel reference after clone");
|
||||
log_error(std::string("Git checkout failed: ") + (e ? e->message : "unknown error"));
|
||||
git_object_free(target);
|
||||
throw std::runtime_error("Git checkout failed");
|
||||
}
|
||||
target.reset(raw_target);
|
||||
|
||||
git_checkout_options co_opts_clone = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
co_opts_clone.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
int checkout_err = git_checkout_tree(newrepo.get(), target.get(), &co_opts_clone);
|
||||
if(checkout_err != 0){
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to checkout tree after clone: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Git checkout after clone failed");
|
||||
}
|
||||
|
||||
git_repository_set_head_detached(newrepo.get(), git_object_id(target.get()));
|
||||
log_info("Checked out branch: " + *branch + " after clone.");
|
||||
git_repository_set_head(repo.get(), fullbranch.c_str());
|
||||
git_object_free(target);
|
||||
log_info("Checked out branch: " + *branch);
|
||||
} else {
|
||||
log_warning("Git checkout of branch " + *branch + " failed after clone.");
|
||||
throw std::runtime_error("Branch checkout failed");
|
||||
log_warning("Branch " + *branch + " not found.");
|
||||
}
|
||||
}
|
||||
// newrepo will be automatically freed when it goes out of scope
|
||||
|
||||
// Initialize and update submodules
|
||||
log_info("Initializing and updating submodules for cloned repository.");
|
||||
git_submodule* submodule = nullptr;
|
||||
git_submodule_iterator* submodule_iterator = nullptr;
|
||||
|
||||
if (git_submodule_iterator_new(&submodule_iterator, repo.get()) == 0) {
|
||||
while (git_submodule_next(&submodule, submodule_iterator) != GIT_ITEROVER) {
|
||||
const char* submodule_name = git_submodule_name(submodule);
|
||||
log_info("Processing submodule: " + std::string(submodule_name ? submodule_name : "unknown"));
|
||||
|
||||
if (git_submodule_update(submodule, 1, nullptr) != 0) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to update submodule ") +
|
||||
(submodule_name ? submodule_name : "unknown") + ": " +
|
||||
(e ? e->message : "unknown error"));
|
||||
git_submodule_free(submodule);
|
||||
throw std::runtime_error("Submodule update failed");
|
||||
}
|
||||
git_submodule_free(submodule);
|
||||
}
|
||||
git_submodule_iterator_free(submodule_iterator);
|
||||
log_info("Submodules initialized and updated successfully.");
|
||||
} else {
|
||||
log_warning("No submodules found in cloned repository.");
|
||||
}
|
||||
}
|
||||
log_verbose("Finished fetching and checking out repository: " + repo_path.string());
|
||||
|
||||
if (!need_clone && repo) {
|
||||
// Remote validation and fetch
|
||||
log_verbose("Validating remote origin.");
|
||||
auto remote_deleter = [](git_remote* r) { if (r) git_remote_free(r); };
|
||||
std::unique_ptr<git_remote, decltype(remote_deleter)> remote(nullptr, remote_deleter);
|
||||
git_remote* raw_remote = nullptr;
|
||||
|
||||
int err = git_remote_lookup(&raw_remote, repo.get(), "origin");
|
||||
if (err < 0) {
|
||||
log_warning("No origin remote found. Recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
throw std::runtime_error("No origin remote found.");
|
||||
}
|
||||
remote.reset(raw_remote);
|
||||
const char* url = git_remote_url(remote.get());
|
||||
if (!url || repo_url != url) {
|
||||
log_warning("Remote URL differs. Recloning.");
|
||||
fs::remove_all(repo_path);
|
||||
throw std::runtime_error("Remote URL mismatch.");
|
||||
}
|
||||
|
||||
// Fetch changes
|
||||
log_verbose("Fetching latest changes.");
|
||||
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
|
||||
if (git_remote_fetch(remote.get(), nullptr, &fetch_opts, nullptr) != 0) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Git fetch failed: ") + (e ? e->message : "unknown error"));
|
||||
throw std::runtime_error("Git fetch failed");
|
||||
}
|
||||
|
||||
log_verbose("Fetch completed.");
|
||||
|
||||
// Update submodules after fetch
|
||||
log_info("Updating submodules after fetching.");
|
||||
git_submodule* submodule = nullptr;
|
||||
git_submodule_iterator* submodule_iterator = nullptr;
|
||||
|
||||
if (git_submodule_iterator_new(&submodule_iterator, repo.get()) == 0) {
|
||||
while (git_submodule_next(&submodule, submodule_iterator) != GIT_ITEROVER) {
|
||||
const char* submodule_name = git_submodule_name(submodule);
|
||||
log_info("Processing submodule: " + std::string(submodule_name ? submodule_name : "unknown"));
|
||||
|
||||
if (git_submodule_update(submodule, 1, nullptr) != 0) {
|
||||
const git_error* e = git_error_last();
|
||||
log_error(std::string("Failed to update submodule ") +
|
||||
(submodule_name ? submodule_name : "unknown") + ": " +
|
||||
(e ? e->message : "unknown error"));
|
||||
git_submodule_free(submodule);
|
||||
throw std::runtime_error("Submodule update failed");
|
||||
}
|
||||
git_submodule_free(submodule);
|
||||
}
|
||||
git_submodule_iterator_free(submodule_iterator);
|
||||
log_info("Submodules updated successfully.");
|
||||
} else {
|
||||
log_warning("No submodules found.");
|
||||
}
|
||||
}
|
||||
log_verbose("Completed fetch and checkout for: " + repo_path.string());
|
||||
}
|
||||
|
||||
static YAML::Node load_config(const fs::path &config_path) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user