1 #include "clar_libgit2.h"
6 #include "git2/sys/filter.h"
7 #include "git2/sys/repository.h"
9 static git_repository
*g_repo
= NULL
;
11 static git_filter
*create_compress_filter(void);
12 static git_filter
*compress_filter
;
14 void test_filter_stream__initialize(void)
16 compress_filter
= create_compress_filter();
18 cl_git_pass(git_filter_register("compress", compress_filter
, 50));
19 g_repo
= cl_git_sandbox_init("empty_standard_repo");
22 void test_filter_stream__cleanup(void)
24 cl_git_sandbox_cleanup();
27 git_filter_unregister("compress");
28 git__free(compress_filter
);
31 #define CHUNKSIZE 10240
33 struct compress_stream
{
34 git_writestream parent
;
35 git_writestream
*next
;
36 git_filter_mode_t mode
;
41 static int compress_stream_write__deflated(struct compress_stream
*stream
, const char *buffer
, size_t len
)
46 size_t chunkremain
, chunksize
;
48 if (stream
->current_chunk
== 0)
49 stream
->current
= buffer
[idx
];
51 chunkremain
= CHUNKSIZE
- stream
->current_chunk
;
52 chunksize
= min(chunkremain
, len
);
54 stream
->current_chunk
+= chunksize
;
58 if (stream
->current_chunk
== CHUNKSIZE
) {
59 cl_git_pass(stream
->next
->write(stream
->next
, &stream
->current
, 1));
60 stream
->current_chunk
= 0;
67 static int compress_stream_write__inflated(struct compress_stream
*stream
, const char *buffer
, size_t len
)
69 char inflated
[CHUNKSIZE
];
72 for (i
= 0; i
< len
; i
++) {
73 for (j
= 0; j
< CHUNKSIZE
; j
++)
74 inflated
[j
] = buffer
[i
];
76 cl_git_pass(stream
->next
->write(stream
->next
, inflated
, CHUNKSIZE
));
82 static int compress_stream_write(git_writestream
*s
, const char *buffer
, size_t len
)
84 struct compress_stream
*stream
= (struct compress_stream
*)s
;
86 return (stream
->mode
== GIT_FILTER_TO_ODB
) ?
87 compress_stream_write__deflated(stream
, buffer
, len
) :
88 compress_stream_write__inflated(stream
, buffer
, len
);
91 static int compress_stream_close(git_writestream
*s
)
93 struct compress_stream
*stream
= (struct compress_stream
*)s
;
94 cl_assert_equal_i(0, stream
->current_chunk
);
95 stream
->next
->close(stream
->next
);
99 static void compress_stream_free(git_writestream
*stream
)
104 static int compress_filter_stream_init(
105 git_writestream
**out
,
108 const git_filter_source
*src
,
109 git_writestream
*next
)
111 struct compress_stream
*stream
= git__calloc(1, sizeof(struct compress_stream
));
117 stream
->parent
.write
= compress_stream_write
;
118 stream
->parent
.close
= compress_stream_close
;
119 stream
->parent
.free
= compress_stream_free
;
121 stream
->mode
= git_filter_source_mode(src
);
123 *out
= (git_writestream
*)stream
;
127 git_filter
*create_compress_filter(void)
129 git_filter
*filter
= git__calloc(1, sizeof(git_filter
));
132 filter
->version
= GIT_FILTER_VERSION
;
133 filter
->attributes
= "+compress";
134 filter
->stream
= compress_filter_stream_init
;
139 static void writefile(const char *filename
, size_t numchunks
)
141 git_buf path
= GIT_BUF_INIT
;
146 cl_git_pass(git_buf_joinpath(&path
, "empty_standard_repo", filename
));
148 fd
= p_open(path
.ptr
, O_RDWR
|O_CREAT
, 0666);
151 for (i
= 0; i
< numchunks
; i
++) {
152 for (j
= 0; j
< CHUNKSIZE
; j
++) {
156 cl_git_pass(p_write(fd
, buf
, CHUNKSIZE
));
160 git_buf_dispose(&path
);
163 static void test_stream(size_t numchunks
)
166 const git_index_entry
*entry
;
169 git_checkout_options checkout_opts
= GIT_CHECKOUT_OPTIONS_INIT
;
171 checkout_opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
174 "empty_standard_repo/.gitattributes",
177 /* write a file to disk */
178 writefile("streamed_file", numchunks
);
180 /* place it in the index */
181 cl_git_pass(git_repository_index(&index
, g_repo
));
182 cl_git_pass(git_index_add_bypath(index
, "streamed_file"));
183 cl_git_pass(git_index_write(index
));
185 /* ensure it was appropriately compressed */
186 cl_assert(entry
= git_index_get_bypath(index
, "streamed_file", 0));
188 cl_git_pass(git_blob_lookup(&blob
, g_repo
, &entry
->id
));
189 cl_assert_equal_i(numchunks
, git_blob_rawsize(blob
));
191 /* check the file back out */
192 cl_must_pass(p_unlink("empty_standard_repo/streamed_file"));
193 cl_git_pass(git_checkout_index(g_repo
, index
, &checkout_opts
));
195 /* ensure it was decompressed */
196 cl_must_pass(p_stat("empty_standard_repo/streamed_file", &st
));
197 cl_assert_equal_sz((numchunks
* CHUNKSIZE
), st
.st_size
);
199 git_index_free(index
);
203 /* write a 50KB file through the "compression" stream */
204 void test_filter_stream__smallfile(void)
209 /* optionally write a 500 MB file through the compression stream */
210 void test_filter_stream__bigfile(void)
212 if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE"))