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

Re: File externals and wc style questions

From: David Glasser <glasser_at_davidglasser.net>
Date: Fri, 6 Jun 2008 10:14:36 -0700

On Fri, Jun 6, 2008 at 8:20 AM, Blair Zajac <blair_at_orcaware.com> wrote:
> 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.

I haven't completely thought through exactly what you're saying, but
anything that makes "externals" more like "repository-defined
suggestions for switches" is great in my book.

> 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?

Parsing sucks. Later we'll decide that you can support, say, the
{DATE} revision type, which can have a space in it. Be less
ambiguous.

(and re: debuggability, as Karl mentioned: I disbelieve that anybody
is smart enough to consistently figure out what line is what in the
entries file by hand. But do see my svn-entries.el.)

--dave

> 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
>
>

-- 
David Glasser | glasser@davidglasser.net | http://www.davidglasser.net/
---------------------------------------------------------------------
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 19:14:53 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.