/*
* The tag page, which shows a single ref under refs/tags and is where the
* branch and tag listings link. An annotated tag is a git object in its own
* right, so its page carries the tagger, the date and the message, while a
* lightweight tag is only a name for a commit and gets a shorter table. Both
* forms link the object the tag points at and, when the repository enables
* snapshots, offer the tree at that tag for download as an archive.
*/
#define USE_THE_REPOSITORY_VARIABLE
#include "cgit.h"
#include "filter.h"
#include "html.h"
#include "parsing.h"
#include "shared.h"
#include "ui-shared.h"
#include "ui-tag.h"
static void print_object_row(struct object *obj)
{
html("
| tagged object | ");
cgit_object_link(obj);
html(" |
\n");
}
static void print_download_row(const char *revname)
{
html("| download | ");
cgit_print_snapshot_links(ctx.repo, revname, " ");
html(" |
\n");
}
/*
* Cutting the subject out terminates the message in place, which is safe only
* because the caller frees it straight after.
*/
static void print_message(char *msg)
{
char *newline;
if (!msg)
return;
html("");
newline = strchr(msg, '\n');
if (newline)
*newline = '\0';
html_txt(msg);
html("
");
if (newline) {
html("");
html_txt(newline + 1);
html("
");
}
}
static void print_annotated_tag(const char *revname,
const struct object_id *oid)
{
struct tag *tag;
struct taginfo *info;
tag = lookup_tag(the_repository, oid);
if (!tag || parse_tag(the_repository, tag) ||
!(info = cgit_parse_tag(tag))) {
cgit_print_error_page(500, "Internal server error",
"Bad tag object: %s", revname);
return;
}
cgit_print_layout_start();
html("\n");
html("| tag name | ");
html_txt(revname);
htmlf(" (%s) |
\n", oid_to_hex(oid));
if (info->tagger_date > 0) {
html("| tag date | ");
html_txt(show_date(info->tagger_date, info->tagger_tz,
cgit_date_mode(DATE_ISO8601)));
html(" |
\n");
}
if (info->tagger) {
html("| tagged by | ");
// A tag can carry a tagger with no address, and a filter must
// not be handed a NULL argument.
cgit_open_filter(ctx.repo->email_filter,
info->tagger_email ? info->tagger_email : "",
"tag");
html_txt(info->tagger);
if (info->tagger_email && !ctx.cfg.noplainemail) {
html(" ");
html_txt(info->tagger_email);
}
cgit_close_filter(ctx.repo->email_filter);
html(" |
\n");
}
print_object_row(tag->tagged);
if (ctx.repo->snapshots)
print_download_row(revname);
html("
\n");
print_message(info->msg);
cgit_print_layout_end();
cgit_free_taginfo(info);
}
static void print_lightweight_tag(const char *revname, struct object *obj)
{
cgit_print_layout_start();
html("\n");
html("| tag name | ");
html_txt(revname);
html(" |
\n");
print_object_row(obj);
if (ctx.repo->snapshots)
print_download_row(revname);
html("
\n");
cgit_print_layout_end();
}
void cgit_print_tag(char *revname)
{
struct strbuf fullref = STRBUF_INIT;
struct object_id oid;
struct object *obj;
if (!revname)
revname = ctx.qry.head;
strbuf_addf(&fullref, "refs/tags/%s", revname);
if (repo_get_oid(the_repository, fullref.buf, &oid)) {
cgit_print_error_page(404, "Not found",
"Bad tag reference: %s", revname);
goto cleanup;
}
obj = parse_object(the_repository, &oid);
if (!obj) {
cgit_print_error_page(500, "Internal server error",
"Bad object id: %s", oid_to_hex(&oid));
goto cleanup;
}
if (obj->type == OBJ_TAG)
print_annotated_tag(revname, &oid);
else
print_lightweight_tag(revname, obj);
cleanup:
strbuf_release(&fullref);
}