I'm working on getting intra-repository file externals into svn's wc, as an 
addition to our support for directory externals.
A couple of design questions, but first a design point.  I'm implementing file 
externals using the existing support in 1.5 that you can do 'touch foo; svn add 
foo; svn switch foo URL'.  So under the hood, having a file external sets up a 
switched file.  The existence of some additional fields in the entries will tell 
the client that it still needs to be treated specially.
Because the svn:externals property can add an external to subdirectories and 
users may do updates from a subdirectory, svn may not know that a switched path 
is a file external, so I need to add a marker in the wc entries that something 
is a file external and not just a switched path.
So I can add a single entry line into .svn/entries with a single line, either of 
the two following form:
[HEAD|r\d+] URL
or two separate lines:
URL
[HEAD|r\d+]
The two have to both be there for this to work, so maybe the first?
Also, representing a HEAD or fixed revision number the svn_opt_revision_t seems 
natural for this, but this has a number of different revision types that I don't 
need.  Should I have a new smaller union type that just reflects a HEAD revision 
and a fixed revision?
Any style feedback welcome.
Patch for two separate lines in .svn/entries is below.
Oh yes, and why do we have svn_wc__atts_to_entry()?  This looks like it's more 
XML entries files related?
Blair
Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h (revision 31613)
+++ subversion/include/svn_wc.h (working copy)
@@ -1861,6 +1861,23 @@
     * @since New in 1.5. */
    svn_depth_t depth;
+  /** The entry is a file external and this is the repository root
+   * relative path to the file, otherwise NULL if the file is not a
+   * file external.
+   *
+   * @since New in 1.6. */
+  const char *file_external_path;
+
+  /** The entry is a file external and this is the revision number
+   * that the external is checked out from.  The only permissable
+   * values are svn_opt_revision_unspecified if the entry is not an
+   * external, svn_opt_revision_head if the external revision is
+   * unspecified or specified with -r HEAD or svn_opt_revision_number
+   * for a specifiec revision number.
+   *
+   * @since New in 1.6. */
+  svn_opt_revision_t file_external_rev;
+
    /* IMPORTANT: If you extend this structure, check the following functions in
     * subversion/libsvn_wc/entries.c, to see if you need to extend them as well.
     *
Index: subversion/libsvn_wc/entries.c
===================================================================
--- subversion/libsvn_wc/entries.c      (revision 31613)
+++ subversion/libsvn_wc/entries.c      (working copy)
@@ -2,7 +2,7 @@
   * entries.c :  manipulating the administrative `entries' file.
   *
   * ====================================================================
- * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
+ * Copyright (c) 2000-2008 CollabNet.  All rights reserved.
   *
   * This software is licensed as described in the file COPYING, which
   * you should have received as part of this distribution.  The terms
@@ -292,6 +292,41 @@
    return SVN_NO_ERROR;
  }
+/* Parse a file external revision number from a NULL terminated string
+   REV_STR into *RESULT.  Valid strings are NULL, "HEAD", or r\d+.  A
+   NULL string converts to a HEAD revision. */
+static svn_error_t *
+parse_file_external_rev(svn_opt_revision_t *result, const char *rev_str,
+                       const char *name)
+{
+  svn_opt_revision_t r;
+
+  if (! rev_str)
+    r.kind = svn_opt_revision_head;
+  else
+    {
+      if (strcmp(rev_str, SVN_WC__ENTRY_VALUE_HEAD) == 0)
+       {
+       }
+      else if (rev_str[0] == 'r')
+       {
+         svn_revnum_t rev;
+         SVN_ERR(svn_revnum_parse(&rev, rev_str+1, NULL));
+         r.kind = svn_opt_revision_number;
+         r.value.number = rev;
+       }
+      else
+       return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+                                _("Entry for '%s' has invalid file external "
+                                  "revision '%s'"),
+                                name ? name : SVN_WC_ENTRY_THIS_DIR,
+                                rev_str);
+    }
+  *result = r;
+
+  return SVN_NO_ERROR;
+}
+
  /* Allocate an entry from POOL and read it from [*BUF, END).  The
     buffer may be modified in place while parsing.  Return the new
     entry in *NEW_ENTRY.  Advance *BUF to point at the end of the entry
@@ -498,6 +533,22 @@
    }
    MAYBE_DONE;
+  /* File external relative path. */
+  SVN_ERR(read_str(&entry->file_external_path, buf, end, pool));
+  MAYBE_DONE;
+
+  /* File external revision. */
+  {
+    const char *rev_str;
+
+    entry->file_external_rev.kind = svn_opt_revision_head;
+
+    SVN_ERR(read_str(&rev_str, buf, end, pool));
+    SVN_ERR(parse_file_external_rev(&(entry->file_external_rev), rev_str,
+                                   name));
+  }
+  MAYBE_DONE;
+
   done:
    *new_entry = entry;
    return SVN_NO_ERROR;
@@ -911,6 +962,30 @@
        }
    }
+  /* File externals */
+  entry->file_external_path =
+    apr_hash_get(atts, SVN_WC__ENTRY_ATTR_FILE_EXTERNAL_PATH,
+                APR_HASH_KEY_STRING);
+  if (entry->file_external_path)
+    {
+      *modify_flags |= SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_PATH;
+      entry->file_external_path = apr_pstrdup(pool, entry->file_external_path);
+    }
+
+  {
+    const char *rev_str;
+
+    rev_str = apr_hash_get(atts, SVN_WC__ENTRY_ATTR_FILE_EXTERNAL_REV,
+                          APR_HASH_KEY_STRING);
+    if (rev_str)
+      {
+       SVN_ERR(parse_file_external_rev(&(entry->file_external_rev),
+                                       rev_str,
+                                       NULL));
+       *modify_flags |= SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_REV;
+      }
+  }
+
    *new_entry = entry;
    return SVN_NO_ERROR;
  }
@@ -1664,6 +1739,27 @@
        write_val(buf, val, strlen(val));
      }
+  /* File externals. */
+  write_str(buf, entry->file_external_path, pool);
+  switch (entry->file_external_rev.kind)
+    {
+    case svn_opt_revision_head:
+      write_val(buf, SVN_WC__ENTRY_VALUE_HEAD,
+               sizeof(SVN_WC__ENTRY_VALUE_HEAD) - 1);
+      break;
+    case svn_opt_revision_number:
+      if (SVN_IS_VALID_REVNUM(entry->file_external_rev.value.number))
+       {
+         svn_stringbuf_appendbytes(buf, "r", 1);
+         write_revnum(buf, entry->file_external_rev.value.number, pool);
+       }
+      else
+       write_val(buf, NULL, 0);
+      break;
+    default:
+      write_val(buf, NULL, 0);
+    }
+
    /* Remove redundant separators at the end of the entry. */
    while (buf->len > 1 && buf->data[buf->len - 2] == '\n')
      buf->len--;
@@ -2311,6 +2407,16 @@
        cur_entry->keep_local = FALSE;
      }
+  /* File externals. */
+  if (modify_flags & SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_PATH)
+    cur_entry->file_external_path = (entry->file_external_path
+                                    ? apr_pstrdup(pool,
+                                                  entry->file_external_path)
+                                    : NULL);
+
+  if (modify_flags & SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_REV)
+    cur_entry->file_external_rev = entry->file_external_rev;
+
    /* Make sure the entry exists in the entries hash.  Possibly it
       already did, in which case this could have been skipped, but what
       the heck. */
@@ -2675,6 +2781,9 @@
      dupentry->cachable_props = apr_pstrdup(pool, entry->cachable_props);
    if (entry->present_props)
      dupentry->present_props = apr_pstrdup(pool, entry->present_props);
+  if (entry->file_external_path)
+    dupentry->file_external_path = apr_pstrdup(pool,
+                                              entry->file_external_path);
    return dupentry;
  }
Index: subversion/libsvn_wc/wc.h
===================================================================
--- subversion/libsvn_wc/wc.h   (revision 31613)
+++ subversion/libsvn_wc/wc.h   (working copy)
@@ -2,7 +2,7 @@
   * wc.h :  shared stuff internal to the svn_wc library.
   *
   * ====================================================================
- * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
+ * Copyright (c) 2000-2008 CollabNet.  All rights reserved.
   *
   * This software is licensed as described in the file COPYING, which
   * you should have received as part of this distribution.  The terms
@@ -69,9 +69,11 @@
   * The change from 8 to 9 was the addition of changelists, keep-local,
   * and sticky depth (for selective/sparse checkouts).
   *
+ * The change from 9 to 10 was the addition of file externals.
+ *
   * Please document any further format changes here.
   */
-#define SVN_WC__VERSION       9
+#define SVN_WC__VERSION       10
  /* A version <= this doesn't have property caching in the entries file. */
  #define SVN_WC__NO_PROPCACHING_VERSION 5
Index: subversion/libsvn_wc/entries.h
===================================================================
--- subversion/libsvn_wc/entries.h      (revision 31613)
+++ subversion/libsvn_wc/entries.h      (working copy)
@@ -77,12 +77,16 @@
  #define SVN_WC__ENTRY_ATTR_CHANGELIST         "changelist"
  #define SVN_WC__ENTRY_ATTR_KEEP_LOCAL         "keep-local"
  #define SVN_WC__ENTRY_ATTR_WORKING_SIZE       "working-size"
+#define SVN_WC__ENTRY_ATTR_FILE_EXTERNAL_PATH "file-external-path"
+#define SVN_WC__ENTRY_ATTR_FILE_EXTERNAL_REV  "file-external-rev"
  /* Attribute values for 'schedule' */
  #define SVN_WC__ENTRY_VALUE_ADD        "add"
  #define SVN_WC__ENTRY_VALUE_DELETE     "delete"
  #define SVN_WC__ENTRY_VALUE_REPLACE    "replace"
+/* Attribute value for 'file-external' */
+#define SVN_WC__ENTRY_VALUE_HEAD       "head"
  /* Initialize an entries file based on URL at INITIAL_REV, in the adm
@@ -159,6 +163,8 @@
  #define SVN_WC__ENTRY_MODIFY_CHANGELIST         APR_INT64_C(0x0000000040000000)
  #define SVN_WC__ENTRY_MODIFY_KEEP_LOCAL         APR_INT64_C(0x0000000080000000)
  #define SVN_WC__ENTRY_MODIFY_WORKING_SIZE       APR_INT64_C(0x0000000100000000)
+#define SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_PATH APR_INT64_C(0x0000000200000000)
+#define SVN_WC__ENTRY_MODIFY_FILE_EXTERNAL_REV  APR_INT64_C(0x0000000400000000)
  /* No #define for DEPTH, because it's only meaningful on this-dir anyway. */
  /* ...ORed together with this to mean "I really mean this, don't be
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-06-06 17:21:06 CEST