Hi, is this any good? ~Neels
Try to find proper URL information on externals during upgrade. This is only for same-repos externals. For externals from a different repos, it is not so easy to find which is the repository root and which is the relpath.
Issue #4016.
* subversion/libsvn_wc/wc_db.c
(svn_wc__db_upgrade_apply_props):
Use svn_wc__resolve_relative_external_url() to fill in the URL parts of
EXTERNALS rows created during upgrade.
* subversion/include/private/svn_wc_private.h,
* subversion/libsvn_wc/externals.c
(svn_wc__resolve_relative_external_url): Move here and rename from ...
* subversion/libsvn_client/externals.c
(resolve_relative_external_url): ... this.
(uri_scheme): Move along with resolve_relative_external_url, keep as static.
(handle_external_item_change, svn_client__export_externals): Apply rename.
Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h (revision 1172371)
+++ subversion/include/private/svn_wc_private.h (working copy)
@@ -1169,6 +1169,14 @@ svn_wc__node_was_moved_here(const char *
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_wc__resolve_relative_external_url(const char **resolved_url,
+ const svn_wc_external_item2_t *item,
+ const char *repos_root_url,
+ const char *parent_dir_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */
Index: subversion/libsvn_client/externals.c
===================================================================
--- subversion/libsvn_client/externals.c (revision 1172371)
+++ subversion/libsvn_client/externals.c (working copy)
@@ -27,7 +27,6 @@
/*** Includes. ***/
-#include <apr_uri.h>
#include "svn_wc.h"
#include "svn_pools.h"
#include "svn_client.h"
@@ -512,218 +511,6 @@ cleanup:
return svn_error_trace(err);
}
-/* Return the scheme of @a uri in @a scheme allocated from @a pool.
- If @a uri does not appear to be a valid URI, then @a scheme will
- not be updated. */
-static svn_error_t *
-uri_scheme(const char **scheme, const char *uri, apr_pool_t *pool)
-{
- apr_size_t i;
-
- for (i = 0; uri[i] && uri[i] != ':'; ++i)
- if (uri[i] == '/')
- goto error;
-
- if (i > 0 && uri[i] == ':' && uri[i+1] == '/' && uri[i+2] == '/')
- {
- *scheme = apr_pstrmemdup(pool, uri, i);
- return SVN_NO_ERROR;
- }
-
-error:
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("URL '%s' does not begin with a scheme"),
- uri);
-}
-
-/* If the URL for @a item is relative, then using the repository root
- URL @a repos_root_url and the parent directory URL @parent_dir_url,
- resolve it into an absolute URL and save it in @a item.
-
- Regardless if the URL is absolute or not, if there are no errors,
- the URL in @a item will be canonicalized.
-
- The following relative URL formats are supported:
-
- ../ relative to the parent directory of the external
- ^/ relative to the repository root
- // relative to the scheme
- / relative to the server's hostname
-
- The ../ and ^/ relative URLs may use .. to remove path elements up
- to the server root.
-
- The external URL should not be canonicalized before calling this function,
- as otherwise the scheme relative URL '//host/some/path' would have been
- canonicalized to '/host/some/path' and we would not be able to match on
- the leading '//'. */
-static svn_error_t *
-resolve_relative_external_url(const char **resolved_url,
- const svn_wc_external_item2_t *item,
- const char *repos_root_url,
- const char *parent_dir_url,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *url = item->url;
- apr_uri_t parent_dir_uri;
- apr_status_t status;
-
- *resolved_url = item->url;
-
- /* If the URL is already absolute, there is nothing to do. */
- if (svn_path_is_url(url))
- {
- /* "http://server/path" */
- *resolved_url = svn_uri_canonicalize(url, result_pool);
- return SVN_NO_ERROR;
- }
-
- if (url[0] == '/')
- {
- /* "/path", "//path", and "///path" */
- int num_leading_slashes = 1;
- if (url[1] == '/')
- {
- num_leading_slashes++;
- if (url[2] == '/')
- num_leading_slashes++;
- }
-
- /* "//schema-relative" and in some cases "///schema-relative".
- This last format is supported on file:// schema relative. */
- url = apr_pstrcat(scratch_pool,
- apr_pstrndup(scratch_pool, url, num_leading_slashes),
- svn_relpath_canonicalize(url + num_leading_slashes,
- scratch_pool),
- (char*)NULL);
- }
- else
- {
- /* "^/path" and "../path" */
- url = svn_relpath_canonicalize(url, scratch_pool);
- }
-
- /* Parse the parent directory URL into its parts. */
- status = apr_uri_parse(scratch_pool, parent_dir_url, &parent_dir_uri);
- if (status)
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("Illegal parent directory URL '%s'"),
- parent_dir_url);
-
- /* If the parent directory URL is at the server root, then the URL
- may have no / after the hostname so apr_uri_parse() will leave
- the URL's path as NULL. */
- if (! parent_dir_uri.path)
- parent_dir_uri.path = apr_pstrmemdup(scratch_pool, "/", 1);
- parent_dir_uri.query = NULL;
- parent_dir_uri.fragment = NULL;
-
- /* Handle URLs relative to the current directory or to the
- repository root. The backpaths may only remove path elements,
- not the hostname. This allows an external to refer to another
- repository in the same server relative to the location of this
- repository, say using SVNParentPath. */
- if ((0 == strncmp("../", url, 3)) ||
- (0 == strncmp("^/", url, 2)))
- {
- apr_array_header_t *base_components;
- apr_array_header_t *relative_components;
- int i;
-
- /* Decompose either the parent directory's URL path or the
- repository root's URL path into components. */
- if (0 == strncmp("../", url, 3))
- {
- base_components = svn_path_decompose(parent_dir_uri.path,
- scratch_pool);
- relative_components = svn_path_decompose(url, scratch_pool);
- }
- else
- {
- apr_uri_t repos_root_uri;
-
- status = apr_uri_parse(scratch_pool, repos_root_url,
- &repos_root_uri);
- if (status)
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("Illegal repository root URL '%s'"),
- repos_root_url);
-
- /* If the repository root URL is at the server root, then
- the URL may have no / after the hostname so
- apr_uri_parse() will leave the URL's path as NULL. */
- if (! repos_root_uri.path)
- repos_root_uri.path = apr_pstrmemdup(scratch_pool, "/", 1);
-
- base_components = svn_path_decompose(repos_root_uri.path,
- scratch_pool);
- relative_components = svn_path_decompose(url + 2, scratch_pool);
- }
-
- for (i = 0; i < relative_components->nelts; ++i)
- {
- const char *component = APR_ARRAY_IDX(relative_components,
- i,
- const char *);
- if (0 == strcmp("..", component))
- {
- /* Constructing the final absolute URL together with
- apr_uri_unparse() requires that the path be absolute,
- so only pop a component if the component being popped
- is not the component for the root directory. */
- if (base_components->nelts > 1)
- apr_array_pop(base_components);
- }
- else
- APR_ARRAY_PUSH(base_components, const char *) = component;
- }
-
- parent_dir_uri.path = (char *)svn_path_compose(base_components,
- scratch_pool);
- *resolved_url = svn_uri_canonicalize(apr_uri_unparse(scratch_pool,
- &parent_dir_uri, 0),
- result_pool);
- return SVN_NO_ERROR;
- }
-
- /* The remaining URLs are relative to the either the scheme or
- server root and can only refer to locations inside that scope, so
- backpaths are not allowed. */
- if (svn_path_is_backpath_present(url + 2))
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("The external relative URL '%s' cannot have "
- "backpaths, i.e. '..'"),
- item->url);
-
- /* Relative to the scheme: Build a new URL from the parts we know. */
- if (0 == strncmp("//", url, 2))
- {
- const char *scheme;
-
- SVN_ERR(uri_scheme(&scheme, repos_root_url, scratch_pool));
- *resolved_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool, scheme,
- ":", url, (char *)NULL),
- result_pool);
- return SVN_NO_ERROR;
- }
-
- /* Relative to the server root: Just replace the path portion of the
- parent's URL. */
- if (url[0] == '/')
- {
- parent_dir_uri.path = (char *)url;
- *resolved_url = svn_uri_canonicalize(apr_uri_unparse(scratch_pool,
- &parent_dir_uri, 0),
- result_pool);
- return SVN_NO_ERROR;
- }
-
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("Unrecognized format for the relative external "
- "URL '%s'"),
- item->url);
-}
static svn_error_t *
handle_external_item_removal(const struct external_change_baton_t *eb,
@@ -832,7 +619,7 @@ handle_external_item_change(const struct
iterpool, since the hash table values outlive the iterpool and
any pointers they have should also outlive the iterpool. */
- SVN_ERR(resolve_relative_external_url(&new_url,
+ SVN_ERR(svn_wc__resolve_relative_external_url(&new_url,
new_item, eb->repos_root_url,
parent_dir_url,
scratch_pool, scratch_pool));
@@ -1232,7 +1019,7 @@ svn_client__export_externals(apr_hash_t
item_abspath = svn_dirent_join(local_abspath, item->target_dir,
sub_iterpool);
- SVN_ERR(resolve_relative_external_url(&new_url, item,
+ SVN_ERR(svn_wc__resolve_relative_external_url(&new_url, item,
repos_root_url, dir_url,
sub_iterpool, sub_iterpool));
Index: subversion/libsvn_wc/externals.c
===================================================================
--- subversion/libsvn_wc/externals.c (revision 1172371)
+++ subversion/libsvn_wc/externals.c (working copy)
@@ -30,6 +30,7 @@
#include <apr_hash.h>
#include <apr_tables.h>
#include <apr_general.h>
+#include <apr_uri.h>
#include "svn_dirent_uri.h"
#include "svn_path.h"
@@ -1248,3 +1249,219 @@ svn_wc__externals_gather_definitions(apr
return SVN_NO_ERROR;
}
}
+
+/* Return the scheme of @a uri in @a scheme allocated from @a pool.
+ If @a uri does not appear to be a valid URI, then @a scheme will
+ not be updated. */
+static svn_error_t *
+uri_scheme(const char **scheme, const char *uri, apr_pool_t *pool)
+{
+ apr_size_t i;
+
+ for (i = 0; uri[i] && uri[i] != ':'; ++i)
+ if (uri[i] == '/')
+ goto error;
+
+ if (i > 0 && uri[i] == ':' && uri[i+1] == '/' && uri[i+2] == '/')
+ {
+ *scheme = apr_pstrmemdup(pool, uri, i);
+ return SVN_NO_ERROR;
+ }
+
+error:
+ return svn_error_createf(SVN_ERR_BAD_URL, 0,
+ _("URL '%s' does not begin with a scheme"),
+ uri);
+}
+
+
+
+/* If the URL for @a item is relative, then using the repository root
+ URL @a repos_root_url and the parent directory URL @parent_dir_url,
+ resolve it into an absolute URL and save it in @a item.
+
+ Regardless if the URL is absolute or not, if there are no errors,
+ the URL in @a item will be canonicalized.
+
+ The following relative URL formats are supported:
+
+ ../ relative to the parent directory of the external
+ ^/ relative to the repository root
+ // relative to the scheme
+ / relative to the server's hostname
+
+ The ../ and ^/ relative URLs may use .. to remove path elements up
+ to the server root.
+
+ The external URL should not be canonicalized before calling this function,
+ as otherwise the scheme relative URL '//host/some/path' would have been
+ canonicalized to '/host/some/path' and we would not be able to match on
+ the leading '//'. */
+svn_error_t *
+svn_wc__resolve_relative_external_url(const char **resolved_url,
+ const svn_wc_external_item2_t *item,
+ const char *repos_root_url,
+ const char *parent_dir_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *url = item->url;
+ apr_uri_t parent_dir_uri;
+ apr_status_t status;
+
+ *resolved_url = item->url;
+
+ /* If the URL is already absolute, there is nothing to do. */
+ if (svn_path_is_url(url))
+ {
+ /* "http://server/path" */
+ *resolved_url = svn_uri_canonicalize(url, result_pool);
+ return SVN_NO_ERROR;
+ }
+
+ if (url[0] == '/')
+ {
+ /* "/path", "//path", and "///path" */
+ int num_leading_slashes = 1;
+ if (url[1] == '/')
+ {
+ num_leading_slashes++;
+ if (url[2] == '/')
+ num_leading_slashes++;
+ }
+
+ /* "//schema-relative" and in some cases "///schema-relative".
+ This last format is supported on file:// schema relative. */
+ url = apr_pstrcat(scratch_pool,
+ apr_pstrndup(scratch_pool, url, num_leading_slashes),
+ svn_relpath_canonicalize(url + num_leading_slashes,
+ scratch_pool),
+ (char*)NULL);
+ }
+ else
+ {
+ /* "^/path" and "../path" */
+ url = svn_relpath_canonicalize(url, scratch_pool);
+ }
+
+ /* Parse the parent directory URL into its parts. */
+ status = apr_uri_parse(scratch_pool, parent_dir_url, &parent_dir_uri);
+ if (status)
+ return svn_error_createf(SVN_ERR_BAD_URL, 0,
+ _("Illegal parent directory URL '%s'"),
+ parent_dir_url);
+
+ /* If the parent directory URL is at the server root, then the URL
+ may have no / after the hostname so apr_uri_parse() will leave
+ the URL's path as NULL. */
+ if (! parent_dir_uri.path)
+ parent_dir_uri.path = apr_pstrmemdup(scratch_pool, "/", 1);
+ parent_dir_uri.query = NULL;
+ parent_dir_uri.fragment = NULL;
+
+ /* Handle URLs relative to the current directory or to the
+ repository root. The backpaths may only remove path elements,
+ not the hostname. This allows an external to refer to another
+ repository in the same server relative to the location of this
+ repository, say using SVNParentPath. */
+ if ((0 == strncmp("../", url, 3)) ||
+ (0 == strncmp("^/", url, 2)))
+ {
+ apr_array_header_t *base_components;
+ apr_array_header_t *relative_components;
+ int i;
+
+ /* Decompose either the parent directory's URL path or the
+ repository root's URL path into components. */
+ if (0 == strncmp("../", url, 3))
+ {
+ base_components = svn_path_decompose(parent_dir_uri.path,
+ scratch_pool);
+ relative_components = svn_path_decompose(url, scratch_pool);
+ }
+ else
+ {
+ apr_uri_t repos_root_uri;
+
+ status = apr_uri_parse(scratch_pool, repos_root_url,
+ &repos_root_uri);
+ if (status)
+ return svn_error_createf(SVN_ERR_BAD_URL, 0,
+ _("Illegal repository root URL '%s'"),
+ repos_root_url);
+
+ /* If the repository root URL is at the server root, then
+ the URL may have no / after the hostname so
+ apr_uri_parse() will leave the URL's path as NULL. */
+ if (! repos_root_uri.path)
+ repos_root_uri.path = apr_pstrmemdup(scratch_pool, "/", 1);
+
+ base_components = svn_path_decompose(repos_root_uri.path,
+ scratch_pool);
+ relative_components = svn_path_decompose(url + 2, scratch_pool);
+ }
+
+ for (i = 0; i < relative_components->nelts; ++i)
+ {
+ const char *component = APR_ARRAY_IDX(relative_components,
+ i,
+ const char *);
+ if (0 == strcmp("..", component))
+ {
+ /* Constructing the final absolute URL together with
+ apr_uri_unparse() requires that the path be absolute,
+ so only pop a component if the component being popped
+ is not the component for the root directory. */
+ if (base_components->nelts > 1)
+ apr_array_pop(base_components);
+ }
+ else
+ APR_ARRAY_PUSH(base_components, const char *) = component;
+ }
+
+ parent_dir_uri.path = (char *)svn_path_compose(base_components,
+ scratch_pool);
+ *resolved_url = svn_uri_canonicalize(apr_uri_unparse(scratch_pool,
+ &parent_dir_uri, 0),
+ result_pool);
+ return SVN_NO_ERROR;
+ }
+
+ /* The remaining URLs are relative to the either the scheme or
+ server root and can only refer to locations inside that scope, so
+ backpaths are not allowed. */
+ if (svn_path_is_backpath_present(url + 2))
+ return svn_error_createf(SVN_ERR_BAD_URL, 0,
+ _("The external relative URL '%s' cannot have "
+ "backpaths, i.e. '..'"),
+ item->url);
+
+ /* Relative to the scheme: Build a new URL from the parts we know. */
+ if (0 == strncmp("//", url, 2))
+ {
+ const char *scheme;
+
+ SVN_ERR(uri_scheme(&scheme, repos_root_url, scratch_pool));
+ *resolved_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool, scheme,
+ ":", url, (char *)NULL),
+ result_pool);
+ return SVN_NO_ERROR;
+ }
+
+ /* Relative to the server root: Just replace the path portion of the
+ parent's URL. */
+ if (url[0] == '/')
+ {
+ parent_dir_uri.path = (char *)url;
+ *resolved_url = svn_uri_canonicalize(apr_uri_unparse(scratch_pool,
+ &parent_dir_uri, 0),
+ result_pool);
+ return SVN_NO_ERROR;
+ }
+
+ return svn_error_createf(SVN_ERR_BAD_URL, 0,
+ _("Unrecognized format for the relative external "
+ "URL '%s'"),
+ item->url);
+}
+
Index: subversion/libsvn_wc/wc_db.c
===================================================================
--- subversion/libsvn_wc/wc_db.c (revision 1172371)
+++ subversion/libsvn_wc/wc_db.c (working copy)
@@ -10241,6 +10241,7 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
svn_wc__db_kind_t kind = svn_wc__db_kind_unknown;
int affected_rows;
+
/* ### working_props: use set_props_txn.
### if working_props == NULL, then skip. what if they equal the
### pristine props? we should probably do the compare here.
@@ -10378,23 +10379,80 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
{
int i;
apr_array_header_t *ext;
+ const char *node_repos_relpath = "";
+ const char *node_repos_root_url = "";
+ const char *node_url = "";
+ apr_int64_t node_repos_id;
+ const char *local_abspath = svn_dirent_join(dir_abspath,
+ local_relpath,
+ scratch_pool);
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_SELECT_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ svn_error_t *err;
+ const char *repos_relpath;
+ err = repos_location_from_columns(&node_repos_id, NULL,
&repos_relpath,
+ stmt, 0, 4, 1, scratch_pool);
+ if (err)
+ svn_error_clear(err);
+ else
+ {
+ node_repos_relpath = repos_relpath;
+ SVN_ERR(fetch_repos_info(&node_repos_root_url, NULL, sdb,
+ node_repos_id, scratch_pool));
+ SVN_DBG(("local_relpath=%s url=%s / %s\n",
+ local_relpath, node_repos_root_url,
+ node_repos_relpath));
+ }
+ }
+ svn_sqlite__reset(stmt);
+
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
STMT_INSERT_EXTERNAL_UPGRADE));
- SVN_ERR(svn_wc_parse_externals_description3(
- &ext, svn_dirent_join(dir_abspath, local_relpath,
- scratch_pool),
- externals, FALSE, scratch_pool));
+ SVN_ERR(svn_wc_parse_externals_description3(&ext, local_abspath,
+ externals, FALSE,
+ scratch_pool));
for (i = 0; i < ext->nelts; i++)
{
const svn_wc_external_item2_t *item;
const char *item_relpath;
+ const char *item_resolved_url;
+ const char *item_repos_relpath;
item = APR_ARRAY_IDX(ext, i, const svn_wc_external_item2_t *);
item_relpath = svn_relpath_join(local_relpath, item->target_dir,
scratch_pool);
+ node_url = svn_path_url_add_component2(node_repos_root_url,
+ node_repos_relpath,
+ scratch_pool);
+
+ SVN_ERR(svn_wc__resolve_relative_external_url(&item_resolved_url,
+ item,
+
node_repos_root_url,
+ node_url,
+ scratch_pool,
+ scratch_pool));
+
+ item_repos_relpath = svn_uri_skip_ancestor(node_repos_root_url,
+ item_resolved_url,
+ scratch_pool);
+
+ if (item_repos_relpath == NULL)
+ {
+ /* It's from another repository.
+ * At this point we would have to contact the repository and
+ * find out its UUID and root. But the same information may
+ * already be lying around in a checked out external dir.
+ * ... currently, this is just wrong: */
+ item_repos_relpath = "";
+ }
+
SVN_ERR(svn_sqlite__bindf(stmt, "issssis",
wc_id,
item_relpath,
@@ -10402,8 +10460,8 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
scratch_pool),
"normal",
local_relpath,
- (apr_int64_t)1, /* repos_id */
- "" /* repos_relpath */));
+ node_repos_id,
+ item_repos_relpath));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
signature.asc
Description: OpenPGP digital signature

