proper repoinfo ctor/dtor, parsing gitconfig, moved age storage to
[webgit] / src / repo.c
1 /*
2     cehtehs git web frontend
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "repo.h"
23 #include "age.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <stdint.h>
30 #include <time.h>
31
32 static struct ctgit_repo_info* in_flight;       /* stupid git callback has no void* userdata; we have to pass self in a global */
33
34 static void
35 ctgit_name_conf (struct ctgit_repo_info* self, const char *value)
36 {
37   self->name = cwa_strndup (value, SIZE_MAX);
38 }
39
40
41 static void
42 ctgit_description_conf (struct ctgit_repo_info* self, const char *value)
43 {
44   self->description = cwa_strndup (value, SIZE_MAX);
45 }
46
47
48 static void
49 ctgit_giturl_conf (struct ctgit_repo_info* self, const char *value)
50 {
51   self->giturl = cwa_strndup (value, SIZE_MAX);
52 }
53
54
55 static void
56 ctgit_readme_conf (struct ctgit_repo_info* self, const char *value)
57 {
58   self->readme = cwa_strndup (value, SIZE_MAX);
59 }
60
61
62 static void
63 ctgit_owner_conf (struct ctgit_repo_info* self, const char *value)
64 {
65   self->owner = cwa_strndup (value, SIZE_MAX);
66 }
67
68
69 int
70 ctgit_repo_conf_cb (const char *var, const char *value)
71 {
72 #define CTGIT_CONF(name, _) {CTGIT_CONF_PREFIX #name, ctgit_##name##_conf},
73   struct conf_table{
74     char* name;
75     void (*cb)(struct ctgit_repo_info* self, const char *value);
76   } cmds[] = {CTGIT_CONFS {"", NULL}};
77 #undef CTGIT_CONF
78
79   for (struct conf_table* j = cmds; j->cb; ++j)
80     {
81       if (!strcmp (j->name, var))
82         {
83           j->cb (in_flight, value);
84           break;
85         }
86     }
87   return 1;
88 }
89
90 struct ctgit_repo_info*
91 ctgit_repoinfo_new (struct ctgit_query* query, const char* path)
92 {
93   if (!path)
94     return NULL;
95
96   struct ctgit_repo_info* self = cwa_malloc (sizeof(struct ctgit_repo_info));
97
98   self->name = NULL;
99   self->owner = NULL;
100   self->description = NULL;
101   self->giturl = NULL;
102   self->readme = NULL;
103
104   llist_init (&self->node);
105   self->path = cwa_strndup (path, SIZE_MAX);
106
107   chdir (path);
108
109   const char* subdir = setup_git_directory ();
110   /* strip subdir part off */
111   self->path [strlen (path) - (subdir ? strlen (subdir):0)] = '\0';
112
113   struct stat st;
114
115   if (!stat (".git/refs/heads", &st))
116     self->age = difftime (query->now, st.st_mtime);
117   else
118     self->age = ~0;
119
120   /* get [ctgit] subsection out of .git/config */
121   in_flight = self;
122   git_config (ctgit_repo_conf_cb);
123
124   if (!self->name)
125     {
126       /* strip 'name' out of path when not in .git/config */
127       const char* n;
128       while ((n = strrchr (self->path, '/')))
129         if (n[1])
130           {
131             ++n;
132             break;
133           }
134
135       if (!n)
136         n = self->path;
137
138       self->name = cwa_strndup (n, SIZE_MAX);
139     }
140
141   char buf[512];
142   //struct stat st;
143   if (stat (path, &st))
144     return NULL; // error ILLEGAL dir
145
146   struct passwd* pw;
147   if (!self->owner)
148     {
149       if ((pw = getpwuid (st.st_uid)) != NULL)
150         self->owner = cwa_strndup (pw->pw_gecos, strchr (pw->pw_gecos, ',') - pw->pw_gecos);
151       else
152         self->owner = cwa_strndup ("unknown", 100);
153     }
154
155
156   //snprintf (buf, 512, "%s/.git/description", path);
157
158   //FILE* desc = fopen (buf, "r");
159   if (!self->description)
160     {
161       FILE* desc = fopen (".git/description", "r");
162       if (desc)
163         {
164           fgets (buf, 512, desc);
165           fclose (desc);
166           char* e = strchr (buf, '\n');
167           if (e)
168             *e = '\0';
169
170           self->description = cwa_strndup (buf, 40);
171         }
172     }
173
174   if (self->description)
175     {
176       size_t l = strlen (self->description);
177       if (l >= 39)
178         {
179           self->description[l-1] = '.';
180           self->description[l-2] = '.';
181           self->description[l-3] = '.';
182         }
183     }
184
185
186   return self;
187 }
188
189 void
190 ctgit_repoinfo_free (struct ctgit_repo_info* self)
191 {
192   if (self)
193     {
194       free (self->path);
195       free (self->name);
196
197       free (self->owner);
198       free (self->description);
199       free (self->giturl);
200       free (self->readme);
201
202       llist_unlink (&self->node);
203       free (self);
204     }
205 }