Skip to content

Commit fa5b183

Browse files
mhaggergitster
authored andcommitted
reflog_expire(): new function in the reference API
Move expire_reflog() into refs.c and rename it to reflog_expire(). Turn the three policy functions into function pointers that are passed into reflog_expire(). Add function prototypes and documentation to refs.h. [jc: squashed in $gmane/261582, drop "extern" in function definition] Signed-off-by: Michael Haggerty <[email protected]> Reviewed-by: Stefan Beller <[email protected]> Tweaked-by: Ramsay Jones Signed-off-by: Junio C Hamano <[email protected]>
1 parent b729eff commit fa5b183

File tree

3 files changed

+190
-133
lines changed

3 files changed

+190
-133
lines changed

builtin/reflog.c

Lines changed: 15 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ static const char reflog_delete_usage[] =
2020
static unsigned long default_reflog_expire;
2121
static unsigned long default_reflog_expire_unreachable;
2222

23-
enum expire_reflog_flags {
24-
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
25-
EXPIRE_REFLOGS_UPDATE_REF = 1 << 1,
26-
EXPIRE_REFLOGS_VERBOSE = 1 << 2,
27-
EXPIRE_REFLOGS_REWRITE = 1 << 3
28-
};
29-
3023
struct cmd_reflog_expire_cb {
3124
struct rev_info revs;
3225
int stalefix;
@@ -48,13 +41,6 @@ struct expire_reflog_policy_cb {
4841
struct commit_list *tips;
4942
};
5043

51-
struct expire_reflog_cb {
52-
unsigned int flags;
53-
void *policy_cb;
54-
FILE *newlog;
55-
unsigned char last_kept_sha1[20];
56-
};
57-
5844
struct collected_reflog {
5945
unsigned char sha1[20];
6046
char reflog[FLEX_ARRAY];
@@ -330,38 +316,6 @@ static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
330316
return 0;
331317
}
332318

333-
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
334-
const char *email, unsigned long timestamp, int tz,
335-
const char *message, void *cb_data)
336-
{
337-
struct expire_reflog_cb *cb = cb_data;
338-
struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
339-
340-
if (cb->flags & EXPIRE_REFLOGS_REWRITE)
341-
osha1 = cb->last_kept_sha1;
342-
343-
if (should_expire_reflog_ent(osha1, nsha1, email, timestamp, tz,
344-
message, policy_cb)) {
345-
if (!cb->newlog)
346-
printf("would prune %s", message);
347-
else if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
348-
printf("prune %s", message);
349-
} else {
350-
if (cb->newlog) {
351-
char sign = (tz < 0) ? '-' : '+';
352-
int zone = (tz < 0) ? (-tz) : tz;
353-
fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
354-
sha1_to_hex(osha1), sha1_to_hex(nsha1),
355-
email, timestamp, sign, zone,
356-
message);
357-
hashcpy(cb->last_kept_sha1, nsha1);
358-
}
359-
if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
360-
printf("keep %s", message);
361-
}
362-
return 0;
363-
}
364-
365319
static int push_tip_to_list(const char *refname, const unsigned char *sha1,
366320
int flags, void *cb_data)
367321
{
@@ -428,90 +382,6 @@ static void reflog_expiry_cleanup(void *cb_data)
428382
}
429383
}
430384

431-
static int expire_reflog(const char *refname, const unsigned char *sha1,
432-
unsigned int flags, void *policy_cb_data)
433-
{
434-
static struct lock_file reflog_lock;
435-
struct expire_reflog_cb cb;
436-
struct ref_lock *lock;
437-
char *log_file;
438-
int status = 0;
439-
440-
memset(&cb, 0, sizeof(cb));
441-
cb.flags = flags;
442-
cb.policy_cb = policy_cb_data;
443-
444-
/*
445-
* The reflog file is locked by holding the lock on the
446-
* reference itself, plus we might need to update the
447-
* reference if --updateref was specified:
448-
*/
449-
lock = lock_any_ref_for_update(refname, sha1, 0, NULL);
450-
if (!lock)
451-
return error("cannot lock ref '%s'", refname);
452-
if (!reflog_exists(refname)) {
453-
unlock_ref(lock);
454-
return 0;
455-
}
456-
457-
log_file = git_pathdup("logs/%s", refname);
458-
if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
459-
/*
460-
* Even though holding $GIT_DIR/logs/$reflog.lock has
461-
* no locking implications, we use the lock_file
462-
* machinery here anyway because it does a lot of the
463-
* work we need, including cleaning up if the program
464-
* exits unexpectedly.
465-
*/
466-
if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
467-
struct strbuf err = STRBUF_INIT;
468-
unable_to_lock_message(log_file, errno, &err);
469-
error("%s", err.buf);
470-
strbuf_release(&err);
471-
goto failure;
472-
}
473-
cb.newlog = fdopen_lock_file(&reflog_lock, "w");
474-
if (!cb.newlog) {
475-
error("cannot fdopen %s (%s)",
476-
reflog_lock.filename.buf, strerror(errno));
477-
goto failure;
478-
}
479-
}
480-
481-
reflog_expiry_prepare(refname, sha1, cb.policy_cb);
482-
for_each_reflog_ent(refname, expire_reflog_ent, &cb);
483-
reflog_expiry_cleanup(cb.policy_cb);
484-
485-
if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
486-
if (close_lock_file(&reflog_lock)) {
487-
status |= error("couldn't write %s: %s", log_file,
488-
strerror(errno));
489-
} else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) &&
490-
(write_in_full(lock->lock_fd,
491-
sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
492-
write_str_in_full(lock->lock_fd, "\n") != 1 ||
493-
close_ref(lock) < 0)) {
494-
status |= error("couldn't write %s",
495-
lock->lk->filename.buf);
496-
rollback_lock_file(&reflog_lock);
497-
} else if (commit_lock_file(&reflog_lock)) {
498-
status |= error("unable to commit reflog '%s' (%s)",
499-
log_file, strerror(errno));
500-
} else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) && commit_ref(lock)) {
501-
status |= error("couldn't set %s", lock->ref_name);
502-
}
503-
}
504-
free(log_file);
505-
unlock_ref(lock);
506-
return status;
507-
508-
failure:
509-
rollback_lock_file(&reflog_lock);
510-
free(log_file);
511-
unlock_ref(lock);
512-
return -1;
513-
}
514-
515385
static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
516386
{
517387
struct collected_reflog *e;
@@ -727,7 +597,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
727597
for (i = 0; i < collected.nr; i++) {
728598
struct collected_reflog *e = collected.e[i];
729599
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
730-
status |= expire_reflog(e->reflog, e->sha1, flags, &cb);
600+
status |= reflog_expire(e->reflog, e->sha1, flags,
601+
reflog_expiry_prepare,
602+
should_expire_reflog_ent,
603+
reflog_expiry_cleanup,
604+
&cb);
731605
free(e);
732606
}
733607
free(collected.e);
@@ -741,7 +615,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
741615
continue;
742616
}
743617
set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
744-
status |= expire_reflog(ref, sha1, flags, &cb);
618+
status |= reflog_expire(ref, sha1, flags,
619+
reflog_expiry_prepare,
620+
should_expire_reflog_ent,
621+
reflog_expiry_cleanup,
622+
&cb);
745623
}
746624
return status;
747625
}
@@ -813,7 +691,11 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
813691
cb.cmd.expire_total = 0;
814692
}
815693

816-
status |= expire_reflog(ref, sha1, flags, &cb);
694+
status |= reflog_expire(ref, sha1, flags,
695+
reflog_expiry_prepare,
696+
should_expire_reflog_ent,
697+
reflog_expiry_cleanup,
698+
&cb);
817699
free(ref);
818700
}
819701
return status;

refs.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,3 +3943,132 @@ int ref_is_hidden(const char *refname)
39433943
}
39443944
return 0;
39453945
}
3946+
3947+
struct expire_reflog_cb {
3948+
unsigned int flags;
3949+
reflog_expiry_should_prune_fn *should_prune_fn;
3950+
void *policy_cb;
3951+
FILE *newlog;
3952+
unsigned char last_kept_sha1[20];
3953+
};
3954+
3955+
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
3956+
const char *email, unsigned long timestamp, int tz,
3957+
const char *message, void *cb_data)
3958+
{
3959+
struct expire_reflog_cb *cb = cb_data;
3960+
struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
3961+
3962+
if (cb->flags & EXPIRE_REFLOGS_REWRITE)
3963+
osha1 = cb->last_kept_sha1;
3964+
3965+
if ((*cb->should_prune_fn)(osha1, nsha1, email, timestamp, tz,
3966+
message, policy_cb)) {
3967+
if (!cb->newlog)
3968+
printf("would prune %s", message);
3969+
else if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
3970+
printf("prune %s", message);
3971+
} else {
3972+
if (cb->newlog) {
3973+
char sign = (tz < 0) ? '-' : '+';
3974+
int zone = (tz < 0) ? (-tz) : tz;
3975+
fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
3976+
sha1_to_hex(osha1), sha1_to_hex(nsha1),
3977+
email, timestamp, sign, zone,
3978+
message);
3979+
hashcpy(cb->last_kept_sha1, nsha1);
3980+
}
3981+
if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
3982+
printf("keep %s", message);
3983+
}
3984+
return 0;
3985+
}
3986+
3987+
int reflog_expire(const char *refname, const unsigned char *sha1,
3988+
unsigned int flags,
3989+
reflog_expiry_prepare_fn prepare_fn,
3990+
reflog_expiry_should_prune_fn should_prune_fn,
3991+
reflog_expiry_cleanup_fn cleanup_fn,
3992+
void *policy_cb_data)
3993+
{
3994+
static struct lock_file reflog_lock;
3995+
struct expire_reflog_cb cb;
3996+
struct ref_lock *lock;
3997+
char *log_file;
3998+
int status = 0;
3999+
4000+
memset(&cb, 0, sizeof(cb));
4001+
cb.flags = flags;
4002+
cb.policy_cb = policy_cb_data;
4003+
cb.should_prune_fn = should_prune_fn;
4004+
4005+
/*
4006+
* The reflog file is locked by holding the lock on the
4007+
* reference itself, plus we might need to update the
4008+
* reference if --updateref was specified:
4009+
*/
4010+
lock = lock_any_ref_for_update(refname, sha1, 0, NULL);
4011+
if (!lock)
4012+
return error("cannot lock ref '%s'", refname);
4013+
if (!reflog_exists(refname)) {
4014+
unlock_ref(lock);
4015+
return 0;
4016+
}
4017+
4018+
log_file = git_pathdup("logs/%s", refname);
4019+
if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
4020+
/*
4021+
* Even though holding $GIT_DIR/logs/$reflog.lock has
4022+
* no locking implications, we use the lock_file
4023+
* machinery here anyway because it does a lot of the
4024+
* work we need, including cleaning up if the program
4025+
* exits unexpectedly.
4026+
*/
4027+
if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
4028+
struct strbuf err = STRBUF_INIT;
4029+
unable_to_lock_message(log_file, errno, &err);
4030+
error("%s", err.buf);
4031+
strbuf_release(&err);
4032+
goto failure;
4033+
}
4034+
cb.newlog = fdopen_lock_file(&reflog_lock, "w");
4035+
if (!cb.newlog) {
4036+
error("cannot fdopen %s (%s)",
4037+
reflog_lock.filename.buf, strerror(errno));
4038+
goto failure;
4039+
}
4040+
}
4041+
4042+
(*prepare_fn)(refname, sha1, cb.policy_cb);
4043+
for_each_reflog_ent(refname, expire_reflog_ent, &cb);
4044+
(*cleanup_fn)(cb.policy_cb);
4045+
4046+
if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
4047+
if (close_lock_file(&reflog_lock)) {
4048+
status |= error("couldn't write %s: %s", log_file,
4049+
strerror(errno));
4050+
} else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) &&
4051+
(write_in_full(lock->lock_fd,
4052+
sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
4053+
write_str_in_full(lock->lock_fd, "\n") != 1 ||
4054+
close_ref(lock) < 0)) {
4055+
status |= error("couldn't write %s",
4056+
lock->lk->filename.buf);
4057+
rollback_lock_file(&reflog_lock);
4058+
} else if (commit_lock_file(&reflog_lock)) {
4059+
status |= error("unable to commit reflog '%s' (%s)",
4060+
log_file, strerror(errno));
4061+
} else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) && commit_ref(lock)) {
4062+
status |= error("couldn't set %s", lock->ref_name);
4063+
}
4064+
}
4065+
free(log_file);
4066+
unlock_ref(lock);
4067+
return status;
4068+
4069+
failure:
4070+
rollback_lock_file(&reflog_lock);
4071+
free(log_file);
4072+
unlock_ref(lock);
4073+
return -1;
4074+
}

refs.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,50 @@ int update_ref(const char *action, const char *refname,
353353
extern int parse_hide_refs_config(const char *var, const char *value, const char *);
354354
extern int ref_is_hidden(const char *);
355355

356+
enum expire_reflog_flags {
357+
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
358+
EXPIRE_REFLOGS_UPDATE_REF = 1 << 1,
359+
EXPIRE_REFLOGS_VERBOSE = 1 << 2,
360+
EXPIRE_REFLOGS_REWRITE = 1 << 3
361+
};
362+
363+
/*
364+
* The following interface is used for reflog expiration. The caller
365+
* calls reflog_expire(), supplying it with three callback functions,
366+
* of the following types. The callback functions define the
367+
* expiration policy that is desired.
368+
*
369+
* reflog_expiry_prepare_fn -- Called once after the reference is
370+
* locked.
371+
*
372+
* reflog_expiry_should_prune_fn -- Called once for each entry in the
373+
* existing reflog. It should return true iff that entry should be
374+
* pruned.
375+
*
376+
* reflog_expiry_cleanup_fn -- Called once before the reference is
377+
* unlocked again.
378+
*/
379+
typedef void reflog_expiry_prepare_fn(const char *refname,
380+
const unsigned char *sha1,
381+
void *cb_data);
382+
typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,
383+
unsigned char *nsha1,
384+
const char *email,
385+
unsigned long timestamp, int tz,
386+
const char *message, void *cb_data);
387+
typedef void reflog_expiry_cleanup_fn(void *cb_data);
388+
389+
/*
390+
* Expire reflog entries for the specified reference. sha1 is the old
391+
* value of the reference. flags is a combination of the constants in
392+
* enum expire_reflog_flags. The three function pointers are described
393+
* above. On success, return zero.
394+
*/
395+
extern int reflog_expire(const char *refname, const unsigned char *sha1,
396+
unsigned int flags,
397+
reflog_expiry_prepare_fn prepare_fn,
398+
reflog_expiry_should_prune_fn should_prune_fn,
399+
reflog_expiry_cleanup_fn cleanup_fn,
400+
void *policy_cb_data);
401+
356402
#endif /* REFS_H */

0 commit comments

Comments
 (0)