summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-04-02 12:49:14 +0300
committerVicent Marti <tanoku@gmail.com>2011-04-02 12:50:25 +0300
commit3e3e4631a0362ba2358c9a2227e3cf0aaec8cf53 (patch)
tree33e4cd3bf2d605c280f6a62f440e76979289c43b
parent720d5472f8aa629161749450a27d3a4e3ecefea3 (diff)
parentac26e2454e71010821f2c85046b5cbd5a522d384 (diff)
downloadlibgit2-3e3e4631a0362ba2358c9a2227e3cf0aaec8cf53.tar.gz
Merge branch 'tagging' of https://github.com/nulltoken/libgit2 into development
Conflicts: include/git2/tag.h src/tag.c
-rw-r--r--include/git2/tag.h75
-rw-r--r--src/tag.c141
-rw-r--r--tests/t08-tag.c135
-rw-r--r--tests/t10-refs.c28
4 files changed, 348 insertions, 31 deletions
diff --git a/include/git2/tag.h b/include/git2/tag.h
index c47e3412c..c751a13c0 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -140,7 +140,8 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t);
* @param repo Repository where to store the tag
*
* @param tag_name Name for the tag; this name is validated
- * for consistency
+ * for consistency. It should also not conflict with an
+ * already existing tag name
*
* @param target OID to which this tag points; note that no
* validation is done on this OID. Use the _o version of this
@@ -202,6 +203,78 @@ GIT_EXTERN(int) git_tag_create_frombuffer(
git_repository *repo,
const char *buffer);
+/**
+ * Create a new tag in the repository from an OID
+ * and overwrite an already existing tag reference, if any.
+ *
+ * @param oid Pointer where to store the OID of the
+ * newly created tag
+ *
+ * @param repo Repository where to store the tag
+ *
+ * @param tag_name Name for the tag; this name is validated
+ * for consistency.
+ *
+ * @param target OID to which this tag points; note that no
+ * validation is done on this OID. Use the _fo version of this
+ * method to assure a proper object is being tagged
+ *
+ * @param target_type Type of the tagged OID; note that no
+ * validation is performed here either
+ *
+ * @param tagger Signature of the tagger for this tag, and
+ * of the tagging time
+ *
+ * @param message Full message for this tag
+ *
+ * @return 0 on success; error code otherwise.
+ * A tag object is written to the ODB, and a proper reference
+ * is written in the /refs/tags folder, pointing to it
+ */
+GIT_EXTERN(int) git_tag_create_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message);
+
+/**
+ * Create a new tag in the repository from an existing
+ * `git_object` instance and overwrite an already existing
+ * tag reference, if any.
+ *
+ * This method replaces the `target` and `target_type`
+ * paremeters of `git_tag_create_f` by a single instance
+ * of a `const git_object *`, which is assured to be
+ * a proper object in the ODB and hence will create
+ * a valid tag
+ *
+ * @see git_tag_create_f
+ */
+GIT_EXTERN(int) git_tag_create_fo(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message);
+
+/**
+ * Delete an existing tag reference.
+ *
+ * @param repo Repository where lives the tag
+ *
+ * @param tag_name Name of the tag to be deleted;
+ * this name is validated for consistency.
+ *
+ * @return 0 on success; error code otherwise.
+ */
+GIT_EXTERN(int) git_tag_delete(
+ git_repository *repo,
+ const char *tag_name);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/tag.c b/src/tag.c
index 5982a053b..ef58e0982 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -153,38 +153,61 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
return GIT_SUCCESS;
}
-int git_tag_create_o(
- git_oid *oid,
- git_repository *repo,
- const char *tag_name,
- const git_object *target,
- const git_signature *tagger,
- const char *message)
+static int retreive_tag_reference(git_reference **tag_reference_out, char *ref_name_out, git_repository *repo, const char *tag_name)
{
- return git_tag_create(
- oid, repo, tag_name,
- git_object_id(target),
- git_object_type(target),
- tagger, message);
+ git_reference *tag_ref;
+ int error;
+
+ git__joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
+ error = git_reference_lookup(&tag_ref, repo, ref_name_out);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ *tag_reference_out = tag_ref;
+
+ return GIT_SUCCESS;
}
-int git_tag_create(
+static int tag_create(
git_oid *oid,
git_repository *repo,
const char *tag_name,
const git_oid *target,
git_otype target_type,
const git_signature *tagger,
- const char *message)
+ const char *message,
+ int allow_ref_overwrite)
{
size_t final_size = 0;
git_odb_stream *stream;
const char *type_str;
char *tagger_str;
+ git_reference *new_ref;
+
+ char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
int type_str_len, tag_name_len, tagger_str_len, message_len;
- int error;
+ int error, should_update_ref = 0;
+
+ /** Ensure the tag name doesn't conflict with an already existing
+ reference unless overwriting has explictly been requested **/
+ error = retreive_tag_reference(&new_ref, ref_name, repo, tag_name);
+
+ switch (error) {
+ case GIT_SUCCESS:
+ if (!allow_ref_overwrite)
+ return GIT_EEXISTS;
+ should_update_ref = 1;
+
+ /* Fall trough */
+
+ case GIT_ENOTFOUND:
+ break;
+
+ default:
+ return error;
+ }
type_str = git_object_type2string(target_type);
@@ -222,13 +245,14 @@ int git_tag_create(
error = stream->finalize_write(oid, stream);
stream->free(stream);
- if (error == GIT_SUCCESS) {
- char ref_name[512];
- git_reference *new_ref;
- git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
- error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
- }
+ if (error < GIT_SUCCESS)
+ return error;
+ if (!should_update_ref)
+ error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
+ else
+ error = git_reference_set_oid(new_ref, oid);
+
return error;
}
@@ -261,6 +285,81 @@ cleanup:
return error;
}
+int git_tag_create_o(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ git_object_id(target),
+ git_object_type(target),
+ tagger, message, 0);
+}
+
+int git_tag_create(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ target,
+ target_type,
+ tagger, message, 0);
+}
+
+int git_tag_create_fo(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ git_object_id(target),
+ git_object_type(target),
+ tagger, message, 1);
+}
+
+int git_tag_create_f(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message)
+{
+ return tag_create(
+ oid, repo, tag_name,
+ target,
+ target_type,
+ tagger, message, 1);
+}
+
+int git_tag_delete(git_repository *repo, const char *tag_name)
+{
+ int error;
+ git_reference *tag_ref;
+ char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
+
+ error = retreive_tag_reference(&tag_ref, ref_name, repo, tag_name);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ return git_reference_delete(tag_ref);
+}
+
int git_tag__parse(git_tag *tag, git_odb_object *obj)
{
assert(tag);
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index 70eeb28a6..5bd3e14b0 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -58,6 +58,9 @@ BEGIN_TEST(read0, "read and parse a tag from the repository")
must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0);
+ git_tag_close(tag1);
+ git_tag_close(tag2);
+ git_commit_close(commit);
git_repository_free(repo);
END_TEST
@@ -72,20 +75,19 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
git_oid target_id, tag_id;
const git_signature *tagger;
git_reference *ref_tag;
- /* char hex_oid[41]; */
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_mkstr(&target_id, tagged_commit);
- /* create signatures */
+ /* create signature */
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
must_be_true(tagger != NULL);
must_pass(git_tag_create(
&tag_id, /* out id */
repo,
- "the-tag", /* do not update the HEAD */
+ "the-tag",
&target_id,
GIT_OBJ_COMMIT,
tagger,
@@ -94,6 +96,7 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
git_signature_free((git_signature *)tagger);
must_pass(git_tag_lookup(&tag, repo, &tag_id));
+ must_be_true(git_oid_cmp(git_tag_target_oid(tag), &target_id) == 0);
/* Check attributes were set correctly */
tagger = git_tag_tagger(tag);
@@ -111,12 +114,136 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
+ git_tag_close(tag);
git_repository_free(repo);
END_TEST
+BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid and read it again")
+ git_repository *repo;
+ git_tag *tag;
+ git_oid target_id, tag_id;
+ const git_signature *tagger;
+ git_reference *ref_tag;
+ git_object *zombie;
+
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+ git_oid_mkstr(&target_id, "deadbeef1b46c854b31185ea97743be6a8774479");
+
+ /* create signature */
+ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+ must_be_true(tagger != NULL);
+
+ must_pass(git_tag_create(
+ &tag_id, /* out id */
+ repo,
+ "the-zombie-tag",
+ &target_id,
+ GIT_OBJ_COMMIT,
+ tagger,
+ TAGGER_MESSAGE));
+
+ git_signature_free((git_signature *)tagger);
+
+ must_pass(git_tag_lookup(&tag, repo, &tag_id));
+
+ /* The non existent target can not be looked up */
+ must_fail(git_tag_target(&zombie, tag));
+
+ must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-zombie-tag"));
+
+ must_pass(git_reference_delete(ref_tag));
+ must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
+
+ git_tag_close(tag);
+ git_repository_free(repo);
+
+END_TEST
+
+BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag")
+ git_repository *repo;
+ git_oid target_id, tag_id;
+ const git_signature *tagger;
+
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+
+ git_oid_mkstr(&target_id, tagged_commit);
+
+ /* create signature */
+ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+ must_be_true(tagger != NULL);
+
+ must_fail(git_tag_create(
+ &tag_id, /* out id */
+ repo,
+ "very-simple",
+ &target_id,
+ GIT_OBJ_COMMIT,
+ tagger,
+ TAGGER_MESSAGE));
+
+ git_signature_free((git_signature *)tagger);
+
+ git_repository_free(repo);
+
+END_TEST
+
+BEGIN_TEST(write3, "Replace an already existing tag")
+ git_repository *repo;
+ git_oid target_id, tag_id, old_tag_id;
+ const git_signature *tagger;
+ git_reference *ref_tag;
+
+ must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
+
+ git_oid_mkstr(&target_id, tagged_commit);
+
+ must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/very-simple"));
+ git_oid_cpy(&old_tag_id, git_reference_oid(ref_tag));
+
+ /* create signature */
+ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
+ must_be_true(tagger != NULL);
+
+ must_pass(git_tag_create_f(
+ &tag_id, /* out id */
+ repo,
+ "very-simple",
+ &target_id,
+ GIT_OBJ_COMMIT,
+ tagger,
+ TAGGER_MESSAGE));
+
+ git_signature_free((git_signature *)tagger);
+
+ must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/very-simple"));
+ must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0);
+ must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &old_tag_id) != 0);
+
+ close_temp_repo(repo);
+
+END_TEST
+
+BEGIN_TEST(write4, "Delete an already existing tag")
+ git_repository *repo;
+ git_reference *ref_tag;
+
+ must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
+
+ must_pass(git_tag_delete(repo,"very-simple"));
+
+ must_fail(git_reference_lookup(&ref_tag, repo, "refs/tags/very-simple"));
+
+ close_temp_repo(repo);
+
+END_TEST
BEGIN_SUITE(tag)
ADD_TEST(read0);
- ADD_TEST(write0);
+ ADD_TEST(write0);
+ ADD_TEST(write1);
+ ADD_TEST(write2);
+ ADD_TEST(write3);
+ ADD_TEST(write4);
END_SUITE
diff --git a/tests/t10-refs.c b/tests/t10-refs.c
index 413811c9d..b1124b36f 100644
--- a/tests/t10-refs.c
+++ b/tests/t10-refs.c
@@ -227,9 +227,8 @@ BEGIN_TEST(create0, "create a new symbolic reference")
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
+ git_reference_delete(looked_up_ref);
git_repository_free(repo);
-
- must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */
END_TEST
BEGIN_TEST(create1, "create a deep symbolic reference")
@@ -250,9 +249,8 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
+ git_reference_delete(looked_up_ref);
git_repository_free(repo);
-
- must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */
END_TEST
BEGIN_TEST(create2, "create a new OID reference")
@@ -290,9 +288,28 @@ BEGIN_TEST(create2, "create a new OID reference")
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head));
must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0);
+ git_reference_delete(looked_up_ref);
git_repository_free(repo);
+END_TEST
+
+BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id")
+ git_reference *new_reference, *looked_up_ref;
+ git_repository *repo;
+ git_oid id;
+
+ const char *new_head = "refs/heads/new-head";
+
+ git_oid_mkstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644");
+
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
- must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */
+ /* Create and write the new object id reference */
+ must_fail(git_reference_create_oid(&new_reference, repo, new_head, &id));
+
+ /* Ensure the reference can't be looked-up... */
+ must_fail(git_reference_lookup(&looked_up_ref, repo, new_head));
+
+ git_repository_free(repo);
END_TEST
static const char *ref_name = "refs/heads/other";
@@ -892,6 +909,7 @@ BEGIN_SUITE(refs)
ADD_TEST(create0);
ADD_TEST(create1);
ADD_TEST(create2);
+ ADD_TEST(create3);
ADD_TEST(overwrite0);
ADD_TEST(overwrite1);