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

svn_client_revision_t change in progress

From: Karl Fogel <kfogel_at_newton.ch.collab.net>
Date: 2002-02-01 06:53:20 CET

Thought I'd post the diff-so-far for review, while I go home and
sleep. This passes "make check" except for copy_tests.py and
diff_tests.py. I know what the problems are, just not solving them
tonight. :-)

Philip, if you want to take a look at the area around

    "/* fooo working here */"

and make a stab at what the logic should be, that would be welcome,
but no worries either way.

-Karl

$ svn st
M ./subversion/clients/cmdline/checkout-cmd.c
M ./subversion/clients/cmdline/cl.h
M ./subversion/clients/cmdline/commit-cmd.c
M ./subversion/clients/cmdline/diff-cmd.c
M ./subversion/clients/cmdline/import-cmd.c
M ./subversion/clients/cmdline/log-cmd.c
M ./subversion/clients/cmdline/main.c
M ./subversion/clients/cmdline/switch-cmd.c
M ./subversion/clients/cmdline/update-cmd.c
M ./subversion/include/svn_client.h
M ./subversion/include/svn_error_codes.h
M ./subversion/libsvn_client/checkout.c
M ./subversion/libsvn_client/client.h
M ./subversion/libsvn_client/commit.c
M ./subversion/libsvn_client/copy.c
M ./subversion/libsvn_client/diff.c
M ./subversion/libsvn_client/log.c
A ./subversion/libsvn_client/revisions.c
M ./subversion/libsvn_client/switch.c
M ./subversion/libsvn_client/update.c
$ cat msg
Do things the new svn_client_revision_t way.

This is part of work on issue #422; it is preliminary to making diff
(and later merge) capable of taking two paths at arbitrary revisions.

* subversion/libsvn_client/client.h (svn_client__get_revision_number):
New prototype.

* subversion/libsvn_client/revisions.c
(svn_client__get_revision_number): New file, new func.

* subversion/include/svn_client.h (svn_client_revision_kind): Add
svn_client_revision_working kind. Doc improvements.
(svn_client_diff): Change prototype to use two new
svn_client_revision_t start and end parameters, instead of separate
start_revision, start_date, end_revision, end_date params. Also, move
`target' parameter to be immediately after revision params.
(svn_client_checkout, svn_client_update): Change type of `revision'
parameter to svn_client_revision_t, remove `tm' param. Doc fixes.
(svn_client_switch): Same, and change `switch_url' to just `url'.
(svn_client_import): Doc rewrite, but leave the revision parameter
alone, it's only for the xml case.
(svn_client_log): Change type of `revision' parameter to
svn_client_revision_t.
(svn_client_move, svn_client_copy): Rename `src_rev' parameter to
`src_revision', change its type to svn_client_revision_t.

* subversion/libsvn_client/diff.c (svn_client_diff): Adjust.

* subversion/libsvn_client/log.c (svn_client_log): Adjust. If no end
revision is given, default to the oldest commit.

* subversion/libsvn_client/copy.c (svn_client_move, svn_client_copy):
Adjust prototypes.
(setup_copy): Rename `src_rev' parameter to `src_revision', change its
type to svn_client_revision_t, fix head check.
(repos_to_repos_copy, repos_to_wc_copy): Rename `src_rev' parameter to
`src_revision', change its type to svn_client_revision_t, adjust
revision accordingly.

* subversion/libsvn_client/checkout.c (svn_client_checkout): Adjust
prototype, remove revision vs date logic, and instead just call
svn_client__get_revision_number. But also attempt an early manual
conversion of the revision, for svn_wc_get_checkout_editor et al.

* subversion/libsvn_client/switch.c (svn_client_switch): Same.

* subversion/libsvn_client/update.c (svn_client_update): Same.

* subversion/clients/cmdline/cl.h (svn_cl__opt_state_t): Fields
start_revision and end_revision become svn_client_revision_t,
replacing themselves and also start_date and end_date.

* subversion/clients/cmdline/main.c (main): Adjust initializations of
start_revision and end_revision.
(parse_revision): Adjust revision parsing.
(parse_date): Adjust date parsing. Fix doc typo.

* subversion/clients/cmdline/diff-cmd.c (svn_cl__diff): Don't pass
dates to svn_client_diff. Set up revisions correctly.

* subversion/clients/cmdline/switch-cmd.c (svn_cl__switch): Don't pass
date to svn_client_switch.

* subversion/clients/cmdline/update-cmd.c (svn_cl__update): Don't pass
date to svn_client_update.

* subversion/clients/cmdline/commit-cmd.c (svn_cl__commit): Attempt an
early manual conversion of revision, for the xml case.

* subversion/clients/cmdline/import-cmd.c (svn_cl__import): Same.

* subversion/include/svn_error_codes.h
(SVN_ERR_CLIENT_RA_ACCESS_REQUIRED, SVN_ERR_CLIENT_BAD_REVISION
SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED): New error codes.

Unrelated cleanups:

* subversion/libsvn_client/commit.c (send_to_repos): Change `base_dir'
param to `base_path', this matches both doc string and semantics.

$ svn diff
Index: ./subversion/include/svn_error_codes.h
===================================================================
--- ./subversion/include/svn_error_codes.h
+++ ./subversion/include/svn_error_codes.h Thu Jan 31 21:44:31 2002
@@ -366,6 +366,20 @@
   SVN_ERRDEF (SVN_ERR_TEST_FAILED,
               "Test failed")
 
+ /* BEGIN libsvn_client errors */
+
+ SVN_ERRDEF (SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED,
+ "A path under revision control is needed for this operation")
+
+ SVN_ERRDEF (SVN_ERR_CLIENT_RA_ACCESS_REQUIRED,
+ "Repository access is needed for this operation")
+
+ SVN_ERRDEF (SVN_ERR_CLIENT_BAD_REVISION,
+ "Bogus revision information given")
+
+ /* END libsvn_client errors */
+
+
   /* BEGIN Client errors */
 
   SVN_ERRDEF (SVN_ERR_CL_ARG_PARSING_ERROR,
Index: ./subversion/include/svn_client.h
===================================================================
--- ./subversion/include/svn_client.h
+++ ./subversion/include/svn_client.h Thu Jan 31 23:39:51 2002
@@ -57,8 +57,15 @@
 
 
 
-/*** Various ways of specifying revisions. ***/
 
+/* Various ways of specifying revisions.
+ *
+ * Note:
+ * In contexts where local mods are relevant, the `working' kind
+ * refers to the uncommitted "working" revision, which may be modified
+ * with respect to its base revision. In other contexts, `working'
+ * should behave the same as `committed' or `current'.
+ */
 enum svn_client_revision_kind {
   svn_client_revision_unspecified, /* No revision information given. */
   svn_client_revision_number, /* revision given as number */
@@ -66,6 +73,7 @@
   svn_client_revision_committed, /* rev of most recent change */
   svn_client_revision_previous, /* (rev of most recent change) - 1 */
   svn_client_revision_current, /* .svn/entries revision */
+ svn_client_revision_working, /* current, plus local mods */
   svn_client_revision_head /* repository youngest */
 };
 
@@ -161,28 +169,28 @@
 
 /*** Milestone 4 Interfaces ***/
 
-/* Perform a checkout from URL, providing pre- and post-checkout hook
- editors and batons (BEFORE_EDITOR, BEFORE_EDIT_BATON /
- AFTER_EDITOR, AFTER_EDIT_BATON). These editors are purely optional
- and exist only for extensibility; pass four NULLs here if you
- don't need them.
-
- PATH will be the root directory of your checked out working copy.
-
- If XML_SRC is NULL, then the checkout will come from the repository
- and subdir specified by URL. An invalid REVISION will cause the
- "latest" tree to be fetched, while a valid REVISION will fetch a
- specific tree. Alternatively, a time TM can be used to implicitly
- select a revision. TM cannot be used at the same time as REVISION.
+/* Checkout a working copy of URL at REVISION, using PATH as the root
+ directory of the newly checked out working copy, and authenticating
+ with AUTH_BATON.
+
+ REVISION must be of kind svn_client_revision_number,
+ svn_client_revision_head, or svn_client_revision_date. In the xml
+ case (see below) svn_client_revision_unspecified is also allowed.
+ If REVISION does not meet these requirements, return the error
+ SVN_ERR_CLIENT_BAD_REVISION.
+
+ BEFORE_EDITOR, BEFORE_EDIT_BATON and AFTER_EDITOR, AFTER_EDIT_BATON
+ are pre- and post-checkout hook editors. They are optional; pass
+ four NULLs if you don't need them.
 
    If XML_SRC is non-NULL, it is an xml file to check out from; in
    this case, the working copy will record the URL as artificial
- ancestry information. An invalid REVISION implies that the
- revision *must* be present in the <delta-pkg> tag, while a valid
- REVISION will be simply be stored in the wc. (Note: a <delta-pkg>
- revision will *always* override the one passed in.)
+ ancestry information. If REVISION is
+ svn_client_revision_unspecified, then the revision *must* be
+ present in the <delta-pkg> tag; otherwise, store REVISION in the
+ wc. (Note: a <delta-pkg> revision still overrides REVISION.)
 
- This operation will use the provided memory POOL. */
+ Use POOL for any temporary allocation. */
 svn_error_t *
 svn_client_checkout (const svn_delta_edit_fns_t *before_editor,
                      void *before_edit_baton,
@@ -191,39 +199,37 @@
                      svn_client_auth_baton_t *auth_baton,
                      svn_stringbuf_t *URL,
                      svn_stringbuf_t *path,
- svn_revnum_t revision,
+ svn_client_revision_t *revision,
                      svn_boolean_t recurse,
- apr_time_t tm,
                      svn_stringbuf_t *xml_src,
                      apr_pool_t *pool);
 
 
-/* Perform an update of PATH (part of a working copy), providing pre-
- and post-checkout hook editors and batons (BEFORE_EDITOR,
- BEFORE_EDIT_BATON / AFTER_EDITOR, AFTER_EDIT_BATON). These editors
- are purely optional and exist only for extensibility; pass four
- NULLs here if you don't need them.
-
- If XML_SRC is NULL, then the update will come from the repository
- that PATH was originally checked-out from. An invalid REVISION
- will cause the PATH to be updated to the "latest" revision, while a
- valid REVISION will update to a specific tree. Alternatively, a
- time TM can be used to implicitly select a revision. TM cannot be
- used at the same time as REVISION.
+/* Update working tree PATH to REVISION, authenticating with
+ AUTH_BATON.
+
+ REVISION must be of kind svn_client_revision_number,
+ svn_client_revision_head, or svn_client_revision_date. In the xml
+ case (see below) svn_client_revision_unspecified is also allowed.
+ If REVISION does not meet these requirements, return the error
+ SVN_ERR_CLIENT_BAD_REVISION.
 
    During an update, files may be restored from the text-base if they
- have been removed from the working copy. When this happens,
+ have been removed from the working copy. When this happens,
    NOTIFY_RESTORE will be called with NOTIFY_BATON and the (relative)
- path of the file that has been restored. NOTIFY_RESTORE may be NULL
- if this information is not required.
+ path of the file that has been restored. NOTIFY_RESTORE may be
+ NULL if this information is not required.
 
- If XML_SRC is non-NULL, it is an xml file to update from. An
- invalid REVISION implies that the revision *must* be present in the
- <delta-pkg> tag, while a valid REVISION will be simply be stored in
- the wc. (Note: a <delta-pkg> revision will *always* override the
- one passed in.)
+ BEFORE_EDITOR, BEFORE_EDIT_BATON and AFTER_EDITOR, AFTER_EDIT_BATON
+ are pre- and post-update hook editors. They are optional; pass
+ four NULLs if you don't need them.
 
- This operation will use the provided memory POOL. */
+ If XML_SRC is non-NULL, it is an xml file to update from. If
+ REVISION is svn_client_revision_unspecified, then the revision
+ *must* be present in the <delta-pkg> tag; otherwise, store REVISION
+ in the wc. (Note: a <delta-pkg> revision still overrides REVISION.)
+
+ Use POOL for any temporary allocation. */
 svn_error_t *
 svn_client_update (const svn_delta_edit_fns_t *before_editor,
                    void *before_edit_baton,
@@ -232,28 +238,24 @@
                    svn_client_auth_baton_t *auth_baton,
                    svn_stringbuf_t *path,
                    svn_stringbuf_t *xml_src,
- svn_revnum_t revision,
- apr_time_t tm,
+ svn_client_revision_t *revision,
                    svn_boolean_t recurse,
                    svn_wc_notify_func_t notify_restore,
                    void *notify_baton,
                    apr_pool_t *pool);
 
 
+/* Switch working tree PATH to URL at REVISION, authenticating with
+ AUTH_BATON.
 
-/* Perform an update of PATH (part of a working copy), providing pre-
- and post-checkout hook editors and batons (BEFORE_EDITOR,
- BEFORE_EDIT_BATON / AFTER_EDITOR, AFTER_EDIT_BATON). These editors
- are purely optional and exist only for extensibility; pass four
- NULLs here if you don't need them.
-
- SWITCH_URL is the new URL that the working copy will be 'switched' to.
-
- An invalid REVISION will cause the PATH to be updated to the
- "latest" revision of SWITCH_URL, while a valid REVISION will update
- to a specific revision of SWITCH_URL. Alternatively, a time TM can
- be used to implicitly select a revision. TM cannot be used at the
- same time as REVISION.
+ Summary of purpose: this is normally used to switch a working
+ directory over to another line of development, such as a branch or
+ a tag. Switching an existing working directory is more efficient
+ than checking out URL from scratch.
+
+ REVISION must be of kind svn_client_revision_number,
+ svn_client_revision_head, or svn_client_revision_date; otherwise,
+ return SVN_ERR_CLIENT_BAD_REVISION.
 
    During a switch, files may be restored from the text-base if they
    have been removed from the working copy. When this happens,
@@ -261,7 +263,11 @@
    path of the file that has been restored. NOTIFY_RESTORE may be NULL
    if this information is not required.
 
- This operation will use the provided memory POOL. */
+ BEFORE_EDITOR, BEFORE_EDIT_BATON and AFTER_EDITOR, AFTER_EDIT_BATON
+ are pre- and post-switch hook editors. They are optional; pass
+ four NULLs if you don't need them.
+
+ Use POOL for any temporary allocation. */
 svn_error_t *
 svn_client_switch (const svn_delta_edit_fns_t *before_editor,
                    void *before_edit_baton,
@@ -269,9 +275,8 @@
                    void *after_edit_baton,
                    svn_client_auth_baton_t *auth_baton,
                    svn_stringbuf_t *path,
- svn_stringbuf_t *switch_url,
- svn_revnum_t revision,
- apr_time_t tm,
+ svn_stringbuf_t *url,
+ svn_client_revision_t *revision,
                    svn_boolean_t recurse,
                    svn_wc_notify_func_t notify_restore,
                    void *notify_baton,
@@ -348,48 +353,48 @@
                    apr_pool_t *pool);
 
 
-/* Import a tree, using optional pre- and post-commit hook editors
- (BEFORE_EDITOR, BEFORE_EDIT_BATON, and AFTER_EDITOR,
- AFTER_EDIT_BATON). These editors are purely optional and exist
- only for extensibility; pass four NULLs here if you don't need
- them.
-
- If the import succeeds, allocate (in POOL) and populate
- *COMMIT_INFO.
-
- Store LOG_MSG as the log of the commit.
-
- PATH is the path to local tree being imported. PATH can be a file
- or directory.
-
- URL is the repository directory where the imported data is placed.
+/* Import file or directory PATH into repository directory URL at
+ head, authenticating with AUTH_BATON, and using LOG_MSG as the log
+ message for the (implied) commit. Set *COMMIT_INFO to the results
+ of the commit, allocated in POOL.
   
    NEW_ENTRY is the new entry created in the repository directory
- identified by URL.
+ identified by URL. NEW_ENTRY may be null (see below), but may not
+ be the empty string.
   
- If PATH is a file, that file is imported as NEW_ENTRY. If PATH is
- a directory, the contents of that directory are imported, under a
- new directory the NEW_ENTRY in the repository. Note and the
- directory itself is not imported; that is, the basename of PATH is
- not part of the import.
-
- If PATH is a directory and NEW_ENTRY is null, then the contents of
- PATH are imported directly into the repository directory identified
- by URL. NEW_ENTRY may not be the empty string.
-
- If NEW_ENTRY already exists in the youngest revision, return error.
+ If PATH is a directory, the contents of that directory are
+ imported, under a new directory named NEW_ENTRY under URL; or if
+ NEW_ENTRY is null, then the contents of PATH are imported directly
+ into the directory identified by URL. Note that the directory PATH
+ itself is not imported -- that is, the basename of PATH is not part
+ of the import.
+
+ If PATH is a file, that file is imported as NEW_ENTRY (which may
+ not be null).
+
+ In all cases, if NEW_ENTRY already exists in URL, return error.
    
+ BEFORE_EDITOR, BEFORE_EDIT_BATON, and AFTER_EDITOR,
+ AFTER_EDIT_BATON are pre- and post-import (i.e., post-commit) hook
+ editors. They are optional; pass four NULLs here if you don't need
+ them.
+
    If XML_DST is non-NULL, it is a file in which to store the xml
    result of the commit, and REVISION is used as the revision.
    
- Use POOL for all allocation.
+ Use POOL for any temporary allocation.
    
+ Note: REVISION is svn_revnum_t, rather than svn_client_revision_t,
+ because only the svn_client_revision_number kind would be useful
+ anyway.
+
    ### kff todo: This import is similar to cvs import, in that it does
    not change the source tree into a working copy. However, this
    behavior confuses most people, and I think eventually svn _should_
    turn the tree into a working copy, or at least should offer the
    option. However, doing so is a bit involved, and we don't need it
- right now. */
+ right now.
+*/
 svn_error_t *svn_client_import (svn_client_commit_info_t **commit_info,
                                 const svn_delta_edit_fns_t *before_editor,
                                 void *before_edit_baton,
@@ -405,19 +410,18 @@
                                 apr_pool_t *pool);
 
 
-/* Perform an commit, providing pre- and post-commit hook editors and
- batons (BEFORE_EDITOR, BEFORE_EDIT_BATON, and AFTER_EDITOR,
- AFTER_EDIT_BATON). These editors are purely optional and exist
- only for extensibility; pass four NULLs here if you don't need
- them.
+/* Commit file or directory PATH into repository, authenticating with
+ AUTH_BATON, and using LOG_MSG as the log message. Set *COMMIT_INFO
+ to the results of the commit, allocated in POOL.
 
- If the commit succeeds, allocate (in POOL) and populate
- *COMMIT_INFO.
-
    TARGETS is an array of svn_stringbuf_t * paths to commit. They need
    not be canonicalized nor condensed; this function will take care of
    that.
 
+ BEFORE_EDITOR, BEFORE_EDIT_BATON, and AFTER_EDITOR,
+ AFTER_EDIT_BATON are pre- and post-commit hook editors. They are
+ optional; pass four NULLs here if you don't need them.
+
    If XML_DST is NULL, then the commit will write to a repository, and
    the REVISION argument is ignored.
 
@@ -426,10 +430,14 @@
    will be updated appropriately. If REVISION is invalid, the working
    copy remains unchanged.
 
- This operation will use the provided memory POOL.
+ Note: REVISION is svn_revnum_t, rather than svn_client_revision_t,
+ because only the svn_client_revision_number kind would be useful
+ anyway.
 
- If no error is returned, and *COMMITTED_REV is set to
- SVN_INVALID_REVNUM, then the commit was a no-op; nothing needed to
+ Use POOL for any temporary allocation.
+
+ If no error is returned and (*COMMIT_INFO)->revision is set to
+ SVN_INVALID_REVNUM, then the commit was a no-op; nothing needed to
    be committed.
  */
 svn_error_t *
@@ -501,8 +509,8 @@
 svn_error_t *
 svn_client_log (svn_client_auth_baton_t *auth_baton,
                 const apr_array_header_t *targets,
- svn_revnum_t start,
- svn_revnum_t end,
+ svn_client_revision_t *start,
+ svn_client_revision_t *end,
                 svn_boolean_t discover_changed_paths,
                 svn_log_message_receiver_t receiver,
                 void *receiver_baton,
@@ -510,30 +518,25 @@
 
 
 /* Given a TARGET which is either a path in the working copy or an URL,
- compare it against the given repository version(s).
-
- START_REVISION/START_DATE and END_REVISION/END_DATE are the two
- repository versions, for each specify either the revision of the
- date. If the two revisions are the different the two repository versions
- are compared. If the two revisions are the same the working copy is
- compared against the repository.
+ compare it against the given repository version(s). START and END
+ are the two revisions to be compared; if either has a `kind' of
+ `svn_client_revision_unspecified' or an unrecognized `kind', return
+ the error SVN_ERR_CLIENT_BAD_REVISION.
   
    If TARGET is a directory and RECURSE is true, this will be a recursive
    operation.
   
    DIFF_OPTIONS is used to pass additional command line options to the diff
- processes invoked to compare files. DIFF_OPTIONS is an array of
+ processes invoked to compare files. DIFF_OPTIONS is an array of
    svn_stringbuf_t * items.
   
    AUTH_BATON is used to communicate with the repository.
  */
-svn_error_t *svn_client_diff (svn_stringbuf_t *target,
- const apr_array_header_t *diff_options,
+svn_error_t *svn_client_diff (const apr_array_header_t *diff_options,
                               svn_client_auth_baton_t *auth_baton,
- svn_revnum_t start_revision,
- apr_time_t start_date,
- svn_revnum_t end_revision,
- apr_time_t end_date,
+ svn_client_revision_t *start,
+ svn_client_revision_t *end,
+ svn_stringbuf_t *target,
                               svn_boolean_t recurse,
                               apr_pool_t *pool);
 
@@ -564,7 +567,7 @@
 
    SRC_PATH must be a file or directory under version control, or the
    URL of a versioned item in the repository. If SRC_PATH is a URL,
- SRC_REV is used to choose the revision from which to copy the
+ SRC_REVISION is used to choose the revision from which to copy the
    SRC_PATH. DST_PATH must be a file or directory under version
    control, or a repository URL, existent or not.
 
@@ -592,7 +595,7 @@
 svn_error_t *
 svn_client_copy (svn_client_commit_info_t **commit_info,
                  svn_stringbuf_t *src_path,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                  svn_stringbuf_t *dst_path,
                  svn_client_auth_baton_t *auth_baton,
                  svn_stringbuf_t *message,
@@ -614,7 +617,7 @@
 
      - DST_PATH must also be a repository URL (existent or not).
 
- - SRC_REV is used to choose the revision from which to copy the
+ - SRC_REVISION is used to choose the revision from which to copy the
        SRC_PATH.
 
      - AUTH_BATON and MESSAGE are used to commit the move.
@@ -626,7 +629,7 @@
 
      - DST_PATH must also be a working copy path (existent or not).
 
- - SRC_REV, AUTH and MESSAGE are ignored.
+ - SRC_REVISION, AUTH and MESSAGE are ignored.
 
      - This is a scheduling operation. No changes will happen to the
        repository until a commit occurs. This scheduling can be
@@ -640,7 +643,7 @@
 svn_error_t *
 svn_client_move (svn_client_commit_info_t **commit_info,
                  svn_stringbuf_t *src_path,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                  svn_stringbuf_t *dst_path,
                  svn_client_auth_baton_t *auth_baton,
                  svn_stringbuf_t *message,
Index: ./subversion/libsvn_client/switch.c
===================================================================
--- ./subversion/libsvn_client/switch.c
+++ ./subversion/libsvn_client/switch.c Thu Jan 31 22:15:34 2002
@@ -56,8 +56,7 @@
                    svn_client_auth_baton_t *auth_baton,
                    svn_stringbuf_t *path,
                    svn_stringbuf_t *switch_url,
- svn_revnum_t revision,
- apr_time_t tm,
+ svn_client_revision_t *revision,
                    svn_boolean_t recurse,
                    svn_wc_notify_func_t notify_restore,
                    void *notify_baton,
@@ -72,6 +71,7 @@
   svn_error_t *err;
   void *ra_baton, *session;
   svn_ra_plugin_t *ra_lib;
+ svn_revnum_t revnum;
 
   /* Sanity check. Without these, the switch is meaningless. */
   assert (path != NULL);
@@ -79,13 +79,6 @@
   assert (switch_url != NULL);
   assert (switch_url->len > 0);
 
- /* If both REVISION and TM are specified, this is an error.
- They mostly likely contradict one another. */
- if ((revision != SVN_INVALID_REVNUM) && tm)
- return
- svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, 0, NULL, pool,
- "Cannot specify _both_ revision and time.");
-
   /* Unlike 'svn up', we do *not* split the local path into an
      anchor/target pair. We do this because we know that the target
      isn't going to be deleted, because we're doing a switch. */
@@ -103,12 +96,19 @@
        "svn_client_update: entry '%s' has no URL", path->data);
   URL = svn_stringbuf_dup (entry->url, pool);
 
+ /* Get revnum set to something meaningful, so we can fetch the
+ switch editor. */
+ if (revision->kind == svn_client_revision_number)
+ revnum = revision->value.number; /* do the trivial conversion manually */
+ else
+ revnum = SVN_INVALID_REVNUM; /* no matter, do real conversion later */
+
   /* Fetch the switch (update) editor. If REVISION is invalid, that's
      okay; the RA driver will call editor->set_target_revision() later
      on. */
   SVN_ERR (svn_wc_get_switch_editor (path,
                                      NULL,
- revision,
+ revnum,
                                      switch_url,
                                      recurse,
                                      &switch_editor,
@@ -129,9 +129,8 @@
   SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, path,
                                         TRUE, TRUE, auth_baton, pool));
   
- /* If TM is given, convert the time into a revision number. */
- if (tm)
- SVN_ERR (ra_lib->get_dated_revision (session, &revision, tm));
+ SVN_ERR (svn_client__get_revision_number
+ (&revnum, ra_lib, session, revision, path->data, pool));
 
   /* ### Note: the whole RA interface below will probably change soon. */
 
@@ -139,7 +138,7 @@
      invalid revnum, that means RA will use the latest revision. */
   SVN_ERR (ra_lib->do_switch (session,
                               &reporter, &report_baton,
- revision,
+ revnum,
                               NULL,
                               recurse,
                               switch_url,
Index: ./subversion/libsvn_client/checkout.c
===================================================================
--- ./subversion/libsvn_client/checkout.c
+++ ./subversion/libsvn_client/checkout.c Thu Jan 31 21:59:31 2002
@@ -45,20 +45,27 @@
                      svn_client_auth_baton_t *auth_baton,
                      svn_stringbuf_t *URL,
                      svn_stringbuf_t *path,
- svn_revnum_t revision,
+ svn_client_revision_t *revision,
                      svn_boolean_t recurse,
- apr_time_t tm,
                      svn_stringbuf_t *xml_src,
                      apr_pool_t *pool)
 {
   const svn_delta_edit_fns_t *checkout_editor;
   void *checkout_edit_baton;
   svn_error_t *err;
+ svn_revnum_t revnum;
 
   /* Sanity check. Without these, the checkout is meaningless. */
   assert (path != NULL);
   assert (URL != NULL);
 
+ /* Get revnum set to something meaningful, so we can fetch the
+ checkout editor. */
+ if (revision->kind == svn_client_revision_number)
+ revnum = revision->value.number; /* do the trivial conversion manually */
+ else
+ revnum = SVN_INVALID_REVNUM; /* no matter, do real conversion later */
+
   /* Canonicalize the URL. */
   svn_path_canonicalize (URL);
 
@@ -67,7 +74,7 @@
      later on. */
   SVN_ERR (svn_wc_get_checkout_editor (path,
                                        URL,
- revision,
+ revnum,
                                        recurse,
                                        &checkout_editor,
                                        &checkout_edit_baton,
@@ -90,28 +97,18 @@
       SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL->data, pool));
 
       /* Open an RA session to URL. Note that we do not have an admin area
- for storing temp files. We do, however, want to store auth data
+ for storing temp files. We do, however, want to store auth data
          after the checkout builds the WC. */
       SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, path,
                                             TRUE, FALSE, auth_baton, pool));
 
- /* Decide which revision to get: */
-
- /* If both REVISION and TM are specified, this is an error.
- They mostly likely contradict one another. */
- if ((revision != SVN_INVALID_REVNUM) && tm)
- return
- svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, 0, NULL, pool,
- "Cannot specify _both_ revision and time.");
-
- /* If only TM is given, convert the time into a revision number. */
- else if (tm)
- SVN_ERR (ra_lib->get_dated_revision (session, &revision, tm));
+ SVN_ERR (svn_client__get_revision_number
+ (&revnum, ra_lib, session, revision, path->data, pool));
 
       /* Tell RA to do a checkout of REVISION; if we pass an invalid
          revnum, that means RA will fetch the latest revision. */
       err = ra_lib->do_checkout (session,
- revision,
+ revnum,
                                  recurse,
                                  checkout_editor,
                                  checkout_edit_baton);
@@ -146,7 +143,7 @@
                                       checkout_editor,
                                       checkout_edit_baton,
                                       URL->data,
- revision,
+ revnum,
                                       pool);
 
       /* Sleep for one second to ensure timestamp integrity. */
Index: ./subversion/libsvn_client/diff.c
===================================================================
--- ./subversion/libsvn_client/diff.c
+++ ./subversion/libsvn_client/diff.c Fri Feb 1 00:45:57 2002
@@ -144,16 +144,15 @@
 */
 
 svn_error_t *
-svn_client_diff (svn_stringbuf_t *path,
- const apr_array_header_t *diff_options,
+svn_client_diff (const apr_array_header_t *diff_options,
                  svn_client_auth_baton_t *auth_baton,
- svn_revnum_t start_revision,
- apr_time_t start_date,
- svn_revnum_t end_revision,
- apr_time_t end_date,
+ svn_client_revision_t *start,
+ svn_client_revision_t *end,
+ svn_stringbuf_t *path,
                  svn_boolean_t recurse,
                  apr_pool_t *pool)
 {
+ svn_revnum_t start_revnum, end_revnum;
   svn_string_t path_str;
   svn_boolean_t path_is_url;
   svn_boolean_t use_admin;
@@ -168,13 +167,14 @@
   void *diff_edit_baton;
   struct diff_cmd_baton diff_cmd_baton;
 
- /* If both a revision and a date/time are specified, this is an error.
- They mostly likely contradict one another. */
- if ((SVN_IS_VALID_REVNUM(start_revision) && start_date)
- || (SVN_IS_VALID_REVNUM(end_revision) && end_date))
- return
- svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, 0, NULL, pool,
- "Cannot specify _both_ revision and time.");
+ /* Sanity check. */
+ if ((start->kind == svn_client_revision_unspecified)
+ || (end->kind == svn_client_revision_unspecified))
+ {
+ return svn_error_create
+ (SVN_ERR_CLIENT_BAD_REVISION, 0, NULL, pool,
+ "svn_client_diff: caller failed to specify any revisions");
+ }
 
   diff_cmd_baton.options = diff_options;
   diff_cmd_baton.pool = pool;
@@ -201,44 +201,62 @@
       URL = svn_stringbuf_create (entry->url->data, pool);
     }
 
- /* ### TODO: awful revision handling */
- if (!path_is_url
- && !SVN_IS_VALID_REVNUM(start_revision) && end_revision == 1
- && !start_date && !end_date)
+ if ((! path_is_url)
+ && ((start->kind == svn_client_revision_committed)
+ || (start->kind == svn_client_revision_current))
+ && (end->kind == svn_client_revision_working))
     {
- /* Not an url and no revisions, this is the 'quick' diff that does
- not contact the repository and simply uses the text base */
+ /* This is the 'quick' diff that does not contact the repository
+ and simply uses the text base. */
       return svn_wc_diff (anchor,
                           target,
                           diff_cmd, &diff_cmd_baton,
                           recurse,
                           pool);
+ /* ### todo: see comments issue #422 about how libsvn_client's
+ diff implementation prints to stdout. Apparently same is
+ true for libsvn_wc! Both will need adjusting; strongly
+ suspect that the callback abstraction will be exactly what is
+ needed to make merge share code -- that is, the same library
+ functions will be called, but with different callbacks that
+ Do The Right Thing. Random Thought: these callbacks probably
+ won't be svn_delta_edit_fns_t, because there's no depth-first
+ requirement and no need to tweak .svn/ metadata. Can be a
+ lot simpler than an editor, therefore */
     }
 
- /* Establish the RA session */
+ /* Else we must contact the repository. */
+
+ /* Establish RA session */
   SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
   SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL->data, pool));
 
   /* ### TODO: We have to pass null for the base_dir here, since the
- working copy does not match the requested revision. It might be
+ working copy does not match the requested revision. It might be
      possible to have a special ra session for diff, where get_wc_prop
      cooperates with the editor and returns values when the file is in the
      wc, and null otherwise. */
   SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, NULL,
                                         FALSE, FALSE, auth_baton, pool));
 
- if (start_date)
- SVN_ERR (ra_lib->get_dated_revision (session, &start_revision, start_date));
- if (end_date)
- SVN_ERR (ra_lib->get_dated_revision (session, &end_revision, end_date));
-
- /* ### TODO: Warn the user? */
- if (path_is_url && start_revision == end_revision)
- return SVN_NO_ERROR;
+ /* ### todo: later, when we take two (or N) targets and a more
+ sophisticated indication of their interaction with start and end,
+ these calls will need to be rearranged. */
+ SVN_ERR (svn_client__get_revision_number
+ (&start_revnum, ra_lib, session, start, path->data, pool));
+ SVN_ERR (svn_client__get_revision_number
+ (&end_revnum, ra_lib, session, end, path->data, pool));
+
+ /* ### todo: For the moment, we'll maintain the two distinct diff
+ editors, svn_wc vs svn_client, in order to get this change done
+ in a finite amount of time. Next the two editors will be unified
+ into one "lazy" editor that uses local data whenever possible. */
 
- if (start_revision == end_revision)
+ /* fooo working here */
+
+ if (end->kind == svn_client_revision_working)
     {
- /* The working copy is involved if only one revision is given */
+ /* The working copy is involved in this case. */
       SVN_ERR (svn_wc_get_diff_editor (anchor, target,
                                        diff_cmd, &diff_cmd_baton,
                                        recurse,
@@ -247,7 +265,7 @@
 
       SVN_ERR (ra_lib->do_update (session,
                                   &reporter, &report_baton,
- end_revision,
+ end_revnum,
                                   target,
                                   recurse,
                                   diff_editor, diff_edit_baton));
@@ -257,9 +275,9 @@
                                        NULL, NULL, /* notification is N/A */
                                        pool));
     }
- else
+ else /* ### todo: there may be uncovered cases remaining */
     {
- /* Pure repository comparison if two revisions are given */
+ /* Pure repository comparison. */
 
       /* Open a second session used to request individual file
          contents. Although a session can be used for multiple requests, it
@@ -282,18 +300,18 @@
                                             &diff_cmd_baton,
                                             recurse,
                                             ra_lib, session2,
- start_revision,
+ start_revnum,
                                             &diff_editor, &diff_edit_baton,
                                             pool));
 
       SVN_ERR (ra_lib->do_update (session,
                                   &reporter, &report_baton,
- end_revision,
+ end_revnum,
                                   target,
                                   recurse,
                                   diff_editor, diff_edit_baton));
 
- SVN_ERR (reporter->set_path (report_baton, "", start_revision));
+ SVN_ERR (reporter->set_path (report_baton, "", start_revnum));
 
       SVN_ERR (reporter->finish_report (report_baton));
 
Index: ./subversion/libsvn_client/copy.c
===================================================================
--- ./subversion/libsvn_client/copy.c
+++ ./subversion/libsvn_client/copy.c Thu Jan 31 23:38:54 2002
@@ -104,7 +104,7 @@
 static svn_error_t *
 repos_to_repos_copy (svn_client_commit_info_t **commit_info,
                      svn_stringbuf_t *src_url,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                      svn_stringbuf_t *dst_url,
                      svn_client_auth_baton_t *auth_baton,
                      svn_stringbuf_t *message,
@@ -124,6 +124,7 @@
   svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
   const char *committed_date = NULL;
   const char *committed_author = NULL;
+ svn_revnum_t src_revnum;
 
   /* ### TODO: Currently, this function will violate the depth-first
      rule of editors when doing a move of something up into one of its
@@ -183,19 +184,25 @@
   SVN_ERR (svn_client__open_ra_session (&sess, ra_lib, top_url, NULL,
                                         FALSE, FALSE, auth_baton, pool));
 
+ /* Pass null for the path, to ensure error if trying to get a
+ revision based on the working copy. */
+ SVN_ERR (svn_client__get_revision_number
+ (&src_revnum, ra_lib, sess, src_revision, NULL, pool));
+
   SVN_ERR (ra_lib->get_latest_revnum (sess, &youngest));
 
   /* Use YOUNGEST for copyfrom args if not provided. */
- if (! SVN_IS_VALID_REVNUM (src_rev))
- src_rev = youngest;
+ if (! SVN_IS_VALID_REVNUM (src_revnum))
+ src_revnum = youngest;
   
   /* Verify that SRC_URL exists in the repository. */
   SVN_ERR (ra_lib->check_path (&src_kind, sess,
- src_rel ? src_rel->data : NULL, src_rev));
+ src_rel ? src_rel->data : NULL, src_revnum));
   if (src_kind == svn_node_none)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FOUND, 0, NULL, pool,
- "path `%s' does not exist in revision `%ld'", src_url->data, src_rev);
+ "path `%s' does not exist in revision `%ld'",
+ src_url->data, src_revnum);
 
   /* Figure out the basename that will result from this operation. */
   SVN_ERR (ra_lib->check_path (&dst_kind, sess,
@@ -244,13 +251,13 @@
   if (src_kind == svn_node_dir)
     {
       SVN_ERR (editor->add_directory (basename, batons[i], src_url,
- src_rev, &baton));
+ src_revnum, &baton));
       SVN_ERR (editor->close_directory (baton));
     }
   else
     {
       SVN_ERR (editor->add_file (basename, batons[i], src_url,
- src_rev, &baton));
+ src_revnum, &baton));
       SVN_ERR (editor->close_file (baton));
     }
 
@@ -405,7 +412,7 @@
 
 static svn_error_t *
 repos_to_wc_copy (svn_stringbuf_t *src_url,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                   svn_stringbuf_t *dst_path,
                   svn_client_auth_baton_t *auth_baton,
                   svn_stringbuf_t *message,
@@ -422,6 +429,7 @@
   svn_node_kind_t src_kind, dst_kind;
   const svn_delta_edit_fns_t *editor;
   void *edit_baton;
+ svn_revnum_t src_revnum;
 
   /* Get the RA vtable that matches URL. */
   SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
@@ -434,14 +442,19 @@
   SVN_ERR (svn_client__open_ra_session (&sess, ra_lib, src_url, NULL,
                                         TRUE, FALSE, auth_baton, pool));
       
+ /* Pass null for the path, to ensure error if trying to get a
+ revision based on the working copy. */
+ SVN_ERR (svn_client__get_revision_number
+ (&src_revnum, ra_lib, sess, src_revision, NULL, pool));
+
   /* Verify that SRC_URL exists in the repository. */
- SVN_ERR (ra_lib->check_path (&src_kind, sess, "", src_rev));
+ SVN_ERR (ra_lib->check_path (&src_kind, sess, "", src_revnum));
   if (src_kind == svn_node_none)
     {
- if (SVN_IS_VALID_REVNUM (src_rev))
+ if (SVN_IS_VALID_REVNUM (src_revnum))
         return svn_error_createf
           (SVN_ERR_FS_NOT_FOUND, 0, NULL, pool,
- "path `%s' not found in revision `%ld'", src_url->data, src_rev);
+ "path `%s' not found in revision `%ld'", src_url->data, src_revnum);
       else
         return svn_error_createf
           (SVN_ERR_FS_NOT_FOUND, 0, NULL, pool,
@@ -497,7 +510,7 @@
       /* Get a checkout editor and wrap it. */
       SVN_ERR (svn_wc_get_checkout_editor (dst_path,
                                            src_url,
- src_rev,
+ src_revnum,
                                            1,
                                            &editor,
                                            &edit_baton,
@@ -510,9 +523,9 @@
       
       /* Check out the new tree. The parent dir will get no entry, so
          it will be as if the new tree isn't really there yet. */
- SVN_ERR (ra_lib->do_checkout (sess, src_rev, 1, editor, edit_baton));
+ SVN_ERR (ra_lib->do_checkout (sess, src_revnum, 1, editor, edit_baton));
 
- if (! SVN_IS_VALID_REVNUM(src_rev))
+ if (! SVN_IS_VALID_REVNUM(src_revnum))
         {
           /* If we just checked out from the "head" revision, that's fine,
              but we don't want to pass a '-1' as a copyfrom_rev to
@@ -531,7 +544,7 @@
              should be the copyfrom_revision when we commit later. */
           svn_wc_entry_t *d_entry;
           SVN_ERR (svn_wc_entry (&d_entry, dst_path, pool));
- src_rev = d_entry->revision;
+ src_revnum = d_entry->revision;
         }
 
     } /* end directory case */
@@ -559,7 +572,7 @@
       /* Have the RA layer 'push' data at this stream. We pass a
          relative path of "", because we opened SRC_URL, which is
          already the full URL to the file. */
- SVN_ERR (ra_lib->get_file (sess, "", src_rev, fstream,
+ SVN_ERR (ra_lib->get_file (sess, "", src_revnum, fstream,
                                  &fetched_rev, &props));
 
       for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
@@ -579,12 +592,12 @@
                                   "failed to close file '%s'.",
                                   dst_path->data);
      
- /* Also, if SRC_REV is invalid ('head'), then FETCHED_REV is now
+ /* Also, if SRC_REVNUM is invalid ('head'), then FETCHED_REV is now
          equal to the revision that was actually retrieved. This is
          the value we want to use as 'copyfrom_rev' in the call to
          svn_wc_add() below. */
- if (! SVN_IS_VALID_REVNUM (src_rev))
- src_rev = fetched_rev;
+ if (! SVN_IS_VALID_REVNUM (src_revnum))
+ src_revnum = fetched_rev;
     }
 
   /* Free the RA session. */
@@ -596,7 +609,7 @@
      rewritten, wcprops removed, and everything marked as 'copied'.
      See comment in svn_wc_add()'s doc about whether svn_wc_add is the
      appropriate place for this. */
- SVN_ERR (svn_wc_add (dst_path, src_url, src_rev,
+ SVN_ERR (svn_wc_add (dst_path, src_url, src_revnum,
                        notify_added, notify_baton, pool));
 
 
@@ -607,7 +620,7 @@
 static svn_error_t *
 setup_copy (svn_client_commit_info_t **commit_info,
             svn_stringbuf_t *src_path,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
             svn_stringbuf_t *dst_path,
             svn_client_auth_baton_t *auth_baton,
             svn_stringbuf_t *message,
@@ -636,8 +649,13 @@
   /* Disallow moves between the working copy and the repository. */
   if (is_move)
     {
- if (SVN_IS_VALID_REVNUM (src_rev))
- return svn_error_create
+ /* ### todo: this check could fail wrongly. For example,
+ someone could pass in an svn_client_revision_number that just
+ happens to be the HEAD. Not sure there's anything we can do
+ about that right now, as we don't want to muck up this
+ function with RA calls and such. */
+ if (src_revision->kind != svn_client_revision_head)
+ return svn_error_create
           (SVN_ERR_UNSUPPORTED_FEATURE, 0, NULL, pool,
            "move operations are only allowed on the HEAD revision");
 
@@ -681,7 +699,7 @@
                                pool));
 
   else if ((src_is_url) && (! dst_is_url))
- SVN_ERR (repos_to_wc_copy (src_path, src_rev,
+ SVN_ERR (repos_to_wc_copy (src_path, src_revision,
                                dst_path, auth_baton, message,
                                before_editor, before_edit_baton,
                                after_editor, after_edit_baton,
@@ -689,8 +707,9 @@
                                pool));
 
   else
- SVN_ERR (repos_to_repos_copy (commit_info, src_path, src_rev, dst_path,
- auth_baton, message, is_move, pool));
+ SVN_ERR (repos_to_repos_copy (commit_info, src_path, src_revision,
+ dst_path, auth_baton, message, is_move,
+ pool));
 
   return SVN_NO_ERROR;
 }
@@ -702,7 +721,7 @@
 svn_error_t *
 svn_client_copy (svn_client_commit_info_t **commit_info,
                  svn_stringbuf_t *src_path,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                  svn_stringbuf_t *dst_path,
                  svn_client_auth_baton_t *auth_baton,
                  svn_stringbuf_t *message,
@@ -715,7 +734,7 @@
                  apr_pool_t *pool)
 {
   return setup_copy (commit_info,
- src_path, src_rev, dst_path, auth_baton, message,
+ src_path, src_revision, dst_path, auth_baton, message,
                      before_editor, before_edit_baton,
                      after_editor, after_edit_baton,
                      FALSE /* is_move */,
@@ -727,7 +746,7 @@
 svn_error_t *
 svn_client_move (svn_client_commit_info_t **commit_info,
                  svn_stringbuf_t *src_path,
- svn_revnum_t src_rev,
+ svn_client_revision_t *src_revision,
                  svn_stringbuf_t *dst_path,
                  svn_client_auth_baton_t *auth_baton,
                  svn_stringbuf_t *message,
@@ -738,7 +757,7 @@
                  apr_pool_t *pool)
 {
   return setup_copy (commit_info,
- src_path, src_rev, dst_path, auth_baton, message,
+ src_path, src_revision, dst_path, auth_baton, message,
                      NULL, NULL, /* no before_editor, before_edit_baton */
                      NULL, NULL, /* no after_editor, after_edit_baton */
                      TRUE /* is_move */,
Index: ./subversion/libsvn_client/log.c
===================================================================
--- ./subversion/libsvn_client/log.c
+++ ./subversion/libsvn_client/log.c Thu Jan 31 23:49:42 2002
@@ -48,8 +48,8 @@
 svn_error_t *
 svn_client_log (svn_client_auth_baton_t *auth_baton,
                 const apr_array_header_t *targets,
- svn_revnum_t start,
- svn_revnum_t end,
+ svn_client_revision_t *start,
+ svn_client_revision_t *end,
                 svn_boolean_t discover_changed_paths,
                 svn_log_message_receiver_t receiver,
                 void *receiver_baton,
@@ -61,6 +61,7 @@
   svn_wc_entry_t *entry;
   svn_stringbuf_t *basename;
   apr_array_header_t *condensed_targets;
+ svn_revnum_t start_revnum, end_revnum;
 
   SVN_ERR (svn_path_condense_targets (&basename, &condensed_targets,
                                       targets, pool));
@@ -85,10 +86,18 @@
   SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, basename,
                                         TRUE, TRUE, auth_baton, pool));
 
+ SVN_ERR (svn_client__get_revision_number
+ (&start_revnum, ra_lib, session, start, basename->data, pool));
+ SVN_ERR (svn_client__get_revision_number
+ (&end_revnum, ra_lib, session, end, basename->data, pool));
+
+ if (! SVN_IS_VALID_REVNUM (end_revnum))
+ end_revnum = 1; /* default to the oldest commit */
+
   SVN_ERR (ra_lib->get_log (session,
                             condensed_targets, /* ### todo: or `targets'? */
- start,
- end,
+ start_revnum,
+ end_revnum,
                             discover_changed_paths,
                             receiver,
                             receiver_baton));
Index: ./subversion/libsvn_client/revisions.c
===================================================================
--- ./subversion/libsvn_client/revisions.c
+++ ./subversion/libsvn_client/revisions.c Fri Feb 1 00:22:20 2002
@@ -0,0 +1,136 @@
+/*
+ * revisions.c: discovering revisions
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2001 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
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include <apr_pools.h>
+
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_ra.h"
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+
+
+svn_error_t *
+svn_client__get_revision_number (svn_revnum_t *revnum,
+ svn_ra_plugin_t *ra_lib,
+ void *sess,
+ svn_client_revision_t *revision,
+ const char *path,
+ apr_pool_t *pool)
+{
+ /* ### When revision->kind == svn_client_revision_date, is there an
+ optimization such that we can compare revision->value->date with
+ the committed-date in the entries file (or rather, with some
+ range of which committed-date is one endpoint), and sometimes
+ avoid a trip over the RA layer? The only optimizations I can
+ think of involve examining other entries to build a timespan
+ across which committed-revision is known to be the head, but it
+ doesn't seem worth it. -kff */
+
+ /* Sanity check. */
+ if (((ra_lib == NULL) || (sess == NULL))
+ && ((revision->kind == svn_client_revision_date)
+ || (revision->kind == svn_client_revision_head)))
+ {
+ return svn_error_create
+ (SVN_ERR_CLIENT_RA_ACCESS_REQUIRED, 0, NULL, pool,
+ "svn_client__get_revision_number: "
+ "need ra_lib and session for date or head revisions.");
+ }
+
+ if (revision->kind == svn_client_revision_number)
+ *revnum = revision->value.number;
+ else if (revision->kind == svn_client_revision_date)
+ SVN_ERR (ra_lib->get_dated_revision (sess, revnum, revision->value.date));
+ else if (revision->kind == svn_client_revision_head)
+ SVN_ERR (ra_lib->get_latest_revnum (sess, revnum));
+ else if (revision->kind == svn_client_revision_unspecified)
+ *revnum = SVN_INVALID_REVNUM;
+ else if ((revision->kind == svn_client_revision_committed)
+ || (revision->kind == svn_client_revision_working)
+ || (revision->kind == svn_client_revision_current)
+ || (revision->kind == svn_client_revision_previous))
+ {
+ /* Darn it, I am not going to propagate the stringbuf madness
+ through to this function's interface. */
+ svn_stringbuf_t *path_strbuf;
+ svn_wc_entry_t *ent;
+
+ /* Sanity check. */
+ if (path == NULL)
+ return svn_error_create
+ (SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, 0, NULL, pool,
+ "svn_client__get_revision_number: "
+ "need a version-controlled path to fetch local revision info.");
+
+ path_strbuf = svn_stringbuf_create (path, pool);
+ SVN_ERR (svn_wc_entry (&ent, path_strbuf, pool));
+
+ if (! ent)
+ return svn_error_createf
+ (SVN_ERR_UNVERSIONED_RESOURCE, 0, NULL, pool,
+ "svn_client__get_revision: '%s' not under revision control", path);
+
+ if ((revision->kind == svn_client_revision_current)
+ || (revision->kind == svn_client_revision_working))
+ *revnum = ent->revision;
+ else
+ {
+ /* ### todo: This whole svn_wc_entry_t thing is a mess, with
+ some kinds of data being "first class", in that they get
+ fields directly in the structure, while other kinds need
+ manual retrieval (augh!) from the hash. There are now
+ several places in Subversion like this, where we grab the
+ value from the entry's attribute hash, and convert it
+ from string to revnum. Wouldn't it be nice to make some
+ sort of accessor layer to svn_wc_entry_t? Or would that
+ just be adding more bureaucracy? Perhaps the committed
+ rev should simply be invited into the first class lounge,
+ where it can enjoy free martinis with current rev? */
+
+ svn_stringbuf_t *revstr = apr_hash_get (ent->attributes,
+ SVN_ENTRY_ATTR_COMMITTED_REV,
+ APR_HASH_KEY_STRING);
+
+ *revnum = SVN_STR_TO_REV (revstr->data);
+ if (revision->kind == svn_client_revision_previous)
+ (*revnum)--;
+ }
+ }
+ else
+ return svn_error_createf
+ (SVN_ERR_CLIENT_BAD_REVISION, 0, NULL, pool,
+ "svn_client__get_revision_number: "
+ "unrecognized revision type requested for '%s'", path);
+
+ return SVN_NO_ERROR;
+}
+
+
+
+/*
+ * local variables:
+ * eval: (load-file "../svn-dev.el")
+ * end: */
Index: ./subversion/libsvn_client/update.c
===================================================================
--- ./subversion/libsvn_client/update.c
+++ ./subversion/libsvn_client/update.c Thu Jan 31 22:23:11 2002
@@ -61,8 +61,7 @@
                    svn_client_auth_baton_t *auth_baton,
                    svn_stringbuf_t *path,
                    svn_stringbuf_t *xml_src,
- svn_revnum_t revision,
- apr_time_t tm,
+ svn_client_revision_t *revision,
                    svn_boolean_t recurse,
                    svn_wc_notify_func_t notify_restore,
                    void *notify_baton,
@@ -76,18 +75,12 @@
   svn_stringbuf_t *URL;
   svn_stringbuf_t *anchor, *target;
   svn_error_t *err;
+ svn_revnum_t revnum;
 
   /* Sanity check. Without this, the update is meaningless. */
   assert (path != NULL);
   assert (path->len > 0);
 
- /* If both REVISION and TM are specified, this is an error.
- They mostly likely contradict one another. */
- if ((revision != SVN_INVALID_REVNUM) && tm)
- return
- svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, 0, NULL, pool,
- "Cannot specify _both_ revision and time.");
-
   /* Use PATH to get the update's anchor and targets. */
   SVN_ERR (svn_wc_get_actual_target (path, &anchor, &target, pool));
 
@@ -103,12 +96,19 @@
        "svn_client_update: entry '%s' has no URL", anchor->data);
   URL = svn_stringbuf_dup (entry->url, pool);
 
+ /* Get revnum set to something meaningful, so we can fetch the
+ update editor. */
+ if (revision->kind == svn_client_revision_number)
+ revnum = revision->value.number; /* do the trivial conversion manually */
+ else
+ revnum = SVN_INVALID_REVNUM; /* no matter, do real conversion later */
+
   /* Fetch the update editor. If REVISION is invalid, that's okay;
      either the RA or XML driver will call editor->set_target_revision
      later on. */
   SVN_ERR (svn_wc_get_update_editor (anchor,
                                      target,
- revision,
+ revnum,
                                      recurse,
                                      &update_editor,
                                      &update_edit_baton,
@@ -134,15 +134,16 @@
       SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, anchor,
                                             TRUE, TRUE, auth_baton, pool));
 
- /* If TM is given, convert the time into a revision number. */
- if (tm)
- SVN_ERR (ra_lib->get_dated_revision (session, &revision, tm));
-
+ /* ### todo: shouldn't svn_client__get_revision_number be able
+ to take a url as easily as a local path? */
+ SVN_ERR (svn_client__get_revision_number
+ (&revnum, ra_lib, session, revision, anchor->data, pool));
+
       /* Tell RA to do a update of URL+TARGET to REVISION; if we pass an
          invalid revnum, that means RA will use the latest revision. */
       SVN_ERR (ra_lib->do_update (session,
                                   &reporter, &report_baton,
- revision,
+ revnum,
                                   target,
                                   recurse,
                                   update_editor, update_edit_baton));
@@ -185,7 +186,7 @@
                                       update_editor,
                                       update_edit_baton,
                                       URL->data,
- revision,
+ revnum,
                                       pool);
 
       /* Sleep for one second to ensure timestamp integrity. */
Index: ./subversion/libsvn_client/client.h
===================================================================
--- ./subversion/libsvn_client/client.h
+++ ./subversion/libsvn_client/client.h Fri Feb 1 00:20:09 2002
@@ -30,6 +30,41 @@
 #include "svn_client.h"
 
 
+
+/* Set *REVNUM to the revision number identified by REVISION.
+ *
+ * If REVISION->kind is svn_client_revision_number, just use
+ * REVISION->value.number, ignoring PATH, RA_LIB, and SESSION.
+ *
+ * Else if REVISION->kind is svn_client_revision_committed,
+ * svn_client_revision_previous, or svn_client_revision_current, or
+ * svn_client_revision_working, then the revision can be identified
+ * purely based on the working copy's administrative information for
+ * PATH, so RA_LIB and SESSION are ignored. If PATH is not under
+ * revision control, return SVN_ERR_UNVERSIONED_RESOURCE, or if PATH
+ * is null, return SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED.
+ *
+ * Else if REVISION->kind is svn_client_revision_date or
+ * svn_client_revision_head, then RA_LIB and SESSION are used to
+ * retrieve the revision from the repository (using
+ * REVISION->value.date in the former case), and PATH is ignored. If
+ * RA_LIB or SESSION is null, return SVN_ERR_CLIENT_RA_ACCESS_REQUIRED.
+ *
+ * Else if REVISION->kind is svn_client_revision_unspecified, set
+ * *REVNUM to SVN_INVALID_REVNUM.
+ *
+ * Else return SVN_ERR_CLIENT_BAD_REVISION.
+ *
+ * Use POOL for any temporary allocation.
+ */
+svn_error_t *svn_client__get_revision_number (svn_revnum_t *revnum,
+ svn_ra_plugin_t *ra_lib,
+ void *session,
+ svn_client_revision_t *revision,
+ const char *path,
+ apr_pool_t *pool);
+
+
 /* ---------------------------------------------------------------- */
 
 /*** RA callbacks ***/
Index: ./subversion/libsvn_client/commit.c
===================================================================
--- ./subversion/libsvn_client/commit.c
+++ ./subversion/libsvn_client/commit.c Thu Jan 31 20:50:59 2002
@@ -391,7 +391,7 @@
                void *before_edit_baton,
                const svn_delta_edit_fns_t *after_editor,
                void *after_edit_baton,
- svn_stringbuf_t *base_dir,
+ svn_stringbuf_t *base_path,
                apr_array_header_t *condensed_targets,
                svn_stringbuf_t *url, /* null unless importing */
                svn_stringbuf_t *new_entry, /* null except when importing */
@@ -426,7 +426,7 @@
      the assignments to committed_date and committed_author near the
      end of this function, as they'll need to allocate new storage. */
   ccb.pool = pool;
- ccb.prefix_path = base_dir;
+ ccb.prefix_path = base_path;
   committed_targets = apr_hash_make (pool);
 
   if (url)
@@ -494,13 +494,13 @@
       if (! is_import)
         {
           /* Construct full URL from PATH. */
- SVN_ERR (svn_wc_entry (&entry, base_dir, pool));
+ SVN_ERR (svn_wc_entry (&entry, base_path, pool));
           url = entry->url;
 
           if (entry->copied)
             return svn_error_createf
               (SVN_ERR_CL_COMMIT_IN_ADDED_DIR, 0, NULL, pool,
- "%s was already scheduled for addition.", base_dir->data);
+ "%s was already scheduled for addition.", base_path->data);
         }
       
       /* Make sure our log message at least exists, even if empty. */
@@ -514,7 +514,7 @@
       /* Open an RA session to URL. */
       /* (Notice that in the case of import, we do NOT want the RA
          layer to attempt to store auth info in the wc.) */
- SVN_ERR (svn_client__open_ra_session (&session, ra_lib, url, base_dir,
+ SVN_ERR (svn_client__open_ra_session (&session, ra_lib, url, base_path,
                                             !is_import, !is_import,
                                             auth_baton, pool));
 
@@ -544,7 +544,7 @@
                                 &test_edit_baton,
                                 svn_stream_from_stdio (stdout, pool),
                                 0,
- base_dir,
+ base_path,
                                 pool));
   
   svn_delta_compose_editors (&editor, &edit_baton,
@@ -563,7 +563,7 @@
   if (is_import)
     {
       /* Crawl a directory tree, importing. */
- err = import (base_dir, new_entry, editor, edit_baton, pool);
+ err = import (base_path, new_entry, editor, edit_baton, pool);
       if (err)
         {
           /* ignoring the return value of this. we're *already* about
@@ -580,14 +580,14 @@
 
       if (xml_dst && xml_dst->data)
         /* committing to XML */
- err = svn_wc_crawl_local_mods (base_dir,
+ err = svn_wc_crawl_local_mods (base_path,
                                        condensed_targets,
                                        editor, edit_baton,
                                        NULL, NULL,
                                        pool);
       else
         /* committing to RA layer */
- err = svn_wc_crawl_local_mods (base_dir,
+ err = svn_wc_crawl_local_mods (base_path,
                                        condensed_targets,
                                        editor, edit_baton,
                                        &(ra_lib->get_latest_revnum), session,
Index: ./subversion/clients/cmdline/cl.h
===================================================================
--- ./subversion/clients/cmdline/cl.h
+++ ./subversion/clients/cmdline/cl.h Fri Feb 1 00:12:55 2002
@@ -57,15 +57,10 @@
    commands. */
 typedef struct svn_cl__opt_state_t
 {
- /* You probably want start_revision to default SVN_INVALID_REVNUM
- (which means `head' to the RA layer), and end_revision to default
- to 0 or 1, which are the two possibilities for oldest revision. */
- svn_revnum_t start_revision; /* X in "svn blah -r X" or "svn blah -r X:Y" */
- svn_revnum_t end_revision; /* Y in "svn blah -r X:Y" */
-
- /* These should default to 0. */
- apr_time_t start_date; /* X in "svn blah -D X" or "svn blah -D X:Y" */
- apr_time_t end_date; /* Y in "svn blah -D X:Y" */
+ /* These get set as a result of revisions or dates being specified.
+ When only one revision is given, it is stored in start_revision,
+ and end_revision remains `svn_client_revision_unspecified'. */
+ svn_client_revision_t *start_revision, *end_revision;
 
   svn_stringbuf_t *message; /* log message */
 
Index: ./subversion/clients/cmdline/checkout-cmd.c
===================================================================
--- ./subversion/clients/cmdline/checkout-cmd.c
+++ ./subversion/clients/cmdline/checkout-cmd.c Thu Jan 31 22:20:28 2002
@@ -122,7 +122,6 @@
                                  local_dir,
                                  opt_state->start_revision,
                                  opt_state->nonrecursive ? FALSE : TRUE,
- opt_state->start_date,
                                  opt_state->xml_file,
                                  pool);
       if (err)
Index: ./subversion/clients/cmdline/diff-cmd.c
===================================================================
--- ./subversion/clients/cmdline/diff-cmd.c
+++ ./subversion/clients/cmdline/diff-cmd.c Fri Feb 1 00:02:47 2002
@@ -56,18 +56,22 @@
 
   auth_baton = svn_cl__make_auth_baton (opt_state, pool);
 
+ if (opt_state->start_revision->kind == svn_client_revision_unspecified)
+ opt_state->start_revision->kind = svn_client_revision_current;
+
+ if (opt_state->end_revision->kind == svn_client_revision_unspecified)
+ opt_state->end_revision->kind = svn_client_revision_working;
+
   for (i = 0; i < condensed_targets->nelts; ++i)
     {
       svn_stringbuf_t *target
         = ((svn_stringbuf_t **) (condensed_targets->elts))[i];
 
- SVN_ERR (svn_client_diff (target,
- options,
+ SVN_ERR (svn_client_diff (options,
                                 auth_baton,
                                 opt_state->start_revision,
- opt_state->start_date,
                                 opt_state->end_revision,
- opt_state->end_date,
+ target,
                                 opt_state->nonrecursive ? FALSE : TRUE,
                                 pool));
     }
Index: ./subversion/clients/cmdline/log-cmd.c
===================================================================
--- ./subversion/clients/cmdline/log-cmd.c
+++ ./subversion/clients/cmdline/log-cmd.c Thu Jan 31 23:46:02 2002
@@ -182,9 +182,6 @@
   /* Add "." if user passed 0 arguments */
   svn_cl__push_implicit_dot_target(targets, pool);
 
- /* ### todo: If opt_state->{start,end}_date, then convert to
- opt_state->{start,end}_revision here. */
-
   lb.first_call = 1;
   lb.pool = pool;
   SVN_ERR (svn_client_log (auth_baton,
Index: ./subversion/clients/cmdline/update-cmd.c
===================================================================
--- ./subversion/clients/cmdline/update-cmd.c
+++ ./subversion/clients/cmdline/update-cmd.c Thu Jan 31 23:43:44 2002
@@ -80,7 +80,6 @@
                 target,
                 opt_state->xml_file,
                 opt_state->start_revision,
- opt_state->start_date,
                 opt_state->nonrecursive ? FALSE : TRUE,
                 (opt_state->quiet ? NULL : svn_cl__notify_restored), NULL,
                 pool));
Index: ./subversion/clients/cmdline/commit-cmd.c
===================================================================
--- ./subversion/clients/cmdline/commit-cmd.c
+++ ./subversion/clients/cmdline/commit-cmd.c Thu Jan 31 22:26:13 2002
@@ -454,6 +454,7 @@
   svn_client_commit_info_t *commit_info = NULL;
   svn_stringbuf_t *messagep=NULL;
   svn_error_t *error;
+ svn_revnum_t revnum;
 
   /* Take our message from ARGV or a FILE */
   if (opt_state->filedata)
@@ -558,6 +559,12 @@
             trace_dir,
             pool));
 
+ /* Get revnum set to something meaningful, to cover the xml case. */
+ if (opt_state->start_revision->kind == svn_client_revision_number)
+ revnum = opt_state->start_revision->value.number;
+ else
+ revnum = SVN_INVALID_REVNUM; /* no matter, this is fine */
+
   /* Commit. */
   error = svn_client_commit (&commit_info,
                              NULL, NULL,
@@ -567,7 +574,7 @@
                              targets,
                              message,
                              opt_state->xml_file,
- opt_state->start_revision,
+ revnum,
                              pool);
 
   if (error)
Index: ./subversion/clients/cmdline/switch-cmd.c
===================================================================
--- ./subversion/clients/cmdline/switch-cmd.c
+++ ./subversion/clients/cmdline/switch-cmd.c Thu Jan 31 23:43:32 2002
@@ -101,7 +101,6 @@
             target,
             switch_url,
             opt_state->start_revision,
- opt_state->start_date,
             opt_state->nonrecursive ? FALSE : TRUE,
             (opt_state->quiet ? NULL : svn_cl__notify_restored), NULL,
             pool));
Index: ./subversion/clients/cmdline/import-cmd.c
===================================================================
--- ./subversion/clients/cmdline/import-cmd.c
+++ ./subversion/clients/cmdline/import-cmd.c Thu Jan 31 22:27:40 2002
@@ -48,6 +48,7 @@
   void *trace_edit_baton;
   svn_client_auth_baton_t *auth_baton;
   svn_client_commit_info_t *commit_info = NULL;
+ svn_revnum_t revnum;
 
   /* Take our message from ARGV or a FILE */
   if (opt_state->filedata)
@@ -127,6 +128,12 @@
                                             printpath,
                                             pool));
 
+ /* Get revnum set to something meaningful, to cover the xml case. */
+ if (opt_state->start_revision->kind == svn_client_revision_number)
+ revnum = opt_state->start_revision->value.number;
+ else
+ revnum = SVN_INVALID_REVNUM; /* no matter, this is fine */
+
   SVN_ERR (svn_client_import (&commit_info,
                               NULL, NULL,
                               opt_state->quiet ? NULL : trace_editor,
@@ -137,7 +144,7 @@
                               new_entry,
                               message,
                               opt_state->xml_file,
- opt_state->start_revision,
+ revnum,
                               pool));
 
   if (commit_info)
Index: ./subversion/clients/cmdline/main.c
===================================================================
--- ./subversion/clients/cmdline/main.c
+++ ./subversion/clients/cmdline/main.c Fri Feb 1 00:16:23 2002
@@ -574,25 +574,44 @@
       *(left_rev + (sep - arg)) = '\0';
       right_rev = (left_rev + (sep - arg)) + 1;
     }
- else /* If no separator, set left_rev, right_rev to same string. */
- left_rev = right_rev = apr_pstrdup (pool, arg);
+ else
+ {
+ left_rev = apr_pstrdup (pool, arg);
+ right_rev = NULL;
+ }
 
   /* Validate each revision individually. */
- if ((validate_revision (left_rev) != 0)
- || (validate_revision (right_rev) != 0))
+ if (validate_revision (left_rev) != 0)
+ return 1;
+ if (right_rev && (validate_revision (right_rev) != 0))
     return 1;
     
   /* Okay, no syntax problems, parse 'em. */
   
   if ((left_rev[0] == 'h') || (left_rev[0] == 'H') || (left_rev[0] == '\0'))
- os->start_revision = SVN_INVALID_REVNUM;
+ os->start_revision->kind = svn_client_revision_head;
   else
- os->start_revision = SVN_STR_TO_REV (left_rev);
+ {
+ os->start_revision->kind = svn_client_revision_number;
+ os->start_revision->value.number = SVN_STR_TO_REV (left_rev);
+ }
 
- if ((right_rev[0] == 'h') || (right_rev[0] == 'H') || (right_rev[0] == '\0'))
- os->end_revision = SVN_INVALID_REVNUM;
- else
- os->end_revision = SVN_STR_TO_REV (right_rev);
+ if (right_rev)
+ {
+ if ((right_rev[0] == 'h')
+ || (right_rev[0] == 'H')
+ || (right_rev[0] == '\0'))
+ {
+ os->end_revision->kind = svn_client_revision_head;
+ }
+ else
+ {
+ os->end_revision->kind = svn_client_revision_number;
+ os->end_revision->value.number = SVN_STR_TO_REV (right_rev);
+ }
+ }
+ else /* probably was already unspecified, but be safe */
+ os->end_revision->kind = svn_client_revision_unspecified;
 
   return SVN_NO_ERROR;
 }
@@ -602,7 +621,7 @@
  * ARG, where ARG is "X", ":X", or "X:Y", like so:
  *
  * - If ARG is "X" set both OPT_STATE->start_date and
- OPT_STATE->end_date to X.
+ * OPT_STATE->end_date to X.
  *
  * - If ARG is "X:", set OPT_STATE->start_date to X and don't
  * touch OPT_STATE->end_date.
@@ -650,17 +669,25 @@
 
       /* Treat each string individually. */
       if (*left_date)
- apr_ansi_time_to_apr_time (&(os->start_date),
- svn_parse_date (left_date, NULL));
+ {
+ os->start_revision->kind = svn_client_revision_date;
+ apr_ansi_time_to_apr_time (&(os->start_revision->value.date),
+ svn_parse_date (left_date, NULL));
+ }
       if (*right_date)
- apr_ansi_time_to_apr_time (&(os->end_date),
- svn_parse_date (right_date, NULL));
+ {
+ os->end_revision->kind = svn_client_revision_date;
+ apr_ansi_time_to_apr_time (&(os->end_revision->value.date),
+ svn_parse_date (right_date, NULL));
+ }
     }
   else
     {
- apr_ansi_time_to_apr_time (&(os->start_date),
+ os->start_revision->kind = svn_client_revision_date;
+ os->end_revision->kind = svn_client_revision_date;
+ apr_ansi_time_to_apr_time (&(os->start_revision->value.date),
                                  svn_parse_date ((char *) arg, NULL));
- os->end_date = os->start_date;
+ os->end_revision->value.date = os->start_revision->value.date;
     }
 
   return SVN_NO_ERROR;
@@ -704,9 +731,14 @@
   apr_initialize ();
   pool = svn_pool_create (NULL);
   memset (&opt_state, 0, sizeof (opt_state));
- opt_state.start_revision = SVN_INVALID_REVNUM; /* default to youngest */
- opt_state.end_revision = 1; /* default to oldest */
 
+ opt_state.start_revision
+ = apr_pcalloc (pool, sizeof (*(opt_state.start_revision)));
+ opt_state.start_revision->kind = svn_client_revision_unspecified;
+ opt_state.end_revision
+ = apr_pcalloc (pool, sizeof (*(opt_state.end_revision)));
+ opt_state.end_revision->kind = svn_client_revision_unspecified;
+
   /* No args? Show usage. */
   if (argc <= 1)
     {
$

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Oct 21 14:37:02 2006

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.