Merge branch 'rj/bundle-ui-updates'

"git bundle" has been taught to use the parse options API.  "git
bundle verify" learned "--quiet" and "git bundle create" learned
options to control the progress output.

* rj/bundle-ui-updates:
  bundle-verify: add --quiet
  bundle-create: progress output control
  bundle: framework for options before bundle file
maint
Junio C Hamano 2019-12-01 09:04:36 -08:00
commit ca5c8aa8e1
4 changed files with 213 additions and 55 deletions

View File

@ -9,8 +9,8 @@ git-bundle - Move objects and refs by archive
SYNOPSIS
--------
[verse]
'git bundle' create <file> <git-rev-list-args>
'git bundle' verify <file>
'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied] <file> <git-rev-list-args>
'git bundle' verify [-q | --quiet] <file>
'git bundle' list-heads <file> [<refname>...]
'git bundle' unbundle <file> [<refname>...]

@ -33,9 +33,11 @@ destination repository.
OPTIONS
-------

create <file>::
create [options] <file> <git-rev-list-args>::
Used to create a bundle named 'file'. This requires the
'git-rev-list-args' arguments to define the bundle contents.
'options' contains the options specific to the 'git bundle create'
subcommand.

verify <file>::
Used to check that a bundle file is valid and will apply
@ -75,6 +77,33 @@ unbundle <file>::
necessarily everything in the pack (in this case, 'git bundle' acts
like 'git fetch-pack').

--progress::
Progress status is reported on the standard error stream
by default when it is attached to a terminal, unless -q
is specified. This flag forces progress status even if
the standard error stream is not directed to a terminal.

--all-progress::
When --stdout is specified then progress report is
displayed during the object count and compression phases
but inhibited during the write-out phase. The reason is
that in some cases the output stream is directly linked
to another command which may wish to display progress
status of its own as it processes incoming pack data.
This flag is like --progress except that it forces progress
report for the write-out phase as well even if --stdout is
used.

--all-progress-implied::
This is used to imply --all-progress whenever progress display
is activated. Unlike --all-progress this flag doesn't actually
force any progress display by itself.

-q::
--quiet::
This flag makes the command not to report its progress
on the standard error stream.

SPECIFYING REFERENCES
---------------------


View File

@ -1,4 +1,6 @@
#include "builtin.h"
#include "argv-array.h"
#include "parse-options.h"
#include "cache.h"
#include "bundle.h"

@ -9,59 +11,184 @@
* bundle supporting "fetch", "pull", and "ls-remote".
*/

static const char builtin_bundle_usage[] =
"git bundle create <file> <git-rev-list args>\n"
" or: git bundle verify <file>\n"
" or: git bundle list-heads <file> [<refname>...]\n"
" or: git bundle unbundle <file> [<refname>...]";
static const char * const builtin_bundle_usage[] = {
N_("git bundle create [<options>] <file> <git-rev-list args>"),
N_("git bundle verify [<options>] <file>"),
N_("git bundle list-heads <file> [<refname>...]"),
N_("git bundle unbundle <file> [<refname>...]"),
NULL
};

static const char * const builtin_bundle_create_usage[] = {
N_("git bundle create [<options>] <file> <git-rev-list args>"),
NULL
};

static const char * const builtin_bundle_verify_usage[] = {
N_("git bundle verify [<options>] <file>"),
NULL
};

static const char * const builtin_bundle_list_heads_usage[] = {
N_("git bundle list-heads <file> [<refname>...]"),
NULL
};

static const char * const builtin_bundle_unbundle_usage[] = {
N_("git bundle unbundle <file> [<refname>...]"),
NULL
};

static int verbose;

static int parse_options_cmd_bundle(int argc,
const char **argv,
const char* prefix,
const char * const usagestr[],
const struct option options[],
const char **bundle_file) {
int newargc;
newargc = parse_options(argc, argv, NULL, options, usagestr,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc < 1)
usage_with_options(usagestr, options);
*bundle_file = prefix_filename(prefix, argv[0]);
return newargc;
}

static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
int all_progress_implied = 0;
int progress = isatty(STDERR_FILENO);
struct argv_array pack_opts;

struct option options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
N_("show progress meter"), 1),
OPT_SET_INT(0, "all-progress", &progress,
N_("show progress meter during object writing phase"), 2),
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
OPT_END()
};
const char* bundle_file;

argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_create_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */

argv_array_init(&pack_opts);
if (progress == 0)
argv_array_push(&pack_opts, "--quiet");
else if (progress == 1)
argv_array_push(&pack_opts, "--progress");
else if (progress == 2)
argv_array_push(&pack_opts, "--all-progress");
if (progress && all_progress_implied)
argv_array_push(&pack_opts, "--all-progress-implied");

if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts);
}

static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;
int quiet = 0;

struct option options[] = {
OPT_BOOL('q', "quiet", &quiet,
N_("do not show bundle details")),
OPT_END()
};
const char* bundle_file;

argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */

memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
close(bundle_fd);
if (verify_bundle(the_repository, &header, !quiet))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
return 0;
}

static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;

struct option options[] = {
OPT_END()
};
const char* bundle_file;

argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */

memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
close(bundle_fd);
return !!list_bundle_refs(&header, argc, argv);
}

static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;

struct option options[] = {
OPT_END()
};
const char* bundle_file;

argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */

memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
return !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
}

int cmd_bundle(int argc, const char **argv, const char *prefix)
{
struct bundle_header header;
const char *cmd, *bundle_file;
int bundle_fd = -1;
struct option options[] = {
OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
OPT_END()
};
int result;

if (argc < 3)
usage(builtin_bundle_usage);
argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

cmd = argv[1];
bundle_file = prefix_filename(prefix, argv[2]);
argc -= 2;
argv += 2;
packet_trace_identity("bundle");

memset(&header, 0, sizeof(header));
if (strcmp(cmd, "create") && (bundle_fd =
read_bundle_header(bundle_file, &header)) < 0)
return 1;
if (argc < 2)
usage_with_options(builtin_bundle_usage, options);

if (!strcmp(cmd, "verify")) {
close(bundle_fd);
if (argc != 1) {
usage(builtin_bundle_usage);
return 1;
}
if (verify_bundle(the_repository, &header, 1))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
return 0;
else if (!strcmp(argv[0], "create"))
result = cmd_bundle_create(argc, argv, prefix);
else if (!strcmp(argv[0], "verify"))
result = cmd_bundle_verify(argc, argv, prefix);
else if (!strcmp(argv[0], "list-heads"))
result = cmd_bundle_list_heads(argc, argv, prefix);
else if (!strcmp(argv[0], "unbundle"))
result = cmd_bundle_unbundle(argc, argv, prefix);
else {
error(_("Unknown subcommand: %s"), argv[0]);
usage_with_options(builtin_bundle_usage, options);
}
if (!strcmp(cmd, "list-heads")) {
close(bundle_fd);
return !!list_bundle_refs(&header, argc, argv);
}
if (!strcmp(cmd, "create")) {
if (argc < 2) {
usage(builtin_bundle_usage);
return 1;
}
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
return !!create_bundle(the_repository, bundle_file, argc, argv);
} else if (!strcmp(cmd, "unbundle")) {
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
return !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
} else
usage(builtin_bundle_usage);
return result ? 1 : 0;
}

View File

@ -249,15 +249,16 @@ out:


/* Write the pack data to bundle_fd */
static int write_pack_data(int bundle_fd, struct rev_info *revs)
static int write_pack_data(int bundle_fd, struct rev_info *revs, struct argv_array *pack_options)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
int i;

argv_array_pushl(&pack_objects.args,
"pack-objects", "--all-progress-implied",
"pack-objects",
"--stdout", "--thin", "--delta-base-offset",
NULL);
argv_array_pushv(&pack_objects.args, pack_options->argv);
pack_objects.in = -1;
pack_objects.out = bundle_fd;
pack_objects.git_cmd = 1;
@ -428,7 +429,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
}

int create_bundle(struct repository *r, const char *path,
int argc, const char **argv)
int argc, const char **argv, struct argv_array *pack_options)
{
struct lock_file lock = LOCK_INIT;
int bundle_fd = -1;
@ -470,7 +471,7 @@ int create_bundle(struct repository *r, const char *path,
goto err;

/* write pack */
if (write_pack_data(bundle_fd, &revs))
if (write_pack_data(bundle_fd, &revs, pack_options))
goto err;

if (!bundle_to_stdout) {

View File

@ -1,6 +1,7 @@
#ifndef BUNDLE_H
#define BUNDLE_H

#include "argv-array.h"
#include "cache.h"

struct ref_list {
@ -19,7 +20,7 @@ struct bundle_header {
int is_bundle(const char *path, int quiet);
int read_bundle_header(const char *path, struct bundle_header *header);
int create_bundle(struct repository *r, const char *path,
int argc, const char **argv);
int argc, const char **argv, struct argv_array *pack_options);
int verify_bundle(struct repository *r, struct bundle_header *header, int verbose);
#define BUNDLE_VERBOSE 1
int unbundle(struct repository *r, struct bundle_header *header,