git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] bundle: rewrite builtin to use parse-options

From
Ramkumar Ramachandra <artagnon@gmail.com>
Date
Dec 8, 2011, 13:10 UTC
Message-ID
<1323349817-15737-4-git-send-email-artagnon@gmail.com>
In-Reply-To
<1323349817-15737-1-git-send-email-artagnon@gmail.com>

The git-bundle builtin currently parses command-line options by hand; this is both fragile and cryptic on failure. Since we now have an OPT_SUBCOMMAND, make use of it to parse the correct subcommand, while forbidding the use of more than one subcommand in the same invocation.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 builtin/bundle.c |  111 +++++++++++++++++++++++++++++++++++------------------
 1 files changed, 73 insertions(+), 38 deletions(-)
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 92a8a60..c977d9f 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "parse-options.h"
 #include "bundle.h"
 
 /*
@@ -9,57 +10,91 @@
  * 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 * builtin_bundle_usage[] = {
+	"git bundle create <file> <git-rev-list args>",
+	"git bundle verify <file>",
+	"git bundle list-heads <file> [<refname>...]",
+	"git bundle unbundle <file> [<refname>...]",
+	NULL
+};
+
+enum bundle_subcommand {
+	BUNDLE_NONE = 0,
+	BUNDLE_CREATE = 1,
+	BUNDLE_VERIFY = 2,
+	BUNDLE_LIST_HEADS = 4,
+	BUNDLE_UNBUNDLE = 8
+};
 
 int cmd_bundle(int argc, const char **argv, const char *prefix)
 {
-	struct bundle_header header;
-	const char *cmd, *bundle_file;
+	int prefix_length;
 	int bundle_fd = -1;
-	char buffer[PATH_MAX];
+	const char *bundle_file;
+	struct bundle_header header;
+	enum bundle_subcommand subcommand = BUNDLE_NONE;
 
-	if (argc < 3)
-		usage(builtin_bundle_usage);
+	struct option options[] = {
+		OPT_SUBCOMMAND("create", &subcommand,
+			"create a new bundle",
+			BUNDLE_CREATE),
+		OPT_SUBCOMMAND("verify", &subcommand,
+			"verify clean application of the bundle",
+			BUNDLE_VERIFY),
+		OPT_SUBCOMMAND("list-heads", &subcommand,
+			"list references defined in the bundle",
+			BUNDLE_LIST_HEADS),
+		OPT_SUBCOMMAND("unbundle", &subcommand,
+			"pass objects in the bundle to 'git index-pack'",
+			BUNDLE_UNBUNDLE),
+		OPT_END(),
+	};
 
-	cmd = argv[1];
-	bundle_file = argv[2];
-	argc -= 2;
-	argv += 2;
+	argc = parse_options(argc, argv, NULL,
+			options, builtin_bundle_usage,
+			PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
 
-	if (prefix && bundle_file[0] != '/') {
-		snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file);
-		bundle_file = buffer;
-	}
+	if (argc < 2)
+		usage_with_options(builtin_bundle_usage, options);
 
-	memset(&header, 0, sizeof(header));
-	if (strcmp(cmd, "create") && (bundle_fd =
-				read_bundle_header(bundle_file, &header)) < 0)
-		return 1;
+	/* The next parameter on the command line is bundle_file */
+	prefix_length = prefix ? strlen(prefix) : 0;
+	bundle_file = prefix_filename(prefix, prefix_length, argv[1]);
+	argc -= 1;
+	argv += 1;
 
-	if (!strcmp(cmd, "verify")) {
+	/* Read out bundle header, except in BUNDLE_CREATE case */
+	if (subcommand == BUNDLE_VERIFY || subcommand == BUNDLE_LIST_HEADS ||
+		subcommand == BUNDLE_UNBUNDLE) {
+		memset(&header, 0, sizeof(header));
+		bundle_fd = read_bundle_header(bundle_file, &header);
+		if (bundle_fd < 0)
+			die_errno(_("Failed to open bundle file '%s'"), bundle_file);
+	}
+
+	switch (subcommand) {
+	case BUNDLE_CREATE:
+		if (!startup_info->have_repository)
+			die(_("Need a repository to create a bundle."));
+		return create_bundle(&header, bundle_file, argc, argv);
+	case BUNDLE_VERIFY:
 		close(bundle_fd);
 		if (verify_bundle(&header, 1))
-			return 1;
+			return -1; /* Error already reported */
 		fprintf(stderr, _("%s is okay\n"), bundle_file);
-		return 0;
-	}
-	if (!strcmp(cmd, "list-heads")) {
+		break;
+	case BUNDLE_LIST_HEADS:
 		close(bundle_fd);
-		return !!list_bundle_refs(&header, argc, argv);
-	}
-	if (!strcmp(cmd, "create")) {
-		if (!startup_info->have_repository)
-			die(_("Need a repository to create a bundle."));
-		return !!create_bundle(&header, bundle_file, argc, argv);
-	} else if (!strcmp(cmd, "unbundle")) {
-		if (!startup_info->have_repository)
+		return list_bundle_refs(&header, argc, argv);
+	case BUNDLE_UNBUNDLE:
+		if (!startup_info->have_repository) {
+			close(bundle_fd);
 			die(_("Need a repository to unbundle."));
-		return !!unbundle(&header, bundle_fd, 0) ||
+		}
+		return unbundle(&header, bundle_fd, 0) ||
 			list_bundle_refs(&header, argc, argv);
-	} else
-		usage(builtin_bundle_usage);
+	default:
+		usage_with_options(builtin_bundle_usage, options);
+	}
+	return 0;
 }
-- 
1.7.7.3
Previous: Ramkumar RamachandraNext: Jonathan Nieder
Message 10 of 50 in “Fix '&&' chaining in tests”
  1. 0/6 Fix '&&' chaining in testsRamkumar Ramachandra, Dec 8, 2011
  2. 1/2 parse-options: introduce OPT_SUBCOMMANDRamkumar Ramachandra, Dec 8, 2011
  3. Jonathan NiederDec 8, 2011
  4. Ramkumar RamachandraDec 8, 2011
  5. 1/6 t3040 (subprojects-basic): modernize styleRamkumar Ramachandra, Dec 8, 2011
  6. Jonathan NiederDec 8, 2011
  7. Ramkumar RamachandraDec 9, 2011
  8. Junio C HamanoDec 9, 2011
  9. Ramkumar RamachandraDec 9, 2011
  10. 2/2 bundle: rewrite builtin to use parse-optionsRamkumar Ramachandra, Dec 8, 2011
  11. Jonathan NiederDec 8, 2011
  12. Ramkumar RamachandraDec 8, 2011
  13. Jonathan NiederDec 8, 2011
  14. Ramkumar RamachandraDec 8, 2011
  15. Jonathan NiederDec 8, 2011
  16. Ramkumar RamachandraDec 8, 2011
  17. Junio C HamanoDec 8, 2011
  18. Jakub NarebskiDec 9, 2011
  19. Junio C HamanoDec 9, 2011
  20. 0/2 Improve git-bundle builtinRamkumar Ramachandra, Dec 15, 2011
  21. 1/2 t5704 (bundle): rewrite for larger coverageRamkumar Ramachandra, Dec 15, 2011
  22. Jonathan NiederDec 15, 2011
  23. 2/2 bundle: rewrite builtin to use parse-optionsRamkumar Ramachandra, Dec 15, 2011
  24. Jonathan NiederDec 15, 2011
  25. Jonathan NiederDec 15, 2011
  26. Junio C HamanoDec 15, 2011
  27. 2/6 t3030 (merge-recursive): use test_expect_codeRamkumar Ramachandra, Dec 8, 2011
  28. 3/6 t1006 (cat-file): use test_cmpRamkumar Ramachandra, Dec 8, 2011
  29. Matthieu MoyDec 8, 2011
  30. Ramkumar RamachandraDec 8, 2011
  31. Matthieu MoyDec 8, 2011
  32. Jonathan NiederDec 8, 2011
  33. 4/6 t3200 (branch): fix '&&' chainingRamkumar Ramachandra, Dec 8, 2011
  34. Jonathan NiederDec 8, 2011
  35. 5/6 t1510 (worktree): fix '&&' chainingRamkumar Ramachandra, Dec 8, 2011
  36. Jonathan NiederDec 8, 2011
  37. Junio C HamanoDec 9, 2011
  38. 6/6 test: fix '&&' chainingRamkumar Ramachandra, Dec 8, 2011
  39. Jonathan NiederDec 8, 2011
  40. Junio C HamanoDec 8, 2011
  41. Ramkumar RamachandraDec 9, 2011
  42. 0/6 Fix '&&' chaining in testsRamkumar Ramachandra, Dec 9, 2011
  43. 1/6 t3040 (subprojects-basic): fix '&&' chaining, modernize styleRamkumar Ramachandra, Dec 9, 2011
  44. 2/6 t3030 (merge-recursive): use test_expect_codeRamkumar Ramachandra, Dec 9, 2011
  45. 3/6 t1006 (cat-file): use test_cmpRamkumar Ramachandra, Dec 9, 2011
  46. Junio C HamanoDec 9, 2011
  47. Ramkumar RamachandraDec 9, 2011
  48. 4/6 t3200 (branch): fix '&&' chainingRamkumar Ramachandra, Dec 9, 2011
  49. 5/6 t1510 (worktree): fix '&&' chainingRamkumar Ramachandra, Dec 9, 2011
  50. 6/6 tests: fix '&&' chainingRamkumar Ramachandra, Dec 9, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.