[PATCH 07/15] refs.c: add a transaction function to append a reflog entry

2014-10-21 Thread Ronnie Sahlberg
commit de045215a52a6a9591b0e786488de2293d79d245 upstream.

Define a new transaction update type, UPDATE_LOG, and a new function
transaction_update_reflog. This function will lock the reflog and append
an entry to it during transaction commit.

Change-Id: I8cc935ef311688d561d447fa51b44ac98492693b
Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 102 +++--
 refs.h |  12 
 2 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index 0e11b1c..100b3a3 100644
--- a/refs.c
+++ b/refs.c
@@ -3517,7 +3517,8 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
 }
 
 enum transaction_update_type {
-   UPDATE_SHA1 = 0
+   UPDATE_SHA1 = 0,
+   UPDATE_LOG = 1
 };
 
 /**
@@ -3535,6 +3536,12 @@ struct ref_update {
struct ref_lock *lock;
int type;
char *msg;
+
+   /* used by reflog updates */
+   int reflog_fd;
+   struct lock_file reflog_lock;
+   char *committer;
+
const char refname[FLEX_ARRAY];
 };
 
@@ -3581,6 +3588,7 @@ void transaction_free(struct transaction *transaction)
 
for (i = 0; i  transaction-nr; i++) {
free(transaction-updates[i]-msg);
+   free(transaction-updates[i]-committer);
free(transaction-updates[i]);
}
free(transaction-updates);
@@ -3601,6 +3609,41 @@ static struct ref_update *add_update(struct transaction 
*transaction,
return update;
 }
 
+int transaction_update_reflog(struct transaction *transaction,
+ const char *refname,
+ const unsigned char *new_sha1,
+ const unsigned char *old_sha1,
+ const unsigned char *email,
+ unsigned long timestamp, int tz,
+ const char *msg, int flags,
+ struct strbuf *err)
+{
+   struct ref_update *update;
+
+   if (transaction-state != TRANSACTION_OPEN)
+   die(BUG: update_reflog called for transaction that is not 
open);
+
+   update = add_update(transaction, refname, UPDATE_LOG);
+   hashcpy(update-new_sha1, new_sha1);
+   hashcpy(update-old_sha1, old_sha1);
+   update-reflog_fd = -1;
+   if (email) {
+   struct strbuf buf = STRBUF_INIT;
+   char sign = (tz  0) ? '-' : '+';
+   int zone = (tz  0) ? (-tz) : tz;
+
+   strbuf_addf(buf, %s %lu %c%04d, email, timestamp, sign,
+   zone);
+   update-committer = xstrdup(buf.buf);
+   strbuf_release(buf);
+   }
+   if (msg)
+   update-msg = xstrdup(msg);
+   update-flags = flags;
+
+   return 0;
+}
+
 int transaction_update_ref(struct transaction *transaction,
   const char *refname,
   const unsigned char *new_sha1,
@@ -3773,7 +3816,28 @@ int transaction_commit(struct transaction *transaction,
}
}
 
-   /* Perform updates first so live commits remain referenced */
+   /* Lock all reflog files */
+   for (i = 0; i  n; i++) {
+   struct ref_update *update = updates[i];
+
+   if (update-update_type != UPDATE_LOG)
+   continue;
+   update-reflog_fd = hold_lock_file_for_append(
+   update-reflog_lock,
+   git_path(logs/%s, update-refname),
+   0);
+   if (update-reflog_fd  0) {
+   const char *str = Cannot lock reflog for '%s'. %s;
+
+   ret = -1;
+   if (err)
+   strbuf_addf(err, str, update-refname,
+   strerror(errno));
+   goto cleanup;
+   }
+   }
+
+   /* Perform ref updates first so live commits remain referenced */
for (i = 0; i  n; i++) {
struct ref_update *update = updates[i];
 
@@ -3809,6 +3873,40 @@ int transaction_commit(struct transaction *transaction,
}
}
 
+   /* Update all reflog files */
+   for (i = 0; i  n; i++) {
+   struct ref_update *update = updates[i];
+
+   if (update-update_type != UPDATE_LOG)
+   continue;
+   if (update-reflog_fd == -1)
+   continue;
+
+   if (log_ref_write_fd(update-reflog_fd, update-old_sha1,
+update-new_sha1,
+update-committer, update-msg)) {
+   error(Could write to reflog: %s. %s,
+ update-refname, strerror(errno));
+   

[PATCH 07/15] refs.c: add a transaction function to append a reflog entry

2014-07-23 Thread Ronnie Sahlberg
Define a new transaction update type, UPDATE_LOG, and a new function
transaction_update_reflog. This function will lock the reflog and append
an entry to it during transaction commit.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
---
 refs.c | 103 +++--
 refs.h |  12 
 2 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index a479ddd..b010d6d 100644
--- a/refs.c
+++ b/refs.c
@@ -3385,7 +3385,8 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
 }
 
 enum transaction_update_type {
-   UPDATE_SHA1 = 0
+   UPDATE_SHA1 = 0,
+   UPDATE_LOG = 1
 };
 
 /**
@@ -3403,6 +3404,12 @@ struct ref_update {
struct ref_lock *lock;
int type;
char *msg;
+
+   /* used by reflog updates */
+   int reflog_fd;
+   struct lock_file reflog_lock;
+   char *committer;
+
const char refname[FLEX_ARRAY];
 };
 
@@ -3451,6 +3458,7 @@ void transaction_free(struct ref_transaction *transaction)
 
for (i = 0; i  transaction-nr; i++) {
free(transaction-updates[i]-msg);
+   free(transaction-updates[i]-committer);
free(transaction-updates[i]);
}
free(transaction-updates);
@@ -3471,6 +3479,42 @@ static struct ref_update *add_update(struct 
ref_transaction *transaction,
return update;
 }
 
+int transaction_update_reflog(struct ref_transaction *transaction,
+ const char *refname,
+ const unsigned char *new_sha1,
+ const unsigned char *old_sha1,
+ const unsigned char *email,
+ unsigned long timestamp, int tz,
+ const char *msg, int flags,
+ struct strbuf *err)
+{
+   struct ref_update *update;
+
+   if (transaction-state != REF_TRANSACTION_OPEN)
+   die(BUG: update_reflog called for transaction that is not 
+   open);
+
+   update = add_update(transaction, refname, UPDATE_LOG);
+   hashcpy(update-new_sha1, new_sha1);
+   hashcpy(update-old_sha1, old_sha1);
+   update-reflog_fd = -1;
+   if (email) {
+   struct strbuf buf = STRBUF_INIT;
+   char sign = (tz  0) ? '-' : '+';
+   int zone = (tz  0) ? (-tz) : tz;
+
+   strbuf_addf(buf, %s %lu %c%04d, email, timestamp, sign,
+   zone);
+   update-committer = xstrdup(buf.buf);
+   strbuf_release(buf);
+   }
+   if (msg)
+   update-msg = xstrdup(msg);
+   update-flags = flags;
+
+   return 0;
+}
+
 int transaction_update_sha1(struct ref_transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
@@ -3646,7 +3690,28 @@ int transaction_commit(struct ref_transaction 
*transaction,
}
}
 
-   /* Perform updates first so live commits remain referenced */
+   /* Lock all reflog files */
+   for (i = 0; i  n; i++) {
+   struct ref_update *update = updates[i];
+
+   if (update-update_type != UPDATE_LOG)
+   continue;
+   update-reflog_fd = hold_lock_file_for_append(
+   update-reflog_lock,
+   git_path(logs/%s, update-refname),
+   0);
+   if (update-reflog_fd  0) {
+   const char *str = Cannot lock reflog for '%s'. %s;
+
+   ret = -1;
+   if (err)
+ strbuf_addf(err, str, update-refname,
+ strerror(errno));
+   goto cleanup;
+   }
+   }
+
+   /* Perform ref updates first so live commits remain referenced */
for (i = 0; i  n; i++) {
struct ref_update *update = updates[i];
 
@@ -3682,6 +3747,40 @@ int transaction_commit(struct ref_transaction 
*transaction,
}
}
 
+   /* Update all reflog files */
+   for (i = 0; i  n; i++) {
+   struct ref_update *update = updates[i];
+
+   if (update-update_type != UPDATE_LOG)
+   continue;
+   if (update-reflog_fd == -1)
+   continue;
+
+   if (log_ref_write_fd(update-reflog_fd, update-old_sha1,
+update-new_sha1,
+update-committer, update-msg)) {
+   error(Could write to reflog: %s. %s,
+ update-refname, strerror(errno));
+   rollback_lock_file(update-reflog_lock);
+   update-reflog_fd = -1;
+   }
+   }
+
+