Coverage Report

Created: 2024-09-08 06:23

/src/git/builtin/bundle.c
Line
Count
Source (jump to first uncovered line)
1
#include "builtin.h"
2
#include "abspath.h"
3
#include "gettext.h"
4
#include "setup.h"
5
#include "strvec.h"
6
#include "parse-options.h"
7
#include "pkt-line.h"
8
#include "repository.h"
9
#include "bundle.h"
10
11
/*
12
 * Basic handler for bundle files to connect repositories via sneakernet.
13
 * Invocation must include action.
14
 * This function can create a bundle or provide information on an existing
15
 * bundle supporting "fetch", "pull", and "ls-remote".
16
 */
17
18
#define BUILTIN_BUNDLE_CREATE_USAGE \
19
  N_("git bundle create [-q | --quiet | --progress]\n" \
20
     "                  [--version=<version>] <file> <git-rev-list-args>")
21
#define BUILTIN_BUNDLE_VERIFY_USAGE \
22
  N_("git bundle verify [-q | --quiet] <file>")
23
#define BUILTIN_BUNDLE_LIST_HEADS_USAGE \
24
  N_("git bundle list-heads <file> [<refname>...]")
25
#define BUILTIN_BUNDLE_UNBUNDLE_USAGE \
26
  N_("git bundle unbundle [--progress] <file> [<refname>...]")
27
28
static char const * const builtin_bundle_usage[] = {
29
  BUILTIN_BUNDLE_CREATE_USAGE,
30
  BUILTIN_BUNDLE_VERIFY_USAGE,
31
  BUILTIN_BUNDLE_LIST_HEADS_USAGE,
32
  BUILTIN_BUNDLE_UNBUNDLE_USAGE,
33
  NULL,
34
};
35
36
static const char * const builtin_bundle_create_usage[] = {
37
  BUILTIN_BUNDLE_CREATE_USAGE,
38
  NULL
39
};
40
41
static const char * const builtin_bundle_verify_usage[] = {
42
  BUILTIN_BUNDLE_VERIFY_USAGE,
43
  NULL
44
};
45
46
static const char * const builtin_bundle_list_heads_usage[] = {
47
  BUILTIN_BUNDLE_LIST_HEADS_USAGE,
48
  NULL
49
};
50
51
static const char * const builtin_bundle_unbundle_usage[] = {
52
  BUILTIN_BUNDLE_UNBUNDLE_USAGE,
53
  NULL
54
};
55
56
static int parse_options_cmd_bundle(int argc,
57
    const char **argv,
58
    const char* prefix,
59
    const char * const usagestr[],
60
    const struct option options[],
61
0
    char **bundle_file) {
62
0
  argc = parse_options(argc, argv, NULL, options, usagestr,
63
0
           PARSE_OPT_STOP_AT_NON_OPTION);
64
0
  if (!argc)
65
0
    usage_msg_opt(_("need a <file> argument"), usagestr, options);
66
0
  *bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
67
0
  return argc;
68
0
}
69
70
0
static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
71
0
  struct strvec pack_opts = STRVEC_INIT;
72
0
  int version = -1;
73
0
  int ret;
74
0
  struct option options[] = {
75
0
    OPT_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
76
0
          N_("do not show progress meter"),
77
0
          PARSE_OPT_NOARG),
78
0
    OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
79
0
          N_("show progress meter"),
80
0
          PARSE_OPT_NOARG),
81
0
    OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
82
0
          N_("historical; same as --progress"),
83
0
          PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
84
0
    OPT_PASSTHRU_ARGV(0, "all-progress-implied", &pack_opts, NULL,
85
0
          N_("historical; does nothing"),
86
0
          PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
87
0
    OPT_INTEGER(0, "version", &version,
88
0
          N_("specify bundle format version")),
89
0
    OPT_END()
90
0
  };
91
0
  char *bundle_file;
92
93
0
  if (isatty(STDERR_FILENO))
94
0
    strvec_push(&pack_opts, "--progress");
95
0
  strvec_push(&pack_opts, "--all-progress-implied");
96
97
0
  argc = parse_options_cmd_bundle(argc, argv, prefix,
98
0
      builtin_bundle_create_usage, options, &bundle_file);
99
  /* bundle internals use argv[1] as further parameters */
100
101
0
  if (!startup_info->have_repository)
102
0
    die(_("Need a repository to create a bundle."));
103
0
  ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
104
0
  strvec_clear(&pack_opts);
105
0
  free(bundle_file);
106
0
  return ret;
107
0
}
108
109
/*
110
 * Similar to read_bundle_header(), but handle "-" as stdin.
111
 */
112
static int open_bundle(const char *path, struct bundle_header *header,
113
           const char **name)
114
0
{
115
0
  if (!strcmp(path, "-")) {
116
0
    if (name)
117
0
      *name = "<stdin>";
118
0
    return read_bundle_header_fd(0, header, "<stdin>");
119
0
  }
120
121
0
  if (name)
122
0
    *name = path;
123
0
  return read_bundle_header(path, header);
124
0
}
125
126
0
int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
127
0
  struct bundle_header header = BUNDLE_HEADER_INIT;
128
0
  int bundle_fd = -1;
129
0
  int quiet = 0;
130
0
  int ret;
131
0
  struct option options[] = {
132
0
    OPT_BOOL('q', "quiet", &quiet,
133
0
          N_("do not show bundle details")),
134
0
    OPT_END()
135
0
  };
136
0
  char *bundle_file;
137
0
  const char *name;
138
139
0
  argc = parse_options_cmd_bundle(argc, argv, prefix,
140
0
      builtin_bundle_verify_usage, options, &bundle_file);
141
  /* bundle internals use argv[1] as further parameters */
142
143
0
  if (!startup_info->have_repository) {
144
0
    ret = error(_("need a repository to verify a bundle"));
145
0
    goto cleanup;
146
0
  }
147
148
0
  if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
149
0
    ret = 1;
150
0
    goto cleanup;
151
0
  }
152
0
  close(bundle_fd);
153
0
  if (verify_bundle(the_repository, &header,
154
0
        quiet ? VERIFY_BUNDLE_QUIET : VERIFY_BUNDLE_VERBOSE)) {
155
0
    ret = 1;
156
0
    goto cleanup;
157
0
  }
158
159
0
  fprintf(stderr, _("%s is okay\n"), name);
160
0
  ret = 0;
161
0
cleanup:
162
0
  free(bundle_file);
163
0
  bundle_header_release(&header);
164
0
  return ret;
165
0
}
166
167
0
static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
168
0
  struct bundle_header header = BUNDLE_HEADER_INIT;
169
0
  int bundle_fd = -1;
170
0
  int ret;
171
0
  struct option options[] = {
172
0
    OPT_END()
173
0
  };
174
0
  char *bundle_file;
175
176
0
  argc = parse_options_cmd_bundle(argc, argv, prefix,
177
0
      builtin_bundle_list_heads_usage, options, &bundle_file);
178
  /* bundle internals use argv[1] as further parameters */
179
180
0
  if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
181
0
    ret = 1;
182
0
    goto cleanup;
183
0
  }
184
0
  close(bundle_fd);
185
0
  ret = !!list_bundle_refs(&header, argc, argv);
186
0
cleanup:
187
0
  free(bundle_file);
188
0
  bundle_header_release(&header);
189
0
  return ret;
190
0
}
191
192
0
static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
193
0
  struct bundle_header header = BUNDLE_HEADER_INIT;
194
0
  int bundle_fd = -1;
195
0
  int ret;
196
0
  int progress = isatty(2);
197
198
0
  struct option options[] = {
199
0
    OPT_BOOL(0, "progress", &progress,
200
0
       N_("show progress meter")),
201
0
    OPT_END()
202
0
  };
203
0
  char *bundle_file;
204
0
  struct strvec extra_index_pack_args = STRVEC_INIT;
205
206
0
  argc = parse_options_cmd_bundle(argc, argv, prefix,
207
0
      builtin_bundle_unbundle_usage, options, &bundle_file);
208
  /* bundle internals use argv[1] as further parameters */
209
210
0
  if (!startup_info->have_repository)
211
0
    die(_("Need a repository to unbundle."));
212
213
0
  if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
214
0
    ret = 1;
215
0
    goto cleanup;
216
0
  }
217
0
  if (progress)
218
0
    strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
219
0
           _("Unbundling objects"), NULL);
220
0
  ret = !!unbundle(the_repository, &header, bundle_fd,
221
0
       &extra_index_pack_args, 0) ||
222
0
    list_bundle_refs(&header, argc, argv);
223
0
  bundle_header_release(&header);
224
225
0
cleanup:
226
0
  strvec_clear(&extra_index_pack_args);
227
0
  free(bundle_file);
228
0
  return ret;
229
0
}
230
231
int cmd_bundle(int argc, const char **argv, const char *prefix)
232
0
{
233
0
  parse_opt_subcommand_fn *fn = NULL;
234
0
  struct option options[] = {
235
0
    OPT_SUBCOMMAND("create", &fn, cmd_bundle_create),
236
0
    OPT_SUBCOMMAND("verify", &fn, cmd_bundle_verify),
237
0
    OPT_SUBCOMMAND("list-heads", &fn, cmd_bundle_list_heads),
238
0
    OPT_SUBCOMMAND("unbundle", &fn, cmd_bundle_unbundle),
239
0
    OPT_END()
240
0
  };
241
242
0
  argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
243
0
           0);
244
245
0
  packet_trace_identity("bundle");
246
247
0
  return !!fn(argc, argv, prefix);
248
0
}