Skip to content

Commit

Permalink
New external API method: git_tree_create
Browse files Browse the repository at this point in the history
Creates a tree by scanning the index file. The method handles recursive
creation of trees for subdirectories and adds them to the parent tree.
  • Loading branch information
t3rm1n4l committed Apr 3, 2011
1 parent 3e3e463 commit 47d8ec5
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
12 changes: 12 additions & 0 deletions include/git2/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,18 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);
*/
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);

/**
* Create tree by scanning the index file.
*
* @param object identity for the tree
* @param repository where to lookup for object db
* @param base directory path
* @param path length for base
* @param index entry offset to start scan
* @return number of items added to the tree
*/
GIT_EXTERN(int) git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no);

/** @} */
GIT_END_DECL
#endif
87 changes: 87 additions & 0 deletions src/tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,90 @@ int git_tree__parse(git_tree *tree, git_odb_object *obj)
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
}

int git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no)
{
unsigned long size, offset;
char *buffer;
int nr, maxentries;
git_index *index;
git_odb_stream *stream;
int error;

git_index_open_inrepo(&index,repo);
maxentries = git_index_entrycount (index);

/* FIXME: A matching error code could not be found. Hence used a close error code GIT_EBAREINDEX */
if (maxentries <= 0) {
return GIT_EBAREINDEX;
}

/* Guess at some random initial size */
size = 8192;
buffer = git__malloc(size);
if (buffer == NULL)
return GIT_ENOMEM;

offset = 0;
nr = entry_no;

do {
git_index_entry *entry = git_index_get(index, nr);
const char *pathname = entry->path, *filename, *dirname;
int pathlen = strlen(pathname), entrylen;
git_oid *entry_oid;
unsigned int mode;
unsigned char *sha1;

/* Did we hit the end of the directory? Return how many we wrote */
if (baselen >= pathlen || memcmp(base, pathname, baselen))
break;

entry_oid = &entry->oid;
mode = entry->mode;
sha1 = entry_oid->id;

/* Do we have _further_ subdirectories? */
filename = pathname + baselen;
dirname = strchr(filename, '/');
if (dirname) {
int subdir_written;
subdir_written = git_tree_create(oid, repo, pathname, dirname-pathname+1, nr);

if (subdir_written == GIT_ENOMEM)
return GIT_ENOMEM;

nr += subdir_written;

/* Now we need to write out the directory entry into this tree.. */
mode = S_IFDIR;
pathlen = dirname - pathname;

/* ..but the directory entry doesn't count towards the total count */
nr--;
sha1 = oid->id;
}

entrylen = pathlen - baselen;
if (offset + entrylen + 100 > size) {
size = alloc_nr(offset + entrylen + 100);
buffer = git__realloc(buffer, size);

if (buffer == NULL)
return GIT_ENOMEM;
}
offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
buffer[offset++] = 0;
memcpy(buffer + offset, sha1, GIT_OID_RAWSZ);
offset += GIT_OID_RAWSZ;
nr++;
} while (nr < maxentries);

if ((error = git_odb_open_wstream(&stream, repo->db, offset, GIT_OBJ_TREE)) < GIT_SUCCESS)
return error;

stream->write(stream, buffer, offset);
error = stream->finalize_write(oid, stream);
stream->free(stream);

return nr;
}
1 change: 1 addition & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
#define git__malloc malloc
#define git__calloc calloc
#define git__realloc realloc
#define git__strdup strdup

extern int git__fmt(char *, size_t, const char *, ...)
Expand Down

0 comments on commit 47d8ec5

Please sign in to comment.