Based on the fact that the svn client is already interpreting things of
the form 'foo://bar/baz' as URLs, I'm assuming it's okay for
svn_path_condense_targets to do the same.
In any case, I'm not feeling so confident as to just commit this
outright, so if somebody could look over it I'd be much obliged.
(I'm in the process of running the full test suite on it; I've already
checked that it passes log_tests and status_tests).
-brian
Log:
Resolves Issue #1108 ('svn log' for switched file reports for unswitched
file.)
* svn_path.h
(svn_path_condense_targets): Update comment.
* svn_client.h
(svn_client_log): Update comment.
* target.c
(get_absolute_path_or_url): New function.
(svn_path_condense_targets): Accept URL targets; don't try to convert
them to absolute paths.
* log.c
(svn_client_log): Find the URL for each target, and send the list of
URLs, not file targets, to svn_path_condense_targets.
* target-test.py
(tests): Add URL test for svn_path_condense_targets.
* switch_tests.py
(log_switched_file): New test function.
Index: subversion/include/svn_path.h
===================================================================
--- subversion/include/svn_path.h (revision 5485)
+++ subversion/include/svn_path.h (working copy)
@@ -223,14 +223,15 @@
*
* Find the common prefix of the paths in @a targets, and remove redundancies.
*
- * The elements in @a targets must be existing files or directories (as
- * const char *).
+ * The elements in @a targets either must all be URLs, or they must all be
+ * existing files or directories (as const char *).
*
* If there are multiple targets, or exactly one target and it's not a
* directory, then
*
* - @a *pbasename is set to the absolute path of the common parent
- * directory of all of those targets, and
+ * directory of those targets (if the targets are files/directories),
+ * or the common URL prefix of the targets (if they are URLs).
*
* - If @a pcondensed_targets is non-null, @a *pcondensed_targets is set
* to an array of targets relative to @a *pbasename, with
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 5489)
+++ subversion/include/svn_client.h (working copy)
@@ -695,10 +695,11 @@
* given log message more than once).
*
* @a targets contains all the working copy paths (as <tt>const char
- * *</tt>'s) for which log messages are desired; the common prefix of @a
- * targets determines the repository and auth info. @a receiver is invoked
- * only on messages whose revisions involved a change to some path in
- * @a targets.
+ * *</tt>'s) for which log messages are desired. The repository info is
+ * determinied by taking the common prefix of the target entries' URLs.
+ * The common prefix of @a targets, if it is a valid working copy,
+ * determines the auth info. @a receiver is invoked only on messages
+ * whose revisions involved a change to some path in @a targets.
*
* ### todo: the above paragraph is not fully implemented yet.
*
Index: subversion/libsvn_subr/target.c
===================================================================
--- subversion/libsvn_subr/target.c (revision 5485)
+++ subversion/libsvn_subr/target.c (working copy)
@@ -32,6 +32,28 @@
/*** Code. ***/
+/* Get the absolute path corresponding to RELATIVE, treating URLs
+ * as absolute paths.
+ *
+ * If RELATIVE is a URL, return the same URL in *PABSOLUTE.
+ * Otherwise return an absolute path for RELATIVE.
+ *
+ * ALLOCATE everything in POOL.
+ */
+static svn_error_t *
+get_absolute_path_or_url (const char **pabsolute,
+ const char *relative,
+ apr_pool_t *pool)
+{
+ if (svn_path_is_url (relative))
+ *pabsolute = apr_pstrdup (pool, relative);
+ else
+ SVN_ERR (svn_path_get_absolute (pabsolute, relative, pool));
+
+ return SVN_NO_ERROR;
+}
+
+
svn_error_t *
svn_path_condense_targets (const char **pbasedir,
apr_array_header_t **pcondensed_targets,
@@ -63,9 +85,9 @@
apr_array_header_t *abs_targets
= apr_array_make (pool, targets->nelts, sizeof (const char *));
- SVN_ERR (svn_path_get_absolute (pbasedir,
- ((const char **) targets->elts)[0],
- pool));
+ SVN_ERR (get_absolute_path_or_url (pbasedir,
+ ((const char **) targets->elts)[0],
+ pool));
(*((const char **)apr_array_push (abs_targets))) = *pbasedir;
@@ -73,7 +95,7 @@
{
const char *rel = ((const char **)targets->elts)[i];
const char *absolute;
- SVN_ERR (svn_path_get_absolute (&absolute, rel, pool));
+ SVN_ERR (get_absolute_path_or_url (&absolute, rel, pool));
(*((const char **)apr_array_push (abs_targets))) = absolute;
*pbasedir = svn_path_get_longest_ancestor (*pbasedir,
absolute,
@@ -163,13 +185,16 @@
}
}
- /* Finally check if pbasedir is a dir or a file. */
- SVN_ERR (svn_path_split_if_file (*pbasedir, pbasedir, &file, pool));
- if ((pcondensed_targets != NULL) && (! svn_path_is_empty (file)))
+ /* Finally check if pbasedir is a dir or a file (or a URL). */
+ if (! svn_path_is_url (*pbasedir))
{
- /* If there was just one target, and it was a file, then
- return it as the sole condensed target. */
- (*((const char **)apr_array_push (*pcondensed_targets))) = file;
+ SVN_ERR (svn_path_split_if_file (*pbasedir, pbasedir, &file, pool));
+ if ((pcondensed_targets != NULL) && (! svn_path_is_empty (file)))
+ {
+ /* If there was just one target, and it was a file, then
+ return it as the sole condensed target. */
+ (*((const char **)apr_array_push (*pcondensed_targets))) = file;
+ }
}
}
Index: subversion/libsvn_client/log.c
===================================================================
--- subversion/libsvn_client/log.c (revision 5485)
+++ subversion/libsvn_client/log.c (working copy)
@@ -59,7 +59,7 @@
svn_ra_plugin_t *ra_lib;
void *ra_baton, *session;
const char *path;
- const char *URL;
+ const char *base_url;
const char *base_name = NULL;
const char *auth_dir;
apr_array_header_t *condensed_targets;
@@ -81,7 +81,7 @@
/* Use the passed URL, if there is one. */
if (svn_path_is_url (path))
{
- URL = path;
+ base_url = path;
/* Initialize this array, since we'll be building it below */
condensed_targets = apr_array_make (pool, 1, sizeof (const char *));
@@ -110,49 +110,59 @@
else
{
svn_wc_adm_access_t *adm_access;
- const svn_wc_entry_t *entry;
+ apr_array_header_t *target_urls;
+ int i;
+
+ /* Get URLs for each target */
+ target_urls = apr_array_make (pool, 1, sizeof (const char *));
+ for (i = 0; i < targets->nelts; i++)
+ {
+ const svn_wc_entry_t *entry;
+ const char *URL;
+ const char *target = APR_ARRAY_IDX(targets, i, const char *);
+ SVN_ERR (svn_wc_adm_probe_open (&adm_access, NULL, target,
+ FALSE, FALSE, pool));
+ SVN_ERR (svn_wc_entry (&entry, target, adm_access, FALSE, pool));
+ if (! entry)
+ return svn_error_createf
+ (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
+ "svn_client_log: '%s' is not under revision control", target);
+ if (! entry->url)
+ return svn_error_createf
+ (SVN_ERR_ENTRY_MISSING_URL, NULL,
+ "svn_client_log: entry '%s' has no URL", target);
+ URL = apr_pstrdup (pool, entry->url);
+ SVN_ERR (svn_wc_adm_close (adm_access));
+ (*((const char **)apr_array_push (target_urls))) = URL;
+ }
- /* Use local working copy. */
+ /* Find the base URL and condensed targets relative to it. */
+ SVN_ERR (svn_path_condense_targets (&base_url, &condensed_targets,
+ target_urls, pool));
- SVN_ERR (svn_path_condense_targets (&base_name, &condensed_targets,
- targets, pool));
-
if (condensed_targets->nelts == 0)
(*((const char **)apr_array_push (condensed_targets))) = "";
-
- SVN_ERR (svn_wc_adm_probe_open (&adm_access, NULL, base_name,
- FALSE, FALSE, pool));
- SVN_ERR (svn_wc_entry (&entry, base_name, adm_access, FALSE, pool));
- if (! entry)
- return svn_error_createf
- (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
- "svn_client_log: '%s' is not under revision control", base_name);
- if (! entry->url)
- return svn_error_createf
- (SVN_ERR_ENTRY_MISSING_URL, NULL,
- "svn_client_log: entry '%s' has no URL", base_name);
- URL = apr_pstrdup (pool, entry->url);
- SVN_ERR (svn_wc_adm_close (adm_access));
}
- /* Get the RA library that handles URL. */
+ /* Get the RA library that handles BASE_URL */
SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
- SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL, pool));
+ SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, base_url, pool));
- /* Open a repository session to the URL. If we got here from a full URL
- passed to the command line, then if the current directory is a
+ /* Open a repository session to the BASE_URL If we got here from a full
+ URL passed to the command line, then if the current directory is a
working copy, we pass it as base_name for authentication
purposes. But we make sure to treat it as read-only, since when
one operates on URLs, one doesn't expect it to change anything in
the working copy. */
+ SVN_ERR (svn_path_condense_targets (&base_name, NULL, targets, pool));
if (NULL != base_name)
- SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, base_name,
- NULL, NULL, TRUE, TRUE,
+ SVN_ERR (svn_client__open_ra_session (&session, ra_lib, base_url,
+ base_name, NULL, NULL, TRUE, TRUE,
ctx, pool));
else
{
SVN_ERR (svn_client__dir_if_wc (&auth_dir, "", pool));
- SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL,
+ SVN_ERR (svn_client__open_ra_session (&session, ra_lib, base_url,
auth_dir,
NULL, NULL, FALSE, TRUE,
ctx, pool));
Index: subversion/tests/libsvn_subr/target-test.py
===================================================================
--- subversion/tests/libsvn_subr/target-test.py (revision 5485)
+++ subversion/tests/libsvn_subr/target-test.py (working copy)
@@ -34,7 +34,10 @@
cwd + '/z/A: \n'),
('single file',
'z/A/file',
- cwd + '/z/A: file, \n')]
+ cwd + '/z/A: file, \n'),
+ ('URLs',
+ 'http://host/A/C http://host/A/C/D http://host/A/B/D',
+ 'http://host/A: C, B/D, \n')]
# (re)Create the test directory
if os.path.exists('z'):
Index: subversion/tests/clients/cmdline/switch_tests.py
===================================================================
--- subversion/tests/clients/cmdline/switch_tests.py (revision 5485)
+++ subversion/tests/clients/cmdline/switch_tests.py (working copy)
@@ -518,6 +518,36 @@
#----------------------------------------------------------------------
+def log_switched_file(sbox):
+ "show logs for a switched file"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Setup some switched things (don't bother verifying)
+ if do_routine_switching(wc_dir, 0):
+ raise svntest.Failure # really, do_routine_switching should raise this
+
+ # edit and commit switched file 'iota'
+ iota_path = os.path.join(wc_dir, 'iota')
+ svntest.main.run_svn (None, 'ps', 'x', 'x', iota_path)
+ svntest.main.run_svn (None, 'ci', '-m',
+ 'set prop on switched iota',
+ iota_path)
+
+ # log switched file 'iota'
+ status = 1
+ output, error = svntest.main.run_svn (None, 'log', iota_path)
+ for line in output:
+ if re.match("set prop on switched iota", line):
+ status = 0
+
+ if (status == 1):
+ raise svntest.Failure
+
+
+#----------------------------------------------------------------------
+
### ...and a slew of others...
########################################################################
@@ -532,6 +562,7 @@
full_rev_update,
update_switched_things,
rev_update_switched_things,
+ log_switched_file,
]
if __name__ == '__main__':
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Mar 28 22:04:48 2003