Skip to content

Commit b47ae1d

Browse files
authored
Merge branch 'main' into diff_find
2 parents 3b4f421 + bec1e72 commit b47ae1d

32 files changed

+1555
-943
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ jobs:
4848
./git2cpp -v
4949
5050
- name: Run tests
51+
env:
52+
GIT2CPP_TEST_PRIVATE_TOKEN: ${{ secrets.GIT2CPP_TEST_PRIVATE_TOKEN }}
5153
run: |
5254
pytest -v
5355
@@ -76,6 +78,8 @@ jobs:
7678
run: cmake --build . --parallel 8
7779

7880
- name: Run tests
81+
env:
82+
GIT2CPP_TEST_PRIVATE_TOKEN: ${{ secrets.GIT2CPP_TEST_PRIVATE_TOKEN }}
7983
run: |
8084
pytest -v
8185
@@ -98,41 +102,3 @@ jobs:
98102
files: coverage.lcov
99103
token: ${{ secrets.CODECOV_TOKEN }}
100104
verbose: true
101-
102-
docs:
103-
name: 'Build docs'
104-
runs-on: ubuntu-latest
105-
steps:
106-
- name: Checkout source
107-
uses: actions/checkout@v6
108-
with:
109-
fetch-depth: 0
110-
111-
- name: Create micromamba environment
112-
uses: mamba-org/setup-micromamba@main
113-
with:
114-
environment-file: dev-environment.yml
115-
cache-environment: true
116-
117-
- name: Configure CMake
118-
run: |
119-
cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX
120-
121-
- name: Build with CMake
122-
working-directory: build
123-
run: cmake --build . --parallel 8
124-
125-
- name: Install docs dependencies
126-
run: |
127-
python -m pip install myst-parser sphinx sphinx-book-theme
128-
129-
- name: Build docs
130-
working-directory: docs
131-
run: |
132-
make html
133-
134-
- name: Upload built docs
135-
uses: actions/upload-artifact@v6
136-
with:
137-
name: git2cpp-docs
138-
path: docs/_build/html

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ set(GIT2CPP_SRC
8888
${GIT2CPP_SOURCE_DIR}/utils/ansi_code.hpp
8989
${GIT2CPP_SOURCE_DIR}/utils/common.cpp
9090
${GIT2CPP_SOURCE_DIR}/utils/common.hpp
91+
${GIT2CPP_SOURCE_DIR}/utils/credentials.cpp
92+
${GIT2CPP_SOURCE_DIR}/utils/credentials.hpp
9193
${GIT2CPP_SOURCE_DIR}/utils/git_exception.cpp
9294
${GIT2CPP_SOURCE_DIR}/utils/git_exception.hpp
93-
${GIT2CPP_SOURCE_DIR}/utils/output.cpp
94-
${GIT2CPP_SOURCE_DIR}/utils/output.hpp
95+
${GIT2CPP_SOURCE_DIR}/utils/input_output.cpp
96+
${GIT2CPP_SOURCE_DIR}/utils/input_output.hpp
9597
${GIT2CPP_SOURCE_DIR}/utils/progress.cpp
9698
${GIT2CPP_SOURCE_DIR}/utils/progress.hpp
9799
${GIT2CPP_SOURCE_DIR}/utils/terminal_pager.cpp

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# git2cpp
2+
[![GithubActions](https://github.com/QuantStack/git2cpp/actions/workflows/test.yml/badge.svg)](https://github.com/QuantStack/git2cpp/actions/workflows/test.yml)
3+
[![Documentation Status](http://readthedocs.org/projects/git2cpp/badge/?version=latest)](https://git2cpp.readthedocs.io/en/latest/?badge=latest)
4+
[![Codecov](https://codecov.io/gh/QuantStack/git2cpp/graph/badge.svg)](https://app.codecov.io/gh/QuantStack/git2cpp)
25

36
This is a C++ wrapper of [libgit2](https://libgit2.org/) to provide a command-line interface (CLI)
47
to `git` functionality. The intended use is in WebAssembly in-browser terminals (see

src/subcommand/clone_subcommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#include <iostream>
22

33
#include "../subcommand/clone_subcommand.hpp"
4-
#include "../utils/output.hpp"
4+
#include "../utils/credentials.hpp"
5+
#include "../utils/input_output.hpp"
56
#include "../utils/progress.hpp"
67
#include "../wrapper/repository_wrapper.hpp"
78

@@ -42,6 +43,7 @@ void clone_subcommand::run()
4243
checkout_opts.progress_cb = checkout_progress;
4344
checkout_opts.progress_payload = &pd;
4445
clone_opts.checkout_opts = checkout_opts;
46+
clone_opts.fetch_opts.callbacks.credentials = user_credentials;
4547
clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
4648
clone_opts.fetch_opts.callbacks.transfer_progress = fetch_progress;
4749
clone_opts.fetch_opts.callbacks.payload = &pd;

src/subcommand/commit_subcommand.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <unistd.h>
33

44
#include "../subcommand/commit_subcommand.hpp"
5+
#include "../utils/input_output.hpp"
56
#include "../wrapper/index_wrapper.hpp"
67
#include "../wrapper/repository_wrapper.hpp"
78

@@ -24,8 +25,7 @@ void commit_subcommand::run()
2425

2526
if (m_commit_message.empty())
2627
{
27-
std::cout << "Please enter a commit message:" << std::endl;
28-
std::getline(std::cin, m_commit_message);
28+
m_commit_message = prompt_input("Please enter a commit message:\n");
2929
if (m_commit_message.empty())
3030
{
3131
throw std::runtime_error("Aborting, no commit message specified.");

src/subcommand/fetch_subcommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#include <git2/remote.h>
44

55
#include "../subcommand/fetch_subcommand.hpp"
6-
#include "../utils/output.hpp"
6+
#include "../utils/credentials.hpp"
7+
#include "../utils/input_output.hpp"
78
#include "../utils/progress.hpp"
89
#include "../wrapper/repository_wrapper.hpp"
910

@@ -34,6 +35,7 @@ void fetch_subcommand::run()
3435

3536
git_indexer_progress pd = {0};
3637
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
38+
fetch_opts.callbacks.credentials = user_credentials;
3739
fetch_opts.callbacks.sideband_progress = sideband_progress;
3840
fetch_opts.callbacks.transfer_progress = fetch_progress;
3941
fetch_opts.callbacks.payload = &pd;

src/subcommand/push_subcommand.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <git2/remote.h>
44

55
#include "../subcommand/push_subcommand.hpp"
6+
#include "../utils/credentials.hpp"
67
#include "../utils/progress.hpp"
78
#include "../wrapper/repository_wrapper.hpp"
89

@@ -27,6 +28,7 @@ void push_subcommand::run()
2728
auto remote = repo.find_remote(remote_name);
2829

2930
git_push_options push_opts = GIT_PUSH_OPTIONS_INIT;
31+
push_opts.callbacks.credentials = user_credentials;
3032
push_opts.callbacks.push_transfer_progress = push_transfer_progress;
3133
push_opts.callbacks.push_update_reference = push_update_reference;
3234

src/utils/credentials.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <git2/credential.h>
2+
#include <iostream>
3+
4+
#include "credentials.hpp"
5+
#include "input_output.hpp"
6+
7+
// git_credential_acquire_cb
8+
int user_credentials(
9+
git_credential** out,
10+
const char* url,
11+
const char* username_from_url,
12+
unsigned int allowed_types,
13+
void* payload)
14+
{
15+
// Check for cached credentials here, if desired.
16+
// It might be necessary to make this function stateful to avoid repeating unnecessary checks.
17+
18+
*out = nullptr;
19+
20+
if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) {
21+
std::string username = username_from_url ? username_from_url : "";
22+
if (username.empty()) {
23+
username = prompt_input("Username: ");
24+
}
25+
if (username.empty()) {
26+
giterr_set_str(GIT_ERROR_HTTP, "No username specified");
27+
return GIT_EAUTH;
28+
}
29+
30+
std::string password = prompt_input("Password: ", false);
31+
if (password.empty()) {
32+
giterr_set_str(GIT_ERROR_HTTP, "No password specified");
33+
return GIT_EAUTH;
34+
}
35+
36+
// If successful, this will create and return a git_credential* in the out argument.
37+
return git_credential_userpass_plaintext_new(out, username.c_str(), password.c_str());
38+
}
39+
40+
giterr_set_str(GIT_ERROR_HTTP, "Unexpected credentials request");
41+
return GIT_ERROR;
42+
}

src/utils/credentials.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include <git2/credential.h>
4+
5+
// Libgit2 callback of type git_credential_acquire_cb to obtain user credentials
6+
// (username and password) to authenticate remote https access.
7+
int user_credentials(
8+
git_credential** out,
9+
const char* url,
10+
const char* username_from_url,
11+
unsigned int allowed_types,
12+
void* payload
13+
);

src/utils/input_output.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "ansi_code.hpp"
2+
#include "input_output.hpp"
3+
4+
// OS-specific libraries.
5+
#include <sys/ioctl.h>
6+
7+
cursor_hider::cursor_hider(bool hide /* = true */)
8+
: m_hide(hide)
9+
{
10+
std::cout << (m_hide ? ansi_code::hide_cursor : ansi_code::show_cursor);
11+
}
12+
13+
cursor_hider::~cursor_hider()
14+
{
15+
std::cout << (m_hide ? ansi_code::show_cursor : ansi_code::hide_cursor);
16+
}
17+
18+
19+
alternative_buffer::alternative_buffer()
20+
{
21+
tcgetattr(fileno(stdin), &m_previous_termios);
22+
auto new_termios = m_previous_termios;
23+
// Disable canonical mode (buffered I/O) and echo from stdin to stdout.
24+
new_termios.c_lflag &= (~ICANON & ~ECHO);
25+
tcsetattr(fileno(stdin), TCSANOW, &new_termios);
26+
27+
std::cout << ansi_code::enable_alternative_buffer;
28+
}
29+
30+
alternative_buffer::~alternative_buffer()
31+
{
32+
std::cout << ansi_code::disable_alternative_buffer;
33+
34+
// Restore previous termios settings.
35+
tcsetattr(fileno(stdin), TCSANOW, &m_previous_termios);
36+
}
37+
38+
echo_control::echo_control(bool echo)
39+
: m_echo(echo)
40+
{
41+
if (!m_echo) {
42+
tcgetattr(fileno(stdin), &m_previous_termios);
43+
auto new_termios = m_previous_termios;
44+
new_termios.c_lflag &= ~ECHO;
45+
tcsetattr(fileno(stdin), TCSANOW, &new_termios);
46+
}
47+
}
48+
49+
echo_control::~echo_control()
50+
{
51+
if (!m_echo) {
52+
// Restore previous termios settings.
53+
tcsetattr(fileno(stdin), TCSANOW, &m_previous_termios);
54+
}
55+
}
56+
57+
58+
std::string prompt_input(const std::string_view prompt, bool echo /* = true */)
59+
{
60+
std::cout << prompt;
61+
62+
echo_control ec(echo);
63+
std::string input;
64+
65+
cursor_hider ch(false); // Re-enable cursor if currently hidden.
66+
std::getline(std::cin, input);
67+
68+
if (!echo) {
69+
std::cout << std::endl;
70+
}
71+
72+
// Maybe sanitise input, removing escape codes?
73+
return input;
74+
}

0 commit comments

Comments
 (0)