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

File externals and wc style questions

From: Blair Zajac <blair_at_orcaware.com>
Date: Fri, 06 Jun 2008 08:20:36 -0700

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

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.