diff options
author | Ben Straub <bstraub@github.com> | 2012-05-30 16:52:11 -0700 |
---|---|---|
committer | Ben Straub <bstraub@github.com> | 2012-05-30 16:52:11 -0700 |
commit | 244d2f6b80161978cce5bacc3ac6e663b530bb65 (patch) | |
tree | 65cdc085f504451ebc6ebf536b01d95326751e82 /src/revparse.c | |
parent | dd9e4abc1ba1701efac0c3af3b1ceede2bd561a4 (diff) | |
download | libgit2-244d2f6b80161978cce5bacc3ac6e663b530bb65.tar.gz |
Rev-parse: add "tag:README" syntax.
Diffstat (limited to 'src/revparse.c')
-rw-r--r-- | src/revparse.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/revparse.c b/src/revparse.c index 3615ac519..1e78d7623 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -10,6 +10,7 @@ #include "common.h" #include "buffer.h" #include "date.h" +#include "tree.h" #include "git2.h" @@ -19,6 +20,7 @@ typedef enum { REVPARSE_STATE_INIT, REVPARSE_STATE_CARET, REVPARSE_STATE_LINEAR, + REVPARSE_STATE_COLON, REVPARSE_STATE_DONE, } revparse_state; @@ -535,6 +537,45 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m return 0; } +static const git_tree_entry* git_tree_entry_bypath(git_tree *tree, git_repository *repo, const char *path) +{ + char *str = git__strdup(path); + char *tok; + git_tree *tree2 = tree; + const git_tree_entry *entry; + + while ((tok = git__strtok(&str, "/\\")) != NULL) { + entry = git_tree_entry_byname(tree2, tok); + if (tree2 != tree) git_tree_free(tree2); + if (entry_is_tree(entry)) { + if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) { + return NULL; + } + } + } + + return entry; +} + +static int handle_colon_syntax(git_object **out, + git_repository *repo, + git_object *obj, + const char *path) +{ + git_tree *tree; + const git_tree_entry *entry; + + /* Dereference until we reach a tree. */ + if (dereference_to_type(&obj, obj, GIT_OBJ_TREE) < 0) { + return GIT_ERROR; + } + tree = (git_tree*)obj; + + /* Find the blob at the given path. */ + entry = git_tree_entry_bypath(tree, repo, path); + return git_tree_entry_2object(out, repo, entry); +} + int git_revparse_single(git_object **out, git_repository *repo, const char *spec) { revparse_state current_state = REVPARSE_STATE_INIT, next_state = REVPARSE_STATE_INIT; @@ -545,6 +586,13 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec assert(out && repo && spec); + if (spec[0] == ':') { + /* Either a global grep (":/foo") or a merge-stage path lookup (":2:Makefile"). + Neither of these are handled just yet. */ + giterr_set(GITERR_INVALID, "Unimplemented"); + return GIT_ERROR; + } + while (current_state != REVPARSE_STATE_DONE) { switch (current_state) { case REVPARSE_STATE_INIT: @@ -561,6 +609,8 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec next_state = REVPARSE_STATE_CARET; } else if (*spec_cur == '~') { next_state = REVPARSE_STATE_LINEAR; + } else if (*spec_cur == ':') { + next_state = REVPARSE_STATE_COLON; } else { git_buf_putc(&specbuffer, *spec_cur); } @@ -617,6 +667,16 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec spec_cur++; break; + case REVPARSE_STATE_COLON: + if (*spec_cur) { + git_buf_putc(&stepbuffer, *spec_cur); + } else { + retcode = handle_colon_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer)); + next_state = REVPARSE_STATE_DONE; + } + spec_cur++; + break; + case REVPARSE_STATE_DONE: if (cur_obj && *out != cur_obj) git_object_free(cur_obj); if (next_obj && *out != next_obj) git_object_free(next_obj); |