summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2008-09-14 22:07:12 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-09-15 21:35:27 (UTC)
commit93397a765b9d9af11b7d10c114406e303ea4fb1c (patch) (unidiff)
treefa40c0c8df7549525123359bf817598ae7e9f43d
parente154edd8078020d6eba41b448afade0a68617f35 (diff)
downloadcgit-93397a765b9d9af11b7d10c114406e303ea4fb1c.zip
cgit-93397a765b9d9af11b7d10c114406e303ea4fb1c.tar.gz
cgit-93397a765b9d9af11b7d10c114406e303ea4fb1c.tar.bz2
Add support for --scan-tree=<path> option to cgit
This option makes cgit scan a directory tree looking for git repositories, generating suitable definitions for a cgitrc file on stdout. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile1
-rw-r--r--cgit.c47
-rw-r--r--scan-tree.c136
-rw-r--r--scan-tree.h3
4 files changed, 184 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index a1caaf4..302ff4c 100644
--- a/Makefile
+++ b/Makefile
@@ -54,6 +54,7 @@ OBJECTS += cmd.o
54OBJECTS += configfile.o 54OBJECTS += configfile.o
55OBJECTS += html.o 55OBJECTS += html.o
56OBJECTS += parsing.o 56OBJECTS += parsing.o
57OBJECTS += scan-tree.o
57OBJECTS += shared.o 58OBJECTS += shared.o
58OBJECTS += ui-atom.o 59OBJECTS += ui-atom.o
59OBJECTS += ui-blob.o 60OBJECTS += ui-blob.o
diff --git a/cgit.c b/cgit.c
index a47cad0..5a93fcd 100644
--- a/cgit.c
+++ b/cgit.c
@@ -12,6 +12,7 @@
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14#include "ui-shared.h" 14#include "ui-shared.h"
15#include "scan-tree.h"
15 16
16const char *cgit_version = CGIT_VERSION; 17const char *cgit_version = CGIT_VERSION;
17 18
@@ -320,9 +321,39 @@ static void process_request(void *cbdata)
320 cgit_print_docend(); 321 cgit_print_docend();
321} 322}
322 323
324int cmp_repos(const void *a, const void *b)
325{
326 const struct cgit_repo *ra = a, *rb = b;
327 return strcmp(ra->url, rb->url);
328}
329
330void print_repo(struct cgit_repo *repo)
331{
332 printf("repo.url=%s\n", repo->url);
333 printf("repo.name=%s\n", repo->name);
334 printf("repo.path=%s\n", repo->path);
335 if (repo->owner)
336 printf("repo.owner=%s\n", repo->owner);
337 if (repo->desc)
338 printf("repo.desc=%s\n", repo->desc);
339 if (repo->readme)
340 printf("repo.readme=%s\n", repo->readme);
341 printf("\n");
342}
343
344void print_repolist(struct cgit_repolist *list)
345{
346 int i;
347
348 for(i = 0; i < list->count; i++)
349 print_repo(&list->repos[i]);
350}
351
352
323static void cgit_parse_args(int argc, const char **argv) 353static void cgit_parse_args(int argc, const char **argv)
324{ 354{
325 int i; 355 int i;
356 int scan = 0;
326 357
327 for (i = 1; i < argc; i++) { 358 for (i = 1; i < argc; i++) {
328 if (!strncmp(argv[i], "--cache=", 8)) { 359 if (!strncmp(argv[i], "--cache=", 8)) {
@@ -351,6 +382,16 @@ static void cgit_parse_args(int argc, const char **argv)
351 if (!strncmp(argv[i], "--ofs=", 6)) { 382 if (!strncmp(argv[i], "--ofs=", 6)) {
352 ctx.qry.ofs = atoi(argv[i]+6); 383 ctx.qry.ofs = atoi(argv[i]+6);
353 } 384 }
385 if (!strncmp(argv[i], "--scan-tree=", 12)) {
386 scan++;
387 scan_tree(argv[i] + 12);
388 }
389 }
390 if (scan) {
391 qsort(cgit_repolist.repos, cgit_repolist.count,
392 sizeof(struct cgit_repo), cmp_repos);
393 print_repolist(&cgit_repolist);
394 exit(0);
354 } 395 }
355} 396}
356 397
@@ -383,14 +424,14 @@ int main(int argc, const char **argv)
383 cgit_repolist.count = 0; 424 cgit_repolist.count = 0;
384 cgit_repolist.repos = NULL; 425 cgit_repolist.repos = NULL;
385 426
386 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
387 config_cb);
388 ctx.repo = NULL;
389 if (getenv("SCRIPT_NAME")) 427 if (getenv("SCRIPT_NAME"))
390 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); 428 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
391 if (getenv("QUERY_STRING")) 429 if (getenv("QUERY_STRING"))
392 ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); 430 ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
393 cgit_parse_args(argc, argv); 431 cgit_parse_args(argc, argv);
432 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
433 config_cb);
434 ctx.repo = NULL;
394 http_parse_querystring(ctx.qry.raw, querystring_cb); 435 http_parse_querystring(ctx.qry.raw, querystring_cb);
395 436
396 /* If virtual-root isn't specified in cgitrc and no url 437 /* If virtual-root isn't specified in cgitrc and no url
diff --git a/scan-tree.c b/scan-tree.c
new file mode 100644
index 0000000..cdafb02
--- a/dev/null
+++ b/scan-tree.c
@@ -0,0 +1,136 @@
1#include "cgit.h"
2#include "html.h"
3
4#define MAX_PATH 4096
5
6/* return 1 if path contains a objects/ directory and a HEAD file */
7static int is_git_dir(const char *path)
8{
9 struct stat st;
10 static char buf[MAX_PATH];
11
12 if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) {
13 fprintf(stderr, "Insanely long path: %s\n", path);
14 return 0;
15 }
16 if (stat(buf, &st)) {
17 if (errno != ENOENT)
18 fprintf(stderr, "Error checking path %s: %s (%d)\n",
19 path, strerror(errno), errno);
20 return 0;
21 }
22 if (!S_ISDIR(st.st_mode))
23 return 0;
24
25 sprintf(buf, "%s/HEAD", path);
26 if (stat(buf, &st)) {
27 if (errno != ENOENT)
28 fprintf(stderr, "Error checking path %s: %s (%d)\n",
29 path, strerror(errno), errno);
30 return 0;
31 }
32 if (!S_ISREG(st.st_mode))
33 return 0;
34
35 return 1;
36}
37
38char *readfile(const char *path)
39{
40 FILE *f;
41 static char buf[MAX_PATH];
42
43 if (!(f = fopen(path, "r")))
44 return NULL;
45 fgets(buf, MAX_PATH, f);
46 fclose(f);
47 return buf;
48}
49
50static void add_repo(const char *base, const char *path)
51{
52 struct cgit_repo *repo;
53 struct stat st;
54 struct passwd *pwd;
55 char *p;
56
57 if (stat(path, &st)) {
58 fprintf(stderr, "Error accessing %s: %s (%d)\n",
59 path, strerror(errno), errno);
60 return;
61 }
62 if ((pwd = getpwuid(st.st_uid)) == NULL) {
63 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
64 path, strerror(errno), errno);
65 return;
66 }
67 if (base == path)
68 p = fmt("%s", path);
69 else
70 p = fmt("%s", path + strlen(base) + 1);
71
72 if (!strcmp(p + strlen(p) - 5, "/.git"))
73 p[strlen(p) - 5] = '\0';
74
75 repo = cgit_add_repo(xstrdup(p));
76 repo->name = repo->url;
77 repo->path = xstrdup(path);
78 repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : "");
79
80 p = fmt("%s/description", path);
81 if (!stat(p, &st))
82 repo->desc = xstrdup(readfile(p));
83
84 p = fmt("%s/README.html", path);
85 if (!stat(p, &st))
86 repo->readme = "README.html";
87}
88
89static void scan_path(const char *base, const char *path)
90{
91 DIR *dir;
92 struct dirent *ent;
93 char *buf;
94 struct stat st;
95
96 if (is_git_dir(path)) {
97 add_repo(base, path);
98 return;
99 }
100 dir = opendir(path);
101 if (!dir) {
102 fprintf(stderr, "Error opening directory %s: %s (%d)\n",
103 path, strerror(errno), errno);
104 return;
105 }
106 while((ent = readdir(dir)) != NULL) {
107 if (ent->d_name[0] == '.') {
108 if (ent->d_name[1] == '\0')
109 continue;
110 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
111 continue;
112 }
113 buf = malloc(strlen(path) + strlen(ent->d_name) + 2);
114 if (!buf) {
115 fprintf(stderr, "Alloc error on %s: %s (%d)\n",
116 path, strerror(errno), errno);
117 exit(1);
118 }
119 sprintf(buf, "%s/%s", path, ent->d_name);
120 if (stat(buf, &st)) {
121 fprintf(stderr, "Error checking path %s: %s (%d)\n",
122 buf, strerror(errno), errno);
123 free(buf);
124 continue;
125 }
126 if (S_ISDIR(st.st_mode))
127 scan_path(base, buf);
128 free(buf);
129 }
130 closedir(dir);
131}
132
133void scan_tree(const char *path)
134{
135 scan_path(path, path);
136}
diff --git a/scan-tree.h b/scan-tree.h
new file mode 100644
index 0000000..b103b16
--- a/dev/null
+++ b/scan-tree.h
@@ -0,0 +1,3 @@
1
2
3extern void scan_tree(const char *path);