10
#include "list-objects.h"
11
#include "list-objects-filter.h"
12
#include "list-objects-filter-options.h"
13
+#include "oidmap.h"
14
#include "oidset.h"
15
#include "object-store.h"
16
85
* A filter for list-objects to omit ALL trees and blobs from the traversal.
86
* Can OPTIONALLY collect a list of the omitted OIDs.
87
*/
87
-struct filter_trees_none_data {
88
+struct filter_trees_depth_data {
89
struct oidset *omits;
90
+
91
+ /*
92
+ * Maps trees to the minimum depth at which they were seen. It is not
93
+ * necessary to re-traverse a tree at deeper or equal depths than it has
94
+ * already been traversed.
95
+ *
96
+ * We can't use LOFR_MARK_SEEN for tree objects since this will prevent
97
+ * it from being traversed at shallower depths.
98
+ */
99
+ struct oidmap seen_at_depth;
100
+
101
+ unsigned long exclude_depth;
102
+ unsigned long current_depth;
103
};
104
91
-static enum list_objects_filter_result filter_trees_none(
105
+struct seen_map_entry {
106
+ struct oidmap_entry base;
107
+ size_t depth;
108
+};
109
+
110
+static void filter_trees_update_omits(
111
+ struct object *obj,
112
+ struct filter_trees_depth_data *filter_data,
113
+ int include_it)
114
+{
115
+ if (!filter_data->omits)
116
+ return;
117
+
118
+ if (include_it)
119
+ oidset_remove(filter_data->omits, &obj->oid);
120
+ else
121
+ oidset_insert(filter_data->omits, &obj->oid);
122
+}
123
+
124
+static enum list_objects_filter_result filter_trees_depth(
125
struct repository *r,
126
enum list_objects_filter_situation filter_situation,
127
struct object *obj,
129
const char *filename,
130
void *filter_data_)
131
{
99
- struct filter_trees_none_data *filter_data = filter_data_;
132
+ struct filter_trees_depth_data *filter_data = filter_data_;
133
+ struct seen_map_entry *seen_info;
134
+ int include_it = filter_data->current_depth <
135
+ filter_data->exclude_depth;
136
+ int filter_res;
137
+ int already_seen;
138
+
139
+ /*
140
+ * Note that we do not use _MARK_SEEN in order to allow re-traversal in
141
+ * case we encounter a tree or blob again at a shallower depth.
142
+ */
143
144
switch (filter_situation) {
145
default:
146
BUG("unknown filter_situation: %d", filter_situation);
147
105
- case LOFS_BEGIN_TREE:
148
+ case LOFS_END_TREE:
149
+ assert(obj->type == OBJ_TREE);
150
+ filter_data->current_depth--;
151
+ return LOFR_ZERO;
152
+
153
case LOFS_BLOB:
107
- if (filter_data->omits) {
108
- oidset_insert(filter_data->omits, &obj->oid);
109
- /* _MARK_SEEN but not _DO_SHOW (hard omit) */
110
- return LOFR_MARK_SEEN;
154
+ filter_trees_update_omits(obj, filter_data, include_it);
155
+ return include_it ? LOFR_MARK_SEEN | LOFR_DO_SHOW : LOFR_ZERO;
156
+
157
+ case LOFS_BEGIN_TREE:
158
+ seen_info = oidmap_get(
159
+ &filter_data->seen_at_depth, &obj->oid);
160
+ if (!seen_info) {
161
+ seen_info = xcalloc(1, sizeof(*seen_info));
162
+ oidcpy(&seen_info->base.oid, &obj->oid);
163
+ seen_info->depth = filter_data->current_depth;
164
+ oidmap_put(&filter_data->seen_at_depth, seen_info);
165
+ already_seen = 0;
166
} else {
112
- /*
113
- * Not collecting omits so no need to to traverse tree.
114
- */
115
- return LOFR_SKIP_TREE | LOFR_MARK_SEEN;
167
+ already_seen =
168
+ filter_data->current_depth >= seen_info->depth;
169
}
170
118
- case LOFS_END_TREE:
119
- assert(obj->type == OBJ_TREE);
120
- return LOFR_ZERO;
171
+ if (already_seen) {
172
+ filter_res = LOFR_SKIP_TREE;
173
+ } else {
174
+ seen_info->depth = filter_data->current_depth;
175
+ filter_trees_update_omits(obj, filter_data, include_it);
176
+
177
+ if (include_it)
178
+ filter_res = LOFR_DO_SHOW;
179
+ else if (filter_data->omits)
180
+ filter_res = LOFR_ZERO;
181
+ else
182
+ filter_res = LOFR_SKIP_TREE;
183
+ }
184
185
+ filter_data->current_depth++;
186
+ return filter_res;
187
}
188
}
189
125
-static void* filter_trees_none__init(
190
+static void filter_trees_free(void *filter_data) {
191
+ struct filter_trees_depth_data *d = filter_data;
192
+ if (!d)
193
+ return;
194
+ oidmap_free(&d->seen_at_depth, 1);
195
+ free(d);
196
+}
197
+
198
+static void *filter_trees_depth__init(
199
struct oidset *omitted,
200
struct list_objects_filter_options *filter_options,
201
filter_object_fn *filter_fn,
202
filter_free_fn *filter_free_fn)
203
{
131
- struct filter_trees_none_data *d = xcalloc(1, sizeof(*d));
204
+ struct filter_trees_depth_data *d = xcalloc(1, sizeof(*d));
205
d->omits = omitted;
206
+ oidmap_init(&d->seen_at_depth, 0);
207
+ d->exclude_depth = filter_options->tree_exclude_depth;
208
+ d->current_depth = 0;
209
134
- *filter_fn = filter_trees_none;
135
- *filter_free_fn = free;
210
+ *filter_fn = filter_trees_depth;
211
+ *filter_free_fn = filter_trees_free;
212
return d;
213
}
214
506
NULL,
507
filter_blobs_none__init,
508
filter_blobs_limit__init,
433
- filter_trees_none__init,
509
+ filter_trees_depth__init,
510
filter_sparse_oid__init,
511
filter_sparse_path__init,
512
};