Skip to content

Commit e08960c

Browse files
authored
Add git config (#77)
* Adds git config * address review comments * remove useless monkeypatch parameter
1 parent 8cc1807 commit e08960c

17 files changed

+301
-35
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ set(GIT2CPP_SRC
5050
${GIT2CPP_SOURCE_DIR}/subcommand/clone_subcommand.hpp
5151
${GIT2CPP_SOURCE_DIR}/subcommand/commit_subcommand.cpp
5252
${GIT2CPP_SOURCE_DIR}/subcommand/commit_subcommand.hpp
53+
${GIT2CPP_SOURCE_DIR}/subcommand/config_subcommand.cpp
54+
${GIT2CPP_SOURCE_DIR}/subcommand/config_subcommand.hpp
5355
${GIT2CPP_SOURCE_DIR}/subcommand/fetch_subcommand.cpp
5456
${GIT2CPP_SOURCE_DIR}/subcommand/fetch_subcommand.hpp
5557
${GIT2CPP_SOURCE_DIR}/subcommand/init_subcommand.cpp
@@ -88,6 +90,8 @@ set(GIT2CPP_SRC
8890
${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.hpp
8991
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.cpp
9092
${GIT2CPP_SOURCE_DIR}/wrapper/commit_wrapper.hpp
93+
${GIT2CPP_SOURCE_DIR}/wrapper/config_wrapper.cpp
94+
${GIT2CPP_SOURCE_DIR}/wrapper/config_wrapper.hpp
9195
${GIT2CPP_SOURCE_DIR}/wrapper/index_wrapper.cpp
9296
${GIT2CPP_SOURCE_DIR}/wrapper/index_wrapper.hpp
9397
${GIT2CPP_SOURCE_DIR}/wrapper/object_wrapper.cpp

src/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "subcommand/checkout_subcommand.hpp"
1111
#include "subcommand/clone_subcommand.hpp"
1212
#include "subcommand/commit_subcommand.hpp"
13+
#include "subcommand/config_subcommand.hpp"
1314
#include "subcommand/fetch_subcommand.hpp"
1415
#include "subcommand/init_subcommand.hpp"
1516
#include "subcommand/log_subcommand.hpp"
@@ -40,6 +41,7 @@ int main(int argc, char** argv)
4041
checkout_subcommand checkout(lg2_obj, app);
4142
clone_subcommand clone(lg2_obj, app);
4243
commit_subcommand commit(lg2_obj, app);
44+
config_subcommand config(lg2_obj, app);
4345
fetch_subcommand fetch(lg2_obj, app);
4446
reset_subcommand reset(lg2_obj, app);
4547
log_subcommand log(lg2_obj, app);

src/subcommand/add_subcommand.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ add_subcommand::add_subcommand(const libgit2_object&, CLI::App& app)
99
{
1010
auto *sub = app.add_subcommand("add", "Add file contents to the index");
1111

12-
sub->add_option("files", m_add_files, "Files to add");
12+
sub->add_option("<files>", m_add_files, "Files to add");
1313

1414
sub->add_flag("-A,--all,--no-ignore-removal", m_all_flag, "");
1515
// sub->add_flag("-n,--dryrun", dryrun_flag, "");
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include <git2/config.h>
2+
#include <git2/types.h>
3+
#include <iostream>
4+
5+
#include <git2/remote.h>
6+
7+
#include "../utils/git_exception.hpp"
8+
#include "../subcommand/config_subcommand.hpp"
9+
#include "../wrapper/config_wrapper.hpp"
10+
#include "../wrapper/repository_wrapper.hpp"
11+
12+
config_subcommand::config_subcommand(const libgit2_object&, CLI::App& app)
13+
{
14+
auto* config = app.add_subcommand("config", "Get and set repository or global options");
15+
auto* list = config->add_subcommand("list", "List all variables set in config file, along with their values.");
16+
auto* get = config->add_subcommand("get", "Emits the value of the specified key. If key is present multiple times in the configuration, emits the last value. If --all is specified, emits all values associated with key. Returns error code 1 if key is not present.");
17+
auto* set = config->add_subcommand("set", "Set value for one or more config options. By default, this command refuses to write multi-valued config options. Passing --all will replace all multi-valued config options with the new value, whereas --value= will replace all config options whose values match the given pattern.");
18+
auto* unset = config->add_subcommand("unset", "Unset value for one or more config options. By default, this command refuses to unset multi-valued keys. Passing --all will unset all multi-valued config options, whereas --value will unset all config options whose values match the given pattern.");
19+
20+
get->add_option("<name>", m_name, "");
21+
set->add_option("<name>", m_name, "");
22+
set->add_option("<value>", m_value, "");
23+
unset->add_option("<name>", m_name, "");
24+
25+
// TODO:
26+
// sub->add_flag("--local", m_local_flag, "");
27+
// sub->add_flag("--global", m_global_flag, "");
28+
// sub->add_flag("--system", m_system_flag, "");
29+
// sub->add_flag("--worktree", m_worktree_flag, "");
30+
31+
list->callback([this]() { this->run_list(); });
32+
get->callback([this]() { this->run_get(); });
33+
set->callback([this]() { this->run_set(); });
34+
unset->callback([this]() { this->run_unset(); });
35+
}
36+
37+
void config_subcommand::run_list()
38+
{
39+
auto directory = get_current_git_path();
40+
auto repo = repository_wrapper::open(directory);
41+
auto cfg = repo.get_config();
42+
43+
git_config_iterator* iter;
44+
throw_if_error(git_config_iterator_new(&iter, cfg));
45+
46+
git_config_entry* entry;
47+
while (git_config_next(&entry, iter) == GIT_OK)
48+
{
49+
std::cout << entry->name << "=" << entry->value << std::endl;
50+
}
51+
52+
git_config_iterator_free(iter);
53+
}
54+
55+
void config_subcommand::run_get()
56+
{
57+
if (m_name.empty())
58+
{
59+
throw git_exception("error: wrong number of arguments, should be 1", 129);
60+
}
61+
62+
auto directory = get_current_git_path();
63+
auto repo = repository_wrapper::open(directory);
64+
auto cfg = repo.get_config();
65+
66+
git_config_entry* entry = cfg.get_entry(m_name);
67+
std::cout << entry->value << std::endl;
68+
69+
git_config_entry_free(entry);
70+
}
71+
72+
void config_subcommand::run_set()
73+
{
74+
if (m_name.empty() | m_value.empty())
75+
{
76+
throw git_exception("error: wrong number of arguments, should be 2", 129);
77+
}
78+
79+
auto directory = get_current_git_path();
80+
auto repo = repository_wrapper::open(directory);
81+
auto cfg = repo.get_config();
82+
83+
cfg.set_entry(m_name, m_value);
84+
}
85+
86+
void config_subcommand::run_unset()
87+
{
88+
if (m_name.empty())
89+
{
90+
throw git_exception("error: wrong number of arguments, should be 1", 129);
91+
}
92+
93+
auto directory = get_current_git_path();
94+
auto repo = repository_wrapper::open(directory);
95+
auto cfg = repo.get_config();
96+
97+
cfg.delete_entry(m_name);
98+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <CLI/CLI.hpp>
4+
5+
#include "../utils/common.hpp"
6+
7+
class config_subcommand
8+
{
9+
public:
10+
11+
explicit config_subcommand(const libgit2_object&, CLI::App& app);
12+
void run_list();
13+
void run_set();
14+
void run_get();
15+
void run_unset();
16+
17+
std::string m_name;
18+
std::string m_value;
19+
20+
// TODO:
21+
// bool m_local_flag = false;
22+
// bool m_global_flag = false;
23+
// bool m_system_flag = false;
24+
// bool m_worktree_flag = false;
25+
};

src/wrapper/config_wrapper.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "../wrapper/config_wrapper.hpp"
2+
#include "../utils/git_exception.hpp"
3+
4+
config_wrapper::config_wrapper(git_config* cfg)
5+
: base_type(cfg)
6+
{
7+
}
8+
9+
config_wrapper::~config_wrapper()
10+
{
11+
git_config_free(p_resource);
12+
p_resource=nullptr;
13+
}
14+
15+
git_config_entry* config_wrapper::get_entry(std::string name)
16+
{
17+
git_config_entry* entry;
18+
throw_if_error(git_config_get_entry(&entry, *this, name.c_str()));
19+
return entry;
20+
}
21+
22+
void config_wrapper::set_entry(std::string name, std::string value)
23+
{
24+
throw_if_error(git_config_set_string(*this, name.c_str(), value.c_str()));
25+
}
26+
27+
void config_wrapper::delete_entry(std::string name)
28+
{
29+
throw_if_error(git_config_delete_entry(*this, name.c_str()));
30+
}

src/wrapper/config_wrapper.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
#include <git2.h>
6+
7+
#include "../wrapper/wrapper_base.hpp"
8+
9+
class config_wrapper : public wrapper_base<git_config>
10+
{
11+
public:
12+
13+
using base_type = wrapper_base<git_config>;
14+
15+
~config_wrapper();
16+
17+
config_wrapper(config_wrapper&&) noexcept = default;
18+
config_wrapper& operator=(config_wrapper&&) noexcept = default;
19+
20+
git_config_entry* get_entry(std::string name);
21+
void set_entry(std::string name, std::string value);
22+
void delete_entry(std::string name);
23+
24+
private:
25+
26+
config_wrapper(git_config* cfg);
27+
28+
friend class repository_wrapper;
29+
};

src/wrapper/repository_wrapper.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "../wrapper/commit_wrapper.hpp"
99
#include "../wrapper/remote_wrapper.hpp"
1010
#include "../wrapper/repository_wrapper.hpp"
11+
#include "config_wrapper.hpp"
1112

1213
repository_wrapper::~repository_wrapper()
1314
{
@@ -426,3 +427,12 @@ std::vector<std::string> repository_wrapper::list_remotes() const
426427
git_strarray_dispose(&remotes);
427428
return result;
428429
}
430+
431+
432+
// Config
433+
config_wrapper repository_wrapper::get_config()
434+
{
435+
git_config* cfg;
436+
throw_if_error(git_repository_config(&cfg, *this));
437+
return config_wrapper(cfg);
438+
}

src/wrapper/repository_wrapper.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../wrapper/annotated_commit_wrapper.hpp"
1111
#include "../wrapper/branch_wrapper.hpp"
1212
#include "../wrapper/commit_wrapper.hpp"
13+
#include "../wrapper/config_wrapper.hpp"
1314
#include "../wrapper/index_wrapper.hpp"
1415
#include "../wrapper/object_wrapper.hpp"
1516
#include "../wrapper/refs_wrapper.hpp"
@@ -96,6 +97,9 @@ class repository_wrapper : public wrapper_base<git_repository>
9697
void set_remote_url(std::string_view name, std::string_view url, bool push = false);
9798
std::vector<std::string> list_remotes() const;
9899

100+
// Config
101+
config_wrapper get_config();
102+
99103
private:
100104

101105
repository_wrapper() = default;

test/conftest.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import os
2+
import subprocess
23
from pathlib import Path
4+
35
import pytest
4-
import subprocess
56

67
GIT2CPP_TEST_WASM = os.getenv('GIT2CPP_TEST_WASM') == "1"
78

@@ -28,11 +29,12 @@ def git2cpp_path():
2829
def xtl_clone(git2cpp_path, tmp_path, run_in_tmp_path):
2930
url = "https://github.com/xtensor-stack/xtl.git"
3031
clone_cmd = [git2cpp_path, "clone", url]
31-
subprocess.run(clone_cmd, capture_output=True, cwd=tmp_path, text=True)
32+
p = subprocess.run(clone_cmd, capture_output=True, cwd=tmp_path, text=True)
33+
assert p.returncode == 0
3234

3335

3436
@pytest.fixture
35-
def git_config(monkeypatch):
37+
def commit_env_config(monkeypatch):
3638
monkeypatch.setenv("GIT_AUTHOR_NAME", "Jane Doe")
3739
monkeypatch.setenv("GIT_AUTHOR_EMAIL", "jane.doe@blabla.com")
3840
monkeypatch.setenv("GIT_COMMITTER_NAME", "Jane Doe")

0 commit comments

Comments
 (0)