WIP: generation of 'virtual' worktrees
authorChristian Thaeter <ct@pipapo.org>
Wed, 13 Feb 2008 06:08:42 +0000 (07:08 +0100)
committerChristian Thaeter <ct@pipapo.org>
Wed, 13 Feb 2008 06:08:42 +0000 (07:08 +0100)
a virtual worktree is a commit object in refs/worktrees with a single
parent which points to the head commit from which it originates and
a tree object which initially is the same tree as in that original head.
With each edit this tree object will be updated (and thus the references
sha1 will change, volatile commit!)

Add a 'editable' per repo config var to enable the edit machinery.

Needed to pass repo instead of query around in object_tree.c

Makefile.am
src/actions.c
src/edit.c
src/object_blob.c
src/object_tree.c
src/repo.c
src/repo.h
src/webgit.h
src/worktree.c [new file with mode: 0644]
src/worktree.h [new file with mode: 0644]

index 1b094ff..5a8d53c 100644 (file)
@@ -55,6 +55,7 @@ webgit_SOURCES =                              \
        $(webgit_srcdir)/login.c                \
        $(webgit_srcdir)/account.c              \
        $(webgit_srcdir)/edit.c                 \
+       $(webgit_srcdir)/worktree.c             \
        $(webgit_srcdir)/rxpd_client.c
 
 noinst_HEADERS =                               \
@@ -72,6 +73,7 @@ noinst_HEADERS =                              \
        $(webgit_srcdir)/login.h                \
        $(webgit_srcdir)/account.h              \
        $(webgit_srcdir)/edit.h                 \
+       $(webgit_srcdir)/worktree.h             \
        $(webgit_srcdir)/rxpd_client.h
 
 webgit_DEPENDENCIES = $(abs_top_builddir)/git/libgit.a $(abs_top_builddir)/git/xdiff/lib.a
index fa9d754..0060dc2 100644 (file)
@@ -568,7 +568,7 @@ webgit_edit_action (struct webgit_query* query)
   webgit_object_deduce (query);
 
   unsigned char sha1[20];
-  if (get_sha1 (query->object, sha1))
+  if (!query->object || get_sha1 (query->object, sha1))
     return html("error: unknown object");
 
   switch (sha1_object_info(sha1, NULL))
index 8462703..a9b4af6 100644 (file)
@@ -50,22 +50,27 @@ webgit_edit_blob_content_action (struct webgit_repo_info* repo, unsigned char* s
 {
   (void) sha1;
 
+  struct webgit_query* query = repo->query;
+
   return html (
                html (html_tag ("form",
                                html_attr ("name", "blob-edit"),
                                html_attr ("enctype", "multipart/form-data"),
                                html_attr ("method", "post"),
-                               html_attr ("action", repo->query->request->script_name)
+                               html_attr ("action", query->request->script_name)
                                ),
                      html (html_tag ("p"), "File: (change this for renaming or copying)",
-                           html_hidden ("repo", repo->name),
+                           html_hidden ("repo", query->repo),
+                           html_hidden ("ref", query->head),
+                           html_hidden ("commit", query->commit),
+                           html_hidden ("path", query->path),
                            html_hidden ("action", "edit"),
                            html (html_tag ("input",
                                            html_attr ("name", "path"),
                                            html_attr ("type", "text"),
                                            html_attr ("maxlen", html_fmt ("%d", PATH_MAX)),
                                            html_attr ("size", "80"),
-                                           html_attr ("value", repo->query->path)
+                                           html_attr ("value", query->path)
                                            )
                                  ),
                            html (html_tag ("input",
@@ -95,7 +100,9 @@ webgit_edit_blob_content_action (struct webgit_repo_info* repo, unsigned char* s
                                  html (html_tag ("textarea",
                                                  html_attr ("id", "blob"),
                                                  html_attr ("name", "blob"),
+#ifdef ENABLE_CODEPRESS
                                                  html_attr ("class", "codepress generic"),
+#endif
                                                  html_attr ("wrap", "off"),
                                                  html_attr ("style", "width:100%;height:600px")
                                                  ),
index 10d72a1..3601650 100644 (file)
@@ -43,13 +43,15 @@ webgit_object_blob_menu_action (struct webgit_repo_info* repo, unsigned char* sh
                // TODO: "blame <br />",
                // TODO: "Back to tree <br />",
                // TODO: ,
-               query->ssign ?
-               webgit_object_link (query, html ("Edit <br />"),
+               repo->worktree ?
+                webgit_object_link (query, html ("Edit <br />"),
                                    "repo", query->repo,
                                    "ref", query->head,
                                    "commit", query->commit,
                                    "path", query->path,
-                                   "action", "edit") : html (),
+                                    /* "object", worktree_object_get () */
+                                    "action", "edit")
+               : html ("TODO difflink this/worktree <br />"),
                webgit_object_tree_parent_link (query, "<<%s"),
                webgit_summary_link (query, repo, html("Summary")), "<br />",
                webgit_main_link (query, html ("Main"))
index 36ce101..8bb5f0e 100644 (file)
@@ -72,6 +72,9 @@ webgit_object_tree_menu_action (struct webgit_repo_info* repo, unsigned char* sh
                // TODO: "history <br />",
                // TODO: "snapshot <br />",
                // TODO: ,
+               repo->worktree
+               ? html ("TODO worktree actions <br />")
+               : html (),
                webgit_object_tree_parent_link (repo->query, "<<%s"),
                webgit_summary_link (repo->query, repo, html("Summary")), "<br />",
                webgit_main_link (repo->query, html ("Main"))
@@ -99,7 +102,7 @@ pretty_mode (unsigned mode)
 }
 
 /* callback has no user-data pointer! */
-static struct webgit_query* query_in_flight = NULL;
+static struct webgit_repo_info* repo_in_flight = NULL;
 static Html tree_in_flight = NULL;
 
 static int
@@ -109,12 +112,14 @@ webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
   (void) stage;
   char pathname[PATH_MAX];
 
+  struct webgit_query* query = repo_in_flight->query;
+
   snprintf (pathname, PATH_MAX-1, "%.*s%s%s", baselen, base, baselen ? "/": "", name);
 
   if (S_ISGITLINK(mode))
     {
-      char* repo = cwa_malloc (strlen (query_in_flight->repo) + strlen (name) + 2);
-      sprintf (repo, "%s/%s", query_in_flight->repo, name);
+      char* repo = cwa_malloc (strlen (query->repo) + strlen (name) + 2);
+      sprintf (repo, "%s/%s", query->repo, name);
 
       html_list_append (tree_in_flight,
                         html (
@@ -122,7 +127,7 @@ webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
                                     html_tag ("tr"),
                                     html (html_tag ("td"), pretty_mode (mode)),
                                     html (html_tag ("td"),
-                                          webgit_object_link (query_in_flight, html_strndup (pathname, SIZE_MAX),
+                                          webgit_object_link (query, html_strndup (pathname, SIZE_MAX),
                                                               "repo", repo,
                                                               "ref","",
                                                               "commit", sha1_to_hex (sha1),
@@ -141,10 +146,10 @@ webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
                               html (html_tag ("tr"),
                                     html (html_tag ("td"), pretty_mode (mode)),
                                     html (html_tag ("td"),
-                                          webgit_object_link (query_in_flight, html_strndup (name, SIZE_MAX),
-                                                              "repo", query_in_flight->repo,
-                                                              "ref", query_in_flight->head,
-                                                              "commit", query_in_flight->commit,
+                                          webgit_object_link (query, html_strndup (name, SIZE_MAX),
+                                                              "repo", query->repo,
+                                                              "ref", query->head,
+                                                              "commit", query->commit,
                                                               "path", pathname)
                                           ),
                                     html (html_tag ("td"), "history snap")
@@ -160,30 +165,31 @@ webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
                               html (html_tag ("tr"),
                                     html (html_tag ("td"), pretty_mode (mode)),
                                     html (html_tag ("td"),
-                                          webgit_object_link (query_in_flight, html_strndup (name, SIZE_MAX),
-                                                              "repo", query_in_flight->repo,
-                                                              "ref", query_in_flight->head,
-                                                              "commit", query_in_flight->commit,
+                                          webgit_object_link (query, html_strndup (name, SIZE_MAX),
+                                                              "repo", query->repo,
+                                                              "ref", query->head,
+                                                              "commit", query->commit,
                                                               "path", pathname)
                                           ),
                                     html (html_tag ("td"),
                                           "history ",
-                                          webgit_object_link (query_in_flight, html ("raw"),
-                                                              "repo", query_in_flight->repo,
-                                                              "ref", query_in_flight->head,
-                                                              "commit", query_in_flight->commit,
+                                          webgit_object_link (query, html ("raw"),
+                                                              "repo", query->repo,
+                                                              "ref", query->head,
+                                                              "commit", query->commit,
                                                               "path", pathname,
                                                               "action", "raw"),
-                                          query_in_flight->ssign ?
-                                          html (
-                                                " ",
-                                                webgit_object_link (query_in_flight, html ("edit"),
-                                                                    "repo", query_in_flight->repo,
-                                                                    "ref", query_in_flight->head,
-                                                                    "commit", query_in_flight->commit,
-                                                                    "path", pathname,
-                                                                    "action", "edit")
-                                                ) : html ()
+                                          repo_in_flight->worktree
+                                          ? html (
+                                                  " ",
+                                                  webgit_object_link (query, html ("edit"),
+                                                                      "repo", query->repo,
+                                                                      "ref", query->head,
+                                                                      "commit", query->commit,
+                                                                      "path", pathname,
+                                                                      "action", "edit")
+                                                  )
+                                          : html ()
                                           )
                                     ),
                               html_nl()
@@ -199,7 +205,7 @@ static Html
 webgit_object_tree_content_action (struct webgit_repo_info* repo, unsigned char* sha1, struct tree *tree)
 {
   (void) sha1;
-  query_in_flight = repo->query;
+  repo_in_flight = repo;
   tree_in_flight = html_list ();
 
   read_tree_recursive (tree, repo->query->path,
index ed7467f..882c711 100644 (file)
@@ -137,6 +137,13 @@ webgit_maxage_conf (struct webgit_repo_info* self, const char *value)
 }
 
 
+static void
+webgit_editable_conf (struct webgit_repo_info* self, const char *value)
+{
+  self->editable = git_config_bool ("", value);
+}
+
+
 int
 webgit_repo_conf_cb (const char *var, const char *value)
 {
@@ -259,6 +266,9 @@ webgit_repo_enter (struct webgit_query* query)
   in_flight = ri;
   git_config (webgit_repo_conf_cb);
 
+  if (ri->editable && query->account_validated && query->head && !!strncmp ("refs/tags/", query->head, 10))
+    webgit_worktree_setup (ri);
+
   return ri;
 }
 
@@ -282,6 +292,9 @@ webgit_repoinfo_new (struct webgit_query* query, const char* path)
   self->logolink = NULL;
   self->readme = NULL;
   self->maxage = query->maxage;
+  self->editable = 0;
+
+  self->worktree = NULL;
 
   llist_init (&self->node);
   self->path = cwa_strndup (path, SIZE_MAX);
@@ -415,6 +428,8 @@ webgit_repoinfo_free (struct webgit_repo_info* self)
       free (self->last_author_name);
       free (self->last_author_email);
 
+      free (self->worktree);
+
       free (self);
     }
 }
index 250c4fd..0bb09ad 100644 (file)
@@ -36,6 +36,7 @@
  WEBGIT_CONF(webskindir, "Set dir to skins from webroot")                       \
  WEBGIT_CONF(skin, "Set default skin")                                          \
  WEBGIT_CONF(maxage, "Age in days to hide inactive repositories")               \
+ WEBGIT_CONF(editable, "Make repository web editable")                          \
  WEBGIT_CONF(readme, "Set a readme.html file to display")
 
 #define WEBGIT_CONF_PREFIX "web."
index 4d38fdb..d0ba4db 100644 (file)
@@ -109,6 +109,7 @@ struct webgit_repo_info
   char* logolink;
   char* readme;
   unsigned long maxage;
+  int editable;
 
   char* last_commit;
   char* last_tree;
@@ -117,8 +118,9 @@ struct webgit_repo_info
   char* last_committer_email;
   char* last_author_name;
   char* last_author_email;
-
   unsigned long age;
+
+  char* worktree;
 };
 
 
diff --git a/src/worktree.c b/src/worktree.c
new file mode 100644 (file)
index 0000000..5e82206
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2008,               Christian Thaeter <ct@pipapo.org>
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Affero General Public License for more details.
+
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "worktree.h"
+
+#define SHA1_HEADER <openssl/sha.h>
+#include "git/cache.h"
+#include "git/commit.h"
+#include "git/refs.h"
+#include "git/tree.h"
+
+
+//webgit_worktree_ensure ;
+
+void
+webgit_worktree_setup (struct webgit_repo_info* repo)
+{
+  char* buf = cwa_buffer_provide (PATH_MAX);
+  snprintf (buf, PATH_MAX, "refs/worktrees/%s", repo->query->head);
+
+  unsigned char sha1_head[20];
+  get_sha1 (repo->query->head, sha1_head);
+
+  unsigned char sha1[20];
+
+  if (!read_ref (buf, sha1))
+    {
+      repo->worktree = cwa_strndup (sha1_to_hex (sha1), 40);
+
+      struct commit* commit = lookup_commit_reference (sha1);
+      parse_commit (commit);
+
+      struct commit* parent = pop_commit(&commit->parents);
+
+      if (!!hashcmp (sha1_head, parent->object.sha1))
+        {
+          /* uh ohh, head diverted from worktree */
+          die ("TODO: uh ohh, head diverted from worktree, needs merge strategy");
+        }
+    }
+  else
+    {
+      struct commit* commit = lookup_commit_reference (sha1_head);
+      parse_commit (commit);
+
+      repo->worktree = cwa_strndup (webgit_object_commit_tree_parse (commit), 40);
+
+      char* cbuf = cwa_buffer_provide (512);
+      sprintf (cbuf,
+               "tree %s\n"
+               "parent %s\n"
+               "author %s <%s> %lu +0000\n"
+               "committer %s <%s> %lu +0000\n\n",
+               repo->worktree,
+               sha1_to_hex (sha1_head),
+               repo->query->name,
+               repo->query->email,
+               repo->query->now,
+               repo->query->name,
+               repo->query->email,
+               repo->query->now
+               );
+
+      if (!!write_sha1_file (cbuf, strlen (cbuf), "commit", sha1))
+        die("error writing worktree %s\n", sha1_to_hex(sha1));
+
+      struct ref_lock * lock = lock_ref_sha1 (buf+5, NULL);
+
+      lock->force_write = 1;
+      write_ref_sha1 (lock, sha1, "");
+    }
+}
+
+
+
+
+#if 0
+int
+webgit_worktree_same_blob (struct webgit_repo_info* repo)
+{
+
+  return 0;
+}
+#endif
+
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/
diff --git a/src/worktree.h b/src/worktree.h
new file mode 100644 (file)
index 0000000..f7dd980
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2008,               Christian Thaeter <ct@pipapo.org>
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Affero General Public License for more details.
+
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef WEBGIT_WORKTREE_H
+#define WEBGIT_WORKTREE_H
+
+#include "webgit.h"
+
+void
+webgit_worktree_setup (struct webgit_repo_info* repo);
+
+
+#if 0
+int
+webgit_worktree_same_blob (struct webgit_repo_info* repo);
+#endif
+
+#endif
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/