2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
8 #include "git2/types.h"
11 #include "fetchhead.h"
17 #include "repository.h"
20 int git_fetchhead_ref_cmp(const void *a
, const void *b
)
22 const git_fetchhead_ref
*one
= (const git_fetchhead_ref
*)a
;
23 const git_fetchhead_ref
*two
= (const git_fetchhead_ref
*)b
;
25 if (one
->is_merge
&& !two
->is_merge
)
27 if (two
->is_merge
&& !one
->is_merge
)
30 if (one
->ref_name
&& two
->ref_name
)
31 return strcmp(one
->ref_name
, two
->ref_name
);
32 else if (one
->ref_name
)
34 else if (two
->ref_name
)
40 int git_fetchhead_ref_create(
41 git_fetchhead_ref
**out
,
43 unsigned int is_merge
,
45 const char *remote_url
)
47 git_fetchhead_ref
*fetchhead_ref
;
53 fetchhead_ref
= git__malloc(sizeof(git_fetchhead_ref
));
54 GITERR_CHECK_ALLOC(fetchhead_ref
);
56 memset(fetchhead_ref
, 0x0, sizeof(git_fetchhead_ref
));
58 git_oid_cpy(&fetchhead_ref
->oid
, oid
);
59 fetchhead_ref
->is_merge
= is_merge
;
62 fetchhead_ref
->ref_name
= git__strdup(ref_name
);
65 fetchhead_ref
->remote_url
= git__strdup(remote_url
);
72 static int fetchhead_ref_write(
74 git_fetchhead_ref
*fetchhead_ref
)
76 char oid
[GIT_OID_HEXSZ
+ 1];
77 const char *type
, *name
;
79 assert(file
&& fetchhead_ref
);
81 git_oid_fmt(oid
, &fetchhead_ref
->oid
);
82 oid
[GIT_OID_HEXSZ
] = '\0';
84 if (git__prefixcmp(fetchhead_ref
->ref_name
, GIT_REFS_HEADS_DIR
) == 0) {
86 name
= fetchhead_ref
->ref_name
+ strlen(GIT_REFS_HEADS_DIR
);
87 } else if(git__prefixcmp(fetchhead_ref
->ref_name
,
88 GIT_REFS_TAGS_DIR
) == 0) {
90 name
= fetchhead_ref
->ref_name
+ strlen(GIT_REFS_TAGS_DIR
);
93 name
= fetchhead_ref
->ref_name
;
96 return git_filebuf_printf(file
, "%s\t%s\t%s'%s' of %s\n",
98 (fetchhead_ref
->is_merge
) ? "" : "not-for-merge",
101 fetchhead_ref
->remote_url
);
104 int git_fetchhead_write(git_repository
*repo
, git_vector
*fetchhead_refs
)
106 git_filebuf file
= GIT_FILEBUF_INIT
;
107 git_buf path
= GIT_BUF_INIT
;
109 git_fetchhead_ref
*fetchhead_ref
;
111 assert(repo
&& fetchhead_refs
);
113 if (git_buf_joinpath(&path
, repo
->path_repository
, GIT_FETCH_HEAD_FILE
) < 0)
116 if (git_filebuf_open(&file
, path
.ptr
, GIT_FILEBUF_FORCE
) < 0) {
123 git_vector_sort(fetchhead_refs
);
125 git_vector_foreach(fetchhead_refs
, i
, fetchhead_ref
)
126 fetchhead_ref_write(&file
, fetchhead_ref
);
128 return git_filebuf_commit(&file
, GIT_REFS_FILE_MODE
);
131 static int fetchhead_ref_parse(
133 unsigned int *is_merge
,
135 const char **remote_url
,
139 char *oid_str
, *is_merge_str
, *desc
, *name
= NULL
;
140 const char *type
= NULL
;
146 giterr_set(GITERR_FETCHHEAD
,
147 "Empty line in FETCH_HEAD line %d", line_num
);
151 /* Compat with old git clients that wrote FETCH_HEAD like a loose ref. */
152 if ((oid_str
= git__strsep(&line
, "\t")) == NULL
) {
154 line
+= strlen(line
);
159 if (strlen(oid_str
) != GIT_OID_HEXSZ
) {
160 giterr_set(GITERR_FETCHHEAD
,
161 "Invalid object ID in FETCH_HEAD line %d", line_num
);
165 if (git_oid_fromstr(oid
, oid_str
) < 0) {
166 const git_error
*oid_err
= giterr_last();
167 const char *err_msg
= oid_err
? oid_err
->message
: "Invalid object ID";
169 giterr_set(GITERR_FETCHHEAD
, "%s in FETCH_HEAD line %d",
174 /* Parse new data from newer git clients */
176 if ((is_merge_str
= git__strsep(&line
, "\t")) == NULL
) {
177 giterr_set(GITERR_FETCHHEAD
,
178 "Invalid description data in FETCH_HEAD line %d", line_num
);
182 if (*is_merge_str
== '\0')
184 else if (strcmp(is_merge_str
, "not-for-merge") == 0)
187 giterr_set(GITERR_FETCHHEAD
,
188 "Invalid for-merge entry in FETCH_HEAD line %d", line_num
);
192 if ((desc
= line
) == NULL
) {
193 giterr_set(GITERR_FETCHHEAD
,
194 "Invalid description in FETCH_HEAD line %d", line_num
);
198 if (git__prefixcmp(desc
, "branch '") == 0) {
199 type
= GIT_REFS_HEADS_DIR
;
201 } else if (git__prefixcmp(desc
, "tag '") == 0) {
202 type
= GIT_REFS_TAGS_DIR
;
204 } else if (git__prefixcmp(desc
, "'") == 0)
208 if ((desc
= strchr(name
, '\'')) == NULL
||
209 git__prefixcmp(desc
, "' of ") != 0) {
210 giterr_set(GITERR_FETCHHEAD
,
211 "Invalid description in FETCH_HEAD line %d", line_num
);
222 git_buf_clear(ref_name
);
225 git_buf_join(ref_name
, '/', type
, name
);
227 git_buf_puts(ref_name
, name
);
232 int git_repository_fetchhead_foreach(git_repository
*repo
,
233 git_repository_fetchhead_foreach_cb cb
,
236 git_buf path
= GIT_BUF_INIT
, file
= GIT_BUF_INIT
, name
= GIT_BUF_INIT
;
237 const char *ref_name
;
239 const char *remote_url
;
240 unsigned int is_merge
= 0;
247 if (git_buf_joinpath(&path
, repo
->path_repository
, GIT_FETCH_HEAD_FILE
) < 0)
250 if ((error
= git_futils_readbuffer(&file
, git_buf_cstr(&path
))) < 0)
255 while ((line
= git__strsep(&buffer
, "\n")) != NULL
) {
258 if ((error
= fetchhead_ref_parse(&oid
, &is_merge
, &name
, &remote_url
,
259 line
, line_num
)) < 0)
262 if (git_buf_len(&name
) > 0)
263 ref_name
= git_buf_cstr(&name
);
267 if ((cb(ref_name
, remote_url
, &oid
, is_merge
, payload
)) != 0) {
274 giterr_set(GITERR_FETCHHEAD
, "No EOL at line %d", line_num
+1);
287 void git_fetchhead_ref_free(git_fetchhead_ref
*fetchhead_ref
)
289 if (fetchhead_ref
== NULL
)
292 git__free(fetchhead_ref
->remote_url
);
293 git__free(fetchhead_ref
->ref_name
);
294 git__free(fetchhead_ref
);