Commit 32054c24 by Vicent Marti

Brush up the refs API

Changed some more API details and updated documentation.

Sketched API for addition/removal of entries.

Signed-off-by: Vicent Marti <tanoku@gmail.com>
parent 2de3b35c
...@@ -44,6 +44,9 @@ GIT_BEGIN_DECL ...@@ -44,6 +44,9 @@ GIT_BEGIN_DECL
* The reference will be created in the repository and written * The reference will be created in the repository and written
* to the disk. * to the disk.
* *
* 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 ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live * @param repo Repository where that reference will live
* @param name The name of the reference * @param name The name of the reference
...@@ -58,6 +61,9 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos ...@@ -58,6 +61,9 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos
* The reference will be created in the repository and written * The reference will be created in the repository and written
* to the disk. * to the disk.
* *
* 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 ref_out Pointer to the newly created reference
* @param repo Repository where that reference will live * @param repo Repository where that reference will live
* @param name The name of the reference * @param name The name of the reference
...@@ -120,22 +126,6 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref); ...@@ -120,22 +126,6 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref);
GIT_EXTERN(int) git_reference_resolve(git_reference **resolved_ref, git_reference *ref); GIT_EXTERN(int) git_reference_resolve(git_reference **resolved_ref, git_reference *ref);
/** /**
* Write a reference back to disk.
*
* The reference must have a valid name and a valid target
* (either direct or symbolic).
*
* If the reference has been loaded from disk and no changes
* have been made, no action will take place.
*
* The writing to disk is atomic.
*
* @param ref The reference
* @return 0 on success; error code otherwise
*/
GIT_EXTERN(int) git_reference_write(git_reference *ref);
/**
* Get the repository where a reference resides * Get the repository where a reference resides
* *
* @param ref The reference * @param ref The reference
...@@ -144,14 +134,13 @@ GIT_EXTERN(int) git_reference_write(git_reference *ref); ...@@ -144,14 +134,13 @@ GIT_EXTERN(int) git_reference_write(git_reference *ref);
GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref); GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref);
/** /**
* Set the target reference of a reference. * Set the symbolic target of a reference.
* *
* This converts the reference into a symbolic * The reference must be a symbolic reference, otherwise
* reference. * this method will fail.
* *
* This marks the reference as modified; changes * The reference will be automatically updated in
* won't take effect until it is manually written back * memory and on disk.
* to disk.
* *
* @param ref The reference * @param ref The reference
* @param target The new target for the reference * @param target The new target for the reference
...@@ -162,12 +151,11 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target) ...@@ -162,12 +151,11 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target)
/** /**
* Set the OID target of a reference. * Set the OID target of a reference.
* *
* This converts the reference into a direct * The reference must be a direct reference, otherwise
* reference. * this method will fail.
* *
* This marks the reference as modified; changes * The reference will be automatically updated in
* won't take effect until it is manually written back * memory and on disk.
* to disk.
* *
* @param ref The reference * @param ref The reference
* @param target The new target OID for the reference * @param target The new target OID for the reference
...@@ -175,6 +163,30 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target) ...@@ -175,6 +163,30 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target)
*/ */
GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id);
/**
* Rename an existing reference
*
* This method works for both direct and symbolic references.
* The new name will be checked for validity and may be
* modified into a normalized form.
*
* The refernece will be immediately renamed in-memory
* and on disk.
*
*/
GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name);
/**
* Delete an existing reference
*
* This method works for both direct and symbolic references.
*
* The reference will be immediately removed on disk and from
* memory. The given reference pointer will no longer be valid.
*
*/
GIT_EXTERN(int) git_reference_delete(git_reference *ref);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#define MAX_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 5
static int reference_write(git_reference *ref);
static const int default_table_size = 32; static const int default_table_size = 32;
static uint32_t reftable_hash(const void *key, int hash_id) static uint32_t reftable_hash(const void *key, int hash_id)
...@@ -43,17 +45,6 @@ static uint32_t reftable_hash(const void *key, int hash_id) ...@@ -43,17 +45,6 @@ static uint32_t reftable_hash(const void *key, int hash_id)
return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]); return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]);
} }
static int check_refname(const char *name)
{
/*
* TODO: To be implemented
* Check if the given name is a valid name
* for a reference
*/
return name ? GIT_SUCCESS : GIT_ERROR;
}
static void reference_free(git_reference *reference) static void reference_free(git_reference *reference)
{ {
if (reference == NULL) if (reference == NULL)
...@@ -68,7 +59,7 @@ static void reference_free(git_reference *reference) ...@@ -68,7 +59,7 @@ static void reference_free(git_reference *reference)
free(reference); free(reference);
} }
static int reference__create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type) { static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type) {
char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_reference *reference = NULL; git_reference *reference = NULL;
...@@ -111,7 +102,7 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, ...@@ -111,7 +102,7 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo,
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_reference *ref = NULL; git_reference *ref = NULL;
error = reference__create(&ref, repo, name, GIT_REF_SYMBOLIC); error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -120,14 +111,11 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, ...@@ -120,14 +111,11 @@ int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo,
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
/* set the target; this will write the reference on disk */
error = git_reference_set_target(ref, normalized); error = git_reference_set_target(ref, normalized);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = git_reference_write(ref);
if (error < GIT_SUCCESS)
goto cleanup;
*ref_out = ref; *ref_out = ref;
return error; return error;
...@@ -142,18 +130,15 @@ int git_reference_create_oid(git_reference **ref_out, git_repository *repo, cons ...@@ -142,18 +130,15 @@ int git_reference_create_oid(git_reference **ref_out, git_repository *repo, cons
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_reference *ref = NULL; git_reference *ref = NULL;
error = reference__create(&ref, repo, name, GIT_REF_OID); error = reference_create(&ref, repo, name, GIT_REF_OID);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
/* set the oid; this will write the reference on disk */
error = git_reference_set_oid(ref, id); error = git_reference_set_oid(ref, id);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = git_reference_write(ref);
if (error < GIT_SUCCESS)
goto cleanup;
*ref_out = ref; *ref_out = ref;
return error; return error;
...@@ -168,7 +153,6 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content) ...@@ -168,7 +153,6 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content)
const unsigned int header_len = strlen(GIT_SYMREF); const unsigned int header_len = strlen(GIT_SYMREF);
const char *refname_start; const char *refname_start;
char *eol; char *eol;
int error;
refname_start = (const char *)file_content->data; refname_start = (const char *)file_content->data;
...@@ -182,9 +166,9 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content) ...@@ -182,9 +166,9 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content)
refname_start += header_len; refname_start += header_len;
error = git_reference_set_target(ref, refname_start); ref->target.ref = git__strdup(refname_start);
if (error < GIT_SUCCESS) if (ref->target.ref == NULL)
return error; return GIT_ENOMEM;
/* remove newline at the end of file */ /* remove newline at the end of file */
eol = strchr(ref->target.ref, '\n'); eol = strchr(ref->target.ref, '\n');
...@@ -202,8 +186,6 @@ static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content) ...@@ -202,8 +186,6 @@ static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content)
{ {
char *buffer; char *buffer;
git_oid id; git_oid id;
int error;
buffer = (char *)file_content->data; buffer = (char *)file_content->data;
/* File format: 40 chars (OID) + newline */ /* File format: 40 chars (OID) + newline */
...@@ -213,9 +195,7 @@ static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content) ...@@ -213,9 +195,7 @@ static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content)
if (git_oid_mkstr(&id, buffer) < GIT_SUCCESS) if (git_oid_mkstr(&id, buffer) < GIT_SUCCESS)
return GIT_EREFCORRUPTED; return GIT_EREFCORRUPTED;
error = git_reference_set_oid(ref, &id); git_oid_cpy(&ref->target.oid, &id);
if (error < GIT_SUCCESS)
return error;
buffer = buffer + GIT_OID_HEXSZ; buffer = buffer + GIT_OID_HEXSZ;
if (*buffer == '\r') if (*buffer == '\r')
...@@ -265,21 +245,19 @@ static int lookup_loose_ref( ...@@ -265,21 +245,19 @@ static int lookup_loose_ref(
goto cleanup; goto cleanup;
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) { if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) {
error = reference__create(&ref, repo, name, GIT_REF_SYMBOLIC); error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = parse_sym_ref(ref, &ref_file); error = parse_sym_ref(ref, &ref_file);
} else { } else {
error = reference__create(&ref, repo, name, GIT_REF_OID); error = reference_create(&ref, repo, name, GIT_REF_OID);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = parse_oid_ref(ref, &ref_file); error = parse_oid_ref(ref, &ref_file);
} }
ref->modified = 0;
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -397,16 +375,13 @@ static int parse_packed_line( ...@@ -397,16 +375,13 @@ static int parse_packed_line(
if (refname[refname_len - 1] == '\r') if (refname[refname_len - 1] == '\r')
refname[refname_len - 1] = 0; refname[refname_len - 1] = 0;
error = reference__create(&ref, repo, refname, GIT_REF_OID); error = reference_create(&ref, repo, refname, GIT_REF_OID);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = git_reference_set_oid(ref, &id); git_oid_cpy(&ref->target.oid, &id);
if (error < GIT_SUCCESS)
goto cleanup;
ref->packed = 1; ref->packed = 1;
ref->modified = 0;
*ref_out = ref; *ref_out = ref;
*buffer_out = refname_end + 1; *buffer_out = refname_end + 1;
...@@ -496,9 +471,7 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id) ...@@ -496,9 +471,7 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id)
git_oid_cpy(&ref->target.oid, id); git_oid_cpy(&ref->target.oid, id);
ref->modified = 1; return reference_write(ref);
return GIT_SUCCESS;
} }
int git_reference_set_target(git_reference *ref, const char *target) int git_reference_set_target(git_reference *ref, const char *target)
...@@ -511,9 +484,7 @@ int git_reference_set_target(git_reference *ref, const char *target) ...@@ -511,9 +484,7 @@ int git_reference_set_target(git_reference *ref, const char *target)
if (ref->target.ref == NULL) if (ref->target.ref == NULL)
return GIT_ENOMEM; return GIT_ENOMEM;
ref->modified = 1; return reference_write(ref);
return GIT_SUCCESS;
} }
const git_oid *git_reference_oid(git_reference *ref) const git_oid *git_reference_oid(git_reference *ref)
...@@ -528,6 +499,8 @@ const git_oid *git_reference_oid(git_reference *ref) ...@@ -528,6 +499,8 @@ const git_oid *git_reference_oid(git_reference *ref)
const char *git_reference_target(git_reference *ref) const char *git_reference_target(git_reference *ref)
{ {
assert(ref);
if (ref->type != GIT_REF_SYMBOLIC) if (ref->type != GIT_REF_SYMBOLIC)
return NULL; return NULL;
...@@ -576,19 +549,14 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) ...@@ -576,19 +549,14 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
return GIT_ETOONESTEDSYMREF; return GIT_ETOONESTEDSYMREF;
} }
int git_reference_write(git_reference *ref) static int reference_write(git_reference *ref)
{ {
git_filebuf file; git_filebuf file;
git_reference *looked_up_reference;
char ref_path[GIT_PATH_MAX]; char ref_path[GIT_PATH_MAX];
int error, contents_size; int error, contents_size;
char *ref_contents = NULL; char *ref_contents = NULL;
if (ref->type == GIT_REF_INVALID || ref->type == GIT_REF_ANY) assert(ref->type == GIT_REF_OID || ref->type == GIT_REF_SYMBOLIC);
return GIT_EINVALIDREFSTATE;
if (!ref->modified)
return GIT_SUCCESS;
git__joinpath(ref_path, ref->owner->path_repository, ref->name); git__joinpath(ref_path, ref->owner->path_repository, ref->name);
...@@ -619,27 +587,25 @@ int git_reference_write(git_reference *ref) ...@@ -619,27 +587,25 @@ int git_reference_write(git_reference *ref)
strcat(ref_contents, ref->target.ref); strcat(ref_contents, ref->target.ref);
} }
/* TODO: win32 carriage return when writing references in Windows? */
ref_contents[contents_size - 1] = '\n'; ref_contents[contents_size - 1] = '\n';
if ((error = git_filebuf_write(&file, ref_contents, contents_size)) < GIT_SUCCESS) if ((error = git_filebuf_write(&file, ref_contents, contents_size)) < GIT_SUCCESS)
goto error_cleanup; goto error_cleanup;
error = git_filebuf_commit(&file); error = git_filebuf_commit(&file);
if (error < GIT_SUCCESS)
goto unlock;
looked_up_reference = git_hashtable_lookup(ref->owner->references.cache, ref->name); error = git_hashtable_insert(ref->owner->references.cache, ref->name, ref);
if (error < GIT_SUCCESS)
if (looked_up_reference == NULL) { goto unlock;
error = git_hashtable_insert(ref->owner->references.cache, ref->name, ref);
if (error < GIT_SUCCESS)
goto cleanup;
}
goto cleanup; free(ref_contents);
return GIT_SUCCESS;
unlock: unlock:
git_filelock_unlock(&lock); git_filebuf_cleanup(&lock);
cleanup:
free(ref_contents); free(ref_contents);
return error; return error;
} }
......
...@@ -21,8 +21,7 @@ struct git_reference { ...@@ -21,8 +21,7 @@ struct git_reference {
git_rtype type; git_rtype type;
char *name; char *name;
unsigned packed:1, unsigned packed:1;
modified:1;
union { union {
char *ref; char *ref;
......
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