]> git.ipfire.org Git - thirdparty/git.git/blobdiff - list-objects-filter.c
list-objects-filter: plug pattern_list leak
[thirdparty/git.git] / list-objects-filter.c
index 39e2f15333694933468f6af9bea6d9804251dfcb..9e5fc15ef73f8de60cfd4ce99a366452a78b918e 100644 (file)
@@ -82,6 +82,16 @@ static enum list_objects_filter_result filter_blobs_none(
        default:
                BUG("unknown filter_situation: %d", filter_situation);
 
+       case LOFS_TAG:
+               assert(obj->type == OBJ_TAG);
+               /* always include all tag objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+       case LOFS_COMMIT:
+               assert(obj->type == OBJ_COMMIT);
+               /* always include all commit objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
                /* always include all tree objects */
@@ -173,6 +183,16 @@ static enum list_objects_filter_result filter_trees_depth(
        default:
                BUG("unknown filter_situation: %d", filter_situation);
 
+       case LOFS_TAG:
+               assert(obj->type == OBJ_TAG);
+               /* always include all tag objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+       case LOFS_COMMIT:
+               assert(obj->type == OBJ_COMMIT);
+               /* always include all commit objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
        case LOFS_END_TREE:
                assert(obj->type == OBJ_TREE);
                filter_data->current_depth--;
@@ -267,6 +287,16 @@ static enum list_objects_filter_result filter_blobs_limit(
        default:
                BUG("unknown filter_situation: %d", filter_situation);
 
+       case LOFS_TAG:
+               assert(obj->type == OBJ_TAG);
+               /* always include all tag objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+       case LOFS_COMMIT:
+               assert(obj->type == OBJ_COMMIT);
+               /* always include all commit objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
                /* always include all tree objects */
@@ -371,6 +401,16 @@ static enum list_objects_filter_result filter_sparse(
        default:
                BUG("unknown filter_situation: %d", filter_situation);
 
+       case LOFS_TAG:
+               assert(obj->type == OBJ_TAG);
+               /* always include all tag objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+       case LOFS_COMMIT:
+               assert(obj->type == OBJ_COMMIT);
+               /* always include all commit objects */
+               return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
                dtype = DT_DIR;
@@ -474,6 +514,7 @@ static enum list_objects_filter_result filter_sparse(
 static void filter_sparse_free(void *filter_data)
 {
        struct filter_sparse_data *d = filter_data;
+       clear_pattern_list(&d->pl);
        free(d->array_frame);
        free(d);
 }
@@ -505,6 +546,81 @@ static void filter_sparse_oid__init(
        filter->free_fn = filter_sparse_free;
 }
 
+/*
+ * A filter for list-objects to omit large blobs.
+ * And to OPTIONALLY collect a list of the omitted OIDs.
+ */
+struct filter_object_type_data {
+       enum object_type object_type;
+};
+
+static enum list_objects_filter_result filter_object_type(
+       struct repository *r,
+       enum list_objects_filter_situation filter_situation,
+       struct object *obj,
+       const char *pathname,
+       const char *filename,
+       struct oidset *omits,
+       void *filter_data_)
+{
+       struct filter_object_type_data *filter_data = filter_data_;
+
+       switch (filter_situation) {
+       default:
+               BUG("unknown filter_situation: %d", filter_situation);
+
+       case LOFS_TAG:
+               assert(obj->type == OBJ_TAG);
+               if (filter_data->object_type == OBJ_TAG)
+                       return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+               return LOFR_MARK_SEEN;
+
+       case LOFS_COMMIT:
+               assert(obj->type == OBJ_COMMIT);
+               if (filter_data->object_type == OBJ_COMMIT)
+                       return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+               return LOFR_MARK_SEEN;
+
+       case LOFS_BEGIN_TREE:
+               assert(obj->type == OBJ_TREE);
+
+               /*
+                * If we only want to show commits or tags, then there is no
+                * need to walk down trees.
+                */
+               if (filter_data->object_type == OBJ_COMMIT ||
+                   filter_data->object_type == OBJ_TAG)
+                       return LOFR_SKIP_TREE;
+
+               if (filter_data->object_type == OBJ_TREE)
+                       return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+
+               return LOFR_MARK_SEEN;
+
+       case LOFS_BLOB:
+               assert(obj->type == OBJ_BLOB);
+
+               if (filter_data->object_type == OBJ_BLOB)
+                       return LOFR_MARK_SEEN | LOFR_DO_SHOW;
+               return LOFR_MARK_SEEN;
+
+       case LOFS_END_TREE:
+               return LOFR_ZERO;
+       }
+}
+
+static void filter_object_type__init(
+       struct list_objects_filter_options *filter_options,
+       struct filter *filter)
+{
+       struct filter_object_type_data *d = xcalloc(1, sizeof(*d));
+       d->object_type = filter_options->object_type;
+
+       filter->filter_data = d;
+       filter->filter_object_fn = filter_object_type;
+       filter->free_fn = free;
+}
+
 /* A filter which only shows objects shown by all sub-filters. */
 struct combine_filter_data {
        struct subfilter *sub;
@@ -651,6 +767,7 @@ static filter_init_fn s_filters[] = {
        filter_blobs_limit__init,
        filter_trees_depth__init,
        filter_sparse_oid__init,
+       filter_object_type__init,
        filter_combine__init,
 };