Git 2.20.4
[git] / list-objects-filter-options.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "config.h"
4 #include "revision.h"
5 #include "argv-array.h"
6 #include "list-objects.h"
7 #include "list-objects-filter.h"
8 #include "list-objects-filter-options.h"
9
10 /*
11  * Parse value of the argument to the "filter" keyword.
12  * On the command line this looks like:
13  *       --filter=<arg>
14  * and in the pack protocol as:
15  *       "filter" SP <arg>
16  *
17  * The filter keyword will be used by many commands.
18  * See Documentation/rev-list-options.txt for allowed values for <arg>.
19  *
20  * Capture the given arg as the "filter_spec".  This can be forwarded to
21  * subordinate commands when necessary.  We also "intern" the arg for
22  * the convenience of the current command.
23  */
24 static int gently_parse_list_objects_filter(
25         struct list_objects_filter_options *filter_options,
26         const char *arg,
27         struct strbuf *errbuf)
28 {
29         const char *v0;
30
31         if (filter_options->choice) {
32                 if (errbuf) {
33                         strbuf_addstr(
34                                 errbuf,
35                                 _("multiple filter-specs cannot be combined"));
36                 }
37                 return 1;
38         }
39
40         filter_options->filter_spec = strdup(arg);
41
42         if (!strcmp(arg, "blob:none")) {
43                 filter_options->choice = LOFC_BLOB_NONE;
44                 return 0;
45
46         } else if (skip_prefix(arg, "blob:limit=", &v0)) {
47                 if (git_parse_ulong(v0, &filter_options->blob_limit_value)) {
48                         filter_options->choice = LOFC_BLOB_LIMIT;
49                         return 0;
50                 }
51
52         } else if (skip_prefix(arg, "tree:", &v0)) {
53                 unsigned long depth;
54                 if (!git_parse_ulong(v0, &depth) || depth != 0) {
55                         if (errbuf) {
56                                 strbuf_addstr(
57                                         errbuf,
58                                         _("only 'tree:0' is supported"));
59                         }
60                         return 1;
61                 }
62                 filter_options->choice = LOFC_TREE_NONE;
63                 return 0;
64
65         } else if (skip_prefix(arg, "sparse:oid=", &v0)) {
66                 struct object_context oc;
67                 struct object_id sparse_oid;
68
69                 /*
70                  * Try to parse <oid-expression> into an OID for the current
71                  * command, but DO NOT complain if we don't have the blob or
72                  * ref locally.
73                  */
74                 if (!get_oid_with_context(v0, GET_OID_BLOB,
75                                           &sparse_oid, &oc))
76                         filter_options->sparse_oid_value = oiddup(&sparse_oid);
77                 filter_options->choice = LOFC_SPARSE_OID;
78                 return 0;
79
80         } else if (skip_prefix(arg, "sparse:path=", &v0)) {
81                 filter_options->choice = LOFC_SPARSE_PATH;
82                 filter_options->sparse_path_value = strdup(v0);
83                 return 0;
84         }
85
86         if (errbuf)
87                 strbuf_addf(errbuf, "invalid filter-spec '%s'", arg);
88
89         memset(filter_options, 0, sizeof(*filter_options));
90         return 1;
91 }
92
93 int parse_list_objects_filter(struct list_objects_filter_options *filter_options,
94                               const char *arg)
95 {
96         struct strbuf buf = STRBUF_INIT;
97         if (gently_parse_list_objects_filter(filter_options, arg, &buf))
98                 die("%s", buf.buf);
99         return 0;
100 }
101
102 int opt_parse_list_objects_filter(const struct option *opt,
103                                   const char *arg, int unset)
104 {
105         struct list_objects_filter_options *filter_options = opt->value;
106
107         if (unset || !arg) {
108                 list_objects_filter_set_no_filter(filter_options);
109                 return 0;
110         }
111
112         return parse_list_objects_filter(filter_options, arg);
113 }
114
115 void list_objects_filter_release(
116         struct list_objects_filter_options *filter_options)
117 {
118         free(filter_options->filter_spec);
119         free(filter_options->sparse_oid_value);
120         free(filter_options->sparse_path_value);
121         memset(filter_options, 0, sizeof(*filter_options));
122 }
123
124 void partial_clone_register(
125         const char *remote,
126         const struct list_objects_filter_options *filter_options)
127 {
128         /*
129          * Record the name of the partial clone remote in the
130          * config and in the global variable -- the latter is
131          * used throughout to indicate that partial clone is
132          * enabled and to expect missing objects.
133          */
134         if (repository_format_partial_clone &&
135             *repository_format_partial_clone &&
136             strcmp(remote, repository_format_partial_clone))
137                 die(_("cannot change partial clone promisor remote"));
138
139         git_config_set("core.repositoryformatversion", "1");
140         git_config_set("extensions.partialclone", remote);
141
142         repository_format_partial_clone = xstrdup(remote);
143
144         /*
145          * Record the initial filter-spec in the config as
146          * the default for subsequent fetches from this remote.
147          */
148         core_partial_clone_filter_default =
149                 xstrdup(filter_options->filter_spec);
150         git_config_set("core.partialclonefilter",
151                        core_partial_clone_filter_default);
152 }
153
154 void partial_clone_get_default_filter_spec(
155         struct list_objects_filter_options *filter_options)
156 {
157         /*
158          * Parse default value, but silently ignore it if it is invalid.
159          */
160         if (!core_partial_clone_filter_default)
161                 return;
162         gently_parse_list_objects_filter(filter_options,
163                                          core_partial_clone_filter_default,
164                                          NULL);
165 }