Commit 3a3ab065 by Edward Thomson

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.
parent d02f4f7a
......@@ -18,6 +18,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
# Optional subsystems
option(BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
option(BUILD_TESTS "Build Tests using the Clar suite" ON)
option(BUILD_CLI "Build the command-line interface" ON)
option(BUILD_EXAMPLES "Build library usage example apps" OFF)
option(BUILD_FUZZERS "Build the fuzz targets" OFF)
......
......@@ -178,6 +178,10 @@ configure_file(features.h.in git2/sys/features.h)
add_subdirectory(libgit2)
add_subdirectory(util)
if(BUILD_CLI)
add_subdirectory(cli)
endif()
# re-export these to the root so that peer projects (tests, fuzzers,
# examples) can use them
set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
......
......@@ -3,6 +3,8 @@
This is the source that makes up the core of libgit2 and its related
projects.
* `cli`
A git-compatible command-line interface that uses libgit2.
* `libgit2`
This is the libgit2 project, a cross-platform, linkable library
implementation of Git that you can use in your application.
......
set(CLI_INCLUDES
"${libgit2_BINARY_DIR}/src"
"${libgit2_SOURCE_DIR}/src/util"
"${libgit2_SOURCE_DIR}/src/cli"
"${libgit2_SOURCE_DIR}/include")
if(WIN32 AND NOT CYGWIN)
file(GLOB CLI_SRC_OS win32/*.c)
list(SORT CLI_SRC_OS)
else()
file(GLOB CLI_SRC_OS unix/*.c)
list(SORT CLI_SRC_OS)
endif()
file(GLOB CLI_SRC_C *.c *.h)
list(SORT CLI_SRC_C)
#
# The CLI currently needs to be statically linked against libgit2 because
# the utility library uses libgit2's thread-local error buffers. TODO:
# remove this dependency and allow us to dynamically link against libgit2.
#
if(BUILD_CLI STREQUAL "dynamic")
set(CLI_LIBGIT2_LIBRARY libgit2package)
else()
set(CLI_LIBGIT2_OBJECTS $<TARGET_OBJECTS:libgit2>)
endif()
#
# Compile and link the CLI
#
add_executable(git2_cli ${CLI_SRC_C} ${CLI_SRC_OS} ${CLI_OBJECTS}
$<TARGET_OBJECTS:util>
${CLI_LIBGIT2_OBJECTS}
${LIBGIT2_DEPENDENCY_OBJECTS})
target_link_libraries(git2_cli ${CLI_LIBGIT2_LIBRARY} ${LIBGIT2_SYSTEM_LIBS})
set_target_properties(git2_cli PROPERTIES C_STANDARD 90)
set_target_properties(git2_cli PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR})
ide_split_sources(git2_cli)
target_include_directories(git2_cli PRIVATE ${CLI_INCLUDES})
if(MSVC_IDE)
# Precompiled headers
set_target_properties(git2_cli PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h")
set_source_files_properties(win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h")
endif()
install(TARGETS git2_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# cli
A git-compatible command-line interface that uses libgit2.
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef CLI_cli_h__
#define CLI_cli_h__
#define PROGRAM_NAME "git2"
#include "git2_util.h"
#include "error.h"
#include "opt.h"
#endif /* CLI_cli_h__ */
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef CLI_error_h__
#define CLI_error_h__
#include "cli.h"
#include <stdio.h>
#define CLI_EXIT_OK 0
#define CLI_EXIT_ERROR 1
#define CLI_EXIT_OS 128
#define CLI_EXIT_GIT 128
#define CLI_EXIT_USAGE 129
#define cli_error__print(fmt) do { \
va_list ap; \
va_start(ap, fmt); \
fprintf(stderr, "%s: ", PROGRAM_NAME); \
vfprintf(stderr, fmt, ap); \
fprintf(stderr, "\n"); \
va_end(ap); \
} while(0)
GIT_INLINE(int) cli_error(const char *fmt, ...)
{
cli_error__print(fmt);
return CLI_EXIT_ERROR;
}
GIT_INLINE(int) cli_error_usage(const char *fmt, ...)
{
cli_error__print(fmt);
return CLI_EXIT_USAGE;
}
GIT_INLINE(int) cli_error_git(void)
{
const git_error *err = git_error_last();
fprintf(stderr, "%s: %s\n", PROGRAM_NAME,
err ? err->message : "unknown error");
return CLI_EXIT_GIT;
}
#define cli_error_os() (perror(PROGRAM_NAME), CLI_EXIT_OS)
#endif /* CLI_error_h__ */
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include <stdio.h>
#include <git2.h>
#include "cli.h"
static int show_version = 0;
static const cli_opt_spec common_opts[] = {
{ CLI_OPT_TYPE_SWITCH, "version", 0, &show_version, 1,
CLI_OPT_USAGE_DEFAULT, NULL, "display the version" },
{ 0 }
};
int main(int argc, char **argv)
{
cli_opt_parser optparser;
cli_opt opt;
int ret = 0;
if (git_libgit2_init() < 0) {
cli_error("failed to initialize libgit2");
exit(CLI_EXIT_GIT);
}
cli_opt_parser_init(&optparser, common_opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU);
/* Parse the top-level (common) options and command information */
while (cli_opt_parser_next(&opt, &optparser)) {
if (!opt.spec) {
cli_opt_status_fprint(stderr, PROGRAM_NAME, &opt);
cli_opt_usage_fprint(stderr, PROGRAM_NAME, common_opts);
ret = CLI_EXIT_USAGE;
goto done;
}
}
if (show_version) {
printf("%s version %s\n", PROGRAM_NAME, LIBGIT2_VERSION);
goto done;
}
done:
git_libgit2_shutdown();
return ret;
}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
#include "precompiled.h"
#include <git2.h>
#include "cli.h"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment