Commit d5afc039 by Vicent Marti

Remove redundant methods from the API

A bunch of redundant methods have been removed from the external API.

- All the reference/tag creation methods with `_f` are gone. The force
flag is now passed as an argument to the normal create methods.

- All the different commit creation methods are gone; commit creation
now always requires a `git_commit` pointer for parents and a `git_tree`
pointer for tree, to ensure that corrupted commits cannot be generated.

- All the different tag creation methods are gone; tag creation now
always requires a `git_object` pointer to ensure that tags are not
created to inexisting objects.
parent 0b10c9ea
......@@ -193,7 +193,8 @@ GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsig
GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned int n);
/**
* Create a new commit in the repository
* Create a new commit in the repository using `git_object`
* instances as parameters.
*
* @param oid Pointer where to store the OID of the
* newly created commit
......@@ -214,16 +215,16 @@ GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned i
*
* @param message Full message for this commit
*
* @param tree_oid Object ID of the tree for this commit. Note that
* no validation is performed on this OID. Use the _o variants of
* this method to assure a proper tree is passed to the commit.
* @param tree An instance of a `git_tree` object that will
* be used as the tree for the commit. This tree object must
* also be owned by the given `repo`.
*
* @param parent_count Number of parents for this commit
*
* @param parent_oids[] Array of pointers to parent OIDs for this commit.
* Note that no validation is performed on these OIDs. Use the _o
* variants of this method to assure that are parents for the commit
* are proper objects.
* @param parents[] Array of `parent_count` pointers to `git_commit`
* objects that will be used as the parents for this commit. This
* array may be NULL if `parent_count` is 0 (root commit). All the
* given commits must be owned by the `repo`.
*
* @return 0 on success; error code otherwise
* The created commit will be written to the Object Database and
......@@ -236,38 +237,13 @@ GIT_EXTERN(int) git_commit_create(
const git_signature *author,
const git_signature *committer,
const char *message,
const git_oid *tree_oid,
int parent_count,
const git_oid *parent_oids[]);
/**
* Create a new commit in the repository using `git_object`
* instances as parameters.
*
* The `tree_oid` and `parent_oids` paremeters now take a instance
* of `git_tree` and `git_commit`, respectively.
*
* All other parameters remain the same
*
* @see git_commit_create
*/
GIT_EXTERN(int) git_commit_create_o(
git_oid *oid,
git_repository *repo,
const char *update_ref,
const git_signature *author,
const git_signature *committer,
const char *message,
const git_tree *tree,
int parent_count,
const git_commit *parents[]);
/**
* Create a new commit in the repository using `git_object`
* instances and a variable argument list.
*
* The `tree_oid` paremeter now takes a instance
* of `const git_tree *`.
* Create a new commit in the repository using a variable
* argument list.
*
* The parents for the commit are specified as a variable
* list of pointers to `const git_commit *`. Note that this
......@@ -278,31 +254,6 @@ GIT_EXTERN(int) git_commit_create_o(
*
* @see git_commit_create
*/
GIT_EXTERN(int) git_commit_create_ov(
git_oid *oid,
git_repository *repo,
const char *update_ref,
const git_signature *author,
const git_signature *committer,
const char *message,
const git_tree *tree,
int parent_count,
...);
/**
* Create a new commit in the repository using
* a variable argument list.
*
* The parents for the commit are specified as a variable
* list of pointers to `const git_oid *`. Note that this
* is a convenience method which may not be safe to export
* for certain languages or compilers
*
* All other parameters remain the same
*
* @see git_commit_create
*/
GIT_EXTERN(int) git_commit_create_v(
git_oid *oid,
git_repository *repo,
......@@ -310,7 +261,7 @@ GIT_EXTERN(int) git_commit_create_v(
const git_signature *author,
const git_signature *committer,
const char *message,
const git_oid *tree_oid,
const git_tree *tree,
int parent_count,
...);
......
......@@ -65,6 +65,19 @@ typedef struct {
GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str);
/**
* Parse N characters of a hex formatted object id into a git_oid
*
* If N is odd, N-1 characters will be parsed instead.
* The remaining space in the git_oid will be set to zero.
*
* @param out oid structure the result is written into.
* @param str input hex string of at least size `length`
* @param length length of the input string
* @return GIT_SUCCESS if valid; GIT_ENOTOID on failure.
*/
GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length);
/**
* Copy an already raw oid into a git_oid structure.
*
* @param out oid structure the result is written into.
......
......@@ -60,34 +60,17 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_reposito
* This reference is owned by the repository and shall not
* be free'd by the user.
*
* @param ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live
* @param name The name of the reference
* @param target The target of the reference
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target);
/**
* Create a new symbolic reference, overwriting an existing one with
* the same name, if it exists.
*
* If the new reference isn't a symbolic one, any pointers to the old
* reference become invalid.
*
* The reference will be created in the repository and written
* to the disk.
*
* This reference is owned by the repository and shall not
* be free'd by the user.
* If `force` is true and there already exists a reference
* with the same name, it will be overwritten.
*
* @param ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live
* @param name The name of the reference
* @param target The target of the reference
* @param force Overwrite existing references
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target);
GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force);
/**
* Create a new object id reference.
......@@ -98,34 +81,17 @@ GIT_EXTERN(int) git_reference_create_symbolic_f(git_reference **ref_out, git_rep
* This reference is owned by the repository and shall not
* be free'd by the user.
*
* @param ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live
* @param name The name of the reference
* @param id The object id pointed to by the reference.
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id);
/**
* Create a new object id reference, overwriting an existing one with
* the same name, if it exists.
*
* If the new reference isn't an object id one, any pointers to the
* old reference become invalid.
*
* The reference will be created in the repository and written
* to the disk.
*
* This reference is owned by the repository and shall not
* be free'd by the user.
* If `force` is true and there already exists a reference
* with the same name, it will be overwritten.
*
* @param ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live
* @param name The name of the reference
* @param id The object id pointed to by the reference.
* @param force Overwrite existing references
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id);
GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force);
/**
* Get the OID pointed to by a reference.
......
......@@ -151,6 +151,10 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *tag);
/**
* Create a new tag in the repository from an OID
*
* A new reference will also be created pointing to
* this tag object. If `force` is true and a reference
* already exists with the given name, it'll be replaced.
*
* @param oid Pointer where to store the OID of the
* newly created tag. If the tag already exists, this parameter
* will be the oid of the existed tag, and the function will
......@@ -162,18 +166,16 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *tag);
* 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
* 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 target Object to which this tag points. This object
* must belong to the given `repo`.
*
* @param tagger Signature of the tagger for this tag, and
* of the tagging time
*
* @param message Full message for this tag
*
* @param force Overwritte existing references
*
* @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
......@@ -182,103 +184,25 @@ GIT_EXTERN(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);
/**
* Create a new tag in the repository from an existing
* `git_object` instance
*
* This method replaces the `target` and `target_type`
* paremeters of `git_tag_create` 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
*/
GIT_EXTERN(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);
const char *message,
int force);
/**
* Create a new tag in the repository from a buffer
*
* @param oid Pointer where to store the OID of the newly created tag
*
* @param repo Repository where to store the tag
*
* @param buffer Raw tag data
* @param force Overwrite existing tags
* @return 0 on sucess; error code otherwise
*/
GIT_EXTERN(int) git_tag_create_frombuffer(
git_oid *oid,
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);
const char *buffer,
int force);
/**
* Delete an existing tag reference.
......
......@@ -74,7 +74,6 @@ const git_oid *git_commit_id(git_commit *c)
return git_object_id((git_object *)c);
}
int git_commit_create_v(
git_oid *oid,
git_repository *repo,
......@@ -82,63 +81,31 @@ int git_commit_create_v(
const git_signature *author,
const git_signature *committer,
const char *message,
const git_oid *tree_oid,
int parent_count,
...)
{
va_list ap;
int i, error;
const git_oid **oids;
oids = git__malloc(parent_count * sizeof(git_oid *));
va_start(ap, parent_count);
for (i = 0; i < parent_count; ++i)
oids[i] = va_arg(ap, const git_oid *);
va_end(ap);
error = git_commit_create(
oid, repo, update_ref, author, committer, message,
tree_oid, parent_count, oids);
free((void *)oids);
return error;
}
int git_commit_create_ov(
git_oid *oid,
git_repository *repo,
const char *update_ref,
const git_signature *author,
const git_signature *committer,
const char *message,
const git_tree *tree,
int parent_count,
...)
{
va_list ap;
int i, error;
const git_oid **oids;
const git_commit **parents;
oids = git__malloc(parent_count * sizeof(git_oid *));
parents = git__malloc(parent_count * sizeof(git_commit *));
va_start(ap, parent_count);
for (i = 0; i < parent_count; ++i)
oids[i] = git_object_id(va_arg(ap, const git_object *));
parents[i] = va_arg(ap, const git_commit *);
va_end(ap);
error = git_commit_create(
oid, repo, update_ref, author, committer, message,
git_object_id((git_object *)tree),
parent_count, oids);
tree, parent_count, parents);
free((void *)oids);
free((void *)parents);
return error;
}
int git_commit_create_o(
int git_commit_create(
git_oid *oid,
git_repository *repo,
const char *update_ref,
......@@ -149,35 +116,6 @@ int git_commit_create_o(
int parent_count,
const git_commit *parents[])
{
int i, error;
const git_oid **oids;
oids = git__malloc(parent_count * sizeof(git_oid *));
for (i = 0; i < parent_count; ++i)
oids[i] = git_object_id((git_object *)parents[i]);
error = git_commit_create(
oid, repo, update_ref, author, committer, message,
git_object_id((git_object *)tree),
parent_count, oids);
free((void *)oids);
return error;
}
int git_commit_create(
git_oid *oid,
git_repository *repo,
const char *update_ref,
const git_signature *author,
const git_signature *committer,
const char *message,
const git_oid *tree_oid,
int parent_count,
const git_oid *parents[])
{
size_t final_size = 0;
int message_length, author_length, committer_length;
......@@ -202,10 +140,17 @@ int git_commit_create(
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create commit");
git__write_oid(stream, "tree", tree_oid);
if (git_object_owner((const git_object *)tree) != repo)
return git__throw(GIT_EINVALIDARGS, "The given tree does not belong to this repository");
for (i = 0; i < parent_count; ++i)
git__write_oid(stream, "parent", parents[i]);
git__write_oid(stream, "tree", git_object_id((const git_object *)tree));
for (i = 0; i < parent_count; ++i) {
if (git_object_owner((const git_object *)parents[i]) != repo)
return git__throw(GIT_EINVALIDARGS, "The given parent does not belong to this repository");
git__write_oid(stream, "parent", git_object_id((const git_object *)parents[i]));
}
stream->write(stream, author_str, author_length);
free(author_str);
......@@ -213,7 +158,6 @@ int git_commit_create(
stream->write(stream, committer_str, committer_length);
free(committer_str);
stream->write(stream, "\n", 1);
stream->write(stream, message, message_length);
......@@ -238,7 +182,7 @@ int git_commit_create(
* point to) or after an orphan checkout, so if the target
* branch doesn't exist yet, create it and return.
*/
return git_reference_create_oid_f(&head, repo, git_reference_target(head), oid);
return git_reference_create_oid(&head, repo, git_reference_target(head), oid, 1);
}
error = git_reference_set_oid(head, oid);
......
......@@ -49,19 +49,37 @@ static signed char from_hex[] = {
};
static char to_hex[] = "0123456789abcdef";
int git_oid_fromstr(git_oid *out, const char *str)
int git_oid_fromstrn(git_oid *out, const char *str, size_t length)
{
size_t p;
for (p = 0; p < sizeof(out->id); p++, str += 2) {
int v = (from_hex[(unsigned char)str[0]] << 4)
| from_hex[(unsigned char)str[1]];
if (length > GIT_OID_HEXSZ)
length = GIT_OID_HEXSZ;
if (length % 2)
length--;
for (p = 0; p < length; p += 2) {
int v = (from_hex[(unsigned char)str[p + 0]] << 4)
| from_hex[(unsigned char)str[p + 1]];
if (v < 0)
return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is not a valid sha1 hash");
out->id[p] = (unsigned char)v;
out->id[p / 2] = (unsigned char)v;
}
for (; p < GIT_OID_HEXSZ; p += 2)
out->id[p / 2] = 0x0;
return GIT_SUCCESS;
}
int git_oid_fromstr(git_oid *out, const char *str)
{
return git_oid_fromstrn(out, str, GIT_OID_HEXSZ);
}
GIT_INLINE(char) *fmt_one(char *str, unsigned int val)
{
*str++ = to_hex[val >> 4];
......
......@@ -920,117 +920,6 @@ cleanup:
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write packed reference");
}
/*****************************************
* Internal methods - reference creation
*****************************************/
static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force)
{
char normalized[GIT_REFNAME_MAX];
int error = GIT_SUCCESS, updated = 0;
git_reference *ref = NULL, *old_ref = NULL;
if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
return git__throw(GIT_EEXISTS, "Failed to create symbolic reference. Reference already exists");
/*
* If they old ref was of the same type, then we can just update
* it (once we've checked that the target is valid). Otherwise we
* need a new reference because we can't make a symbolic ref out
* of an oid one.
* If if didn't exist, then we need to create a new one anyway.
*/
if (ref && ref->type & GIT_REF_SYMBOLIC){
updated = 1;
} else {
ref = NULL;
error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
if (error < GIT_SUCCESS)
goto cleanup;
}
/* The target can aither be the name of an object id reference or the name of another symbolic reference */
error = normalize_name(normalized, sizeof(normalized), target, 0);
if (error < GIT_SUCCESS)
goto cleanup;
/* set the target; this will write the reference on disk */
error = git_reference_set_target(ref, normalized);
if (error < GIT_SUCCESS)
goto cleanup;
/*
* If we didn't update the ref, then we need to insert or replace
* it in the loose cache. If we replaced a ref, free it.
*/
if (!updated){
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
if (error < GIT_SUCCESS)
goto cleanup;
if(old_ref)
reference_free(old_ref);
}
*ref_out = ref;
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
cleanup:
reference_free(ref);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
}
static int reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force)
{
int error = GIT_SUCCESS, updated = 0;
git_reference *ref = NULL, *old_ref = NULL;
if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
return git__throw(GIT_EEXISTS, "Failed to create reference OID. Reference already exists");
if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create reference");
/*
* If they old ref was of the same type, then we can just update
* it (once we've checked that the target is valid). Otherwise we
* need a new reference because we can't make a symbolic ref out
* of an oid one.
* If if didn't exist, then we need to create a new one anyway.
*/
if (ref && ref-> type & GIT_REF_OID){
updated = 1;
} else {
ref = NULL;
error = reference_create(&ref, repo, name, GIT_REF_OID);
if (error < GIT_SUCCESS)
goto cleanup;
}
/* set the oid; this will write the reference on disk */
error = git_reference_set_oid(ref, id);
if (error < GIT_SUCCESS)
goto cleanup;
if(!updated){
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
if (error < GIT_SUCCESS)
goto cleanup;
if(old_ref)
reference_free(old_ref);
}
*ref_out = ref;
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
cleanup:
reference_free(ref);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
}
static int _reference_available_cb(const char *ref, void *data)
{
const char *new, *old;
......@@ -1261,26 +1150,6 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch
return git__throw(GIT_ENOTFOUND, "Failed to lookup reference. Reference doesn't exist");
}
int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target)
{
return reference_create_symbolic(ref_out, repo, name, target, 0);
}
int git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target)
{
return reference_create_symbolic(ref_out, repo, name, target, 1);
}
int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id)
{
return reference_create_oid(ref_out, repo, name, id, 0);
}
int git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id)
{
return reference_create_oid(ref_out, repo, name, id, 1);
}
/**
* Getters
*/
......@@ -1335,6 +1204,113 @@ const char *git_reference_target(git_reference *ref)
return ((reference_symbolic *)ref)->target;
}
int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force)
{
char normalized[GIT_REFNAME_MAX];
int error = GIT_SUCCESS, updated = 0;
git_reference *ref = NULL, *old_ref = NULL;
if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
return git__throw(GIT_EEXISTS, "Failed to create symbolic reference. Reference already exists");
/*
* If they old ref was of the same type, then we can just update
* it (once we've checked that the target is valid). Otherwise we
* need a new reference because we can't make a symbolic ref out
* of an oid one.
* If if didn't exist, then we need to create a new one anyway.
*/
if (ref && ref->type & GIT_REF_SYMBOLIC){
updated = 1;
} else {
ref = NULL;
error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
if (error < GIT_SUCCESS)
goto cleanup;
}
/* The target can aither be the name of an object id reference or the name of another symbolic reference */
error = normalize_name(normalized, sizeof(normalized), target, 0);
if (error < GIT_SUCCESS)
goto cleanup;
/* set the target; this will write the reference on disk */
error = git_reference_set_target(ref, normalized);
if (error < GIT_SUCCESS)
goto cleanup;
/*
* If we didn't update the ref, then we need to insert or replace
* it in the loose cache. If we replaced a ref, free it.
*/
if (!updated){
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
if (error < GIT_SUCCESS)
goto cleanup;
if(old_ref)
reference_free(old_ref);
}
*ref_out = ref;
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
cleanup:
reference_free(ref);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
}
int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force)
{
int error = GIT_SUCCESS, updated = 0;
git_reference *ref = NULL, *old_ref = NULL;
if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
return git__throw(GIT_EEXISTS, "Failed to create reference OID. Reference already exists");
if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create reference");
/*
* If they old ref was of the same type, then we can just update
* it (once we've checked that the target is valid). Otherwise we
* need a new reference because we can't make a symbolic ref out
* of an oid one.
* If if didn't exist, then we need to create a new one anyway.
*/
if (ref && ref-> type & GIT_REF_OID){
updated = 1;
} else {
ref = NULL;
error = reference_create(&ref, repo, name, GIT_REF_OID);
if (error < GIT_SUCCESS)
goto cleanup;
}
/* set the oid; this will write the reference on disk */
error = git_reference_set_oid(ref, id);
if (error < GIT_SUCCESS)
goto cleanup;
if(!updated){
error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref);
if (error < GIT_SUCCESS)
goto cleanup;
if(old_ref)
reference_free(old_ref);
}
*ref_out = ref;
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
cleanup:
reference_free(ref);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
}
/**
* Setters
*/
......
......@@ -626,7 +626,7 @@ static int repo_init_reinit(repo_init *results)
static int repo_init_createhead(git_repository *repo)
{
git_reference *head_reference;
return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE); /* TODO: finalize moving refs.c to new error handling */
return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0);
}
static int repo_init_check_head_existence(char * repository_path)
......
......@@ -180,52 +180,11 @@ static int retreive_tag_reference(git_reference **tag_reference_out, char *ref_n
return GIT_SUCCESS;
}
/* tag_reference_out will contain the reference of the tag if exists, otherwise NULL */
static int tag_valid_in_odb(
git_reference **tag_reference_out,
char *ref_name_out,
const git_oid *target,
git_otype target_type,
git_repository *repo,
const char *tag_name) {
int error;
*tag_reference_out = NULL;
error = retreive_tag_reference(tag_reference_out, ref_name_out, repo, tag_name);
switch (error) {
case GIT_SUCCESS:
/* Fall trough */
case GIT_ENOTFOUND:
break;
default:
return git__rethrow(error, "Failed to create tag");
}
if (!git_odb_exists(repo->db, target))
return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist");
/* Try to find out what the type is */
if (target_type == GIT_OBJ_ANY) {
size_t _unused;
error = git_odb_read_header(&_unused, &target_type, repo->db, target);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
}
return GIT_SUCCESS;
}
static int tag_create(
int git_tag_create(
git_oid *oid,
git_repository *repo,
const char *tag_name,
const git_oid *target,
git_otype target_type,
const git_object *target,
const git_signature *tagger,
const char *message,
int allow_ref_overwrite)
......@@ -235,20 +194,31 @@ static int tag_create(
const char *type_str;
char *tagger_str;
git_reference *new_ref;
git_reference *new_ref = NULL;
char ref_name[GIT_REFNAME_MAX];
int type_str_len, tag_name_len, tagger_str_len, message_len;
int error, should_update_ref = 0;
if ((error = tag_valid_in_odb(&new_ref, ref_name, target, target_type, repo, tag_name)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
if (git_object_owner(target) != repo)
return git__throw(GIT_EINVALIDARGS, "The given target does not belong to this repository");
error = retreive_tag_reference(&new_ref, ref_name, repo, tag_name);
switch (error) {
case GIT_SUCCESS:
case GIT_ENOTFOUND:
break;
default:
return git__rethrow(error, "Failed to create tag");
}
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/
if(new_ref != NULL) {
if(!allow_ref_overwrite) {
if (new_ref != NULL) {
if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref));
return git__throw(GIT_EEXISTS, "Tag already exists");
} else {
......@@ -256,8 +226,7 @@ static int tag_create(
}
}
type_str = git_object_type2string(target_type);
type_str = git_object_type2string(git_object_type(target));
tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
type_str_len = strlen(type_str);
......@@ -273,7 +242,7 @@ static int tag_create(
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_TAG)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
git__write_oid(stream, "object", target);
git__write_oid(stream, "object", git_object_id(target));
stream->write(stream, "type ", STRLEN("type "));
stream->write(stream, type_str, type_str_len);
......@@ -296,18 +265,19 @@ static int tag_create(
return git__rethrow(error, "Failed to create tag");
if (!should_update_ref)
error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0);
else
error = git_reference_set_oid(new_ref, oid);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
}
int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer)
int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite)
{
git_tag tag;
int error;
int error, should_update_ref = 0;
git_odb_stream *stream;
git_odb_object *target_obj;
git_reference *new_ref;
char ref_name[GIT_REFNAME_MAX];
......@@ -317,16 +287,38 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
memset(&tag, 0, sizeof(tag));
/* validate the buffer */
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
if ((error = tag_valid_in_odb(&new_ref, ref_name, &tag.target, tag.type, repo, tag.tag_name)) < GIT_SUCCESS)
/* validate the target */
if ((error = git_odb_read(&target_obj, repo->db, &tag.target)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
if (tag.type != target_obj->raw.type)
return git__throw(error, "The type for the given target is invalid");
git_odb_object_close(target_obj);
error = retreive_tag_reference(&new_ref, ref_name, repo, tag.tag_name);
switch (error) {
case GIT_SUCCESS:
case GIT_ENOTFOUND:
break;
default:
return git__rethrow(error, "Failed to create tag");
}
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/
if (new_ref != NULL) {
git_oid_cpy(oid, git_reference_oid(new_ref));
return git__throw(GIT_EEXISTS, "Tag already exists");
if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref));
return git__throw(GIT_EEXISTS, "Tag already exists");
} else {
should_update_ref = 1;
}
}
/* write the buffer */
......@@ -340,9 +332,11 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
if (!should_update_ref)
error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0);
else
error = git_reference_set_oid(new_ref, oid);
git_signature_free(tag.tagger);
free(tag.tag_name);
......@@ -351,68 +345,6 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
}
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;
......
......@@ -415,19 +415,21 @@ This is a commit created in memory and it will be written back to disk\n"
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
BEGIN_TEST(write0, "write a new commit object from memory to disk")
git_repository *repo;
git_commit *commit;
git_oid tree_id, parent_id, commit_id;
const git_signature *author, *committer;
/* char hex_oid[41]; */
git_commit *parent;
git_tree *tree;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&tree_id, tree_oid);
must_pass(git_tree_lookup(&tree, repo, &tree_id));
git_oid_fromstr(&parent_id, commit_ids[4]);
must_pass(git_commit_lookup(&parent, repo, &parent_id));
/* create signatures */
committer = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60);
......@@ -443,8 +445,11 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk")
author,
committer,
COMMIT_MESSAGE,
&tree_id,
1, &parent_id));
tree,
1, parent));
git_object_close((git_object *)parent);
git_object_close((git_object *)tree);
git_signature_free((git_signature *)committer);
git_signature_free((git_signature *)author);
......@@ -486,10 +491,12 @@ BEGIN_TEST(root0, "create a root commit")
const char *branch_name = "refs/heads/root-commit-branch";
git_reference *head, *branch;
char *head_old;
git_tree *tree;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&tree_id, tree_oid);
must_pass(git_tree_lookup(&tree, repo, &tree_id));
/* create signatures */
committer = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60);
......@@ -513,9 +520,10 @@ BEGIN_TEST(root0, "create a root commit")
author,
committer,
ROOT_COMMIT_MESSAGE,
&tree_id,
tree,
0));
git_object_close((git_object *)tree);
git_signature_free((git_signature *)committer);
git_signature_free((git_signature *)author);
......
......@@ -88,10 +88,12 @@ 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;
git_object *target;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&target_id, tagged_commit);
must_pass(git_object_lookup(&target, repo, &target_id, GIT_OBJ_COMMIT));
/* create signature */
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
......@@ -101,11 +103,12 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
&tag_id, /* out id */
repo,
"the-tag",
&target_id,
GIT_OBJ_COMMIT,
target,
tagger,
TAGGER_MESSAGE));
TAGGER_MESSAGE,
0));
git_object_close(target);
git_signature_free((git_signature *)tagger);
must_pass(git_tag_lookup(&tag, repo, &tag_id));
......@@ -132,42 +135,16 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
END_TEST
BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid should fail")
git_repository *repo;
git_oid target_id, tag_id;
const git_signature *tagger;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&target_id, "deadbeef1b46c854b31185ea97743be6a8774479");
/* 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,
"the-zombie-tag",
&target_id,
GIT_OBJ_COMMIT,
tagger,
TAGGER_MESSAGE));
git_signature_free((git_signature *)tagger);
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;
git_object *target;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&target_id, tagged_commit);
must_pass(git_object_lookup(&target, repo, &target_id, GIT_OBJ_COMMIT));
/* create signature */
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
......@@ -177,11 +154,12 @@ BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already
&tag_id, /* out id */
repo,
"e90810b",
&target_id,
GIT_OBJ_COMMIT,
target,
tagger,
TAGGER_MESSAGE));
TAGGER_MESSAGE,
0));
git_object_close(target);
git_signature_free((git_signature *)tagger);
git_repository_free(repo);
......@@ -193,10 +171,12 @@ BEGIN_TEST(write3, "Replace an already existing tag")
git_oid target_id, tag_id, old_tag_id;
const git_signature *tagger;
git_reference *ref_tag;
git_object *target;
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
git_oid_fromstr(&target_id, tagged_commit);
must_pass(git_object_lookup(&target, repo, &target_id, GIT_OBJ_COMMIT));
must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b"));
git_oid_cpy(&old_tag_id, git_reference_oid(ref_tag));
......@@ -205,15 +185,16 @@ BEGIN_TEST(write3, "Replace an already existing tag")
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
must_be_true(tagger != NULL);
must_pass(git_tag_create_f(
must_pass(git_tag_create(
&tag_id, /* out id */
repo,
"e90810b",
&target_id,
GIT_OBJ_COMMIT,
target,
tagger,
TAGGER_MESSAGE));
TAGGER_MESSAGE,
1));
git_object_close(target);
git_signature_free((git_signature *)tagger);
must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b"));
......@@ -242,7 +223,6 @@ BEGIN_SUITE(tag)
ADD_TEST(read0);
ADD_TEST(read1);
ADD_TEST(write0);
ADD_TEST(write1);
ADD_TEST(write2);
ADD_TEST(write3);
ADD_TEST(write4);
......
......@@ -212,7 +212,7 @@ BEGIN_TEST(create0, "create a new symbolic reference")
git__joinpath(ref_path, repo->path_repository, new_head_tracker);
/* Create and write the new symbolic reference */
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target));
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0));
/* Ensure the reference can be looked-up... */
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker));
......@@ -252,7 +252,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
git__joinpath(ref_path, repo->path_repository, new_head_tracker);
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target));
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0));
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker));
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
......@@ -276,7 +276,7 @@ BEGIN_TEST(create2, "create a new OID reference")
git__joinpath(ref_path, repo->path_repository, new_head);
/* Create and write the new object id reference */
must_pass(git_reference_create_oid(&new_reference, repo, new_head, &id));
must_pass(git_reference_create_oid(&new_reference, repo, new_head, &id, 0));
/* Ensure the reference can be looked-up... */
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head));
......@@ -310,7 +310,7 @@ BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unkn
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
/* Create and write the new object id reference */
must_fail(git_reference_create_oid(&new_reference, repo, new_head, &id));
must_fail(git_reference_create_oid(&new_reference, repo, new_head, &id, 0));
/* Ensure the reference can't be looked-up... */
must_fail(git_reference_lookup(&looked_up_ref, repo, new_head));
......@@ -329,16 +329,16 @@ BEGIN_TEST(overwrite0, "Overwrite an existing symbolic reference")
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* The target needds to exist and we need to check the name has changed */
must_pass(git_reference_create_symbolic(&branch_ref, repo, ref_branch_name, ref_master_name));
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_branch_name));
must_pass(git_reference_create_symbolic(&branch_ref, repo, ref_branch_name, ref_master_name, 0));
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_branch_name, 0));
/* Ensure it points to the right place*/
must_pass(git_reference_lookup(&ref, repo, ref_name));
must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC);
must_be_true(!strcmp(git_reference_target(ref), ref_branch_name));
/* Ensure we can't create it unless we force it to */
must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name));
must_pass(git_reference_create_symbolic_f(&ref, repo, ref_name, ref_master_name));
must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name, 0));
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name, 1));
/* Ensure it points to the right place */
must_pass(git_reference_lookup(&ref, repo, ref_name));
......@@ -360,15 +360,15 @@ BEGIN_TEST(overwrite1, "Overwrite an existing object id reference")
git_oid_cpy(&id, git_reference_oid(ref));
/* Create it */
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id));
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
must_pass(git_reference_lookup(&ref, repo, ref_test_name));
must_be_true(ref->type & GIT_REF_OID);
git_oid_cpy(&id, git_reference_oid(ref));
/* Ensure we can't overwrite unless we force it */
must_fail(git_reference_create_oid(&ref, repo, ref_name, &id));
must_pass(git_reference_create_oid_f(&ref, repo, ref_name, &id));
must_fail(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 1));
/* Ensure it has been overwritten */
must_pass(git_reference_lookup(&ref, repo, ref_name));
......@@ -388,9 +388,9 @@ BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symboli
must_be_true(ref->type & GIT_REF_OID);
git_oid_cpy(&id, git_reference_oid(ref));
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id));
must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name));
must_pass(git_reference_create_symbolic_f(&ref, repo, ref_name, ref_master_name));
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name, 0));
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name, 1));
/* Ensure it points to the right place */
must_pass(git_reference_lookup(&ref, repo, ref_name));
......@@ -412,10 +412,10 @@ BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object
git_oid_cpy(&id, git_reference_oid(ref));
/* Create the symbolic ref */
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name));
must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name, 0));
/* It shouldn't overwrite unless we tell it to */
must_fail(git_reference_create_oid(&ref, repo, ref_name, &id));
must_pass(git_reference_create_oid_f(&ref, repo, ref_name, &id));
must_fail(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 1));
/* Ensure it points to the right place */
must_pass(git_reference_lookup(&ref, repo, ref_name));
......@@ -671,14 +671,14 @@ BEGIN_TEST(rename6, "can not overwrite name of existing reference")
git_oid_cpy(&id, git_reference_oid(ref));
/* Create loose references */
must_pass(git_reference_create_oid(&ref_one, repo, ref_one_name, &id));
must_pass(git_reference_create_oid(&ref_two, repo, ref_two_name, &id));
must_pass(git_reference_create_oid(&ref_one, repo, ref_one_name, &id, 0));
must_pass(git_reference_create_oid(&ref_two, repo, ref_two_name, &id, 0));
/* Pack everything */
must_pass(git_reference_packall(repo));
/* Attempt to create illegal reference */
must_fail(git_reference_create_oid(&ref_one_new, repo, ref_one_name_new, &id));
must_fail(git_reference_create_oid(&ref_one_new, repo, ref_one_name_new, &id, 0));
/* Illegal reference couldn't be created so this is supposed to fail */
must_fail(git_reference_lookup(&ref_one_new, repo, ref_one_name_new));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment