Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7a7ee98

Browse files
committed
clone: bundle transport
1 parent 5ab90d3 commit 7a7ee98

File tree

18 files changed

+884
-0
lines changed

18 files changed

+884
-0
lines changed

include/git2/sys/transport.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,19 @@ GIT_EXTERN(int) git_transport_local(
259259
git_remote *owner,
260260
/* NULL */ void *payload);
261261

262+
/**
263+
* Create an instance of the bundle transport.
264+
*
265+
* @param out The newly created transport (out)
266+
* @param owner The git_remote which will own this transport
267+
* @param payload You must pass NULL for this parameter.
268+
* @return 0 or an error code
269+
*/
270+
GIT_EXTERN(int) git_transport_bundle(
271+
git_transport **out,
272+
git_remote *owner,
273+
/* NULL */ void *payload);
274+
262275
/**
263276
* Create an instance of the smart transport.
264277
*

src/libgit2/bundle.c

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "bundle.h"
9+
#include "futils.h"
10+
#include "parse.h"
11+
#include "repository.h"
12+
#include "git2/odb_backend.h"
13+
14+
#define GIT_BUNDLE_V2_SIGNATURE "# v2 git bundle\n"
15+
#define GIT_BUNDLE_V3_SIGNATURE "# v3 git bundle\n"
16+
17+
/**
18+
* A bundle file is made up of a header plus a packfile, separated by two
19+
* newlines.
20+
*/
21+
static int read_until_packfile(git_str *str, git_file fd)
22+
{
23+
ssize_t bytes_read = 0;
24+
char buf[1];
25+
26+
while ((bytes_read = p_read(fd, buf, 1)) == 1) {
27+
if (buf[0] == '\n' && git_str_len(str) > 0 &&
28+
git_str_cstr(str)[git_str_len(str) - 1] == '\n') {
29+
return 0;
30+
}
31+
32+
if (git_str_putc(str, buf[0]) < 0) {
33+
return -1;
34+
}
35+
}
36+
37+
return 0;
38+
}
39+
40+
static int read_bundle_version(git_bundle_header *header, git_file fd)
41+
{
42+
int error = 0;
43+
git_str version = GIT_STR_INIT;
44+
45+
if ((error = git_futils_readbuffer_fd(&version, fd, 16)) < 0) {
46+
goto cleanup;
47+
}
48+
49+
if (git__strncmp(git_str_cstr(&version), GIT_BUNDLE_V2_SIGNATURE, 16) ==
50+
0) {
51+
header->version = 2;
52+
} else {
53+
if (git__strncmp(
54+
git_str_cstr(&version), GIT_BUNDLE_V3_SIGNATURE,
55+
16) == 0) {
56+
header->version = 3;
57+
} else {
58+
error = GIT_EINVALID;
59+
}
60+
}
61+
62+
cleanup:
63+
git_str_dispose(&version);
64+
return error;
65+
}
66+
67+
static int
68+
parse_bundle_capabilities(git_bundle_header *header, git_parse_ctx *parser)
69+
{
70+
int error = 0;
71+
72+
git_parse_advance_chars(parser, 1);
73+
74+
if (git_parse_ctx_contains(parser, "object-format=", 14)) {
75+
git_parse_advance_chars(parser, 14);
76+
if (git_parse_ctx_contains(parser, "sha1", 4)) {
77+
header->oid_type = GIT_OID_SHA1;
78+
}
79+
if (git_parse_ctx_contains(parser, "sha256", 6)) {
80+
#ifdef GIT_EXPERIMENTAL_SHA256
81+
header->oid_type = GIT_OID_SHA256;
82+
#else
83+
error = GIT_ENOTSUPPORTED;
84+
#endif
85+
}
86+
goto cleanup;
87+
}
88+
89+
if (git_parse_ctx_contains(parser, "filter=", 7)) {
90+
error = GIT_ENOTSUPPORTED;
91+
goto cleanup;
92+
}
93+
94+
error = GIT_EINVALID;
95+
96+
cleanup:
97+
return error;
98+
}
99+
100+
static int
101+
parse_bundle_prerequisites(git_bundle_header *header, git_parse_ctx *parser)
102+
{
103+
int error = 0;
104+
git_str name = GIT_STR_INIT;
105+
git_oid *oid;
106+
107+
oid = git__calloc(1, sizeof(git_oid));
108+
GIT_ERROR_CHECK_ALLOC(oid);
109+
110+
git_parse_advance_chars(parser, 1);
111+
if ((error = git_parse_advance_oid(oid, parser, header->oid_type)) <
112+
0 ||
113+
(error = git_vector_insert(&header->prerequisites, oid)) < 0) {
114+
git__free(oid);
115+
goto cleanup;
116+
};
117+
118+
cleanup:
119+
git_str_dispose(&name);
120+
return error;
121+
}
122+
123+
static int
124+
parse_bundle_references(git_bundle_header *header, git_parse_ctx *parser)
125+
{
126+
int error = 0;
127+
git_str name = GIT_STR_INIT;
128+
git_remote_head *head;
129+
130+
head = git__calloc(1, sizeof(git_remote_head));
131+
GIT_ERROR_CHECK_ALLOC(head);
132+
133+
if ((error = git_parse_advance_oid(
134+
&head->oid, parser, header->oid_type)) < 0 ||
135+
(error = git_parse_advance_ws(parser)) < 0 ||
136+
(error = git_str_set(&name, parser->line, parser->line_len)) < 0) {
137+
goto cleanup;
138+
};
139+
140+
git_str_rtrim(&name);
141+
head->name = git_str_detach(&name);
142+
git_vector_insert(&header->refs, head);
143+
144+
cleanup:
145+
git_str_dispose(&name);
146+
return error;
147+
}
148+
149+
static int parse_bundle_header(git_bundle_header *header, git_str *buf)
150+
{
151+
int error = 0;
152+
git_parse_ctx parser;
153+
char c;
154+
155+
if ((error = git_parse_ctx_init(
156+
&parser, git_str_cstr(buf), git_str_len(buf))) < 0)
157+
goto cleanup;
158+
159+
for (; parser.remain_len; git_parse_advance_line(&parser)) {
160+
if ((error = git_parse_peek(
161+
&c, &parser, GIT_PARSE_PEEK_SKIP_WHITESPACE)) <
162+
0) {
163+
goto cleanup;
164+
}
165+
166+
if (header->version == 3 && c == '@') {
167+
if ((error = parse_bundle_capabilities(
168+
header, &parser)) < 0) {
169+
goto cleanup;
170+
}
171+
continue;
172+
}
173+
174+
if (c == '-') {
175+
if ((error = parse_bundle_prerequisites(
176+
header, &parser)) < 0) {
177+
goto cleanup;
178+
}
179+
continue;
180+
}
181+
182+
if ((error = parse_bundle_references(header, &parser)) < 0) {
183+
goto cleanup;
184+
}
185+
}
186+
187+
cleanup:
188+
return error;
189+
}
190+
191+
int git_bundle_header_open(git_bundle_header **out, const char *url)
192+
{
193+
int error = 0;
194+
int fd = 0;
195+
git_bundle_header *header = NULL;
196+
git_str buf = GIT_STR_INIT;
197+
198+
if ((fd = git_futils_open_ro(url)) < 0) {
199+
git_str_dispose(&buf);
200+
return fd;
201+
}
202+
203+
header = git__calloc(1, sizeof(git_bundle_header));
204+
GIT_ERROR_CHECK_ALLOC(header);
205+
header->version = 0;
206+
header->oid_type = GIT_OID_SHA1;
207+
if ((error = git_vector_init(&header->refs, 0, NULL)) < 0 ||
208+
(error = git_vector_init(&header->prerequisites, 0, NULL)) < 0 ||
209+
(error = read_bundle_version(header, fd)) < 0 ||
210+
(error = read_until_packfile(&buf, fd)) < 0 ||
211+
(error = parse_bundle_header(header, &buf)) < 0) {
212+
git_bundle_header_free(header);
213+
goto cleanup;
214+
}
215+
216+
*out = header;
217+
218+
cleanup:
219+
git_str_dispose(&buf);
220+
p_close(fd);
221+
return error;
222+
}
223+
224+
void git_bundle_header_free(git_bundle_header *bundle)
225+
{
226+
size_t i;
227+
git_remote_head *ref;
228+
git_oid *prerequisites;
229+
230+
if (!bundle) {
231+
return;
232+
}
233+
234+
git_vector_foreach (&bundle->refs, i, ref) {
235+
git__free(ref->name);
236+
git__free(ref->symref_target);
237+
git__free(ref);
238+
}
239+
git_vector_dispose(&bundle->refs);
240+
241+
i = 0;
242+
git_vector_foreach (&bundle->prerequisites, i, prerequisites) {
243+
git__free(prerequisites);
244+
}
245+
git_vector_dispose(&bundle->prerequisites);
246+
247+
git__free(bundle);
248+
}
249+
250+
int git_bundle__is_bundle(const char *url)
251+
{
252+
int error = 0;
253+
git_bundle_header *header = NULL;
254+
255+
if ((error = git_bundle_header_open(&header, url)) < 0) {
256+
return 0;
257+
}
258+
259+
git_bundle_header_free(header);
260+
return 1;
261+
}
262+
263+
int git_bundle__read_pack(
264+
git_repository *repo,
265+
const char *url,
266+
git_indexer_progress *stats)
267+
{
268+
int error = 0;
269+
int fd = 0;
270+
git_str buf = GIT_STR_INIT;
271+
git_odb *odb;
272+
ssize_t bytes_read = 0;
273+
char buffer[1024];
274+
struct git_odb_writepack *writepack = NULL;
275+
276+
if ((fd = git_futils_open_ro(url)) < 0) {
277+
git_str_dispose(&buf);
278+
return fd;
279+
}
280+
281+
if ((error = read_until_packfile(&buf, fd)) < 0 ||
282+
(error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
283+
(error = git_odb_write_pack(&writepack, odb, NULL, NULL)) != 0) {
284+
goto cleanup;
285+
}
286+
287+
while ((bytes_read = p_read(fd, buffer, 1024)) > 0) {
288+
if ((error = writepack->append(
289+
writepack, buffer, bytes_read, stats)) < 0)
290+
goto cleanup;
291+
}
292+
293+
if ((error = writepack->commit(writepack, stats)) < 0)
294+
goto cleanup;
295+
296+
cleanup:
297+
if (writepack)
298+
writepack->free(writepack);
299+
git_str_dispose(&buf);
300+
p_close(fd);
301+
return error;
302+
}

src/libgit2/bundle.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_bundle_h__
8+
#define INCLUDE_bundle_h__
9+
10+
#include "common.h"
11+
#include "vector.h"
12+
13+
#include "git2/indexer.h"
14+
#include "git2/oid.h"
15+
#include "git2/types.h"
16+
17+
typedef struct {
18+
int version;
19+
git_oid_t oid_type;
20+
git_vector prerequisites;
21+
git_vector refs;
22+
} git_bundle_header;
23+
24+
int git_bundle_header_open(git_bundle_header **out, const char *url);
25+
void git_bundle_header_free(git_bundle_header *bundle);
26+
27+
int git_bundle__is_bundle(const char *url);
28+
29+
int git_bundle__read_pack(
30+
git_repository *repo,
31+
const char *url,
32+
git_indexer_progress *stats);
33+
34+
#endif

src/libgit2/transport.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "git2/net.h"
1313
#include "git2/transport.h"
1414
#include "git2/sys/transport.h"
15+
#include "bundle.h"
1516
#include "fs_path.h"
1617

1718
typedef struct transport_definition {
@@ -28,6 +29,9 @@ static git_smart_subtransport_definition ssh_subtransport_definition = { git_sma
2829
#endif
2930

3031
static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
32+
static transport_definition bundle_transport_definition = {
33+
"", git_transport_bundle, NULL
34+
};
3135

3236
static transport_definition transports[] = {
3337
{ "git://", git_transport_smart, &git_subtransport_definition },
@@ -105,6 +109,11 @@ static int transport_find_fn(
105109
definition = &local_transport_definition;
106110
#endif
107111

112+
if (!definition && git_fs_path_isfile(url) &&
113+
git_bundle__is_bundle(url)) {
114+
definition = &bundle_transport_definition;
115+
}
116+
108117
if (!definition)
109118
return GIT_ENOTFOUND;
110119

0 commit comments

Comments
 (0)