summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c2
-rw-r--r--cgit.h1
-rw-r--r--ui-repolist.c39
3 files changed, 39 insertions, 3 deletions
diff --git a/cgit.c b/cgit.c
index c82587b..e09c86e 100644
--- a/cgit.c
+++ b/cgit.c
@@ -125,64 +125,66 @@ void config_cb(const char *name, const char *value)
125 125
126static void querystring_cb(const char *name, const char *value) 126static void querystring_cb(const char *name, const char *value)
127{ 127{
128 if (!strcmp(name,"r")) { 128 if (!strcmp(name,"r")) {
129 ctx.qry.repo = xstrdup(value); 129 ctx.qry.repo = xstrdup(value);
130 ctx.repo = cgit_get_repoinfo(value); 130 ctx.repo = cgit_get_repoinfo(value);
131 } else if (!strcmp(name, "p")) { 131 } else if (!strcmp(name, "p")) {
132 ctx.qry.page = xstrdup(value); 132 ctx.qry.page = xstrdup(value);
133 } else if (!strcmp(name, "url")) { 133 } else if (!strcmp(name, "url")) {
134 ctx.qry.url = xstrdup(value); 134 ctx.qry.url = xstrdup(value);
135 cgit_parse_url(value); 135 cgit_parse_url(value);
136 } else if (!strcmp(name, "qt")) { 136 } else if (!strcmp(name, "qt")) {
137 ctx.qry.grep = xstrdup(value); 137 ctx.qry.grep = xstrdup(value);
138 } else if (!strcmp(name, "q")) { 138 } else if (!strcmp(name, "q")) {
139 ctx.qry.search = xstrdup(value); 139 ctx.qry.search = xstrdup(value);
140 } else if (!strcmp(name, "h")) { 140 } else if (!strcmp(name, "h")) {
141 ctx.qry.head = xstrdup(value); 141 ctx.qry.head = xstrdup(value);
142 ctx.qry.has_symref = 1; 142 ctx.qry.has_symref = 1;
143 } else if (!strcmp(name, "id")) { 143 } else if (!strcmp(name, "id")) {
144 ctx.qry.sha1 = xstrdup(value); 144 ctx.qry.sha1 = xstrdup(value);
145 ctx.qry.has_sha1 = 1; 145 ctx.qry.has_sha1 = 1;
146 } else if (!strcmp(name, "id2")) { 146 } else if (!strcmp(name, "id2")) {
147 ctx.qry.sha2 = xstrdup(value); 147 ctx.qry.sha2 = xstrdup(value);
148 ctx.qry.has_sha1 = 1; 148 ctx.qry.has_sha1 = 1;
149 } else if (!strcmp(name, "ofs")) { 149 } else if (!strcmp(name, "ofs")) {
150 ctx.qry.ofs = atoi(value); 150 ctx.qry.ofs = atoi(value);
151 } else if (!strcmp(name, "path")) { 151 } else if (!strcmp(name, "path")) {
152 ctx.qry.path = trim_end(value, '/'); 152 ctx.qry.path = trim_end(value, '/');
153 } else if (!strcmp(name, "name")) { 153 } else if (!strcmp(name, "name")) {
154 ctx.qry.name = xstrdup(value); 154 ctx.qry.name = xstrdup(value);
155 } else if (!strcmp(name, "mimetype")) { 155 } else if (!strcmp(name, "mimetype")) {
156 ctx.qry.mimetype = xstrdup(value); 156 ctx.qry.mimetype = xstrdup(value);
157 } else if (!strcmp(name, "s")){
158 ctx.qry.sort = xstrdup(value);
157 } 159 }
158} 160}
159 161
160static void prepare_context(struct cgit_context *ctx) 162static void prepare_context(struct cgit_context *ctx)
161{ 163{
162 memset(ctx, 0, sizeof(ctx)); 164 memset(ctx, 0, sizeof(ctx));
163 ctx->cfg.agefile = "info/web/last-modified"; 165 ctx->cfg.agefile = "info/web/last-modified";
164 ctx->cfg.nocache = 0; 166 ctx->cfg.nocache = 0;
165 ctx->cfg.cache_size = 0; 167 ctx->cfg.cache_size = 0;
166 ctx->cfg.cache_dynamic_ttl = 5; 168 ctx->cfg.cache_dynamic_ttl = 5;
167 ctx->cfg.cache_max_create_time = 5; 169 ctx->cfg.cache_max_create_time = 5;
168 ctx->cfg.cache_repo_ttl = 5; 170 ctx->cfg.cache_repo_ttl = 5;
169 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 171 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
170 ctx->cfg.cache_root_ttl = 5; 172 ctx->cfg.cache_root_ttl = 5;
171 ctx->cfg.cache_static_ttl = -1; 173 ctx->cfg.cache_static_ttl = -1;
172 ctx->cfg.css = "/cgit.css"; 174 ctx->cfg.css = "/cgit.css";
173 ctx->cfg.logo = "/git-logo.png"; 175 ctx->cfg.logo = "/git-logo.png";
174 ctx->cfg.local_time = 0; 176 ctx->cfg.local_time = 0;
175 ctx->cfg.max_repo_count = 50; 177 ctx->cfg.max_repo_count = 50;
176 ctx->cfg.max_commit_count = 50; 178 ctx->cfg.max_commit_count = 50;
177 ctx->cfg.max_lock_attempts = 5; 179 ctx->cfg.max_lock_attempts = 5;
178 ctx->cfg.max_msg_len = 80; 180 ctx->cfg.max_msg_len = 80;
179 ctx->cfg.max_repodesc_len = 80; 181 ctx->cfg.max_repodesc_len = 80;
180 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 182 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
181 ctx->cfg.renamelimit = -1; 183 ctx->cfg.renamelimit = -1;
182 ctx->cfg.robots = "index, nofollow"; 184 ctx->cfg.robots = "index, nofollow";
183 ctx->cfg.root_title = "Git repository browser"; 185 ctx->cfg.root_title = "Git repository browser";
184 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 186 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
185 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 187 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
186 ctx->cfg.summary_branches = 10; 188 ctx->cfg.summary_branches = 10;
187 ctx->cfg.summary_log = 10; 189 ctx->cfg.summary_log = 10;
188 ctx->cfg.summary_tags = 10; 190 ctx->cfg.summary_tags = 10;
diff --git a/cgit.h b/cgit.h
index 91db98a..ea90833 100644
--- a/cgit.h
+++ b/cgit.h
@@ -92,64 +92,65 @@ struct taginfo {
92struct refinfo { 92struct refinfo {
93 const char *refname; 93 const char *refname;
94 struct object *object; 94 struct object *object;
95 union { 95 union {
96 struct taginfo *tag; 96 struct taginfo *tag;
97 struct commitinfo *commit; 97 struct commitinfo *commit;
98 }; 98 };
99}; 99};
100 100
101struct reflist { 101struct reflist {
102 struct refinfo **refs; 102 struct refinfo **refs;
103 int alloc; 103 int alloc;
104 int count; 104 int count;
105}; 105};
106 106
107struct cgit_query { 107struct cgit_query {
108 int has_symref; 108 int has_symref;
109 int has_sha1; 109 int has_sha1;
110 char *raw; 110 char *raw;
111 char *repo; 111 char *repo;
112 char *page; 112 char *page;
113 char *search; 113 char *search;
114 char *grep; 114 char *grep;
115 char *head; 115 char *head;
116 char *sha1; 116 char *sha1;
117 char *sha2; 117 char *sha2;
118 char *path; 118 char *path;
119 char *name; 119 char *name;
120 char *mimetype; 120 char *mimetype;
121 char *url; 121 char *url;
122 int ofs; 122 int ofs;
123 int nohead; 123 int nohead;
124 char *sort;
124}; 125};
125 126
126struct cgit_config { 127struct cgit_config {
127 char *agefile; 128 char *agefile;
128 char *cache_root; 129 char *cache_root;
129 char *clone_prefix; 130 char *clone_prefix;
130 char *css; 131 char *css;
131 char *favicon; 132 char *favicon;
132 char *footer; 133 char *footer;
133 char *index_header; 134 char *index_header;
134 char *index_info; 135 char *index_info;
135 char *logo; 136 char *logo;
136 char *logo_link; 137 char *logo_link;
137 char *module_link; 138 char *module_link;
138 char *repo_group; 139 char *repo_group;
139 char *robots; 140 char *robots;
140 char *root_title; 141 char *root_title;
141 char *root_desc; 142 char *root_desc;
142 char *root_readme; 143 char *root_readme;
143 char *script_name; 144 char *script_name;
144 char *virtual_root; 145 char *virtual_root;
145 int cache_size; 146 int cache_size;
146 int cache_dynamic_ttl; 147 int cache_dynamic_ttl;
147 int cache_max_create_time; 148 int cache_max_create_time;
148 int cache_repo_ttl; 149 int cache_repo_ttl;
149 int cache_root_ttl; 150 int cache_root_ttl;
150 int cache_static_ttl; 151 int cache_static_ttl;
151 int enable_index_links; 152 int enable_index_links;
152 int enable_log_filecount; 153 int enable_log_filecount;
153 int enable_log_linecount; 154 int enable_log_linecount;
154 int local_time; 155 int local_time;
155 int max_repo_count; 156 int max_repo_count;
diff --git a/ui-repolist.c b/ui-repolist.c
index c23232c..312a7ee 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -46,113 +46,146 @@ static void print_modtime(struct cgit_repo *repo)
46} 46}
47 47
48int is_match(struct cgit_repo *repo) 48int is_match(struct cgit_repo *repo)
49{ 49{
50 if (!ctx.qry.search) 50 if (!ctx.qry.search)
51 return 1; 51 return 1;
52 if (repo->url && strcasestr(repo->url, ctx.qry.search)) 52 if (repo->url && strcasestr(repo->url, ctx.qry.search))
53 return 1; 53 return 1;
54 if (repo->name && strcasestr(repo->name, ctx.qry.search)) 54 if (repo->name && strcasestr(repo->name, ctx.qry.search))
55 return 1; 55 return 1;
56 if (repo->desc && strcasestr(repo->desc, ctx.qry.search)) 56 if (repo->desc && strcasestr(repo->desc, ctx.qry.search))
57 return 1; 57 return 1;
58 if (repo->owner && strcasestr(repo->owner, ctx.qry.search)) 58 if (repo->owner && strcasestr(repo->owner, ctx.qry.search))
59 return 1; 59 return 1;
60 return 0; 60 return 0;
61} 61}
62 62
63int is_in_url(struct cgit_repo *repo) 63int is_in_url(struct cgit_repo *repo)
64{ 64{
65 if (!ctx.qry.url) 65 if (!ctx.qry.url)
66 return 1; 66 return 1;
67 if (repo->url && !prefixcmp(repo->url, ctx.qry.url)) 67 if (repo->url && !prefixcmp(repo->url, ctx.qry.url))
68 return 1; 68 return 1;
69 return 0; 69 return 0;
70} 70}
71 71
72void print_header(int columns) 72void print_header(int columns)
73{ 73{
74 html("<tr class='nohover'>" 74 html("<tr class='nohover'>"
75 "<th class='left'>Name</th>" 75 "<th class='left'>Name</th>"
76 "<th class='left'>Description</th>" 76 "<th class='left'>Description</th>"
77 "<th class='left'>Owner</th>" 77 "<th class='left'>Owner</th>"
78 "<th class='left'>Idle</th>"); 78 "<th class='left'><a href=\"?s=1\">Idle</a></th>");
79 if (ctx.cfg.enable_index_links) 79 if (ctx.cfg.enable_index_links)
80 html("<th class='left'>Links</th>"); 80 html("<th class='left'>Links</th>");
81 html("</tr>\n"); 81 html("</tr>\n");
82} 82}
83 83
84 84
85void print_pager(int items, int pagelen, char *search) 85void print_pager(int items, int pagelen, char *search)
86{ 86{
87 int i; 87 int i;
88 html("<div class='pager'>"); 88 html("<div class='pager'>");
89 for(i = 0; i * pagelen < items; i++) 89 for(i = 0; i * pagelen < items; i++)
90 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, 90 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL,
91 search, i * pagelen); 91 search, i * pagelen);
92 html("</div>"); 92 html("</div>");
93} 93}
94 94
95static int cgit_reposort_modtime(const void *a, const void *b)
96{
97 const struct cgit_repo *r1 = a;
98 const struct cgit_repo *r2 = b;
99 char *path;
100 struct stat s;
101 time_t t1, t2;
102 path = fmt("%s/%s", r1->path, ctx.cfg.agefile);
103 if (stat(path, &s) == 0) {
104 t1 = read_agefile(path);
105 } else {
106 path = fmt("%s/refs/heads/%s", r1->path, r1->defbranch);
107 if (stat(path, &s) != 0)
108 return 0;
109 t1 =s.st_mtime;
110 }
111
112 path = fmt("%s/%s", r2->path, ctx.cfg.agefile);
113 if (stat(path, &s) == 0) {
114 t2 = read_agefile(path);
115 } else {
116 path = fmt("%s/refs/heads/%s", r2->path, r2->defbranch);
117 if (stat(path, &s) != 0)
118 return 0;
119 t2 =s.st_mtime;
120 }
121 return t2-t1;
122}
123
95void cgit_print_repolist() 124void cgit_print_repolist()
96{ 125{
97 int i, columns = 4, hits = 0, header = 0; 126 int i, columns = 4, hits = 0, header = 0;
98 char *last_group = NULL; 127 char *last_group = NULL;
99 128
100 if (ctx.cfg.enable_index_links) 129 if (ctx.cfg.enable_index_links)
101 columns++; 130 columns++;
102 131
103 ctx.page.title = ctx.cfg.root_title; 132 ctx.page.title = ctx.cfg.root_title;
104 cgit_print_http_headers(&ctx); 133 cgit_print_http_headers(&ctx);
105 cgit_print_docstart(&ctx); 134 cgit_print_docstart(&ctx);
106 cgit_print_pageheader(&ctx); 135 cgit_print_pageheader(&ctx);
107 136
108 if (ctx.cfg.index_header) 137 if (ctx.cfg.index_header)
109 html_include(ctx.cfg.index_header); 138 html_include(ctx.cfg.index_header);
110 139
140 if(ctx.qry.sort)
141 qsort(cgit_repolist.repos,cgit_repolist.count,sizeof(struct cgit_repo),cgit_reposort_modtime);
142
111 html("<table summary='repository list' class='list nowrap'>"); 143 html("<table summary='repository list' class='list nowrap'>");
112 for (i=0; i<cgit_repolist.count; i++) { 144 for (i=0; i<cgit_repolist.count; i++) {
113 ctx.repo = &cgit_repolist.repos[i]; 145 ctx.repo = &cgit_repolist.repos[i];
114 if (!(is_match(ctx.repo) && is_in_url(ctx.repo))) 146 if (!(is_match(ctx.repo) && is_in_url(ctx.repo)))
115 continue; 147 continue;
116 hits++; 148 hits++;
117 if (hits <= ctx.qry.ofs) 149 if (hits <= ctx.qry.ofs)
118 continue; 150 continue;
119 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) 151 if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count)
120 continue; 152 continue;
121 if (!header++) 153 if (!header++)
122 print_header(columns); 154 print_header(columns);
123 if ((last_group == NULL && ctx.repo->group != NULL) || 155 if (!ctx.qry.sort &&
156 ((last_group == NULL && ctx.repo->group != NULL) ||
124 (last_group != NULL && ctx.repo->group == NULL) || 157 (last_group != NULL && ctx.repo->group == NULL) ||
125 (last_group != NULL && ctx.repo->group != NULL && 158 (last_group != NULL && ctx.repo->group != NULL &&
126 strcmp(ctx.repo->group, last_group))) { 159 strcmp(ctx.repo->group, last_group)))) {
127 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", 160 htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
128 columns); 161 columns);
129 html_txt(ctx.repo->group); 162 html_txt(ctx.repo->group);
130 html("</td></tr>"); 163 html("</td></tr>");
131 last_group = ctx.repo->group; 164 last_group = ctx.repo->group;
132 } 165 }
133 htmlf("<tr><td class='%s'>", 166 htmlf("<tr><td class='%s'>",
134 ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); 167 ctx.repo->group ? "sublevel-repo" : "toplevel-repo");
135 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); 168 cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);
136 html("</td><td>"); 169 html("</td><td>");
137 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); 170 html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL);
138 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); 171 html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc);
139 html_link_close(); 172 html_link_close();
140 html("</td><td>"); 173 html("</td><td>");
141 html_txt(ctx.repo->owner); 174 html_txt(ctx.repo->owner);
142 html("</td><td>"); 175 html("</td><td>");
143 print_modtime(ctx.repo); 176 print_modtime(ctx.repo);
144 html("</td>"); 177 html("</td>");
145 if (ctx.cfg.enable_index_links) { 178 if (ctx.cfg.enable_index_links) {
146 html("<td>"); 179 html("<td>");
147 cgit_summary_link("summary", NULL, "button", NULL); 180 cgit_summary_link("summary", NULL, "button", NULL);
148 cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 181 cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
149 0, NULL, NULL); 182 0, NULL, NULL);
150 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); 183 cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL);
151 html("</td>"); 184 html("</td>");
152 } 185 }
153 html("</tr>\n"); 186 html("</tr>\n");
154 } 187 }
155 html("</table>"); 188 html("</table>");
156 if (!hits) 189 if (!hits)
157 cgit_print_error("No repositories found"); 190 cgit_print_error("No repositories found");
158 else if (hits > ctx.cfg.max_repo_count) 191 else if (hits > ctx.cfg.max_repo_count)