Skip to content

Commit 3a3ab06

Browse files
committed
cli: infrastructure for a cli project
Introduce a command-line interface for libgit2. The goal is for it to be git-compatible. 1. The libgit2 developers can more easily dogfood libgit2 to find bugs, and performance issues. 2. There is growing usage of libgit2's examples as a client; libgit2's examples should be exactly that - simple code samples that illustrate libgit2's usage. This satisfies that need directly. 3. By producing a client ourselves, we can better understand the needs of client creators, possibly producing a shared "middleware" for commonly-used pieces of client functionality like interacting with external tools. 4. Since git is the reference implementation, we may be able to benefit from git's unit tests, running their test suite against our CLI to ensure correct behavior. This commit introduces a simple infrastructure for the CLI. The CLI is currently links libgit2 statically; this is because the utility layer is required for libgit2 _but_ shares the error state handling with libgit2 itself. There's no obviously good solution here without introducing annoying indirection or more complexity. Until we can untangle that dependency, this is a good step forward. In the meantime, we link the libgit2 object files, but we do not include the (private) libgit2 headers. This constrains the CLI to the public libgit2 interfaces.
1 parent d02f4f7 commit 3a3ab06

12 files changed

+1299
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
1818
# Optional subsystems
1919
option(BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
2020
option(BUILD_TESTS "Build Tests using the Clar suite" ON)
21+
option(BUILD_CLI "Build the command-line interface" ON)
2122
option(BUILD_EXAMPLES "Build library usage example apps" OFF)
2223
option(BUILD_FUZZERS "Build the fuzz targets" OFF)
2324

src/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ configure_file(features.h.in git2/sys/features.h)
178178
add_subdirectory(libgit2)
179179
add_subdirectory(util)
180180

181+
if(BUILD_CLI)
182+
add_subdirectory(cli)
183+
endif()
184+
181185
# re-export these to the root so that peer projects (tests, fuzzers,
182186
# examples) can use them
183187
set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)

src/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
This is the source that makes up the core of libgit2 and its related
44
projects.
55

6+
* `cli`
7+
A git-compatible command-line interface that uses libgit2.
68
* `libgit2`
79
This is the libgit2 project, a cross-platform, linkable library
810
implementation of Git that you can use in your application.

src/cli/CMakeLists.txt

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
set(CLI_INCLUDES
2+
"${libgit2_BINARY_DIR}/src"
3+
"${libgit2_SOURCE_DIR}/src/util"
4+
"${libgit2_SOURCE_DIR}/src/cli"
5+
"${libgit2_SOURCE_DIR}/include")
6+
7+
if(WIN32 AND NOT CYGWIN)
8+
file(GLOB CLI_SRC_OS win32/*.c)
9+
list(SORT CLI_SRC_OS)
10+
else()
11+
file(GLOB CLI_SRC_OS unix/*.c)
12+
list(SORT CLI_SRC_OS)
13+
endif()
14+
15+
file(GLOB CLI_SRC_C *.c *.h)
16+
list(SORT CLI_SRC_C)
17+
18+
#
19+
# The CLI currently needs to be statically linked against libgit2 because
20+
# the utility library uses libgit2's thread-local error buffers. TODO:
21+
# remove this dependency and allow us to dynamically link against libgit2.
22+
#
23+
24+
if(BUILD_CLI STREQUAL "dynamic")
25+
set(CLI_LIBGIT2_LIBRARY libgit2package)
26+
else()
27+
set(CLI_LIBGIT2_OBJECTS $<TARGET_OBJECTS:libgit2>)
28+
endif()
29+
30+
#
31+
# Compile and link the CLI
32+
#
33+
34+
add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS}
35+
$<TARGET_OBJECTS:util>
36+
${CLI_LIBGIT2_OBJECTS}
37+
${LIBGIT2_DEPENDENCY_OBJECTS})
38+
target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS})
39+
40+
set_target_properties(git2_cli PROPERTIES C_STANDARD 90)
41+
set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR})
42+
43+
ide_split_sources(git2_cli)
44+
45+
target_include_directories(git2_cli PRIVATE ${CLI_INCLUDES})
46+
47+
if(MSVC_IDE)
48+
# Precompiled headers
49+
set_target_properties(git2_cli PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
50+
set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h")
51+
endif()
52+
53+
install(TARGETS git2_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

src/cli/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cli
2+
3+
A git-compatible command-line interface that uses libgit2.

src/cli/cli.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#ifndef CLI_cli_h__
9+
#define CLI_cli_h__
10+
11+
#define PROGRAM_NAME "git2"
12+
13+
#include "git2_util.h"
14+
15+
#include "error.h"
16+
#include "opt.h"
17+
18+
#endif /* CLI_cli_h__ */

src/cli/error.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#ifndef CLI_error_h__
9+
#define CLI_error_h__
10+
11+
#include "cli.h"
12+
#include <stdio.h>
13+
14+
#define CLI_EXIT_OK 0
15+
#define CLI_EXIT_ERROR 1
16+
#define CLI_EXIT_OS 128
17+
#define CLI_EXIT_GIT 128
18+
#define CLI_EXIT_USAGE 129
19+
20+
#define cli_error__print(fmt) do { \
21+
va_list ap; \
22+
va_start(ap, fmt); \
23+
fprintf(stderr, "%s: ", PROGRAM_NAME); \
24+
vfprintf(stderr, fmt, ap); \
25+
fprintf(stderr, "\n"); \
26+
va_end(ap); \
27+
} while(0)
28+
29+
GIT_INLINE(int) cli_error(const char *fmt, ...)
30+
{
31+
cli_error__print(fmt);
32+
return CLI_EXIT_ERROR;
33+
}
34+
35+
GIT_INLINE(int) cli_error_usage(const char *fmt, ...)
36+
{
37+
cli_error__print(fmt);
38+
return CLI_EXIT_USAGE;
39+
}
40+
41+
GIT_INLINE(int) cli_error_git(void)
42+
{
43+
const git_error *err = git_error_last();
44+
fprintf(stderr, "%s: %s\n", PROGRAM_NAME,
45+
err ? err->message : "unknown error");
46+
return CLI_EXIT_GIT;
47+
}
48+
49+
#define cli_error_os() (perror(PROGRAM_NAME), CLI_EXIT_OS)
50+
51+
#endif /* CLI_error_h__ */

src/cli/main.c

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include <stdio.h>
9+
#include <git2.h>
10+
#include "cli.h"
11+
12+
static int show_version = 0;
13+
14+
static const cli_opt_spec common_opts[] = {
15+
{ CLI_OPT_TYPE_SWITCH, "version", 0, &show_version, 1,
16+
CLI_OPT_USAGE_DEFAULT, NULL, "display the version" },
17+
{ 0 }
18+
};
19+
20+
int main(int argc, char **argv)
21+
{
22+
cli_opt_parser optparser;
23+
cli_opt opt;
24+
int ret = 0;
25+
26+
if (git_libgit2_init() < 0) {
27+
cli_error("failed to initialize libgit2");
28+
exit(CLI_EXIT_GIT);
29+
}
30+
31+
cli_opt_parser_init(&optparser, common_opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU);
32+
33+
/* Parse the top-level (common) options and command information */
34+
while (cli_opt_parser_next(&opt, &optparser)) {
35+
if (!opt.spec) {
36+
cli_opt_status_fprint(stderr, PROGRAM_NAME, &opt);
37+
cli_opt_usage_fprint(stderr, PROGRAM_NAME, common_opts);
38+
ret = CLI_EXIT_USAGE;
39+
goto done;
40+
}
41+
}
42+
43+
if (show_version) {
44+
printf("%s version %s\n", PROGRAM_NAME, LIBGIT2_VERSION);
45+
goto done;
46+
}
47+
48+
done:
49+
git_libgit2_shutdown();
50+
return ret;
51+
}

0 commit comments

Comments
 (0)