Commit 5915a2a255010f45987a1f03ff15d8f9a73153ae

Carlos Martín Nieto 2015-08-03T19:25:03

Merge pull request #3349 from libgit2/cmn/for-v23 A second round of 0.23 maint updates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c55ddd..4747818 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@
 # > cmake --build . --target install
 
 PROJECT(libgit2 C)
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 CMAKE_POLICY(SET CMP0015 NEW)
 
 # Add find modules to the path
@@ -412,6 +412,7 @@ ELSE ()
 		SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 	ENDIF ()
 
+	ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation)
 	ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers)
 	ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2)
 	ADD_C_FLAG_IF_SUPPORTED(-Wstrict-prototypes)
diff --git a/README.md b/README.md
index 4ee1fdc..3191aee 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthrea
 they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
 for threading.
 
-The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.6 or newer) on all platforms.
+The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.8 or newer) on all platforms.
 
 On most systems you can build the library using the following commands
 
diff --git a/include/git2/repository.h b/include/git2/repository.h
index ce56fef..cf268ef 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -745,7 +745,7 @@ GIT_EXTERN(int) git_repository_ident(const char **name, const char **email, cons
  *
  * @param repo the repository to configure
  * @param name the name to use for the reflog entries
- * @param name the email to use for the reflog entries
+ * @param email the email to use for the reflog entries
  */
 GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email);
 
diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index b5b7df1..044e344 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -76,7 +76,7 @@ struct git_config_backend {
  * Initializes a `git_config_backend` with default values. Equivalent to
  * creating an instance with GIT_CONFIG_BACKEND_INIT.
  *
- * @param opts the `git_config_backend` struct to initialize.
+ * @param backend the `git_config_backend` struct to initialize.
  * @param version Version of struct; pass `GIT_CONFIG_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/include/git2/sys/diff.h b/include/git2/sys/diff.h
index 034d5c4..aefd7b9 100644
--- a/include/git2/sys/diff.h
+++ b/include/git2/sys/diff.h
@@ -38,7 +38,7 @@ GIT_EXTERN(int) git_diff_print_callback__to_buf(
 	const git_diff_delta *delta,
 	const git_diff_hunk *hunk,
 	const git_diff_line *line,
-	void *payload); /*< payload must be a `git_buf *` */
+	void *payload); /**< payload must be a `git_buf *` */
 
 /**
  * Diff print callback that writes to stdio FILE handle.
@@ -58,7 +58,7 @@ GIT_EXTERN(int) git_diff_print_callback__to_file_handle(
 	const git_diff_delta *delta,
 	const git_diff_hunk *hunk,
 	const git_diff_line *line,
-	void *payload); /*< payload must be a `FILE *` */
+	void *payload); /**< payload must be a `FILE *` */
 
 
 /**
@@ -66,8 +66,8 @@ GIT_EXTERN(int) git_diff_print_callback__to_file_handle(
  */
 typedef struct {
 	unsigned int version;
-	size_t stat_calls; /*< Number of stat() calls performed */
-	size_t oid_calculations; /*< Number of ID calculations */
+	size_t stat_calls; /**< Number of stat() calls performed */
+	size_t oid_calculations; /**< Number of ID calculations */
 } git_diff_perfdata;
 
 #define GIT_DIFF_PERFDATA_VERSION 1
diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h
index 0a51c6d..fe102ff 100644
--- a/include/git2/sys/odb_backend.h
+++ b/include/git2/sys/odb_backend.h
@@ -93,7 +93,7 @@ struct git_odb_backend {
  * Initializes a `git_odb_backend` with default values. Equivalent to
  * creating an instance with GIT_ODB_BACKEND_INIT.
  *
- * @param opts the `git_odb_backend` struct to initialize.
+ * @param backend the `git_odb_backend` struct to initialize.
  * @param version Version the struct; pass `GIT_ODB_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index d943e55..8b004a7 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -175,7 +175,7 @@ struct git_refdb_backend {
  * Initializes a `git_refdb_backend` with default values. Equivalent to
  * creating an instance with GIT_REFDB_BACKEND_INIT.
  *
- * @param opts the `git_refdb_backend` struct to initialize
+ * @param backend the `git_refdb_backend` struct to initialize
  * @param version Version of struct; pass `GIT_REFDB_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/src/describe.c b/src/describe.c
index 5aea927..48f04e8 100644
--- a/src/describe.c
+++ b/src/describe.c
@@ -19,7 +19,7 @@
 #include "vector.h"
 #include "repository.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */
 
diff --git a/src/filebuf.c b/src/filebuf.c
index 848ac34..838f4b4 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -101,7 +101,7 @@ void git_filebuf_cleanup(git_filebuf *file)
 	if (file->fd_is_open && file->fd >= 0)
 		p_close(file->fd);
 
-	if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock))
+	if (file->created_lock && !file->did_rename && file->path_lock && git_path_exists(file->path_lock))
 		p_unlink(file->path_lock);
 
 	if (file->compute_digest) {
@@ -258,6 +258,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
 			goto cleanup;
 		}
 		file->fd_is_open = true;
+		file->created_lock = true;
 
 		/* No original path */
 		file->path_original = NULL;
@@ -281,6 +282,8 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
 		/* open the file for locking */
 		if ((error = lock_file(file, flags, mode)) < 0)
 			goto cleanup;
+
+		file->created_lock = true;
 	}
 
 	return 0;
@@ -340,6 +343,8 @@ int git_filebuf_commit(git_filebuf *file)
 		goto on_error;
 	}
 
+	file->did_rename = true;
+
 	git_filebuf_cleanup(file);
 	return 0;
 
diff --git a/src/filebuf.h b/src/filebuf.h
index 2bd18dc..f4d255b 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -44,6 +44,8 @@ struct git_filebuf {
 	size_t buf_size, buf_pos;
 	git_file fd;
 	bool fd_is_open;
+	bool created_lock;
+	bool did_rename;
 	bool do_not_buffer;
 	int last_error;
 };
diff --git a/src/index.c b/src/index.c
index 501498e..73f0b3d 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1228,6 +1228,45 @@ int git_index_add_frombuffer(
 	return 0;
 }
 
+static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
+{
+	git_repository *sub;
+	git_buf abspath = GIT_BUF_INIT;
+	git_repository *repo = INDEX_OWNER(index);
+	git_reference *head;
+	git_index_entry *entry;
+	struct stat st;
+	int error;
+
+	if (index_entry_create(&entry, INDEX_OWNER(index), path) < 0)
+		return -1;
+
+	if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
+		return error;
+
+	if ((error = p_stat(abspath.ptr, &st)) < 0) {
+		giterr_set(GITERR_OS, "failed to stat repository dir");
+		return -1;
+	}
+
+	git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
+
+	if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
+		return error;
+
+	if ((error = git_repository_head(&head, sub)) < 0)
+		return error;
+
+	git_oid_cpy(&entry->id, git_reference_target(head));
+	entry->mode = GIT_FILEMODE_COMMIT;
+
+	git_reference_free(head);
+	git_repository_free(sub);
+	git_buf_free(&abspath);
+
+	*out = entry;
+	return 0;
+}
 
 int git_index_add_bypath(git_index *index, const char *path)
 {
@@ -1252,12 +1291,26 @@ int git_index_add_bypath(git_index *index, const char *path)
 		ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
 		if (ret == GIT_ENOTFOUND)
 			return giterr_restore(&err);
-		else
-			git__free(err.error_msg.message);
 
-		ret = git_submodule_add_to_index(sm, false);
-		git_submodule_free(sm);
-		return ret;
+		git__free(err.error_msg.message);
+
+		/*
+		 * EEXISTS means that there is a repository at that path, but it's not known
+		 * as a submodule. We add its HEAD as an entry and don't register it.
+		 */
+		if (ret == GIT_EEXISTS) {
+			if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
+				return ret;
+
+			if ((ret = index_insert(index, &entry, 1, false)) < 0)
+				return ret;
+		} else if (ret < 0) {
+			return ret;
+		} else {
+			ret = git_submodule_add_to_index(sm, false);
+			git_submodule_free(sm);
+			return ret;
+		}
 	}
 
 	/* Adding implies conflict was resolved, move conflict entries to REUC */
diff --git a/src/indexer.c b/src/indexer.c
index 512addf..9aa0925 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -18,7 +18,7 @@
 #include "oidmap.h"
 #include "zstream.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 extern git_mutex git__mwindow_mutex;
 
diff --git a/src/iterator.c b/src/iterator.c
index a312afb..cf51a34 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1027,8 +1027,11 @@ static int dirload_with_stat(
 	strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
 		git__strncasecmp : git__strncmp;
 
-	if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0)
+	/* Any error here is equivalent to the dir not existing, skip over it */
+	if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0) {
+		error = GIT_ENOTFOUND;
 		goto done;
+	}
 
 	while ((error = git_path_diriter_next(&diriter)) == 0) {
 		if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
diff --git a/src/pack-objects.c b/src/pack-objects.c
index e287e33..c4c061a 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -41,7 +41,7 @@ struct pack_write_context {
 	git_transfer_progress *stats;
 };
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 #ifdef GIT_THREADS
 
diff --git a/src/pack.c b/src/pack.c
index cd65267..45dd4d5 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -16,8 +16,8 @@
 
 #include <zlib.h>
 
-GIT__USE_OFFMAP;
-GIT__USE_OIDMAP;
+GIT__USE_OFFMAP
+GIT__USE_OIDMAP
 
 static int packfile_open(struct git_pack_file *p);
 static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
diff --git a/src/path.h b/src/path.h
index 5927a53..e6be06f 100644
--- a/src/path.h
+++ b/src/path.h
@@ -319,7 +319,7 @@ extern int git_path_cmp(
  * @param callback Function to invoke on each path.  Passed the `payload`
  *		and the buffer containing the current path.  The path should not
  *		be modified in any way. Return non-zero to stop iteration.
- * @param state Passed to fn as the first ath.
+ * @param payload Passed to fn as the first ath.
  */
 extern int git_path_walk_up(
 	git_buf *pathbuf,
diff --git a/src/push.h b/src/push.h
index 094f96c..a847ee0 100644
--- a/src/push.h
+++ b/src/push.h
@@ -83,7 +83,7 @@ int git_push_add_refspec(git_push *push, const char *refspec);
  * Update remote tips after a push
  *
  * @param push The push object
- * @param signature The identity to use when updating reflogs
+ * @param callbacks the callbacks to use for this connection
  *
  * @return 0 or an error code
  */
@@ -100,6 +100,7 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks);
  * order to find out which updates were accepted or rejected.
  *
  * @param push The push object
+ * @param callbacks the callbacks to use for this connection
  *
  * @return 0 or an error code
  */
@@ -117,6 +118,7 @@ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks);
  *
  * @param push The push object
  * @param cb The callback to call on each object
+ * @param data The payload passed to the callback
  *
  * @return 0 on success, non-zero callback return value, or error code
  */
diff --git a/src/revwalk.c b/src/revwalk.c
index 6acc5d0..dcdd979 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -14,7 +14,7 @@
 #include "git2/revparse.h"
 #include "merge.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 git_commit_list_node *git_revwalk__commit_lookup(
 	git_revwalk *walk, const git_oid *oid)
diff --git a/src/transports/git.c b/src/transports/git.c
index 7e0a474..52de92d 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -50,6 +50,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
 	}
 
 	repo = delim;
+	if (repo[1] == '~')
+		++repo;
 
 	delim = strchr(url, ':');
 	if (delim == NULL)
diff --git a/src/transports/http.c b/src/transports/http.c
index 1ed292b..e3d90de 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -255,7 +255,7 @@ static int on_header_ready(http_subtransport *t)
 			GITERR_CHECK_ALLOC(t->content_type);
 		}
 	}
-	else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
+	else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
 		char *dup = git__strdup(git_buf_cstr(value));
 		GITERR_CHECK_ALLOC(dup);
 
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 83af137..e3792eb 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -66,6 +66,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
 	if (!git__prefixcmp(url, prefix_ssh)) {
 		url = url + strlen(prefix_ssh);
 		repo = strchr(url, '/');
+		if (repo && repo[1] == '~')
+			++repo;
 	} else {
 		repo = strchr(url, ':');
 		if (repo) repo++;
diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c
index 5a3e751..3f7dc85 100644
--- a/tests/core/filebuf.c
+++ b/tests/core/filebuf.c
@@ -124,3 +124,30 @@ void test_core_filebuf__umask(void)
 	cl_must_pass(p_unlink(test));
 }
 
+void test_core_filebuf__rename_error(void)
+{
+	git_filebuf file = GIT_FILEBUF_INIT;
+	char *dir = "subdir",  *test = "subdir/test", *test_lock = "subdir/test.lock";
+	int fd;
+
+#ifndef GIT_WIN32
+	cl_skip();
+#endif
+
+	cl_git_pass(p_mkdir(dir, 0666));
+	cl_git_mkfile(test, "dummy content");
+	fd = p_open(test, O_RDONLY);
+	cl_assert(fd > 0);
+	cl_git_pass(git_filebuf_open(&file, test, 0, 0666));
+
+	cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
+
+	cl_assert_equal_i(true, git_path_exists(test_lock));
+
+	cl_git_fail(git_filebuf_commit(&file));
+	p_close(fd);
+
+	git_filebuf_cleanup(&file);
+
+	cl_assert_equal_i(false, git_path_exists(test_lock));
+}
diff --git a/tests/index/bypath.c b/tests/index/bypath.c
index ddb766a..9706a88 100644
--- a/tests/index/bypath.c
+++ b/tests/index/bypath.c
@@ -33,3 +33,16 @@ void test_index_bypath__add_submodule(void)
 	cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
 	cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
 }
+
+void test_index_bypath__add_submodule_unregistered(void)
+{
+	const char *sm_name = "not-submodule";
+	const char *sm_head = "68e92c611b80ee1ed8f38314ff9577f0d15b2444";
+	const git_index_entry *entry;
+
+	cl_git_pass(git_index_add_bypath(g_idx, sm_name));
+
+	cl_assert(entry = git_index_get_bypath(g_idx, sm_name, 0));
+	cl_assert_equal_s(sm_head, git_oid_tostr_s(&entry->id));
+	cl_assert_equal_s(sm_name, entry->path);
+}
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 26e8954..bb2d3a1 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -928,7 +928,7 @@ void test_repo_iterator__fs2(void)
 	git_iterator_free(i);
 }
 
-void test_repo_iterator__fs_preserves_error(void)
+void test_repo_iterator__unreadable_dir(void)
 {
 	git_iterator *i;
 	const git_index_entry *e;
@@ -951,10 +951,6 @@ void test_repo_iterator__fs_preserves_error(void)
 
 	cl_git_pass(git_iterator_advance(&e, i)); /* a */
 	cl_git_fail(git_iterator_advance(&e, i)); /* b */
-	cl_assert(giterr_last());
-	cl_assert(giterr_last()->message != NULL);
-	/* skip 'c/' empty directory */
-	cl_git_pass(git_iterator_advance(&e, i)); /* d */
 	cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i));
 
 	cl_must_pass(p_chmod("empty_standard_repo/r/b", 0777));