use (enhanced) libgit to iterate over the repository list
authorChristian Thaeter <ct@pipapo.org>
Sun, 6 Jan 2008 01:41:14 +0000 (02:41 +0100)
committerChristian Thaeter <ct@pipapo.org>
Sun, 6 Jan 2008 01:41:14 +0000 (02:41 +0100)
src/repo.c
src/webgit.h

index 616e275..3c4ecf0 100644 (file)
@@ -22,6 +22,9 @@
 #include "repo.h"
 #include "age.h"
 
+#define SHA1_HEADER <openssl/sha.h>
+#include "git/cache.h"
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -119,13 +122,93 @@ webgit_repo_conf_cb (const char *var, const char *value)
   return 1;
 }
 
+
+static int
+find_last (const char *refname, const unsigned char *sha1, int flags, void *ri)
+{
+  struct webgit_repo_info* self = (struct webgit_repo_info*) ri;
+
+  void* buf;
+  unsigned long size;
+
+  buf = read_object_with_reference (sha1, "commit", &size, NULL);
+
+  if (!buf)
+    return 1;
+
+  const char* author_beg = NULL;
+  const char* author_end = NULL;
+
+  unsigned long age = ~0;
+
+  /* first pass, get last commit time */
+  const char* i = buf;
+  while (i && i < (const char*)buf+size)
+    {
+      if (*i == '\n')
+        break;
+      if (!strncmp (i, "committer ", 10))
+        {
+          char* time_beg = strchr (i, '>');
+          if (time_beg)
+            {
+              struct tm tm;
+              if (strptime (time_beg + 2, "%s %Z", &tm))
+                {
+                  age = difftime (self->query->now, mktime (&tm));
+                }
+            }
+        }
+      i = strchr (i, '\n');
+      if (i)
+        ++i;
+    }
+
+  /* second pass, found a newer commit */
+  if (age != ~0 && (self->age == ~0 || age < self->age))
+    {
+      self->age = age;
+      free (self->last_commit);
+      self->last_commit = cwa_strndup (sha1_to_hex (sha1), 40);
+      free (self->last_head);
+      self->last_head = cwa_strndup (refname, SIZE_MAX);
+
+      i = buf;
+      while (i && i < buf+size)
+        {
+          if (*i == '\n')
+            break;
+          if (!strncmp (i, "tree ", 5))
+            {
+              self->last_tree = cwa_strndup (i+5, 40);
+            }
+          else if (!strncmp (i, "author ", 7))
+            {
+              const char* author_beg = i+7;
+              char* email_beg = strchr (i, '<');
+              char* email_end = strchr (email_beg, '>');
+
+              self->last_author = cwa_strndup (i+7, email_beg - i - 8);
+              self->last_email = cwa_strndup (email_beg + 1, email_end - email_beg - 1);
+            }
+          (i = strchr (i, '\n')) && ++i;
+        }
+    }
+  return 0;
+}
+
+
 struct webgit_repo_info*
 webgit_repoinfo_new (struct webgit_query* query, const char* path)
 {
+  char buf[512];
+
   if (!path)
     return NULL;
 
-  struct webgit_repo_info* self = cwa_malloc (sizeof(struct webgit_repo_info));
+  struct webgit_repo_info* self = cwa_malloc (sizeof (struct webgit_repo_info));
+
+  self->query = query;
 
   self->name = NULL;
   self->owner = NULL;
@@ -133,9 +216,6 @@ webgit_repoinfo_new (struct webgit_query* query, const char* path)
   self->giturl = NULL;
   self->readme = NULL;
 
-  self->last_commit = NULL;
-  self->last_tree = NULL;
-  self->last_head = NULL;
 
   llist_init (&self->node);
   self->path = cwa_strndup (path, SIZE_MAX);
@@ -146,40 +226,6 @@ webgit_repoinfo_new (struct webgit_query* query, const char* path)
   /* strip subdir part off */
   self->path [strlen (path) - (subdir ? strlen (subdir):0)] = '\0';
 
-  struct stat st;
-
-  if (!stat (".git/refs/heads", &st))
-    self->age = difftime (query->now, st.st_mtime);
-  else
-    self->age = ~0;
-
-  /* find the head which points to the last commit */
-  FILE* branches = webgit_git_open ("branch --no-color --no-abbrev -v");
-  char name[128] = ".git/refs/heads/";
-  char sha1[41];
-  char* head = name + 16;
-
-  while (fscanf (branches, "%*[* ] %111s %40s", head, sha1) == 2)
-    {
-      while (fgetc(branches) != '\n');
-
-      if (!stat (name, &st))
-        if (difftime (query->now, st.st_mtime) == self->age)
-          break;
-    }
-  webgit_git_close (branches);
-  self->last_commit = cwa_strndup (sha1, 40);
-  self->last_head = cwa_strndup (name + 5, SIZE_MAX);
-
-  /* find the tree for the last commit */
-  FILE* commit = webgit_git_open ("cat-file commit %s", sha1);
-  if (fscanf (commit, "tree %40s", sha1) == 1)
-    {
-      self->last_tree = cwa_strndup (sha1, 40);
-    }
-  webgit_git_close (commit);
-
-  /* get [webgit] subsection out of .git/config */
   in_flight = self;
   git_config (webgit_repo_conf_cb);
 
@@ -200,13 +246,13 @@ webgit_repoinfo_new (struct webgit_query* query, const char* path)
       self->name = cwa_strndup (n, SIZE_MAX);
     }
 
-  char buf[512];
-  if (stat (path, &st))
-    return NULL; // error ILLEGAL dir
-
   /* set owner if not already set by gitconfig */
   if (!self->owner)
     {
+      struct stat st;
+      if (stat (path, &st))
+        return NULL; // error ILLEGAL dir
+
       struct passwd* pw;
       if ((pw = getpwuid (st.st_uid)) != NULL)
         self->owner = cwa_strndup (pw->pw_gecos, strchr (pw->pw_gecos, ',') - pw->pw_gecos);
@@ -242,6 +288,26 @@ webgit_repoinfo_new (struct webgit_query* query, const char* path)
         }
     }
 
+
+
+  /* find 'last' information */
+  struct webgit_repo_info ri;
+  ri.last_commit = NULL;
+  ri.last_tree = NULL;
+  ri.last_head = NULL;
+  ri.last_author = NULL;
+  ri.last_email = NULL;
+  ri.query = query;
+  ri.age = ~0;
+  for_each_branch_ref (find_last, &ri);
+
+  self->last_commit = ri.last_commit ? ri.last_commit : cwa_strndup("NO_COMMIT", SIZE_MAX);
+  self->last_tree = ri.last_tree ? ri.last_tree : cwa_strndup("NO_TREE", SIZE_MAX);
+  self->last_head = ri.last_head ? ri.last_head : cwa_strndup("NO_HEAD", SIZE_MAX);
+  self->last_author = ri.last_author ? ri.last_author : cwa_strndup("NO_AUTHOR", SIZE_MAX);
+  self->last_email = ri.last_email ? ri.last_email : cwa_strndup("NO_EMAIL", SIZE_MAX);
+  self->age = ri.age;
+
   return self;
 }
 
@@ -263,6 +329,8 @@ webgit_repoinfo_free (struct webgit_repo_info* self)
       free (self->last_commit);
       free (self->last_tree);
       free (self->last_head);
+      free (self->last_author);
+      free (self->last_email);
 
       free (self);
     }
index 67de130..3a1680a 100644 (file)
 extern Html error_log;
 
 
+struct webgit_query
+{
+  Cgi request;
+  time_t now;
+
+  /* confiuration parameters */
+  //int cache_read;
+  //int cache_write;
+  //int cache_expire;
+
+  /* cgi parameters*/
+  char* repo;
+  char* action;
+  char* object;
+  char* head;
+
+  /* list of repositories */
+  llist repos;
+};
+
+
 struct webgit_repo_info
 {
   llist node;
 
+  struct webgit_query* query;
+
   char* path;
   char* name;
   char* owner;
@@ -42,38 +65,28 @@ struct webgit_repo_info
   char* last_commit;
   char* last_tree;
   char* last_head;
+  char* last_author;
+  char* last_email;
 
   unsigned long age;
 };
 
 
-struct webgit_query
-{
-  Cgi request;
-  time_t now;
 
-  /* confiuration parameters */
-  //int cache_read;
-  //int cache_write;
-  //int cache_expire;
 
-  /* cgi parameters*/
-  char* repo;
-  char* action;
-  char* object;
-  char* head;
+FILE*
+webgit_git_open (const char* fmt, ...);
 
-  /* list of repositories */
-  llist repos;
-};
+int
+webgit_git_close (FILE* handle);
 
 
+typedef int (*webgit_fork_fn)(void* data);
 
 FILE*
-webgit_git_open (const char* fmt, ...);
+webgit_fork (webgit_fork_fn fn, void* data, pid_t* pid);
 
-
-void
-webgit_git_close (FILE* handle);
+int
+webgit_closewait (FILE* fd, pid_t pid);
 
 #endif