summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--cgit.c6
-rw-r--r--cgit.h1
-rw-r--r--cgitrc.5.txt6
-rw-r--r--scan-tree.c2
-rw-r--r--shared.c2
-rw-r--r--ui-summary.c42
6 files changed, 39 insertions, 20 deletions
diff --git a/cgit.c b/cgit.c
index d6146e2..04cef23 100644
--- a/cgit.c
+++ b/cgit.c
@@ -51,73 +51,71 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
51 repo->clone_url = xstrdup(value); 51 repo->clone_url = xstrdup(value);
52 else if (!strcmp(name, "desc")) 52 else if (!strcmp(name, "desc"))
53 repo->desc = xstrdup(value); 53 repo->desc = xstrdup(value);
54 else if (!strcmp(name, "owner")) 54 else if (!strcmp(name, "owner"))
55 repo->owner = xstrdup(value); 55 repo->owner = xstrdup(value);
56 else if (!strcmp(name, "defbranch")) 56 else if (!strcmp(name, "defbranch"))
57 repo->defbranch = xstrdup(value); 57 repo->defbranch = xstrdup(value);
58 else if (!strcmp(name, "snapshots")) 58 else if (!strcmp(name, "snapshots"))
59 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); 59 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
60 else if (!strcmp(name, "enable-log-filecount")) 60 else if (!strcmp(name, "enable-log-filecount"))
61 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 61 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
62 else if (!strcmp(name, "enable-log-linecount")) 62 else if (!strcmp(name, "enable-log-linecount"))
63 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 63 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
64 else if (!strcmp(name, "enable-remote-branches")) 64 else if (!strcmp(name, "enable-remote-branches"))
65 repo->enable_remote_branches = atoi(value); 65 repo->enable_remote_branches = atoi(value);
66 else if (!strcmp(name, "enable-subject-links")) 66 else if (!strcmp(name, "enable-subject-links"))
67 repo->enable_subject_links = atoi(value); 67 repo->enable_subject_links = atoi(value);
68 else if (!strcmp(name, "max-stats")) 68 else if (!strcmp(name, "max-stats"))
69 repo->max_stats = cgit_find_stats_period(value, NULL); 69 repo->max_stats = cgit_find_stats_period(value, NULL);
70 else if (!strcmp(name, "module-link")) 70 else if (!strcmp(name, "module-link"))
71 repo->module_link= xstrdup(value); 71 repo->module_link= xstrdup(value);
72 else if (!strcmp(name, "section")) 72 else if (!strcmp(name, "section"))
73 repo->section = xstrdup(value); 73 repo->section = xstrdup(value);
74 else if (!strcmp(name, "readme") && value != NULL) { 74 else if (!strcmp(name, "readme") && value != NULL) {
75 char *colon;
76 if (*value == '/' || ((colon = strchr(value, ':')) != NULL && colon != value && *(colon + 1) != '\0'))
77 repo->readme = xstrdup(value); 75 repo->readme = xstrdup(value);
78 else
79 repo->readme = xstrdup(fmt("%s/%s", repo->path, value));
80 } else if (ctx.cfg.enable_filter_overrides) { 76 } else if (ctx.cfg.enable_filter_overrides) {
81 if (!strcmp(name, "about-filter")) 77 if (!strcmp(name, "about-filter"))
82 repo->about_filter = new_filter(value, 0); 78 repo->about_filter = new_filter(value, 0);
83 else if (!strcmp(name, "commit-filter")) 79 else if (!strcmp(name, "commit-filter"))
84 repo->commit_filter = new_filter(value, 0); 80 repo->commit_filter = new_filter(value, 0);
85 else if (!strcmp(name, "source-filter")) 81 else if (!strcmp(name, "source-filter"))
86 repo->source_filter = new_filter(value, 1); 82 repo->source_filter = new_filter(value, 1);
87 } 83 }
88} 84}
89 85
90void config_cb(const char *name, const char *value) 86void config_cb(const char *name, const char *value)
91{ 87{
92 if (!strcmp(name, "section") || !strcmp(name, "repo.group")) 88 if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
93 ctx.cfg.section = xstrdup(value); 89 ctx.cfg.section = xstrdup(value);
94 else if (!strcmp(name, "repo.url")) 90 else if (!strcmp(name, "repo.url"))
95 ctx.repo = cgit_add_repo(value); 91 ctx.repo = cgit_add_repo(value);
96 else if (ctx.repo && !strcmp(name, "repo.path")) 92 else if (ctx.repo && !strcmp(name, "repo.path"))
97 ctx.repo->path = trim_end(value, '/'); 93 ctx.repo->path = trim_end(value, '/');
98 else if (ctx.repo && !prefixcmp(name, "repo.")) 94 else if (ctx.repo && !prefixcmp(name, "repo."))
99 repo_config(ctx.repo, name + 5, value); 95 repo_config(ctx.repo, name + 5, value);
96 else if (!strcmp(name, "readme"))
97 ctx.cfg.readme = xstrdup(value);
100 else if (!strcmp(name, "root-title")) 98 else if (!strcmp(name, "root-title"))
101 ctx.cfg.root_title = xstrdup(value); 99 ctx.cfg.root_title = xstrdup(value);
102 else if (!strcmp(name, "root-desc")) 100 else if (!strcmp(name, "root-desc"))
103 ctx.cfg.root_desc = xstrdup(value); 101 ctx.cfg.root_desc = xstrdup(value);
104 else if (!strcmp(name, "root-readme")) 102 else if (!strcmp(name, "root-readme"))
105 ctx.cfg.root_readme = xstrdup(value); 103 ctx.cfg.root_readme = xstrdup(value);
106 else if (!strcmp(name, "css")) 104 else if (!strcmp(name, "css"))
107 ctx.cfg.css = xstrdup(value); 105 ctx.cfg.css = xstrdup(value);
108 else if (!strcmp(name, "favicon")) 106 else if (!strcmp(name, "favicon"))
109 ctx.cfg.favicon = xstrdup(value); 107 ctx.cfg.favicon = xstrdup(value);
110 else if (!strcmp(name, "footer")) 108 else if (!strcmp(name, "footer"))
111 ctx.cfg.footer = xstrdup(value); 109 ctx.cfg.footer = xstrdup(value);
112 else if (!strcmp(name, "head-include")) 110 else if (!strcmp(name, "head-include"))
113 ctx.cfg.head_include = xstrdup(value); 111 ctx.cfg.head_include = xstrdup(value);
114 else if (!strcmp(name, "header")) 112 else if (!strcmp(name, "header"))
115 ctx.cfg.header = xstrdup(value); 113 ctx.cfg.header = xstrdup(value);
116 else if (!strcmp(name, "logo")) 114 else if (!strcmp(name, "logo"))
117 ctx.cfg.logo = xstrdup(value); 115 ctx.cfg.logo = xstrdup(value);
118 else if (!strcmp(name, "index-header")) 116 else if (!strcmp(name, "index-header"))
119 ctx.cfg.index_header = xstrdup(value); 117 ctx.cfg.index_header = xstrdup(value);
120 else if (!strcmp(name, "index-info")) 118 else if (!strcmp(name, "index-info"))
121 ctx.cfg.index_info = xstrdup(value); 119 ctx.cfg.index_info = xstrdup(value);
122 else if (!strcmp(name, "logo-link")) 120 else if (!strcmp(name, "logo-link"))
123 ctx.cfg.logo_link = xstrdup(value); 121 ctx.cfg.logo_link = xstrdup(value);
diff --git a/cgit.h b/cgit.h
index 4090cd4..72fb1c7 100644
--- a/cgit.h
+++ b/cgit.h
@@ -147,48 +147,49 @@ struct cgit_query {
147 char *sort; 147 char *sort;
148 int showmsg; 148 int showmsg;
149 int ssdiff; 149 int ssdiff;
150 int show_all; 150 int show_all;
151 int context; 151 int context;
152 int ignorews; 152 int ignorews;
153 char *vpath; 153 char *vpath;
154}; 154};
155 155
156struct cgit_config { 156struct cgit_config {
157 char *agefile; 157 char *agefile;
158 char *cache_root; 158 char *cache_root;
159 char *clone_prefix; 159 char *clone_prefix;
160 char *css; 160 char *css;
161 char *favicon; 161 char *favicon;
162 char *footer; 162 char *footer;
163 char *head_include; 163 char *head_include;
164 char *header; 164 char *header;
165 char *index_header; 165 char *index_header;
166 char *index_info; 166 char *index_info;
167 char *logo; 167 char *logo;
168 char *logo_link; 168 char *logo_link;
169 char *module_link; 169 char *module_link;
170 char *project_list; 170 char *project_list;
171 char *readme;
171 char *robots; 172 char *robots;
172 char *root_title; 173 char *root_title;
173 char *root_desc; 174 char *root_desc;
174 char *root_readme; 175 char *root_readme;
175 char *script_name; 176 char *script_name;
176 char *section; 177 char *section;
177 char *virtual_root; 178 char *virtual_root;
178 int cache_size; 179 int cache_size;
179 int cache_dynamic_ttl; 180 int cache_dynamic_ttl;
180 int cache_max_create_time; 181 int cache_max_create_time;
181 int cache_repo_ttl; 182 int cache_repo_ttl;
182 int cache_root_ttl; 183 int cache_root_ttl;
183 int cache_scanrc_ttl; 184 int cache_scanrc_ttl;
184 int cache_static_ttl; 185 int cache_static_ttl;
185 int embedded; 186 int embedded;
186 int enable_filter_overrides; 187 int enable_filter_overrides;
187 int enable_gitweb_owner; 188 int enable_gitweb_owner;
188 int enable_index_links; 189 int enable_index_links;
189 int enable_log_filecount; 190 int enable_log_filecount;
190 int enable_log_linecount; 191 int enable_log_linecount;
191 int enable_remote_branches; 192 int enable_remote_branches;
192 int enable_subject_links; 193 int enable_subject_links;
193 int enable_tree_linenumbers; 194 int enable_tree_linenumbers;
194 int local_time; 195 int local_time;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index c643fae..187031a 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -213,48 +213,52 @@ mimetype.<ext>::
213module-link:: 213module-link::
214 Text which will be used as the formatstring for a hyperlink when a 214 Text which will be used as the formatstring for a hyperlink when a
215 submodule is printed in a directory listing. The arguments for the 215 submodule is printed in a directory listing. The arguments for the
216 formatstring are the path and SHA1 of the submodule commit. Default 216 formatstring are the path and SHA1 of the submodule commit. Default
217 value: "./?repo=%s&page=commit&id=%s" 217 value: "./?repo=%s&page=commit&id=%s"
218 218
219nocache:: 219nocache::
220 If set to the value "1" caching will be disabled. This settings is 220 If set to the value "1" caching will be disabled. This settings is
221 deprecated, and will not be honored starting with cgit-1.0. Default 221 deprecated, and will not be honored starting with cgit-1.0. Default
222 value: "0". 222 value: "0".
223 223
224noplainemail:: 224noplainemail::
225 If set to "1" showing full author email adresses will be disabled. 225 If set to "1" showing full author email adresses will be disabled.
226 Default value: "0". 226 Default value: "0".
227 227
228noheader:: 228noheader::
229 Flag which, when set to "1", will make cgit omit the standard header 229 Flag which, when set to "1", will make cgit omit the standard header
230 on all pages. Default value: none. See also: "embedded". 230 on all pages. Default value: none. See also: "embedded".
231 231
232project-list:: 232project-list::
233 A list of subdirectories inside of scan-path, relative to it, that 233 A list of subdirectories inside of scan-path, relative to it, that
234 should loaded as git repositories. This must be defined prior to 234 should loaded as git repositories. This must be defined prior to
235 scan-path. Default value: none. See also: scan-path. 235 scan-path. Default value: none. See also: scan-path.
236 236
237readme::
238 Text which will be used as default value for "repo.readme". Default
239 value: none.
240
237remove-suffix:: 241remove-suffix::
238 If set to "1" and scan-path is enabled, if any repositories are found 242 If set to "1" and scan-path is enabled, if any repositories are found
239 with a suffix of ".git", this suffix will be removed for the url and 243 with a suffix of ".git", this suffix will be removed for the url and
240 name. Default value: "0". See also: scan-path. 244 name. Default value: "0". See also: scan-path.
241 245
242renamelimit:: 246renamelimit::
243 Maximum number of files to consider when detecting renames. The value 247 Maximum number of files to consider when detecting renames. The value
244 "-1" uses the compiletime value in git (for further info, look at 248 "-1" uses the compiletime value in git (for further info, look at
245 `man git-diff`). Default value: "-1". 249 `man git-diff`). Default value: "-1".
246 250
247repo.group:: 251repo.group::
248 Legacy alias for "section". This option is deprecated and will not be 252 Legacy alias for "section". This option is deprecated and will not be
249 supported in cgit-1.0. 253 supported in cgit-1.0.
250 254
251robots:: 255robots::
252 Text used as content for the "robots" meta-tag. Default value: 256 Text used as content for the "robots" meta-tag. Default value:
253 "index, nofollow". 257 "index, nofollow".
254 258
255root-desc:: 259root-desc::
256 Text printed below the heading on the repository index page. Default 260 Text printed below the heading on the repository index page. Default
257 value: "a fast webinterface for the git dscm". 261 value: "a fast webinterface for the git dscm".
258 262
259root-readme:: 263root-readme::
260 The content of the file specified with this option will be included 264 The content of the file specified with this option will be included
@@ -352,49 +356,49 @@ repo.enable-remote-branches::
352repo.enable-subject-links:: 356repo.enable-subject-links::
353 A flag which can be used to override the global setting 357 A flag which can be used to override the global setting
354 `enable-subject-links'. Default value: none. 358 `enable-subject-links'. Default value: none.
355 359
356repo.max-stats:: 360repo.max-stats::
357 Override the default maximum statistics period. Valid values are equal 361 Override the default maximum statistics period. Valid values are equal
358 to the values specified for the global "max-stats" setting. Default 362 to the values specified for the global "max-stats" setting. Default
359 value: none. 363 value: none.
360 364
361repo.name:: 365repo.name::
362 The value to show as repository name. Default value: <repo.url>. 366 The value to show as repository name. Default value: <repo.url>.
363 367
364repo.owner:: 368repo.owner::
365 A value used to identify the owner of the repository. Default value: 369 A value used to identify the owner of the repository. Default value:
366 none. 370 none.
367 371
368repo.path:: 372repo.path::
369 An absolute path to the repository directory. For non-bare repositories 373 An absolute path to the repository directory. For non-bare repositories
370 this is the .git-directory. Default value: none. 374 this is the .git-directory. Default value: none.
371 375
372repo.readme:: 376repo.readme::
373 A path (relative to <repo.path>) which specifies a file to include 377 A path (relative to <repo.path>) which specifies a file to include
374 verbatim as the "About" page for this repo. You may also specify a 378 verbatim as the "About" page for this repo. You may also specify a
375 git refspec by head or by hash by prepending the refspec followed by 379 git refspec by head or by hash by prepending the refspec followed by
376 a colon. For example, "master:docs/readme.mkd" Default value: none. 380 a colon. For example, "master:docs/readme.mkd" Default value: <readme>.
377 381
378repo.snapshots:: 382repo.snapshots::
379 A mask of allowed snapshot-formats for this repo, restricted by the 383 A mask of allowed snapshot-formats for this repo, restricted by the
380 "snapshots" global setting. Default value: <snapshots>. 384 "snapshots" global setting. Default value: <snapshots>.
381 385
382repo.section:: 386repo.section::
383 Override the current section name for this repository. Default value: 387 Override the current section name for this repository. Default value:
384 none. 388 none.
385 389
386repo.source-filter:: 390repo.source-filter::
387 Override the default source-filter. Default value: none. See also: 391 Override the default source-filter. Default value: none. See also:
388 "enable-filter-overrides". 392 "enable-filter-overrides".
389 393
390repo.url:: 394repo.url::
391 The relative url used to access the repository. This must be the first 395 The relative url used to access the repository. This must be the first
392 setting specified for each repo. Default value: none. 396 setting specified for each repo. Default value: none.
393 397
394 398
395REPOSITORY-SPECIFIC CGITRC FILE 399REPOSITORY-SPECIFIC CGITRC FILE
396------------------------------- 400-------------------------------
397When the option "scan-path" is used to auto-discover git repositories, cgit 401When the option "scan-path" is used to auto-discover git repositories, cgit
398will try to parse the file "cgitrc" within any found repository. Such a 402will try to parse the file "cgitrc" within any found repository. Such a
399repo-specific config file may contain any of the repo-specific options 403repo-specific config file may contain any of the repo-specific options
400described above, except "repo.url" and "repo.path". Additionally, the "filter" 404described above, except "repo.url" and "repo.path". Additionally, the "filter"
diff --git a/scan-tree.c b/scan-tree.c
index e987824..780d405 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -89,51 +89,53 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)
89 89
90 repo = cgit_add_repo(xstrdup(p)); 90 repo = cgit_add_repo(xstrdup(p));
91 if (ctx.cfg.remove_suffix) 91 if (ctx.cfg.remove_suffix)
92 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git")) 92 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git"))
93 *p = '\0'; 93 *p = '\0';
94 repo->name = repo->url; 94 repo->name = repo->url;
95 repo->path = xstrdup(path); 95 repo->path = xstrdup(path);
96 while (!owner) { 96 while (!owner) {
97 if ((pwd = getpwuid(st.st_uid)) == NULL) { 97 if ((pwd = getpwuid(st.st_uid)) == NULL) {
98 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", 98 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
99 path, strerror(errno), errno); 99 path, strerror(errno), errno);
100 break; 100 break;
101 } 101 }
102 if (pwd->pw_gecos) 102 if (pwd->pw_gecos)
103 if ((p = strchr(pwd->pw_gecos, ','))) 103 if ((p = strchr(pwd->pw_gecos, ',')))
104 *p = '\0'; 104 *p = '\0';
105 owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name); 105 owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name);
106 } 106 }
107 repo->owner = owner; 107 repo->owner = owner;
108 108
109 p = fmt("%s/description", path); 109 p = fmt("%s/description", path);
110 if (!stat(p, &st)) 110 if (!stat(p, &st))
111 readfile(p, &repo->desc, &size); 111 readfile(p, &repo->desc, &size);
112 112
113 if (!repo->readme) {
113 p = fmt("%s/README.html", path); 114 p = fmt("%s/README.html", path);
114 if (!stat(p, &st)) 115 if (!stat(p, &st))
115 repo->readme = "README.html"; 116 repo->readme = "README.html";
117 }
116 118
117 p = fmt("%s/cgitrc", path); 119 p = fmt("%s/cgitrc", path);
118 if (!stat(p, &st)) { 120 if (!stat(p, &st)) {
119 config_fn = fn; 121 config_fn = fn;
120 parse_configfile(xstrdup(p), &repo_config); 122 parse_configfile(xstrdup(p), &repo_config);
121 } 123 }
122} 124}
123 125
124static void scan_path(const char *base, const char *path, repo_config_fn fn) 126static void scan_path(const char *base, const char *path, repo_config_fn fn)
125{ 127{
126 DIR *dir; 128 DIR *dir;
127 struct dirent *ent; 129 struct dirent *ent;
128 char *buf; 130 char *buf;
129 struct stat st; 131 struct stat st;
130 132
131 if (is_git_dir(path)) { 133 if (is_git_dir(path)) {
132 add_repo(base, path, fn); 134 add_repo(base, path, fn);
133 return; 135 return;
134 } 136 }
135 if (is_git_dir(fmt("%s/.git", path))) { 137 if (is_git_dir(fmt("%s/.git", path))) {
136 add_repo(base, fmt("%s/.git", path), fn); 138 add_repo(base, fmt("%s/.git", path), fn);
137 return; 139 return;
138 } 140 }
139 dir = opendir(path); 141 dir = opendir(path);
diff --git a/shared.c b/shared.c
index b42c2a2..72ac140 100644
--- a/shared.c
+++ b/shared.c
@@ -41,49 +41,49 @@ struct cgit_repo *cgit_add_repo(const char *url)
41 cgit_repolist.length = 8; 41 cgit_repolist.length = 8;
42 else 42 else
43 cgit_repolist.length *= 2; 43 cgit_repolist.length *= 2;
44 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 44 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
45 cgit_repolist.length * 45 cgit_repolist.length *
46 sizeof(struct cgit_repo)); 46 sizeof(struct cgit_repo));
47 } 47 }
48 48
49 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 49 ret = &cgit_repolist.repos[cgit_repolist.count-1];
50 memset(ret, 0, sizeof(struct cgit_repo)); 50 memset(ret, 0, sizeof(struct cgit_repo));
51 ret->url = trim_end(url, '/'); 51 ret->url = trim_end(url, '/');
52 ret->name = ret->url; 52 ret->name = ret->url;
53 ret->path = NULL; 53 ret->path = NULL;
54 ret->desc = "[no description]"; 54 ret->desc = "[no description]";
55 ret->owner = NULL; 55 ret->owner = NULL;
56 ret->section = ctx.cfg.section; 56 ret->section = ctx.cfg.section;
57 ret->defbranch = "master"; 57 ret->defbranch = "master";
58 ret->snapshots = ctx.cfg.snapshots; 58 ret->snapshots = ctx.cfg.snapshots;
59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
61 ret->enable_remote_branches = ctx.cfg.enable_remote_branches; 61 ret->enable_remote_branches = ctx.cfg.enable_remote_branches;
62 ret->enable_subject_links = ctx.cfg.enable_subject_links; 62 ret->enable_subject_links = ctx.cfg.enable_subject_links;
63 ret->max_stats = ctx.cfg.max_stats; 63 ret->max_stats = ctx.cfg.max_stats;
64 ret->module_link = ctx.cfg.module_link; 64 ret->module_link = ctx.cfg.module_link;
65 ret->readme = NULL; 65 ret->readme = ctx.cfg.readme;
66 ret->mtime = -1; 66 ret->mtime = -1;
67 ret->about_filter = ctx.cfg.about_filter; 67 ret->about_filter = ctx.cfg.about_filter;
68 ret->commit_filter = ctx.cfg.commit_filter; 68 ret->commit_filter = ctx.cfg.commit_filter;
69 ret->source_filter = ctx.cfg.source_filter; 69 ret->source_filter = ctx.cfg.source_filter;
70 return ret; 70 return ret;
71} 71}
72 72
73struct cgit_repo *cgit_get_repoinfo(const char *url) 73struct cgit_repo *cgit_get_repoinfo(const char *url)
74{ 74{
75 int i; 75 int i;
76 struct cgit_repo *repo; 76 struct cgit_repo *repo;
77 77
78 for (i=0; i<cgit_repolist.count; i++) { 78 for (i=0; i<cgit_repolist.count; i++) {
79 repo = &cgit_repolist.repos[i]; 79 repo = &cgit_repolist.repos[i];
80 if (!strcmp(repo->url, url)) 80 if (!strcmp(repo->url, url))
81 return repo; 81 return repo;
82 } 82 }
83 return NULL; 83 return NULL;
84} 84}
85 85
86void *cgit_free_commitinfo(struct commitinfo *info) 86void *cgit_free_commitinfo(struct commitinfo *info)
87{ 87{
88 free(info->author); 88 free(info->author);
89 free(info->author_email); 89 free(info->author_email);
diff --git a/ui-summary.c b/ui-summary.c
index 02f191e..b203bcc 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -49,62 +49,76 @@ static void print_urls(char *txt, char *suffix)
49 h = t; 49 h = t;
50 } 50 }
51} 51}
52 52
53void cgit_print_summary() 53void cgit_print_summary()
54{ 54{
55 html("<table summary='repository info' class='list nowrap'>"); 55 html("<table summary='repository info' class='list nowrap'>");
56 cgit_print_branches(ctx.cfg.summary_branches); 56 cgit_print_branches(ctx.cfg.summary_branches);
57 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 57 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
58 cgit_print_tags(ctx.cfg.summary_tags); 58 cgit_print_tags(ctx.cfg.summary_tags);
59 if (ctx.cfg.summary_log > 0) { 59 if (ctx.cfg.summary_log > 0) {
60 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>"); 60 html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
61 cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, 61 cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL,
62 NULL, NULL, 0); 62 NULL, NULL, 0);
63 } 63 }
64 if (ctx.repo->clone_url) 64 if (ctx.repo->clone_url)
65 print_urls(ctx.repo->clone_url, NULL); 65 print_urls(ctx.repo->clone_url, NULL);
66 else if (ctx.cfg.clone_prefix) 66 else if (ctx.cfg.clone_prefix)
67 print_urls(ctx.cfg.clone_prefix, ctx.repo->url); 67 print_urls(ctx.cfg.clone_prefix, ctx.repo->url);
68 html("</table>"); 68 html("</table>");
69} 69}
70 70
71void cgit_print_repo_readme(char *path) 71void cgit_print_repo_readme(char *path)
72{ 72{
73 char *slash, *tmp, *colon, *ref = 0; 73 char *slash, *tmp, *colon, *ref;
74 74
75 if (!ctx.repo->readme) 75 if (!ctx.repo->readme || !(*ctx.repo->readme))
76 return; 76 return;
77 77
78 ref = NULL;
79
80 /* Check if the readme is tracked in the git repo. */
81 colon = strchr(ctx.repo->readme, ':');
82 if (colon && strlen(colon) > 1) {
83 *colon = '\0';
84 ref = ctx.repo->readme;
85 ctx.repo->readme = colon + 1;
86 if (!(*ctx.repo->readme))
87 return;
88 }
89
90 /* Prepend repo path to relative readme path unless tracked. */
91 if (!ref && *ctx.repo->readme != '/')
92 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path,
93 ctx.repo->readme));
94
95 /* If a subpath is specified for the about page, make it relative
96 * to the directory containing the configured readme.
97 */
78 if (path) { 98 if (path) {
79 slash = strrchr(ctx.repo->readme, '/'); 99 slash = strrchr(ctx.repo->readme, '/');
80 if (!slash) { 100 if (!slash) {
81 slash = strchr(ctx.repo->readme, ':'); 101 if (!colon)
82 if (!slash)
83 return; 102 return;
103 slash = colon;
84 } 104 }
85 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1); 105 tmp = xmalloc(slash - ctx.repo->readme + 1 + strlen(path) + 1);
86 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1); 106 strncpy(tmp, ctx.repo->readme, slash - ctx.repo->readme + 1);
87 strcpy(tmp + (slash - ctx.repo->readme + 1), path); 107 strcpy(tmp + (slash - ctx.repo->readme + 1), path);
88 } else 108 } else
89 tmp = ctx.repo->readme; 109 tmp = ctx.repo->readme;
90 colon = strchr(tmp, ':'); 110
91 if (colon && strlen(colon) > 1) { 111 /* Print the calculated readme, either from the git repo or from the
92 *colon = '\0'; 112 * filesystem, while applying the about-filter.
93 ref = tmp; 113 */
94 tmp = colon + 1;
95 while ((*tmp == '/' || *tmp == ':') && *tmp != '\0')
96 ++tmp;
97 if (!(*tmp))
98 return;
99 }
100 html("<div id='summary'>"); 114 html("<div id='summary'>");
101 if (ctx.repo->about_filter) 115 if (ctx.repo->about_filter)
102 cgit_open_filter(ctx.repo->about_filter); 116 cgit_open_filter(ctx.repo->about_filter);
103 if (ref) 117 if (ref)
104 cgit_print_file(tmp, ref); 118 cgit_print_file(tmp, ref);
105 else 119 else
106 html_include(tmp); 120 html_include(tmp);
107 if (ctx.repo->about_filter) 121 if (ctx.repo->about_filter)
108 cgit_close_filter(ctx.repo->about_filter); 122 cgit_close_filter(ctx.repo->about_filter);
109 html("</div>"); 123 html("</div>");
110} 124}