Compare commits
10 Commits
ce2062d9e2
...
00ecfaadea
Author | SHA1 | Date | |
---|---|---|---|
|
00ecfaadea | ||
|
907134b7a2 | ||
|
aee39b4e9a | ||
|
093ac96970 | ||
|
91f25909b9 | ||
|
852cb3b0e2 | ||
|
4c520cefc9 | ||
|
d071f28cfa | ||
|
c1a1d23111 | ||
|
a0f6669bdb |
1
Makefile
1
Makefile
@ -87,6 +87,7 @@ install: all
|
||||
$(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
|
||||
$(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
|
||||
$(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
|
||||
$(INSTALL) -m 0644 cgit.js $(DESTDIR)$(CGIT_DATA_PATH)/cgit.js
|
||||
$(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
|
||||
$(INSTALL) -m 0644 favicon.ico $(DESTDIR)$(CGIT_DATA_PATH)/favicon.ico
|
||||
$(INSTALL) -m 0644 robots.txt $(DESTDIR)$(CGIT_DATA_PATH)/robots.txt
|
||||
|
39
cache.c
39
cache.c
@ -85,40 +85,45 @@ static int close_slot(struct cache_slot *slot)
|
||||
/* Print the content of the active cache slot (but skip the key). */
|
||||
static int print_slot(struct cache_slot *slot)
|
||||
{
|
||||
off_t off;
|
||||
#ifdef HAVE_LINUX_SENDFILE
|
||||
off_t start_off;
|
||||
int ret;
|
||||
off_t size;
|
||||
#endif
|
||||
|
||||
start_off = slot->keylen + 1;
|
||||
off = slot->keylen + 1;
|
||||
|
||||
#ifdef HAVE_LINUX_SENDFILE
|
||||
size = slot->cache_st.st_size;
|
||||
|
||||
do {
|
||||
ret = sendfile(STDOUT_FILENO, slot->cache_fd, &start_off,
|
||||
slot->cache_st.st_size - start_off);
|
||||
ssize_t ret;
|
||||
ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
/* Fall back to read/write on EINVAL or ENOSYS */
|
||||
if (errno == EINVAL || errno == ENOSYS)
|
||||
break;
|
||||
return errno;
|
||||
}
|
||||
if (off == size)
|
||||
return 0;
|
||||
} while (1);
|
||||
#else
|
||||
ssize_t i, j;
|
||||
#endif
|
||||
|
||||
i = lseek(slot->cache_fd, slot->keylen + 1, SEEK_SET);
|
||||
if (i != slot->keylen + 1)
|
||||
if (lseek(slot->cache_fd, off, SEEK_SET) != off)
|
||||
return errno;
|
||||
|
||||
do {
|
||||
i = j = xread(slot->cache_fd, slot->buf, sizeof(slot->buf));
|
||||
if (i > 0)
|
||||
j = xwrite(STDOUT_FILENO, slot->buf, i);
|
||||
} while (i > 0 && j == i);
|
||||
|
||||
if (i < 0 || j != i)
|
||||
ssize_t ret;
|
||||
ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf));
|
||||
if (ret < 0)
|
||||
return errno;
|
||||
else
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
#endif
|
||||
if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0)
|
||||
return errno;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/* Check if the slot has expired */
|
||||
|
19
cgit.c
19
cgit.c
@ -142,7 +142,9 @@ static void config_cb(const char *name, const char *value)
|
||||
else if (!strcmp(name, "root-readme"))
|
||||
ctx.cfg.root_readme = xstrdup(value);
|
||||
else if (!strcmp(name, "css"))
|
||||
ctx.cfg.css = xstrdup(value);
|
||||
string_list_append(&ctx.cfg.css, xstrdup(value));
|
||||
else if (!strcmp(name, "js"))
|
||||
string_list_append(&ctx.cfg.js, xstrdup(value));
|
||||
else if (!strcmp(name, "favicon"))
|
||||
ctx.cfg.favicon = xstrdup(value);
|
||||
else if (!strcmp(name, "footer"))
|
||||
@ -237,9 +239,11 @@ static void config_cb(const char *name, const char *value)
|
||||
ctx.cfg.max_repodesc_len = atoi(value);
|
||||
else if (!strcmp(name, "max-blob-size"))
|
||||
ctx.cfg.max_blob_size = atoi(value);
|
||||
else if (!strcmp(name, "max-repo-count"))
|
||||
else if (!strcmp(name, "max-repo-count")) {
|
||||
ctx.cfg.max_repo_count = atoi(value);
|
||||
else if (!strcmp(name, "max-commit-count"))
|
||||
if (ctx.cfg.max_repo_count <= 0)
|
||||
ctx.cfg.max_repo_count = INT_MAX;
|
||||
} else if (!strcmp(name, "max-commit-count"))
|
||||
ctx.cfg.max_commit_count = atoi(value);
|
||||
else if (!strcmp(name, "project-list"))
|
||||
ctx.cfg.project_list = xstrdup(expand_macros(value));
|
||||
@ -376,7 +380,6 @@ static void prepare_context(void)
|
||||
ctx.cfg.case_sensitive_sort = 1;
|
||||
ctx.cfg.branch_sort = 0;
|
||||
ctx.cfg.commit_sort = 0;
|
||||
ctx.cfg.css = "/cgit.css";
|
||||
ctx.cfg.logo = "/cgit.png";
|
||||
ctx.cfg.favicon = "/favicon.ico";
|
||||
ctx.cfg.local_time = 0;
|
||||
@ -507,9 +510,11 @@ static inline void parse_readme(const char *readme, char **filename, char **ref,
|
||||
/* Check if the readme is tracked in the git repo. */
|
||||
colon = strchr(readme, ':');
|
||||
if (colon && strlen(colon) > 1) {
|
||||
/* If it starts with a colon, we want to use
|
||||
* the default branch */
|
||||
if (colon == readme && repo->defbranch)
|
||||
/* If it starts with a colon, we want to use head given
|
||||
* from query or the default branch */
|
||||
if (colon == readme && ctx.qry.head)
|
||||
*ref = xstrdup(ctx.qry.head);
|
||||
else if (colon == readme && repo->defbranch)
|
||||
*ref = xstrdup(repo->defbranch);
|
||||
else
|
||||
*ref = xstrndup(readme, colon - readme);
|
||||
|
4
cgit.css
4
cgit.css
@ -363,6 +363,10 @@ div#cgit table.blame td.lines > div > pre {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
div#cgit table.blame .oid {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
div#cgit table.bin-blob {
|
||||
margin-top: 0.5em;
|
||||
border: solid 1px black;
|
||||
|
4
cgit.h
4
cgit.h
@ -25,6 +25,7 @@
|
||||
#include <utf8.h>
|
||||
#include <notes.h>
|
||||
#include <graph.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Add isgraph(x) to Git's sane ctype support (see git-compat-util.h) */
|
||||
#undef isgraph
|
||||
@ -195,7 +196,6 @@ struct cgit_config {
|
||||
char *cache_root;
|
||||
char *clone_prefix;
|
||||
char *clone_url;
|
||||
char *css;
|
||||
char *favicon;
|
||||
char *footer;
|
||||
char *head_include;
|
||||
@ -206,6 +206,7 @@ struct cgit_config {
|
||||
char *module_link;
|
||||
char *project_list;
|
||||
struct string_list readme;
|
||||
struct string_list css;
|
||||
char *robots;
|
||||
char *root_title;
|
||||
char *root_desc;
|
||||
@ -264,6 +265,7 @@ struct cgit_config {
|
||||
int branch_sort;
|
||||
int commit_sort;
|
||||
struct string_list mimetypes;
|
||||
struct string_list js;
|
||||
struct cgit_filter *about_filter;
|
||||
struct cgit_filter *commit_filter;
|
||||
struct cgit_filter *source_filter;
|
||||
|
68
cgit.js
Normal file
68
cgit.js
Normal file
@ -0,0 +1,68 @@
|
||||
/* cgit.js: javacript functions for cgit
|
||||
*
|
||||
* Copyright (C) 2006-2018 cgit Development Team <cgit@lists.zx2c4.com>
|
||||
*
|
||||
* Licensed under GNU General Public License v2
|
||||
* (see COPYING for full license text)
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
/* This follows the logic and suffixes used in ui-shared.c */
|
||||
|
||||
var age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks", "age-months", "age-years" ];
|
||||
var age_suffix = [ "min.", "hours", "days", "weeks", "months", "years", "years" ];
|
||||
var age_next = [ 60, 3600, 24 * 3600, 7 * 24 * 3600, 30 * 24 * 3600, 365 * 24 * 3600, 365 * 24 * 3600 ];
|
||||
var age_limit = [ 7200, 24 * 7200, 7 * 24 * 7200, 30 * 24 * 7200, 365 * 25 * 7200, 365 * 25 * 7200 ];
|
||||
var update_next = [ 10, 5 * 60, 1800, 24 * 3600, 24 * 3600, 24 * 3600, 24 * 3600 ];
|
||||
|
||||
function render_age(e, age) {
|
||||
var t, n;
|
||||
|
||||
for (n = 0; n < age_classes.length; n++)
|
||||
if (age < age_limit[n])
|
||||
break;
|
||||
|
||||
t = Math.round(age / age_next[n]) + " " + age_suffix[n];
|
||||
|
||||
if (e.textContent != t) {
|
||||
e.textContent = t;
|
||||
if (n == age_classes.length)
|
||||
n--;
|
||||
if (e.className != age_classes[n])
|
||||
e.className = age_classes[n];
|
||||
}
|
||||
}
|
||||
|
||||
function aging() {
|
||||
var n, next = 24 * 3600,
|
||||
now_ut = Math.round((new Date().getTime() / 1000));
|
||||
|
||||
for (n = 0; n < age_classes.length; n++) {
|
||||
var m, elems = document.getElementsByClassName(age_classes[n]);
|
||||
|
||||
if (elems.length && update_next[n] < next)
|
||||
next = update_next[n];
|
||||
|
||||
for (m = 0; m < elems.length; m++) {
|
||||
var age = now_ut - elems[m].getAttribute("data-ut");
|
||||
|
||||
render_age(elems[m], age);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We only need to come back when the age might have changed.
|
||||
* Eg, if everything is counted in hours already, once per
|
||||
* 5 minutes is accurate enough.
|
||||
*/
|
||||
|
||||
window.setTimeout(aging, next * 1000);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
/* we can do the aging on DOM content load since no layout dependency */
|
||||
aging();
|
||||
}, false);
|
||||
|
||||
})();
|
21
cgitrc.5.txt
21
cgitrc.5.txt
@ -126,7 +126,8 @@ commit-sort::
|
||||
|
||||
css::
|
||||
Url which specifies the css document to include in all cgit pages.
|
||||
Default value: "/cgit.css".
|
||||
Default value: "/cgit.css". May be given multiple times, each
|
||||
css URL path is added in the head section of the document in turn.
|
||||
|
||||
email-filter::
|
||||
Specifies a command which will be invoked to format names and email
|
||||
@ -238,6 +239,11 @@ include::
|
||||
Name of a configfile to include before the rest of the current config-
|
||||
file is parsed. Default value: none. See also: "MACRO EXPANSION".
|
||||
|
||||
js::
|
||||
Url which specifies the javascript script document to include in all cgit
|
||||
pages. Default value: "/cgit.js". Setting this to an empty string will
|
||||
disable generation of the link to this file in the head section.
|
||||
|
||||
local-time::
|
||||
Flag which, if set to "1", makes cgit print commit and tag times in the
|
||||
servers timezone. Default value: "0".
|
||||
@ -269,7 +275,8 @@ max-message-length::
|
||||
|
||||
max-repo-count::
|
||||
Specifies the number of entries to list per page on the repository
|
||||
index page. Default value: "50".
|
||||
index page. The value "0" shows all repositories without limitation.
|
||||
Default value: "50".
|
||||
|
||||
max-repodesc-length::
|
||||
Specifies the maximum number of repo description characters to display
|
||||
@ -579,11 +586,11 @@ repo.readme::
|
||||
verbatim as the "About" page for this repo. You may also specify a
|
||||
git refspec by head or by hash by prepending the refspec followed by
|
||||
a colon. For example, "master:docs/readme.mkd". If the value begins
|
||||
with a colon, i.e. ":docs/readme.rst", the default branch of the
|
||||
repository will be used. Sharing any file will expose that entire
|
||||
directory tree to the "/about/PATH" endpoints, so be sure that there
|
||||
are no non-public files located in the same directory as the readme
|
||||
file. Default value: <readme>.
|
||||
with a colon, i.e. ":docs/readme.rst", the head giving in query or
|
||||
the default branch of the repository will be used. Sharing any file
|
||||
will expose that entire directory tree to the "/about/PATH" endpoints,
|
||||
so be sure that there are no non-public files located in the same
|
||||
directory as the readme file. Default value: <readme>.
|
||||
|
||||
repo.section::
|
||||
Override the current section name for this repository. Default value:
|
||||
|
@ -149,8 +149,7 @@ void cgit_print_atom(char *tip, const char *path, int max_count)
|
||||
first = false;
|
||||
}
|
||||
add_entry(commit, host);
|
||||
free_commit_buffer(the_repository->parsed_objects, commit);
|
||||
free_commit_list(commit->parents);
|
||||
release_commit_memory(the_repository->parsed_objects, commit);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
html("</feed>\n");
|
||||
|
@ -54,6 +54,15 @@ static void emit_blame_entry_hash(struct blame_entry *ent)
|
||||
html("</span>");
|
||||
free(detail);
|
||||
|
||||
if (!parse_commit(suspect->commit) && suspect->commit->parents) {
|
||||
struct commit *parent = suspect->commit->parents->item;
|
||||
|
||||
html(" ");
|
||||
cgit_blame_link("^", "Blame the previous revision", NULL,
|
||||
ctx.qry.head, oid_to_hex(&parent->object.oid),
|
||||
suspect->path);
|
||||
}
|
||||
|
||||
while (line++ < ent->num_lines)
|
||||
html("\n");
|
||||
}
|
||||
|
6
ui-log.c
6
ui-log.c
@ -489,8 +489,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
|
||||
for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; /* nop */) {
|
||||
if (show_commit(commit, &rev))
|
||||
i++;
|
||||
free_commit_buffer(the_repository->parsed_objects, commit);
|
||||
free_commit_list(commit->parents);
|
||||
release_commit_memory(the_repository->parsed_objects, commit);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
|
||||
@ -511,8 +510,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
|
||||
i++;
|
||||
print_commit(commit, &rev);
|
||||
}
|
||||
free_commit_buffer(the_repository->parsed_objects, commit);
|
||||
free_commit_list(commit->parents);
|
||||
release_commit_memory(the_repository->parsed_objects, commit);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
if (pager) {
|
||||
|
48
ui-shared.c
48
ui-shared.c
@ -673,7 +673,7 @@ const struct date_mode *cgit_date_mode(enum date_mode_type type)
|
||||
static void print_rel_date(time_t t, int tz, double value,
|
||||
const char *class, const char *suffix)
|
||||
{
|
||||
htmlf("<span class='%s' title='", class);
|
||||
htmlf("<span class='%s' data-ut='%" PRIu64 "' title='", class, (uint64_t)t);
|
||||
html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
|
||||
htmlf("'>%.0f %s</span>", value, suffix);
|
||||
}
|
||||
@ -768,6 +768,38 @@ static void print_rel_vcs_link(const char *url)
|
||||
html(" Git repository'/>\n");
|
||||
}
|
||||
|
||||
static int emit_css_link(struct string_list_item *s, void *arg)
|
||||
{
|
||||
/* Do not emit anything if css= is specified. */
|
||||
if (s && *s->string == '\0')
|
||||
return 0;
|
||||
|
||||
html("<link rel='stylesheet' type='text/css' href='");
|
||||
if (s)
|
||||
html_attr(s->string);
|
||||
else
|
||||
html_attr((const char *)arg);
|
||||
html("'/>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_js_link(struct string_list_item *s, void *arg)
|
||||
{
|
||||
/* Do not emit anything if js= is specified. */
|
||||
if (s && *s->string == '\0')
|
||||
return 0;
|
||||
|
||||
html("<script type='text/javascript' src='");
|
||||
if (s)
|
||||
html_attr(s->string);
|
||||
else
|
||||
html_attr((const char *)arg);
|
||||
html("'></script>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cgit_print_docstart(void)
|
||||
{
|
||||
char *host = cgit_hosturl();
|
||||
@ -787,9 +819,17 @@ void cgit_print_docstart(void)
|
||||
htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
|
||||
if (ctx.cfg.robots && *ctx.cfg.robots)
|
||||
htmlf("<meta name='robots' content='%s'/>\n", ctx.cfg.robots);
|
||||
html("<link rel='stylesheet' type='text/css' href='");
|
||||
html_attr(ctx.cfg.css);
|
||||
html("'/>\n");
|
||||
|
||||
if (ctx.cfg.css.items)
|
||||
for_each_string_list(&ctx.cfg.css, emit_css_link, NULL);
|
||||
else
|
||||
emit_css_link(NULL, "/cgit.css");
|
||||
|
||||
if (ctx.cfg.js.items)
|
||||
for_each_string_list(&ctx.cfg.js, emit_js_link, NULL);
|
||||
else
|
||||
emit_js_link(NULL, "/cgit.js");
|
||||
|
||||
if (ctx.cfg.favicon) {
|
||||
html("<link rel='shortcut icon' href='");
|
||||
html_attr(ctx.cfg.favicon);
|
||||
|
@ -241,8 +241,7 @@ static struct string_list collect_stats(const struct cgit_period *period)
|
||||
memset(&authors, 0, sizeof(authors));
|
||||
while ((commit = get_revision(&rev)) != NULL) {
|
||||
add_commit(&authors, commit, period);
|
||||
free_commit_buffer(the_repository->parsed_objects, commit);
|
||||
free_commit_list(commit->parents);
|
||||
release_commit_memory(the_repository->parsed_objects, commit);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
return authors;
|
||||
|
Loading…
x
Reference in New Issue
Block a user