Merge branch 'sl/worktree-sparse'
[alt-git.git] / builtin / bundle.c
blob44113389d7a34a7cf3fde15a52c3387d851f44db
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 "cache.h"
10 #include "bundle.h"
13 * Basic handler for bundle files to connect repositories via sneakernet.
14 * Invocation must include action.
15 * This function can create a bundle or provide information on an existing
16 * bundle supporting "fetch", "pull", and "ls-remote".
19 #define BUILTIN_BUNDLE_CREATE_USAGE \
20 N_("git bundle create [-q | --quiet | --progress]\n" \
21 " [--version=<version>] <file> <git-rev-list-args>")
22 #define BUILTIN_BUNDLE_VERIFY_USAGE \
23 N_("git bundle verify [-q | --quiet] <file>")
24 #define BUILTIN_BUNDLE_LIST_HEADS_USAGE \
25 N_("git bundle list-heads <file> [<refname>...]")
26 #define BUILTIN_BUNDLE_UNBUNDLE_USAGE \
27 N_("git bundle unbundle [--progress] <file> [<refname>...]")
29 static char const * const builtin_bundle_usage[] = {
30 BUILTIN_BUNDLE_CREATE_USAGE,
31 BUILTIN_BUNDLE_VERIFY_USAGE,
32 BUILTIN_BUNDLE_LIST_HEADS_USAGE,
33 BUILTIN_BUNDLE_UNBUNDLE_USAGE,
34 NULL,
37 static const char * const builtin_bundle_create_usage[] = {
38 BUILTIN_BUNDLE_CREATE_USAGE,
39 NULL
42 static const char * const builtin_bundle_verify_usage[] = {
43 BUILTIN_BUNDLE_VERIFY_USAGE,
44 NULL
47 static const char * const builtin_bundle_list_heads_usage[] = {
48 BUILTIN_BUNDLE_LIST_HEADS_USAGE,
49 NULL
52 static const char * const builtin_bundle_unbundle_usage[] = {
53 BUILTIN_BUNDLE_UNBUNDLE_USAGE,
54 NULL
57 static int parse_options_cmd_bundle(int argc,
58 const char **argv,
59 const char* prefix,
60 const char * const usagestr[],
61 const struct option options[],
62 char **bundle_file) {
63 argc = parse_options(argc, argv, NULL, options, usagestr,
64 PARSE_OPT_STOP_AT_NON_OPTION);
65 if (!argc)
66 usage_msg_opt(_("need a <file> argument"), usagestr, options);
67 *bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
68 return argc;
71 static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
72 int all_progress_implied = 1;
73 int progress = isatty(STDERR_FILENO);
74 struct strvec pack_opts;
75 int version = -1;
76 int ret;
77 struct option options[] = {
78 OPT_SET_INT('q', "quiet", &progress,
79 N_("do not show progress meter"), 0),
80 OPT_SET_INT(0, "progress", &progress,
81 N_("show progress meter"), 1),
82 OPT_SET_INT_F(0, "all-progress", &progress,
83 N_("historical; same as --progress"), 2,
84 PARSE_OPT_HIDDEN),
85 OPT_HIDDEN_BOOL(0, "all-progress-implied",
86 &all_progress_implied,
87 N_("historical; does nothing")),
88 OPT_INTEGER(0, "version", &version,
89 N_("specify bundle format version")),
90 OPT_END()
92 char *bundle_file;
94 argc = parse_options_cmd_bundle(argc, argv, prefix,
95 builtin_bundle_create_usage, options, &bundle_file);
96 /* bundle internals use argv[1] as further parameters */
98 strvec_init(&pack_opts);
99 if (progress == 0)
100 strvec_push(&pack_opts, "--quiet");
101 else if (progress == 1)
102 strvec_push(&pack_opts, "--progress");
103 else if (progress == 2)
104 strvec_push(&pack_opts, "--all-progress");
105 if (progress && all_progress_implied)
106 strvec_push(&pack_opts, "--all-progress-implied");
108 if (!startup_info->have_repository)
109 die(_("Need a repository to create a bundle."));
110 ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
111 strvec_clear(&pack_opts);
112 free(bundle_file);
113 return ret;
117 * Similar to read_bundle_header(), but handle "-" as stdin.
119 static int open_bundle(const char *path, struct bundle_header *header,
120 const char **name)
122 if (!strcmp(path, "-")) {
123 if (name)
124 *name = "<stdin>";
125 return read_bundle_header_fd(0, header, "<stdin>");
128 if (name)
129 *name = path;
130 return read_bundle_header(path, header);
133 static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
134 struct bundle_header header = BUNDLE_HEADER_INIT;
135 int bundle_fd = -1;
136 int quiet = 0;
137 int ret;
138 struct option options[] = {
139 OPT_BOOL('q', "quiet", &quiet,
140 N_("do not show bundle details")),
141 OPT_END()
143 char *bundle_file;
144 const char *name;
146 argc = parse_options_cmd_bundle(argc, argv, prefix,
147 builtin_bundle_verify_usage, options, &bundle_file);
148 /* bundle internals use argv[1] as further parameters */
150 if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
151 ret = 1;
152 goto cleanup;
154 close(bundle_fd);
155 if (verify_bundle(the_repository, &header,
156 quiet ? VERIFY_BUNDLE_QUIET : VERIFY_BUNDLE_VERBOSE)) {
157 ret = 1;
158 goto cleanup;
161 fprintf(stderr, _("%s is okay\n"), name);
162 ret = 0;
163 cleanup:
164 free(bundle_file);
165 bundle_header_release(&header);
166 return ret;
169 static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
170 struct bundle_header header = BUNDLE_HEADER_INIT;
171 int bundle_fd = -1;
172 int ret;
173 struct option options[] = {
174 OPT_END()
176 char *bundle_file;
178 argc = parse_options_cmd_bundle(argc, argv, prefix,
179 builtin_bundle_list_heads_usage, options, &bundle_file);
180 /* bundle internals use argv[1] as further parameters */
182 if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
183 ret = 1;
184 goto cleanup;
186 close(bundle_fd);
187 ret = !!list_bundle_refs(&header, argc, argv);
188 cleanup:
189 free(bundle_file);
190 bundle_header_release(&header);
191 return ret;
194 static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
195 struct bundle_header header = BUNDLE_HEADER_INIT;
196 int bundle_fd = -1;
197 int ret;
198 int progress = isatty(2);
200 struct option options[] = {
201 OPT_BOOL(0, "progress", &progress,
202 N_("show progress meter")),
203 OPT_END()
205 char *bundle_file;
206 struct strvec extra_index_pack_args = STRVEC_INIT;
208 argc = parse_options_cmd_bundle(argc, argv, prefix,
209 builtin_bundle_unbundle_usage, options, &bundle_file);
210 /* bundle internals use argv[1] as further parameters */
212 if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
213 ret = 1;
214 goto cleanup;
216 if (!startup_info->have_repository)
217 die(_("Need a repository to unbundle."));
218 if (progress)
219 strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
220 _("Unbundling objects"), NULL);
221 ret = !!unbundle(the_repository, &header, bundle_fd,
222 &extra_index_pack_args, 0) ||
223 list_bundle_refs(&header, argc, argv);
224 bundle_header_release(&header);
225 cleanup:
226 free(bundle_file);
227 return ret;
230 int cmd_bundle(int argc, const char **argv, const char *prefix)
232 parse_opt_subcommand_fn *fn = NULL;
233 struct option options[] = {
234 OPT_SUBCOMMAND("create", &fn, cmd_bundle_create),
235 OPT_SUBCOMMAND("verify", &fn, cmd_bundle_verify),
236 OPT_SUBCOMMAND("list-heads", &fn, cmd_bundle_list_heads),
237 OPT_SUBCOMMAND("unbundle", &fn, cmd_bundle_unbundle),
238 OPT_END()
241 argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
244 packet_trace_identity("bundle");
246 return !!fn(argc, argv, prefix);