diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/diff.c | 4 | ||||
| -rw-r--r-- | src/iterator.c | 43 | ||||
| -rw-r--r-- | src/merge_file.c | 4 | ||||
| -rw-r--r-- | src/odb.c | 24 | ||||
| -rw-r--r-- | src/odb_mempack.c | 182 | ||||
| -rw-r--r-- | src/refspec.h | 1 | ||||
| -rw-r--r-- | src/remote.c | 8 | ||||
| -rw-r--r-- | src/submodule.c | 15 | ||||
| -rw-r--r-- | src/submodule.h | 3 |
9 files changed, 252 insertions, 32 deletions
diff --git a/src/diff.c b/src/diff.c index 25c5937e6..484273f4a 100644 --- a/src/diff.c +++ b/src/diff.c @@ -880,8 +880,10 @@ static int handle_unmatched_new_item( git_buf *full = NULL; if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) return -1; - if (full && git_path_contains_dir(full, DOT_GIT)) + if (full && git_path_contains(full, DOT_GIT)) { + /* TODO: warning if not a valid git repository */ recurse_into_dir = false; + } } /* still have to look into untracked directories to match core git - diff --git a/src/iterator.c b/src/iterator.c index e9ec65250..a7a44914c 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -10,7 +10,7 @@ #include "index.h" #include "ignore.h" #include "buffer.h" -#include "git2/submodule.h" +#include "submodule.h" #include <ctype.h> #define ITERATOR_SET_CB(P,NAME_LC) do { \ @@ -1275,14 +1275,38 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) static int workdir_iterator__enter_dir(fs_iterator *fi) { + fs_iterator_frame *ff = fi->stack; + size_t pos; + git_path_with_stat *entry; + bool found_submodules = false; + /* only push new ignores if this is not top level directory */ - if (fi->stack->next != NULL) { + if (ff->next != NULL) { workdir_iterator *wi = (workdir_iterator *)fi; ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } + /* convert submodules to GITLINK and remove trailing slashes */ + git_vector_foreach(&ff->entries, pos, entry) { + if (S_ISDIR(entry->st.st_mode) && + git_submodule__is_submodule(fi->base.repo, entry->path)) + { + entry->st.st_mode = GIT_FILEMODE_COMMIT; + entry->path_len--; + entry->path[entry->path_len] = '\0'; + found_submodules = true; + } + } + + /* if we renamed submodules, re-sort and re-seek to start */ + if (found_submodules) { + git_vector_set_sorted(&ff->entries, 0); + git_vector_sort(&ff->entries); + fs_iterator__seek_frame_start(fi, ff); + } + return 0; } @@ -1295,7 +1319,6 @@ static int workdir_iterator__leave_dir(fs_iterator *fi) static int workdir_iterator__update_entry(fs_iterator *fi) { - int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; /* skip over .git entries */ @@ -1305,20 +1328,6 @@ static int workdir_iterator__update_entry(fs_iterator *fi) /* reset is_ignored since we haven't checked yet */ wi->is_ignored = -1; - /* check if apparent tree entries are actually submodules */ - if (fi->entry.mode != GIT_FILEMODE_TREE) - return 0; - - error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); - if (error < 0) - giterr_clear(); - - /* mark submodule as GITLINK and remove slash */ - if (!error) { - fi->entry.mode = S_IFGITLINK; - fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; - } - return 0; } diff --git a/src/merge_file.c b/src/merge_file.c index ab9ca4168..ff0364432 100644 --- a/src/merge_file.c +++ b/src/merge_file.c @@ -117,7 +117,7 @@ static int git_merge_file__from_inputs( memset(out, 0x0, sizeof(git_merge_file_result)); - merge_file_normalize_opts(&options, given_opts); + merge_file_normalize_opts(&options, given_opts); memset(&xmparam, 0x0, sizeof(xmparam_t)); @@ -165,7 +165,7 @@ static int git_merge_file__from_inputs( } out->automergeable = (xdl_result == 0); - out->ptr = (unsigned char *)mmbuffer.ptr; + out->ptr = (const char *)mmbuffer.ptr; out->len = mmbuffer.size; out->mode = merge_file_best_mode(ancestor, ours, theirs); @@ -640,7 +640,7 @@ int git_odb_exists_prefix( { int error = GIT_ENOTFOUND, num_found = 0; size_t i; - git_oid last_found = {{0}}, found; + git_oid key = {{0}}, last_found = {{0}}, found; assert(db && short_id); @@ -659,6 +659,11 @@ int git_odb_exists_prefix( } } + /* just copy valid part of short_id */ + memcpy(&key.id, short_id->id, (len + 1) / 2); + if (len & 1) + key.id[len / 2] &= 0xF0; + for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; @@ -666,7 +671,7 @@ int git_odb_exists_prefix( if (!b->exists_prefix) continue; - error = b->exists_prefix(&found, b, short_id, len); + error = b->exists_prefix(&found, b, &key, len); if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) continue; if (error) @@ -683,11 +688,11 @@ int git_odb_exists_prefix( } if (!num_found) - return git_odb__error_notfound("no match for id prefix", short_id); + return git_odb__error_notfound("no match for id prefix", &key); if (out) git_oid_cpy(out, &last_found); - return error; + return 0; } int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id) @@ -790,7 +795,7 @@ int git_odb_read_prefix( { size_t i; int error = GIT_ENOTFOUND; - git_oid found_full_oid = {{0}}; + git_oid key = {{0}}, found_full_oid = {{0}}; git_rawobj raw; void *data = NULL; bool found = false; @@ -809,13 +814,18 @@ int git_odb_read_prefix( return 0; } + /* just copy valid part of short_id */ + memcpy(&key.id, short_id->id, (len + 1) / 2); + if (len & 1) + key.id[len / 2] &= 0xF0; + for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->read_prefix != NULL) { git_oid full_oid; - error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len); + error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, &key, len); if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) continue; @@ -836,7 +846,7 @@ int git_odb_read_prefix( } if (!found) - return git_odb__error_notfound("no match for prefix", short_id); + return git_odb__error_notfound("no match for prefix", &key); if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) return -1; diff --git a/src/odb_mempack.c b/src/odb_mempack.c new file mode 100644 index 000000000..d9b3a1824 --- /dev/null +++ b/src/odb_mempack.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "git2/object.h" +#include "git2/sys/odb_backend.h" +#include "fileops.h" +#include "hash.h" +#include "odb.h" +#include "array.h" +#include "oidmap.h" + +#include "git2/odb_backend.h" +#include "git2/types.h" +#include "git2/pack.h" + +GIT__USE_OIDMAP; + +struct memobject { + git_oid oid; + size_t len; + git_otype type; + char data[]; +}; + +struct memory_packer_db { + git_odb_backend parent; + git_oidmap *objects; + git_array_t(struct memobject *) commits; +}; + +static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void *data, size_t len, git_otype type) +{ + struct memory_packer_db *db = (struct memory_packer_db *)_backend; + struct memobject *obj = NULL; + khiter_t pos; + int rval; + + pos = kh_put(oid, db->objects, oid, &rval); + if (rval < 0) + return -1; + + if (rval == 0) + return 0; + + obj = git__malloc(sizeof(struct memobject) + len); + GITERR_CHECK_ALLOC(obj); + + memcpy(obj->data, data, len); + git_oid_cpy(&obj->oid, oid); + obj->len = len; + obj->type = type; + + kh_key(db->objects, pos) = &obj->oid; + kh_val(db->objects, pos) = obj; + + if (type == GIT_OBJ_COMMIT) { + struct memobject **store = git_array_alloc(db->commits); + GITERR_CHECK_ALLOC(store); + *store = obj; + } + + return 0; +} + +static int impl__exists(git_odb_backend *backend, const git_oid *oid) +{ + struct memory_packer_db *db = (struct memory_packer_db *)backend; + khiter_t pos; + + pos = kh_get(oid, db->objects, oid); + if (pos != kh_end(db->objects)) + return 1; + + return 0; +} + +static int impl__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) +{ + struct memory_packer_db *db = (struct memory_packer_db *)backend; + struct memobject *obj = NULL; + khiter_t pos; + + pos = kh_get(oid, db->objects, oid); + if (pos == kh_end(db->objects)) + return GIT_ENOTFOUND; + + obj = kh_val(db->objects, pos); + + *len_p = obj->len; + *type_p = obj->type; + *buffer_p = git__malloc(obj->len); + GITERR_CHECK_ALLOC(*buffer_p); + + memcpy(*buffer_p, obj->data, obj->len); + return 0; +} + +static int impl__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) +{ + struct memory_packer_db *db = (struct memory_packer_db *)backend; + struct memobject *obj = NULL; + khiter_t pos; + + pos = kh_get(oid, db->objects, oid); + if (pos == kh_end(db->objects)) + return GIT_ENOTFOUND; + + obj = kh_val(db->objects, pos); + + *len_p = obj->len; + *type_p = obj->type; + return 0; +} + +int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *_backend) +{ + struct memory_packer_db *db = (struct memory_packer_db *)_backend; + git_packbuilder *packbuilder; + uint32_t i; + int err = -1; + + if (git_packbuilder_new(&packbuilder, repo) < 0) + return -1; + + for (i = 0; i < db->commits.size; ++i) { + struct memobject *commit = db->commits.ptr[i]; + + err = git_packbuilder_insert_commit(packbuilder, &commit->oid); + if (err < 0) + goto cleanup; + } + + err = git_packbuilder_write_buf(pack, packbuilder); + +cleanup: + git_packbuilder_free(packbuilder); + return err; +} + +void git_mempack_reset(git_odb_backend *_backend) +{ + struct memory_packer_db *db = (struct memory_packer_db *)_backend; + struct memobject *object = NULL; + + kh_foreach_value(db->objects, object, { + git__free(object); + }); + + git_array_clear(db->commits); +} + +static void impl__free(git_odb_backend *_backend) +{ + git_mempack_reset(_backend); + git__free(_backend); +} + +int git_mempack_new(git_odb_backend **out) +{ + struct memory_packer_db *db; + + assert(out); + + db = git__calloc(1, sizeof(struct memory_packer_db)); + GITERR_CHECK_ALLOC(db); + + db->objects = git_oidmap_alloc(); + + db->parent.read = &impl__read; + db->parent.write = &impl__write; + db->parent.read_header = &impl__read_header; + db->parent.exists = &impl__exists; + db->parent.free = &impl__free; + + *out = (git_odb_backend *)db; + return 0; +} diff --git a/src/refspec.h b/src/refspec.h index 375465f61..9a87c97a5 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -23,7 +23,6 @@ struct git_refspec { #define GIT_REFSPEC_TAGS "refs/tags/*:refs/tags/*" -int git_refspec_parse(struct git_refspec *refspec, const char *str); int git_refspec__parse( struct git_refspec *refspec, const char *str, diff --git a/src/remote.c b/src/remote.c index caefc686e..62ee90375 100644 --- a/src/remote.c +++ b/src/remote.c @@ -236,7 +236,7 @@ on_error: return -1; } -int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url) +int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url, const char *fetch) { int error; git_remote *remote; @@ -502,7 +502,7 @@ int git_remote_save(const git_remote *remote) assert(remote); if (!remote->name) { - giterr_set(GITERR_INVALID, "Can't save an in-memory remote."); + giterr_set(GITERR_INVALID, "Can't save an anonymous remote."); return GIT_EINVALIDSPEC; } @@ -1433,7 +1433,7 @@ static int rename_fetch_refspecs( if (spec->push) continue; - /* Every refspec is a problem refspec for an in-memory remote, OR */ + /* Every refspec is a problem refspec for an anonymous remote, OR */ /* Does the dst part of the refspec follow the expected format? */ if (!remote->name || strcmp(git_buf_cstr(&base), spec->string)) { @@ -1481,7 +1481,7 @@ int git_remote_rename( assert(remote && new_name); if (!remote->name) { - giterr_set(GITERR_INVALID, "Can't rename an in-memory remote."); + giterr_set(GITERR_INVALID, "Can't rename an anonymous remote."); return GIT_EINVALIDSPEC; } diff --git a/src/submodule.c b/src/submodule.c index e1500b847..fdcc2251a 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -135,6 +135,21 @@ static int submodule_lookup( * PUBLIC APIS */ +bool git_submodule__is_submodule(git_repository *repo, const char *name) +{ + git_strmap *map; + + if (load_submodule_config(repo, false) < 0) { + giterr_clear(); + return false; + } + + if (!(map = repo->submodules)) + return false; + + return git_strmap_valid_index(map, git_strmap_lookup_index(map, name)); +} + int git_submodule_lookup( git_submodule **out, /* NULL if user only wants to test existence */ git_repository *repo, diff --git a/src/submodule.h b/src/submodule.h index 053cb61e0..1c41897e3 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -119,6 +119,9 @@ enum { #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ ((S) & ~(0xFFFFFFFFu << 20)) +/* Internal submodule check does not attempt to refresh cached data */ +extern bool git_submodule__is_submodule(git_repository *repo, const char *name); + /* Internal status fn returns status and optionally the various OIDs */ extern int git_submodule__status( unsigned int *out_status, |
