#include "../subcommand/remote_subcommand.hpp" #include #include #include "../wrapper/repository_wrapper.hpp" remote_subcommand::remote_subcommand(const libgit2_object&, CLI::App& app) { m_subcommand = app.add_subcommand("remote", "Manage set of tracked repositories"); m_subcommand->add_option("operation", m_operation, "Operation: add, remove, rename, set-url, show") ->check(CLI::IsMember({"add", "remove", "rm", "rename", "set-url", "show"})); m_subcommand->add_flag("-v,--verbose", m_verbose_flag, "Be verbose"); m_subcommand->add_flag("--push", m_push_flag, "Set push URL instead of fetch URL"); // Allow positional arguments after operation m_subcommand->allow_extras(); m_subcommand->callback( [this]() { this->run(); } ); } void remote_subcommand::run() { auto directory = get_current_git_path(); auto repo = repository_wrapper::open(directory); // Get extra positional arguments auto extras = m_subcommand->remaining(); // Parse positional arguments based on operation if (m_operation == "add") { if (extras.size() == 2) { m_remote_name = extras[0]; m_url = extras[1]; } run_add(repo); } else if (m_operation == "remove" || m_operation == "rm") { if (extras.size() == 1) { m_remote_name = extras[0]; } run_remove(repo); } else if (m_operation == "rename") { if (extras.size() == 2) { m_old_name = extras[0]; m_new_name = extras[1]; } run_rename(repo); } else if (m_operation == "set-url") { // Handle --push flag before arguments size_t arg_idx = 0; if (extras.size() > 0 && extras[0] == "--push") { m_push_flag = true; arg_idx = 1; } if (extras.size() >= arg_idx + 2) { m_remote_name = extras[arg_idx]; m_new_name = extras[arg_idx + 1]; run_seturl(repo); } else if (m_remote_name.empty() || m_new_name.empty()) { throw std::runtime_error("remote set-url requires both name and new URL"); } else { run_seturl(repo); } } else if (m_operation.empty() || m_operation == "show") { if (extras.size() >= 1) { m_remote_name = extras[0]; } run_show(repo); } } void remote_subcommand::run_add(repository_wrapper& repo) { if (m_remote_name.empty()) { throw std::runtime_error("usage: git remote add "); // TODO: add [] when // implemented } repo.create_remote(m_remote_name, m_url); } void remote_subcommand::run_remove(repository_wrapper& repo) { if (m_remote_name.empty()) { throw std::runtime_error("usage: git remote remove "); } repo.delete_remote(m_remote_name); } void remote_subcommand::run_rename(repository_wrapper& repo) { if (m_old_name.empty()) { throw std::runtime_error("usage: git remote rename "); // TODO: add [--[no-]progress] // when implemented } repo.rename_remote(m_old_name, m_new_name); } void remote_subcommand::run_seturl(repository_wrapper& repo) { if (m_remote_name.empty() || m_new_name.empty()) { throw std::runtime_error("remote set-url requires both name and new URL"); } repo.set_remote_url(m_remote_name, m_new_name, m_push_flag); } void remote_subcommand::run_show(const repository_wrapper& repo) { auto remotes = repo.list_remotes(); if (m_remote_name.empty()) { // Show all remotes for (const auto& name : remotes) { if (m_verbose_flag) { auto remote = repo.find_remote(name); auto fetch_url = remote.url(); auto push_url = remote.pushurl(); if (!fetch_url.empty()) { std::cout << name << "\t" << fetch_url << " (fetch)" << std::endl; } if (!push_url.empty()) { std::cout << name << "\t" << push_url << " (push)" << std::endl; } else if (!fetch_url.empty()) { std::cout << name << "\t" << fetch_url << " (push)" << std::endl; } } else { std::cout << name << std::endl; } } } else { // Show specific remote auto remote = repo.find_remote(m_remote_name); std::cout << "* remote " << m_remote_name << std::endl; auto fetch_url = remote.url(); if (!fetch_url.empty()) { std::cout << " Fetch URL: " << fetch_url << std::endl; } auto push_url = remote.pushurl(); if (!push_url.empty()) { std::cout << " Push URL: " << push_url << std::endl; } else if (!fetch_url.empty()) { std::cout << " Push URL: " << fetch_url << std::endl; } auto refspecs = remote.refspecs(); if (!refspecs.empty()) { std::cout << " HEAD branch: (not yet implemented)" << std::endl; for (const auto& refspec : refspecs) { std::cout << " " << refspec << std::endl; } } } }