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