[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] ra_dav date support

From: Greg Hudson <ghudson_at_MIT.EDU>
Date: 2002-10-17 02:03:41 CEST

Okay, with some help from Ben Collins-Sussman, I was able to write
support for date-based operations over libsvn_ra_dav. Since this is
my first time hacking on DAV code, and because I'm changing the
protocol, I figured I would send this here for prior review.

  Implement ra_dav support for getting a revision by date. DeltaV
  provides no way of doing this, so we use a custom report.

  * mod_dav_svn/version.c
    (dav_svn__drev_report): New function to deliver a dated-rev
      report.
    (dav_svn_deliver_report): Recognize dated-rev report.
  * libsvn_ra_dav/ra_dav.h (ELEM_dated_rev_report): New constant.
  * libsvn_ra_dav/fetch.c
    (svn_ra_dav__get_dated_revision): Implement by making the custom
    report and parsing the answer. Returns a reasonable error message
    if the server doesn't support the new report.
    (drev_report_elements, drev_validate_element, drev_start_element,
    drev_end_element): New helper functions for the dated-rev
    implementation.

Index: mod_dav_svn/version.c
===================================================================
--- mod_dav_svn/version.c
+++ mod_dav_svn/version.c Wed Oct 16 18:29:23 2002
@@ -26,6 +26,7 @@
 #include "svn_xml.h"
 #include "svn_repos.h"
 #include "svn_dav.h"
+#include "svn_time.h"
 
 #include "dav_svn.h"
 
@@ -474,6 +475,61 @@
   return 0;
 }
 
+/* Respond to a S:dated-rev-report request. The request contains a
+ * DAV:creationdate element giving the requested date; the response
+ * contains a DAV:version-name element giving the most recent revision
+ * as of that date. */
+static dav_error * dav_svn__drev_report(const dav_resource *resource,
+ const apr_xml_doc *doc,
+ ap_filter_t *output)
+{
+ apr_xml_elem *child;
+ int ns;
+ apr_time_t tm = (apr_time_t) -1;
+ svn_revnum_t rev;
+ apr_bucket_brigade *bb;
+
+ /* Find the DAV:creationdate element and get the requested time from it. */
+ ns = dav_svn_find_ns(doc->namespaces, "DAV:");
+ if (ns != -1)
+ {
+ for (child = doc->root->first_child; child != NULL; child = child->next)
+ {
+ if (child->ns != ns || strcmp(child->name, "creationdate") != 0)
+ continue;
+ /* If this fails, we'll notice below. */
+ svn_time_from_nts(&tm, child->first_cdata.first->text,
+ resource->pool);
+ }
+ }
+
+ if (tm == (apr_time_t) -1)
+ {
+ return dav_new_error(resource->pool, HTTP_BAD_REQUEST, 0,
+ "The request does not contain a valid "
+ "'DAV:creationdate' element.");
+ }
+
+ /* Do the actual work of finding the revision by date. */
+ if (svn_repos_dated_revision(&rev, resource->info->repos->repos, tm,
+ resource->pool) != SVN_NO_ERROR)
+ {
+ return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
+ "Could not access revision times.");
+ }
+
+ bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ ap_fprintf(output, bb,
+ DAV_XML_HEADER DEBUG_CR
+ "<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
+ "xmlns:D=\"DAV:\">" DEBUG_CR
+ "<D:version-name>%" SVN_REVNUM_T_FMT "</D:version-name>"
+ "</S:dated-rev-report>", rev);
+ ap_fflush(output, bb);
+
+ return NULL;
+}
+
 static dav_error *dav_svn_deliver_report(request_rec *r,
                                          const dav_resource *resource,
                                          const apr_xml_doc *doc,
@@ -489,10 +545,14 @@
         {
           return dav_svn__update_report(resource, doc, output);
         }
- if (strcmp(doc->root->name, "log-report") == 0)
+ else if (strcmp(doc->root->name, "log-report") == 0)
         {
           return dav_svn__log_report(resource, doc, output);
         }
+ else if (strcmp(doc->root->name, "dated-rev-report") == 0)
+ {
+ return dav_svn__drev_report(resource, doc, output);
+ }
     }
 
   /* ### what is a good error for an unknown report? */
Index: libsvn_ra_dav/ra_dav.h
===================================================================
--- libsvn_ra_dav/ra_dav.h
+++ libsvn_ra_dav/ra_dav.h Wed Oct 16 00:32:11 2002
@@ -417,6 +417,7 @@
   ELEM_resource_walk,
   ELEM_resource,
   ELEM_prop,
+ ELEM_dated_rev_report,
   ELEM_name_version_name,
   ELEM_name_creationdate,
   ELEM_name_creator_displayname,
Index: libsvn_ra_dav/fetch.c
===================================================================
--- libsvn_ra_dav/fetch.c
+++ libsvn_ra_dav/fetch.c Wed Oct 16 18:42:18 2002
@@ -180,6 +180,13 @@
   { NULL }
 };
 
+/* Elements used in a dated-rev-report response */
+static const struct ne_xml_elm drev_report_elements[] =
+{
+ { SVN_XML_NAMESPACE, "dated-rev-report", ELEM_dated_rev_report, 0 },
+ { "DAV:", "version-name", ELEM_version_name, NE_XML_CDATA },
+ { NULL }
+};
 
 static svn_stringbuf_t *my_basename(const char *url, apr_pool_t *pool)
 {
@@ -1448,25 +1455,78 @@
 }
 
 
-/* ### DUMMY FUNC. To be marshalled over network like previous
- routine. */
+/* -------------------------------------------------------------------------
+**
+** DATED REV REPORT HANDLING
+**
+** DeltaV provides no mechanism for mapping a date to a revision, so
+** we use a custom report, S:dated-rev-report. The request contains a
+** DAV:creationdate element giving the requested date; the response
+** contains a DAV:version-name element giving the most recent revision
+** as of that date.
+**
+** Since this report is so simple, we don't bother with validation or
+** baton structures or anything; we just set the revision number in
+** the end-element handler for DAV:version-name.
+*/
+
+/* This implements the `ne_xml_validate_cb' prototype. */
+static int drev_validate_element(void *userdata, ne_xml_elmid parent,
+ ne_xml_elmid child)
+{
+ return NE_XML_VALID;
+}
+
+/* This implements the `ne_xml_startelm_cb' prototype. */
+static int drev_start_element(void *userdata, const struct ne_xml_elm *elm,
+ const char **atts)
+{
+ return 0;
+}
+
+/* This implements the `ne_xml_endelm_cb' prototype. */
+static int drev_end_element(void *userdata, const struct ne_xml_elm *elm,
+ const char *cdata)
+{
+ if (elm->id == ELEM_version_name)
+ *((svn_revnum_t *) userdata) = SVN_STR_TO_REV(cdata);
+
+ return 0;
+}
 
 svn_error_t *svn_ra_dav__get_dated_revision (void *session_baton,
                                              svn_revnum_t *revision,
                                              apr_time_t timestamp)
 {
   svn_ra_session_t *ras = session_baton;
+ const char *body;
+ svn_error_t *err;
 
- /* ### need to implement this function...
- ###
- ### marshal the query over and call svn_repos_dated_revision()
- */
+ body = apr_psprintf(ras->pool,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
+ "xmlns:D=\"DAV:\">"
+ "<D:creationdate>%s</D:creationdate>"
+ "</S:dated-rev-report>",
+ svn_time_to_nts(timestamp, ras->pool));
 
   *revision = SVN_INVALID_REVNUM;
+ err = svn_ra_dav__parsed_request(ras, "REPORT", ras->root.path, body, -1,
+ drev_report_elements,
+ drev_validate_element,
+ drev_start_element, drev_end_element,
+ revision, ras->pool);
+ if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
+ return svn_error_quick_wrap(err, "Server does not support date-based "
+ "operations.");
+ else if (err)
+ return err;
 
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, 0, NULL, ras->pool,
- "ra_dav does not currently support date-based "
- "operations.");
+ if (*revision == SVN_INVALID_REVNUM)
+ return svn_error_create(SVN_ERR_INCOMPLETE_DATA, 0, NULL, ras->pool,
+ "Invalid server response to dated-rev request.");
+
+ return SVN_NO_ERROR;
 }
 
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Oct 17 02:08:57 2002

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.