On 10/25/2017 12:14 AM, Jonathan Tan wrote:
On Tue, Oct 24, 2017 at 11:53 AM, Jeff Hostetler <git@xxxxxxxxxxxxxxxxx> wrote:
+ * <arg> ::= blob:none
+ * blob:limit:<n>[kmg]
+ * sparse:oid:<oid-expression>
+ * sparse:path:<pathname>
I notice in the code below that there are some usages of "=" instead
of ":" - could you clarify which one it is? (Ideally this would point
to one point of documentation which serves as both user and technical
documentation.)
good catch. thanks!
+ */
+int parse_list_objects_filter(struct list_objects_filter_options *filter_options,
+ const char *arg)
+{
+ struct object_context oc;
+ struct object_id sparse_oid;
+ const char *v0;
+ const char *v1;
+
+ if (filter_options->choice)
+ die(_("multiple object filter types cannot be combined"));
+
+ /*
+ * TODO consider rejecting 'arg' if it contains any
+ * TODO injection characters (since we might send this
+ * TODO to a sub-command or to the server and we don't
+ * TODO want to deal with legacy quoting/escaping for
+ * TODO a new feature).
+ */
+
+ filter_options->raw_value = strdup(arg);
+
+ if (skip_prefix(arg, "blob:", &v0) || skip_prefix(arg, "blobs:", &v0)) {
I know that some people prefer leniency, but I think it's better to
standardize on one form ("blob" instead of both "blob" and "blobs").
I could go either way on this. (I kept mistyping it during interactive testing,
so I added both cases...)
+ if (!strcmp(v0, "none")) {
+ filter_options->choice = LOFC_BLOB_NONE;
+ return 0;
+ }
+
+ if (skip_prefix(v0, "limit=", &v1) &&
+ git_parse_ulong(v1, &filter_options->blob_limit_value)) {
+ filter_options->choice = LOFC_BLOB_LIMIT;
+ return 0;
+ }
+ }
+ else if (skip_prefix(arg, "sparse:", &v0)) {
+ if (skip_prefix(v0, "oid=", &v1)) {
+ filter_options->choice = LOFC_SPARSE_OID;
+ if (!get_oid_with_context(v1, GET_OID_BLOB,
+ &sparse_oid, &oc)) {
+ /*
+ * We successfully converted the <oid-expr>
+ * into an actual OID. Rewrite the raw_value
+ * in canonoical form with just the OID.
+ * (If we send this request to the server, we
+ * want an absolute expression rather than a
+ * local-ref-relative expression.)
+ */
+ free((char *)filter_options->raw_value);
+ filter_options->raw_value =
+ xstrfmt("sparse:oid=%s",
+ oid_to_hex(&sparse_oid));
+ filter_options->sparse_oid_value =
+ oiddup(&sparse_oid);
+ } else {
+ /*
+ * We could not turn the <oid-expr> into an
+ * OID. Leave the raw_value as is in case
+ * the server can parse it. (It may refer to
+ * a branch, commit, or blob we don't have.)
+ */
+ }
+ return 0;
+ }
+
+ if (skip_prefix(v0, "path=", &v1)) {
+ filter_options->choice = LOFC_SPARSE_PATH;
+ filter_options->sparse_path_value = strdup(v1);
+ return 0;
+ }
+ }
+
+ die(_("invalid filter expression '%s'"), arg);
+ return 0;
+}
+
+int opt_parse_list_objects_filter(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct list_objects_filter_options *filter_options = opt->value;
+
+ assert(arg);
+ assert(!unset);
+
+ return parse_list_objects_filter(filter_options, arg);
+}
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
new file mode 100644
index 0000000..23bd68e
--- /dev/null
+++ b/list-objects-filter-options.h
@@ -0,0 +1,50 @@
+#ifndef LIST_OBJECTS_FILTER_OPTIONS_H
+#define LIST_OBJECTS_FILTER_OPTIONS_H
+
+#include "parse-options.h"
+
+/*
+ * Common declarations and utilities for filtering objects (such as omitting
+ * large blobs) in list_objects:traverse_commit_list() and git-rev-list.
+ */
+
+enum list_objects_filter_choice {
+ LOFC_DISABLED = 0,
+ LOFC_BLOB_NONE,
+ LOFC_BLOB_LIMIT,
+ LOFC_SPARSE_OID,
+ LOFC_SPARSE_PATH,
+};
+
+struct list_objects_filter_options {
+ /*
+ * The raw argument value given on the command line or
+ * protocol request. (The part after the "--keyword=".)
+ */
+ char *raw_value;
+
+ /*
+ * Parsed values. Only 1 will be set depending on the flags below.
+ */
+ struct object_id *sparse_oid_value;
+ char *sparse_path_value;
+ unsigned long blob_limit_value;
+
+ enum list_objects_filter_choice choice;
+};
+
+/* Normalized command line arguments */
+#define CL_ARG__FILTER "filter"
+
+int parse_list_objects_filter(struct list_objects_filter_options *filter_options,
+ const char *arg);
+
+int opt_parse_list_objects_filter(const struct option *opt,
+ const char *arg, int unset);
+
+#define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
+ { OPTION_CALLBACK, 0, CL_ARG__FILTER, fo, N_("args"), \
+ N_("object filtering"), PARSE_OPT_NONEG, \
+ opt_parse_list_objects_filter }
Thanks - this does make it easier to have a standard argument name and
description everywhere.
+
+#endif /* LIST_OBJECTS_FILTER_OPTIONS_H */
--
2.9.3