Skip to content

Commit

Permalink
Merge branch 'js/libgit-rust' into seen
Browse files Browse the repository at this point in the history
Foreign language interface for Rust into our code base has been added.

* js/libgit-rust:
  fixup! common-main: split init and exit code into new files
  Makefile: add option to build and test libgit-rs and libgit-rs-sys
  libgit: add higher-level libgit crate
  libgit-sys: also export some config_set functions
  libgit-sys: introduce Rust wrapper for libgit.a
  common-main: split init and exit code into new files
  • Loading branch information
gitster committed Jan 22, 2025
2 parents 18eaf57 + 2b8ee5e commit 7ce6aae
Show file tree
Hide file tree
Showing 23 changed files with 644 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,5 @@ Release/
/git.VC.db
*.dSYM
/contrib/buildsystems/out
/contrib/libgit-rs/target
/contrib/libgit-sys/target
44 changes: 44 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ include shared.mak
# Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
# programs in oss-fuzz/.
#
# Define INCLUDE_LIBGIT_RS if you want `make all` and `make test` to build and
# test the Rust crates in contrib/libgit-rs/ and contrib/libgit-rs/libgit-sys/.
#
# === Optional library: libintl ===
#
# Define NO_GETTEXT if you don't want Git output to be translated.
Expand Down Expand Up @@ -658,6 +661,8 @@ CURL_CONFIG = curl-config
GCOV = gcov
STRIP = strip
SPATCH = spatch
LD = ld
OBJCOPY = objcopy

export TCL_PATH TCLTK_PATH

Expand Down Expand Up @@ -984,6 +989,8 @@ LIB_OBJS += combine-diff.o
LIB_OBJS += commit-graph.o
LIB_OBJS += commit-reach.o
LIB_OBJS += commit.o
LIB_OBJS += common-exit.o
LIB_OBJS += common-init.o
LIB_OBJS += compat/nonblock.o
LIB_OBJS += compat/obstack.o
LIB_OBJS += compat/terminal.o
Expand Down Expand Up @@ -2254,6 +2261,13 @@ ifdef WITH_BREAKING_CHANGES
BASIC_CFLAGS += -DWITH_BREAKING_CHANGES
endif

ifdef INCLUDE_LIBGIT_RS
# Enable symbol hiding in contrib/libgit-rs/libgit-sys/libgitpub.a
# without making us rebuild the whole tree every time we run a Rust
# build.
BASIC_CFLAGS += -fvisibility=hidden
endif

ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
Expand Down Expand Up @@ -2749,6 +2763,7 @@ OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
OBJECTS += $(UNIT_TEST_OBJS)
OBJECTS += $(CLAR_TEST_OBJS)
OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
OBJECTS += contrib/libgit-sys/public_symbol_export.o

ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
Expand Down Expand Up @@ -3745,6 +3760,10 @@ clean: profile-clean coverage-clean cocciclean
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(MAKE) -C Documentation/ clean
$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
$(RM) -r contrib/libgit-rs/target contrib/libgit-sys/target
$(RM) -r contrib/libgit-sys/partial_symbol_export.o
$(RM) -r contrib/libgit-sys/hidden_symbol_export.o
$(RM) -r contrib/libgit-sys/libgitpub.a
ifndef NO_PERL
$(RM) -r perl/build/
endif
Expand Down Expand Up @@ -3906,3 +3925,28 @@ $(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) GIT-
build-unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) t/helper/test-tool$X
$(MAKE) -C t/ unit-tests

.PHONY: libgit-sys
libgit-sys:
$(QUIET)(\
cd contrib/libgit-sys && \
cargo build \
)
.PHONY: libgit-rs
libgit-rs:
$(QUIET)(\
cd contrib/libgit-rs && \
cargo build \
)
ifdef INCLUDE_LIBGIT_RS
all:: libgit-rs
endif

contrib/libgit-sys/partial_symbol_export.o: contrib/libgit-sys/public_symbol_export.o libgit.a reftable/libreftable.a xdiff/lib.a
$(LD) -r $^ -o $@

contrib/libgit-sys/hidden_symbol_export.o: contrib/libgit-sys/partial_symbol_export.o
$(OBJCOPY) --localize-hidden $^ $@

contrib/libgit-sys/libgitpub.a: contrib/libgit-sys/hidden_symbol_export.o
$(AR) $(ARFLAGS) $@ $^
26 changes: 26 additions & 0 deletions common-exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "git-compat-util.h"
#include "trace2.h"

static void check_bug_if_BUG(void)
{
if (!bug_called_must_BUG)
return;
BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
}

/* We wrap exit() to call common_exit() in git-compat-util.h */
int common_exit(const char *file, int line, int code)
{
/*
* For non-POSIX systems: Take the lowest 8 bits of the "code"
* to e.g. turn -1 into 255. On a POSIX system this is
* redundant, see exit(3) and wait(2), but as it doesn't harm
* anything there we don't need to guard this with an "ifdef".
*/
code &= 0xff;

check_bug_if_BUG();
trace2_cmd_exit_fl(file, line, code);

return code;
}
63 changes: 63 additions & 0 deletions common-init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "common-init.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "attr.h"
#include "repository.h"
#include "setup.h"
#include "strbuf.h"
#include "trace2.h"

/*
* Many parts of Git have subprograms communicate via pipe, expect the
* upstream of a pipe to die with SIGPIPE when the downstream of a
* pipe does not need to read all that is written. Some third-party
* programs that ignore or block SIGPIPE for their own reason forget
* to restore SIGPIPE handling to the default before spawning Git and
* break this carefully orchestrated machinery.
*
* Restore the way SIGPIPE is handled to default, which is what we
* expect.
*/
static void restore_sigpipe_to_default(void)
{
sigset_t unblock;

sigemptyset(&unblock);
sigaddset(&unblock, SIGPIPE);
sigprocmask(SIG_UNBLOCK, &unblock, NULL);
signal(SIGPIPE, SIG_DFL);
}

void init_git(const char **argv)
{
struct strbuf tmp = STRBUF_INIT;

trace2_initialize_clock();

/*
* Always open file descriptors 0/1/2 to avoid clobbering files
* in die(). It also avoids messing up when the pipes are dup'ed
* onto stdin/stdout/stderr in the child processes we spawn.
*/
sanitize_stdfds();
restore_sigpipe_to_default();

git_resolve_executable_dir(argv[0]);

setlocale(LC_CTYPE, "");
git_setup_gettext();

initialize_repository(the_repository);

attr_start();

trace2_initialize();
trace2_cmd_start(argv);
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);

if (!strbuf_getcwd(&tmp))
tmp_original_cwd = strbuf_detach(&tmp, NULL);
}
6 changes: 6 additions & 0 deletions common-init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef COMMON_INIT_H
#define COMMON_INIT_H

void init_git(const char **argv);

#endif /* COMMON_INIT_H */
83 changes: 2 additions & 81 deletions common-main.c
Original file line number Diff line number Diff line change
@@ -1,92 +1,13 @@
#define USE_THE_REPOSITORY_VARIABLE

#include "git-compat-util.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "attr.h"
#include "repository.h"
#include "setup.h"
#include "strbuf.h"
#include "trace2.h"

/*
* Many parts of Git have subprograms communicate via pipe, expect the
* upstream of a pipe to die with SIGPIPE when the downstream of a
* pipe does not need to read all that is written. Some third-party
* programs that ignore or block SIGPIPE for their own reason forget
* to restore SIGPIPE handling to the default before spawning Git and
* break this carefully orchestrated machinery.
*
* Restore the way SIGPIPE is handled to default, which is what we
* expect.
*/
static void restore_sigpipe_to_default(void)
{
sigset_t unblock;

sigemptyset(&unblock);
sigaddset(&unblock, SIGPIPE);
sigprocmask(SIG_UNBLOCK, &unblock, NULL);
signal(SIGPIPE, SIG_DFL);
}
#include "common-init.h"

int main(int argc, const char **argv)
{
int result;
struct strbuf tmp = STRBUF_INIT;

trace2_initialize_clock();

/*
* Always open file descriptors 0/1/2 to avoid clobbering files
* in die(). It also avoids messing up when the pipes are dup'ed
* onto stdin/stdout/stderr in the child processes we spawn.
*/
sanitize_stdfds();
restore_sigpipe_to_default();

git_resolve_executable_dir(argv[0]);

setlocale(LC_CTYPE, "");
git_setup_gettext();

initialize_repository(the_repository);

attr_start();

trace2_initialize();
trace2_cmd_start(argv);
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);

if (!strbuf_getcwd(&tmp))
tmp_original_cwd = strbuf_detach(&tmp, NULL);

init_git(argv);
result = cmd_main(argc, argv);

/* Not exit(3), but a wrapper calling our common_exit() */
exit(result);
}

static void check_bug_if_BUG(void)
{
if (!bug_called_must_BUG)
return;
BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
}

/* We wrap exit() to call common_exit() in git-compat-util.h */
int common_exit(const char *file, int line, int code)
{
/*
* For non-POSIX systems: Take the lowest 8 bits of the "code"
* to e.g. turn -1 into 255. On a POSIX system this is
* redundant, see exit(3) and wait(2), but as it doesn't harm
* anything there we don't need to guard this with an "ifdef".
*/
code &= 0xff;

check_bug_if_BUG();
trace2_cmd_exit_fl(file, line, code);

return code;
}
77 changes: 77 additions & 0 deletions contrib/libgit-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions contrib/libgit-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "libgit"
version = "0.1.0"
edition = "2021"
build = "build.rs"
rust-version = "1.63"

[lib]
path = "src/lib.rs"

[dependencies]
libgit-sys = { version = "0.1.0", path = "../libgit-sys" }

[build-dependencies]
autocfg = "1.4.0"
13 changes: 13 additions & 0 deletions contrib/libgit-rs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# libgit-rs

Proof-of-concept Git bindings for Rust.

```toml
[dependencies]
libgit = "0.1.0"
```

## Rust version requirements

libgit-rs should support Rust versions at least as old as the version included
in Debian stable (currently 1.63).
Loading

0 comments on commit 7ce6aae

Please sign in to comment.