Modified: subversion/branches/authzperf/subversion/mod_dav_svn/reports/log.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/reports/log.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/reports/log.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/reports/log.c Thu Oct 13 15:25:15 2016 @@ -50,7 +50,7 @@ struct log_receiver_baton apr_bucket_brigade *bb; /* where to deliver the output */ - ap_filter_t *output; + dav_svn__output *output; /* Whether we've written the <S:log-report> header. Allows for lazy writes to support mod_dav-based error handling. */ @@ -334,25 +334,17 @@ log_revision_receiver(void *baton, lrb->result_count++; if (lrb->result_count == lrb->next_forced_flush) { - apr_status_t apr_err; + apr_bucket *bkt; - /* This flush is similar to that in dav_svn__final_flush_or_error(). - - Compared to using ap_filter_flush(), which we use in other place + /* Compared to using ap_filter_flush(), which we use in other place this adds a flush frame before flushing the brigade, to make output filters perform a flush as well */ /* No brigade empty check. We want output filters to flush anyway */ - apr_err = ap_fflush(lrb->output, lrb->bb); - if (apr_err) - return svn_error_create(apr_err, NULL, NULL); - - /* Check for an aborted connection, just like our brigade write - helper functions, since the brigade functions don't appear to - be return useful errors when the connection is dropped. */ - if (lrb->output->c->aborted) - return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, - NULL, NULL); + bkt = apr_bucket_flush_create( + dav_svn__output_get_bucket_alloc(lrb->output)); + APR_BRIGADE_INSERT_TAIL(lrb->bb, bkt); + SVN_ERR(dav_svn__output_pass_brigade(lrb->output, lrb->bb)); if (lrb->result_count < 256) lrb->next_forced_flush = lrb->next_forced_flush * 4; @@ -365,7 +357,7 @@ log_revision_receiver(void *baton, dav_error * dav_svn__log_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_error_t *serr; dav_error *derr = NULL; @@ -497,7 +489,7 @@ dav_svn__log_report(const dav_resource * /* Build log receiver baton */ lrb.bb = apr_brigade_create(resource->pool, /* not the subpool! */ - output->c->bucket_alloc); + dav_svn__output_get_bucket_alloc(output)); lrb.output = output; lrb.needs_header = TRUE; lrb.needs_log_item = TRUE;
Modified: subversion/branches/authzperf/subversion/mod_dav_svn/reports/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/reports/mergeinfo.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/reports/mergeinfo.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/reports/mergeinfo.c Thu Oct 13 15:25:15 2016 @@ -46,7 +46,7 @@ dav_error * dav_svn__get_mergeinfo_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_error_t *serr; dav_error *derr = NULL; @@ -124,7 +124,8 @@ dav_svn__get_mergeinfo_report(const dav_ arb.repos = resource->info->repos; /* Build mergeinfo brigade */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); serr = svn_repos_fs_get_mergeinfo(&catalog, repos->repos, paths, rev, inherit, include_descendants, Modified: subversion/branches/authzperf/subversion/mod_dav_svn/reports/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/reports/replay.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/reports/replay.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/reports/replay.c Thu Oct 13 15:25:15 2016 @@ -44,7 +44,7 @@ typedef struct edit_baton_t { apr_bucket_brigade *bb; - ap_filter_t *output; + dav_svn__output *output; svn_boolean_t started; svn_boolean_t sending_textdelta; int compression_level; @@ -367,7 +367,7 @@ static void make_editor(const svn_delta_editor_t **editor, void **edit_baton, apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, int compression_level, apr_pool_t *pool) { @@ -413,7 +413,7 @@ malformed_element_error(const char *tagn dav_error * dav_svn__replay_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { dav_error *derr = NULL; svn_revnum_t low_water_mark = SVN_INVALID_REVNUM; @@ -530,7 +530,8 @@ dav_svn__replay_report(const dav_resourc if (! base_dir) base_dir = ""; - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); if ((err = svn_fs_revision_root(&root, resource->info->repos->fs, rev, resource->pool))) Modified: subversion/branches/authzperf/subversion/mod_dav_svn/reports/update.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/reports/update.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/reports/update.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/reports/update.c Thu Oct 13 15:25:15 2016 @@ -68,7 +68,7 @@ typedef struct update_ctx_t { apr_bucket_brigade *bb; /* where to deliver the output */ - ap_filter_t *output; + dav_svn__output *output; /* where do these editor paths *really* point to? */ apr_hash_t *pathmap; @@ -954,7 +954,7 @@ validate_input_revision(svn_revnum_t rev dav_error * dav_svn__update_report(const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + dav_svn__output *output) { svn_delta_editor_t *editor; apr_xml_elem *child; @@ -1202,7 +1202,8 @@ dav_svn__update_report(const dav_resourc uc.output = output; uc.anchor = src_path; uc.target = target; - uc.bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); + uc.bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); uc.pathmap = NULL; uc.enable_v2_response = ((resource->info->restype == DAV_SVN_RESTYPE_ME) && (resource->info->repos->v2_protocol)); Modified: subversion/branches/authzperf/subversion/mod_dav_svn/repos.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/repos.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/repos.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/repos.c Thu Oct 13 15:25:15 2016 @@ -3236,8 +3236,8 @@ set_headers(request_rec *r, const dav_re typedef struct diff_ctx_t { - ap_filter_t *output; - apr_pool_t *pool; + dav_svn__output *output; + apr_bucket_brigade *bb; } diff_ctx_t; @@ -3245,18 +3245,9 @@ static svn_error_t * __attribute__((war write_to_filter(void *baton, const char *buffer, apr_size_t *len) { diff_ctx_t *dc = baton; - apr_bucket_brigade *bb; - apr_bucket *bkt; - apr_status_t status; /* take the current data and shove it into the filter */ - bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc); - bkt = apr_bucket_transient_create(buffer, *len, dc->output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) { - return svn_error_create(status, NULL, - "Could not write data to filter"); - } + SVN_ERR(dav_svn__brigade_write(dc->bb, dc->output, buffer, *len)); return SVN_NO_ERROR; } @@ -3266,28 +3257,270 @@ static svn_error_t * __attribute__((war close_filter(void *baton) { diff_ctx_t *dc = baton; - apr_bucket_brigade *bb; apr_bucket *bkt; - apr_status_t status; /* done with the file. write an EOS bucket now. */ - bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc); - bkt = apr_bucket_eos_create(dc->output->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) - return svn_error_create(status, NULL, "Could not write EOS to filter"); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(dc->output)); + APR_BRIGADE_INSERT_TAIL(dc->bb, bkt); + SVN_ERR(dav_svn__output_pass_brigade(dc->output, dc->bb)); + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_head(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + /* XML schema for the directory index if xslt_uri is set: + + <?xml version="1.0"?> + <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */ + static const char xml_index_dtd[] = + "<!DOCTYPE svn [\n" + " <!ELEMENT svn (index)>\n" + " <!ATTLIST svn version CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + " <!ELEMENT index (updir?, (file | dir)*)>\n" + " <!ATTLIST index name CDATA #IMPLIED\n" + " path CDATA #IMPLIED\n" + " rev CDATA #IMPLIED\n" + " base CDATA #IMPLIED>\n" + " <!ELEMENT updir EMPTY>\n" + " <!ATTLIST updir href CDATA #REQUIRED>\n" + " <!ELEMENT file EMPTY>\n" + " <!ATTLIST file name CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + " <!ELEMENT dir EMPTY>\n" + " <!ATTLIST dir name CDATA #REQUIRED\n" + " href CDATA #REQUIRED>\n" + "]>\n"; + + if (gen_html) + { + const char *title; + if (resource->info->repos_path == NULL) + title = "unknown location"; + else + title = resource->info->repos_path; + + if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) + { + if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) + title = apr_psprintf(pool, + "Revision %ld: %s", + resource->info->root.rev, title); + if (resource->info->repos->repo_basename) + title = apr_psprintf(pool, "%s - %s", + resource->info->repos->repo_basename, + title); + if (resource->info->repos->repo_name) + title = apr_psprintf(pool, "%s: %s", + resource->info->repos->repo_name, + title); + } + + SVN_ERR(dav_svn__brigade_printf(bb, output, + "<html><head><title>%s</title></head>\n" + "<body>\n <h2>%s</h2>\n <ul>\n", + title, title)); + } + else + { + const char *name = resource->info->repos->repo_name; + const char *href = resource->info->repos_path; + const char *base = resource->info->repos->repo_basename; + + SVN_ERR(dav_svn__brigade_puts(bb, output, "<?xml version=\"1.0\"?>\n")); + SVN_ERR(dav_svn__brigade_printf(bb, output, + "<?xml-stylesheet type=\"text/xsl\" " + "href=\"%s\"?>\n", + resource->info->repos->xslt_uri)); + SVN_ERR(dav_svn__brigade_puts(bb, output, xml_index_dtd)); + SVN_ERR(dav_svn__brigade_puts(bb, output, + "<svn version=\"" SVN_VERSION "\"\n" + " href=\"http://subversion.apache.org/\">\n")); + SVN_ERR(dav_svn__brigade_puts(bb, output, " <index")); + + if (name) + SVN_ERR(dav_svn__brigade_printf(bb, output, + " name=\"%s\"", + apr_xml_quote_string(resource->pool, + name, 1))); + if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) + SVN_ERR(dav_svn__brigade_printf(bb, output, " rev=\"%ld\"", + resource->info->root.rev)); + if (href) + SVN_ERR(dav_svn__brigade_printf(bb, output, " path=\"%s\"", + apr_xml_quote_string(resource->pool, + href, 1))); + if (base) + SVN_ERR(dav_svn__brigade_printf(bb, output, " base=\"%s\"", base)); + + SVN_ERR(dav_svn__brigade_puts(bb, output, ">\n")); + } + + if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) + && resource->info->repos_path + && ((resource->info->repos_path[1] != '\0') + || dav_svn__get_list_parentpath_flag(resource->info->r))) + { + const char *href; + if (resource->info->pegged) + { + href = apr_psprintf(pool, "../?p=%ld", resource->info->root.rev); + } + else + { + href = "../"; + } + + if (gen_html) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s\">..</a></li>\n", + href)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <updir href=\"%s\"/>\n", + href)); + } + } + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_entry(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + const svn_fs_dirent_t *entry, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + const char *name = entry->name; + const char *href = name; + svn_boolean_t is_dir = (entry->kind == svn_node_dir); + + /* append a trailing slash onto the name for directories. we NEED + this for the href portion so that the relative reference will + descend properly. for the visible portion, it is just nice. */ + /* ### The xml output doesn't like to see a trailing slash on + ### the visible portion, so avoid that. */ + if (is_dir) + href = apr_pstrcat(pool, href, "/", SVN_VA_NULL); + + if (gen_html) + name = href; + + /* We quote special characters in both XML and HTML. */ + name = apr_xml_quote_string(pool, name, !gen_html); + + /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path() + behaves differently on different platforms. It claims to + "convert an OS path to a URL in an OS dependant way". + Nevertheless, there appears to be only one implementation + of the function in httpd, and the code seems completely + platform independent, so we'll assume it's appropriate for + mod_dav_svn to use it to quote outbound paths. */ + href = ap_os_escape_path(pool, href, 0); + href = apr_xml_quote_string(pool, href, 1); + + if (gen_html) + { + /* If our directory was access using the public peg-rev + CGI query interface, we'll let its dirents carry that + peg-rev, too. */ + if (resource->info->pegged) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s?p=%ld\">%s</a></li>\n", + href, resource->info->root.rev, name)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <li><a href=\"%s\">%s</a></li>\n", + href, name)); + } + } + else + { + const char *const tag = (is_dir ? "dir" : "file"); + + /* This is where we could search for props */ + + /* If our directory was access using the public peg-rev + CGI query interface, we'll let its dirents carry that + peg-rev, too. */ + if (resource->info->pegged) + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <%s name=\"%s\" href=\"%s?p=%ld\" />\n", + tag, name, href, resource->info->root.rev)); + } + else + { + SVN_ERR(dav_svn__brigade_printf(bb, output, + " <%s name=\"%s\" href=\"%s\" />\n", + tag, name, href)); + } + } + + return SVN_NO_ERROR; +} + + +static svn_error_t * +emit_collection_tail(const dav_resource *resource, + apr_bucket_brigade *bb, + dav_svn__output *output, + svn_boolean_t gen_html, + apr_pool_t *pool) +{ + if (gen_html) + { + if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0) + { + /* Apache's signature generation code didn't eat our prefix. + ServerSignature must be enabled. Print our version info. + + WARNING: This is a kludge!! ap_psignature() doesn't promise + to return the empty string when ServerSignature is off. We + know it does by code inspection, but this behavior is subject + to change. (Perhaps we should try to get the Apache folks to + make this promise, though. Seems harmless/useful enough...) + */ + SVN_ERR(dav_svn__brigade_puts(bb, output, + " </ul>\n <hr noshade><em>Powered by " + "<a href=\"http://subversion.apache.org/\">" + "Apache Subversion" + "</a> version " SVN_VERSION "." + "</em>\n</body></html>")); + } + else + SVN_ERR(dav_svn__brigade_puts(bb, output, " </ul>\n</body></html>")); + } + else + SVN_ERR(dav_svn__brigade_puts(bb, output, " </index>\n</svn>\n")); return SVN_NO_ERROR; } static dav_error * -deliver(const dav_resource *resource, ap_filter_t *output) +deliver(const dav_resource *resource, ap_filter_t *unused) { svn_error_t *serr; apr_bucket_brigade *bb; apr_bucket *bkt; - apr_status_t status; + dav_svn__output *output; /* Check resource type */ if (resource->baselined @@ -3300,39 +3533,17 @@ deliver(const dav_resource *resource, ap "Cannot GET this type of resource."); } + output = dav_svn__output_create(resource->info->r, resource->pool); + if (resource->collection) { const int gen_html = !resource->info->repos->xslt_uri; apr_hash_t *entries; - apr_pool_t *entry_pool; + apr_pool_t *iterpool; apr_array_header_t *sorted; svn_revnum_t dir_rev = SVN_INVALID_REVNUM; int i; - /* XML schema for the directory index if xslt_uri is set: - - <?xml version="1.0"?> - <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */ - static const char xml_index_dtd[] = - "<!DOCTYPE svn [\n" - " <!ELEMENT svn (index)>\n" - " <!ATTLIST svn version CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - " <!ELEMENT index (updir?, (file | dir)*)>\n" - " <!ATTLIST index name CDATA #IMPLIED\n" - " path CDATA #IMPLIED\n" - " rev CDATA #IMPLIED\n" - " base CDATA #IMPLIED>\n" - " <!ELEMENT updir EMPTY>\n" - " <!ATTLIST updir href CDATA #REQUIRED>\n" - " <!ELEMENT file EMPTY>\n" - " <!ATTLIST file name CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - " <!ELEMENT dir EMPTY>\n" - " <!ATTLIST dir name CDATA #REQUIRED\n" - " href CDATA #REQUIRED>\n" - "]>\n"; - /* <svn version="1.3.0 (dev-build)" href="http://subversion.apache.org"> <index name="[info->repos->repo_name]" @@ -3413,99 +3624,21 @@ deliver(const dav_resource *resource, ap resource->pool); } - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - - if (gen_html) - { - const char *title; - if (resource->info->repos_path == NULL) - title = "unknown location"; - else - title = resource->info->repos_path; - - if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) - { - if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) - title = apr_psprintf(resource->pool, - "Revision %ld: %s", - resource->info->root.rev, title); - if (resource->info->repos->repo_basename) - title = apr_psprintf(resource->pool, "%s - %s", - resource->info->repos->repo_basename, - title); - if (resource->info->repos->repo_name) - title = apr_psprintf(resource->pool, "%s: %s", - resource->info->repos->repo_name, - title); - } + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); - ap_fprintf(output, bb, "<html><head><title>%s</title></head>\n" - "<body>\n <h2>%s</h2>\n <ul>\n", title, title); - } - else - { - const char *name = resource->info->repos->repo_name; - const char *href = resource->info->repos_path; - const char *base = resource->info->repos->repo_basename; - - ap_fputs(output, bb, "<?xml version=\"1.0\"?>\n"); - ap_fprintf(output, bb, - "<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n", - resource->info->repos->xslt_uri); - ap_fputs(output, bb, xml_index_dtd); - ap_fputs(output, bb, - "<svn version=\"" SVN_VERSION "\"\n" - " href=\"http://subversion.apache.org/\">\n"); - ap_fputs(output, bb, " <index"); - if (name) - ap_fprintf(output, bb, " name=\"%s\"", - apr_xml_quote_string(resource->pool, name, 1)); - if (SVN_IS_VALID_REVNUM(resource->info->root.rev)) - ap_fprintf(output, bb, " rev=\"%ld\"", - resource->info->root.rev); - if (href) - ap_fprintf(output, bb, " path=\"%s\"", - apr_xml_quote_string(resource->pool, - href, - 1)); - if (base) - ap_fprintf(output, bb, " base=\"%s\"", base); - - ap_fputs(output, bb, ">\n"); - } - - if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION) - && resource->info->repos_path - && ((resource->info->repos_path[1] != '\0') - || dav_svn__get_list_parentpath_flag(resource->info->r))) - { - const char *href; - if (resource->info->pegged) - { - href = apr_psprintf(resource->pool, "../?p=%ld", - resource->info->root.rev); - } - else - { - href = "../"; - } - - if (gen_html) - { - ap_fprintf(output, bb, - " <li><a href=\"%s\">..</a></li>\n", href); - } - else - { - ap_fprintf(output, bb, " <updir href=\"%s\"/>\n", href); - } - } + serr = emit_collection_head(resource, bb, output, gen_html, + resource->pool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection", + resource->pool); /* get a sorted list of the entries */ sorted = svn_sort__hash(entries, svn_sort_compare_items_as_paths, resource->pool); - entry_pool = svn_pool_create(resource->pool); + iterpool = svn_pool_create(resource->pool); for (i = 0; i < sorted->nelts; ++i) { @@ -3513,11 +3646,9 @@ deliver(const dav_resource *resource, ap const svn_sort__item_t); const svn_fs_dirent_t *entry = item->value; const char *name = item->key; - const char *href = name; - svn_boolean_t is_dir = (entry->kind == svn_node_dir); const char *repos_relpath = NULL; - svn_pool_clear(entry_pool); + svn_pool_clear(iterpool); /* DIR_REV is set to a valid revision if we're looking at the entries of a versioned directory. Otherwise, we're @@ -3525,121 +3656,45 @@ deliver(const dav_resource *resource, ap if (SVN_IS_VALID_REVNUM(dir_rev)) { repos_relpath = svn_fspath__join(resource->info->repos_path, - name, entry_pool); + name, iterpool); if (! dav_svn__allow_read(resource->info->r, resource->info->repos, repos_relpath, dir_rev, - entry_pool)) + iterpool)) continue; } else { if (! dav_svn__allow_list_repos(resource->info->r, - entry->name, entry_pool)) + entry->name, iterpool)) continue; } - /* append a trailing slash onto the name for directories. we NEED - this for the href portion so that the relative reference will - descend properly. for the visible portion, it is just nice. */ - /* ### The xml output doesn't like to see a trailing slash on - ### the visible portion, so avoid that. */ - if (is_dir) - href = apr_pstrcat(entry_pool, href, "/", SVN_VA_NULL); - - if (gen_html) - name = href; - - /* We quote special characters in both XML and HTML. */ - name = apr_xml_quote_string(entry_pool, name, !gen_html); - - /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path() - behaves differently on different platforms. It claims to - "convert an OS path to a URL in an OS dependant way". - Nevertheless, there appears to be only one implementation - of the function in httpd, and the code seems completely - platform independent, so we'll assume it's appropriate for - mod_dav_svn to use it to quote outbound paths. */ - href = ap_os_escape_path(entry_pool, href, 0); - href = apr_xml_quote_string(entry_pool, href, 1); - - if (gen_html) - { - /* If our directory was access using the public peg-rev - CGI query interface, we'll let its dirents carry that - peg-rev, too. */ - if (resource->info->pegged) - { - ap_fprintf(output, bb, - " <li><a href=\"%s?p=%ld\">%s</a></li>\n", - href, resource->info->root.rev, name); - } - else - { - ap_fprintf(output, bb, - " <li><a href=\"%s\">%s</a></li>\n", - href, name); - } - } - else - { - const char *const tag = (is_dir ? "dir" : "file"); - - /* This is where we could search for props */ - - /* If our directory was access using the public peg-rev - CGI query interface, we'll let its dirents carry that - peg-rev, too. */ - if (resource->info->pegged) - { - ap_fprintf(output, bb, - " <%s name=\"%s\" href=\"%s?p=%ld\" />\n", - tag, name, href, resource->info->root.rev); - } - else - { - ap_fprintf(output, bb, - " <%s name=\"%s\" href=\"%s\" />\n", - tag, name, href); - } - } + serr = emit_collection_entry(resource, bb, output, entry, gen_html, + iterpool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection entry", + resource->pool); } - svn_pool_destroy(entry_pool); - - if (gen_html) - { - if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0) - { - /* Apache's signature generation code didn't eat our prefix. - ServerSignature must be enabled. Print our version info. + svn_pool_destroy(iterpool); - WARNING: This is a kludge!! ap_psignature() doesn't promise - to return the empty string when ServerSignature is off. We - know it does by code inspection, but this behavior is subject - to change. (Perhaps we should try to get the Apache folks to - make this promise, though. Seems harmless/useful enough...) - */ - ap_fputs(output, bb, - " </ul>\n <hr noshade><em>Powered by " - "<a href=\"http://subversion.apache.org/\">" - "Apache Subversion" - "</a> version " SVN_VERSION "." - "</em>\n</body></html>"); - } - else - ap_fputs(output, bb, " </ul>\n</body></html>"); - } - else - ap_fputs(output, bb, " </index>\n</svn>\n"); + serr = emit_collection_tail(resource, bb, output, gen_html, + resource->pool); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "could not output collection", + resource->pool); - bkt = apr_bucket_eos_create(output->c->bucket_alloc); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) - return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, - 0, status, - "Could not write EOS to filter."); + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write EOS to filter.", + resource->pool); return NULL; } @@ -3702,10 +3757,13 @@ deliver(const dav_resource *resource, ap "could not prepare to read a delta", resource->pool); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); + /* create a stream that svndiff data will be written to, which will copy it to the network */ dc.output = output; - dc.pool = resource->pool; + dc.bb = bb; o_stream = svn_stream_create(&dc, resource->pool); svn_stream_set_write(o_stream, write_to_filter); svn_stream_set_close(o_stream, close_filter); @@ -3721,6 +3779,8 @@ deliver(const dav_resource *resource, ap to the network. */ serr = svn_txdelta_send_txstream(txd_stream, handler, h_baton, resource->pool); + apr_brigade_destroy(bb); + if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not deliver the txdelta stream", @@ -3826,6 +3886,9 @@ deliver(const dav_resource *resource, ap ### which will read from the FS stream on demand */ block = apr_palloc(resource->pool, SVN__STREAM_CHUNK_SIZE); + bb = apr_brigade_create(resource->pool, + dav_svn__output_get_bucket_alloc(output)); + while (1) { apr_size_t bufsize = SVN__STREAM_CHUNK_SIZE; @@ -3833,6 +3896,7 @@ deliver(const dav_resource *resource, ap serr = svn_stream_read_full(stream, block, &bufsize); if (serr != NULL) { + apr_brigade_destroy(bb); return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not read the file contents", resource->pool); @@ -3840,30 +3904,35 @@ deliver(const dav_resource *resource, ap if (bufsize == 0) break; - /* build a brigade and write to the filter ... */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - bkt = apr_bucket_transient_create(block, bufsize, - output->c->bucket_alloc); + /* write to the filter ... */ + bkt = apr_bucket_transient_create( + block, bufsize, dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - /* ### that HTTP code... */ - return dav_svn__new_error(resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, status, - "Could not write data to filter."); - } + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + { + apr_brigade_destroy(bb); + /* ### that HTTP code... */ + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write data to filter.", + resource->pool); + } } /* done with the file. write an EOS bucket now. */ - bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); - bkt = apr_bucket_eos_create(output->c->bucket_alloc); + bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output)); APR_BRIGADE_INSERT_TAIL(bb, bkt); - if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { - /* ### that HTTP code... */ - return dav_svn__new_error(resource->pool, - HTTP_INTERNAL_SERVER_ERROR, 0, status, - "Could not write EOS to filter."); - } + serr = dav_svn__output_pass_brigade(output, bb); + if (serr != NULL) + { + apr_brigade_destroy(bb); + /* ### that HTTP code... */ + return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Could not write EOS to filter.", + resource->pool); + } + apr_brigade_destroy(bb); return NULL; } } @@ -4642,7 +4711,7 @@ dav_svn__create_version_resource(dav_res static dav_error * handle_post_request(request_rec *r, dav_resource *resource, - ap_filter_t *output) + dav_svn__output *output) { svn_skel_t *request_skel, *post_skel; int status; @@ -4725,7 +4794,9 @@ int dav_svn__method_post(request_rec *r) content_type = apr_table_get(r->headers_in, "content-type"); if (content_type && (strcmp(content_type, SVN_SKEL_MIME_TYPE) == 0)) { - derr = handle_post_request(r, resource, r->output_filters); + dav_svn__output *output = dav_svn__output_create(resource->info->r, + resource->pool); + derr = handle_post_request(r, resource, output); } else { Modified: subversion/branches/authzperf/subversion/mod_dav_svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/util.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/util.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/util.c Thu Oct 13 15:25:15 2016 @@ -465,6 +465,48 @@ dav_svn__find_ns(const apr_array_header_ return -1; } + +/*** Output helpers ***/ + + +struct dav_svn__output +{ + request_rec *r; +}; + +dav_svn__output * +dav_svn__output_create(request_rec *r, + apr_pool_t *pool) +{ + dav_svn__output *output = apr_pcalloc(pool, sizeof(*output)); + output->r = r; + return output; +} + +apr_bucket_alloc_t * +dav_svn__output_get_bucket_alloc(dav_svn__output *output) +{ + return output->r->connection->bucket_alloc; +} + +svn_error_t * +dav_svn__output_pass_brigade(dav_svn__output *output, + apr_bucket_brigade *bb) +{ + apr_status_t status; + + status = ap_pass_brigade(output->r->output_filters, bb); + /* Empty the brigade here, as required by ap_pass_brigade(). */ + apr_brigade_cleanup(bb); + if (status) + return svn_error_create(status, NULL, "Could not write data to filter"); + + /* Check for an aborted connection, since the brigade functions don't + appear to return useful errors when the connection is dropped. */ + if (output->r->connection->aborted) + return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL); + return SVN_NO_ERROR; +} /*** Brigade I/O wrappers ***/ @@ -472,17 +514,18 @@ dav_svn__find_ns(const apr_array_header_ svn_error_t * dav_svn__brigade_write(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *data, apr_size_t len) { apr_status_t apr_err; - apr_err = apr_brigade_write(bb, ap_filter_flush, output, data, len); + apr_err = apr_brigade_write(bb, ap_filter_flush, + output->r->output_filters, data, len); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } @@ -490,16 +533,17 @@ dav_svn__brigade_write(apr_bucket_brigad svn_error_t * dav_svn__brigade_puts(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *str) { apr_status_t apr_err; - apr_err = apr_brigade_puts(bb, ap_filter_flush, output, str); + apr_err = apr_brigade_puts(bb, ap_filter_flush, + output->r->output_filters, str); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } @@ -507,7 +551,7 @@ dav_svn__brigade_puts(apr_bucket_brigade svn_error_t * dav_svn__brigade_printf(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, const char *fmt, ...) { @@ -515,18 +559,41 @@ dav_svn__brigade_printf(apr_bucket_briga va_list ap; va_start(ap, fmt); - apr_err = apr_brigade_vprintf(bb, ap_filter_flush, output, fmt, ap); + apr_err = apr_brigade_vprintf(bb, ap_filter_flush, + output->r->output_filters, fmt, ap); va_end(ap); if (apr_err) return svn_error_create(apr_err, 0, NULL); /* Check for an aborted connection, since the brigade functions don't appear to be return useful errors when the connection is dropped. */ - if (output->c->aborted) + if (output->r->connection->aborted) return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL); return SVN_NO_ERROR; } +svn_error_t * +dav_svn__brigade_putstrs(apr_bucket_brigade *bb, + dav_svn__output *output, + ...) +{ + apr_status_t apr_err; + va_list ap; + + va_start(ap, output); + apr_err = apr_brigade_vputstrs(bb, ap_filter_flush, + output->r->output_filters, ap); + va_end(ap); + if (apr_err) + return svn_error_create(apr_err, NULL, NULL); + /* Check for an aborted connection, since the brigade functions don't + appear to return useful errors when the connection is dropped. */ + if (output->r->connection->aborted) + return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL); + return SVN_NO_ERROR; +} + + dav_error * @@ -588,7 +655,7 @@ dav_svn__sanitize_error(svn_error_t *ser struct brigade_write_baton { apr_bucket_brigade *bb; - ap_filter_t *output; + dav_svn__output *output; }; @@ -599,7 +666,8 @@ brigade_write_fn(void *baton, const char struct brigade_write_baton *wb = baton; apr_status_t apr_err; - apr_err = apr_brigade_write(wb->bb, ap_filter_flush, wb->output, data, *len); + apr_err = apr_brigade_write(wb->bb, ap_filter_flush, + wb->output->r->output_filters, data, *len); if (apr_err != APR_SUCCESS) return svn_error_wrap_apr(apr_err, "Error writing base64 data"); @@ -610,7 +678,7 @@ brigade_write_fn(void *baton, const char svn_stream_t * dav_svn__make_base64_output_stream(apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, apr_pool_t *pool) { struct brigade_write_baton *wb = apr_palloc(pool, sizeof(*wb)); @@ -637,7 +705,7 @@ dav_svn__operational_log(struct dav_reso dav_error * dav_svn__final_flush_or_error(request_rec *r, apr_bucket_brigade *bb, - ap_filter_t *output, + dav_svn__output *output, dav_error *preferred_err, apr_pool_t *pool) { @@ -659,7 +727,7 @@ dav_svn__final_flush_or_error(request_re provided a more-important DERR, though. */ if (do_flush) { - apr_status_t apr_err = ap_fflush(output, bb); + apr_status_t apr_err = ap_fflush(output->r->output_filters, bb); if (apr_err && (! derr)) derr = dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, apr_err, "Error flushing brigade."); Modified: subversion/branches/authzperf/subversion/mod_dav_svn/version.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/version.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/version.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/version.c Thu Oct 13 15:25:15 2016 @@ -1096,12 +1096,16 @@ static dav_error * deliver_report(request_rec *r, const dav_resource *resource, const apr_xml_doc *doc, - ap_filter_t *output) + ap_filter_t *unused) { int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (doc->root->ns == ns) { + dav_svn__output *output; + + output = dav_svn__output_create(resource->info->r, resource->pool); + /* ### note that these report names should have symbols... */ if (strcmp(doc->root->name, "update-report") == 0) @@ -1408,7 +1412,7 @@ merge(dav_resource *target, int no_auto_merge, int no_checkout, apr_xml_elem *prop_elem, - ap_filter_t *output) + ap_filter_t *unused) { apr_pool_t *pool; dav_error *err; @@ -1419,6 +1423,7 @@ merge(dav_resource *target, svn_revnum_t new_rev; apr_hash_t *locks; svn_boolean_t disable_merge_response = FALSE; + dav_svn__output *output; /* We'll use the target's pool for our operation. We happen to know that it matches the request pool, which (should) have the proper lifetime. */ @@ -1588,6 +1593,7 @@ merge(dav_resource *target, } /* process the response for the new revision. */ + output = dav_svn__output_create(target->info->r, pool); return dav_svn__merge_response(output, source->info->repos, new_rev, post_commit_err, prop_elem, disable_merge_response, pool); Modified: subversion/branches/authzperf/subversion/svn/cl.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/cl.h?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/cl.h (original) +++ subversion/branches/authzperf/subversion/svn/cl.h Thu Oct 13 15:25:15 2016 @@ -249,6 +249,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t show_passwords; /* show cached passwords */ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */ const char *show_item; /* print only the given item */ + svn_boolean_t adds_as_modification; /* update 'add vs add' no tree conflict */ } svn_cl__opt_state_t; /* Conflict stats for operations such as update and merge. */ Modified: subversion/branches/authzperf/subversion/svn/conflict-callbacks.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/conflict-callbacks.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/conflict-callbacks.c (original) +++ subversion/branches/authzperf/subversion/svn/conflict-callbacks.c Thu Oct 13 15:25:15 2016 @@ -229,8 +229,8 @@ merge_prop_conflict(svn_stream_t *output base_propval = svn_string_create_empty(pool); if (my_propval == NULL) my_propval = svn_string_create_empty(pool); - if (my_propval == NULL) - my_propval = svn_string_create_empty(pool); + if (their_propval == NULL) + their_propval = svn_string_create_empty(pool); options->ignore_eol_style = TRUE; SVN_ERR(svn_diff_mem_string_diff3(&diff, base_propval, @@ -338,23 +338,19 @@ edit_prop_conflict(const svn_string_t ** apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_file_t *file; const char *file_path; svn_boolean_t performed_edit = FALSE; svn_stream_t *merged_prop; - SVN_ERR(svn_io_open_unique_file3(&file, &file_path, NULL, - svn_io_file_del_on_pool_cleanup, - result_pool, scratch_pool)); - merged_prop = svn_stream_from_aprfile2(file, TRUE /* disown */, - scratch_pool); + SVN_ERR(svn_stream_open_unique(&merged_prop, &file_path, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); SVN_ERR(merge_prop_conflict(merged_prop, base_propval, my_propval, their_propval, NULL, pb->cancel_func, pb->cancel_baton, scratch_pool)); SVN_ERR(svn_stream_close(merged_prop)); - SVN_ERR(svn_io_file_flush(file, scratch_pool)); SVN_ERR(open_editor(&performed_edit, file_path, editor_cmd, config, scratch_pool)); if (performed_edit && merged_propval) @@ -388,7 +384,7 @@ typedef struct resolver_option_t /* Resolver options for conflict options offered by libsvn_client. */ static const resolver_option_t builtin_resolver_options[] = { - { "r", N_("mark resolved"), NULL, + { "r", NULL, NULL, svn_client_conflict_option_merged_text, SVN_CL__ACCEPT_WORKING }, { "mc", NULL, NULL, @@ -408,7 +404,7 @@ static const resolver_option_t builtin_r SVN_CL__ACCEPT_POSTPONE }, /* This option resolves a tree conflict to the current working copy state. */ - { "r", N_("accept current working copy state"), NULL, + { "r", NULL, NULL, svn_client_conflict_option_accept_current_wc_state, SVN_CL__ACCEPT_WORKING }, @@ -419,25 +415,23 @@ static const resolver_option_t builtin_r { "u", N_("update any moved-away children"), NULL, svn_client_conflict_option_update_any_moved_away_children }, - /* Options for incoming add vs local add upon merge. */ + /* Options for incoming add vs local add. */ { "i", N_("ignore incoming addition"), NULL, - svn_client_conflict_option_merge_incoming_add_ignore }, + svn_client_conflict_option_incoming_add_ignore }, /* Options for incoming file add vs local file add upon merge. */ { "m", N_("merge the files"), NULL, - svn_client_conflict_option_merge_incoming_added_file_text_merge }, - { "R", N_("replace my file with incoming file"), NULL, - svn_client_conflict_option_merge_incoming_added_file_replace }, + svn_client_conflict_option_incoming_added_file_text_merge }, { "M", N_("replace my file with incoming file and merge the files"), NULL, - svn_client_conflict_option_merge_incoming_added_file_replace_and_merge }, + svn_client_conflict_option_incoming_added_file_replace_and_merge }, /* Options for incoming dir add vs local dir add upon merge. */ { "m", N_("merge the directories"), NULL, - svn_client_conflict_option_merge_incoming_added_dir_merge }, - { "R", N_("replace my directory with incoming directory"), NULL, - svn_client_conflict_option_merge_incoming_added_dir_replace }, + svn_client_conflict_option_incoming_added_dir_merge }, + { "R", N_("delete my directory and replace it with incoming directory"), NULL, + svn_client_conflict_option_incoming_added_dir_replace }, { "M", N_("replace my directory with incoming directory and merge"), NULL, - svn_client_conflict_option_merge_incoming_added_dir_replace_and_merge }, + svn_client_conflict_option_incoming_added_dir_replace_and_merge }, /* Options for incoming delete vs any. */ { "i", N_("ignore incoming deletion"), NULL, @@ -445,6 +439,10 @@ static const resolver_option_t builtin_r { "a", N_("accept incoming deletion"), NULL, svn_client_conflict_option_incoming_delete_accept }, + /* Options for incoming move vs local edit. */ + { "m", NULL, NULL, svn_client_conflict_option_incoming_move_file_text_merge }, + { "m", NULL, NULL, svn_client_conflict_option_incoming_move_dir_merge }, + { NULL } }; @@ -498,7 +496,7 @@ static const resolver_option_t extra_res svn_client_conflict_option_undefined, SVN_CL__ACCEPT_EDIT }, { "h", N_("help"), N_("show this help (also '?')"), - svn_client_conflict_option_undefined }, + svn_client_conflict_option_undefined }, { NULL } }; @@ -507,8 +505,17 @@ static const resolver_option_t extra_res { /* Translators: keep long_desc below 70 characters (wrap with a left margin of 9 spaces if needed) */ + { "d", N_("set repository move destination path"), + N_("pick repository move target from list of possible targets"), + svn_client_conflict_option_undefined }, + + { "w", N_("set working copy move destination path"), + N_("pick working copy move target from list of possible targets"), + svn_client_conflict_option_undefined }, + { "h", N_("help"), N_("show this help (also '?')"), - svn_client_conflict_option_undefined }, + svn_client_conflict_option_undefined }, + { NULL } }; @@ -531,7 +538,7 @@ find_option(const resolver_option_t *opt } /* Return a pointer to the option description in OPTIONS matching the - * the conflict option ID CHOICE. Return NULL if not found. */ + * conflict option ID CHOICE. Return NULL if not found. */ static const resolver_option_t * find_option_by_id(const resolver_option_t *options, svn_client_conflict_option_id_t choice) @@ -570,6 +577,8 @@ prompt_string(const resolver_option_t *o if (! *option_codes) break; opt = find_option(options, *option_codes++); + if (opt == NULL) + continue; } else { @@ -686,6 +695,7 @@ prompt_user(const resolver_option_t **op static svn_error_t * build_text_conflict_options(resolver_option_t **options, svn_client_conflict_t *conflict, + svn_client_ctx_t *ctx, svn_boolean_t is_binary, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -698,7 +708,7 @@ build_text_conflict_options(resolver_opt apr_pool_t *iterpool; SVN_ERR(svn_client_conflict_text_get_resolution_options(&builtin_options, - conflict, + conflict, ctx, scratch_pool, scratch_pool)); nopt = builtin_options->nelts + ARRAY_LEN(extra_resolver_options); @@ -772,7 +782,7 @@ mark_conflict_resolved(svn_client_confli if (text_conflicted) { SVN_ERR(svn_client_conflict_text_resolve_by_id(conflict, option_id, - scratch_pool)); + ctx, scratch_pool)); svn_cl__conflict_stats_resolved(conflict_stats, local_relpath, svn_wc_conflict_kind_text); } @@ -780,7 +790,7 @@ mark_conflict_resolved(svn_client_confli if (propname) { SVN_ERR(svn_client_conflict_prop_resolve_by_id(conflict, propname, - option_id, + option_id, ctx, scratch_pool)); svn_cl__conflict_stats_resolved(conflict_stats, local_relpath, svn_wc_conflict_kind_property); @@ -789,7 +799,7 @@ mark_conflict_resolved(svn_client_confli if (tree_conflicted) { SVN_ERR(svn_client_conflict_tree_resolve_by_id(conflict, option_id, - scratch_pool)); + ctx, scratch_pool)); svn_cl__conflict_stats_resolved(conflict_stats, local_relpath, svn_wc_conflict_kind_tree); } @@ -871,7 +881,7 @@ handle_text_conflict(svn_boolean_t *reso || (!base_abspath && my_abspath && their_abspath))) diff_allowed = TRUE; - SVN_ERR(build_text_conflict_options(&text_conflict_options, conflict, + SVN_ERR(build_text_conflict_options(&text_conflict_options, conflict, ctx, is_binary, scratch_pool, scratch_pool)); while (TRUE) { @@ -1157,6 +1167,7 @@ handle_text_conflict(svn_boolean_t *reso static svn_error_t * build_prop_conflict_options(resolver_option_t **options, svn_client_conflict_t *conflict, + svn_client_ctx_t *ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -1168,7 +1179,7 @@ build_prop_conflict_options(resolver_opt apr_pool_t *iterpool; SVN_ERR(svn_client_conflict_prop_get_resolution_options(&builtin_options, - conflict, + conflict, ctx, scratch_pool, scratch_pool)); nopt = builtin_options->nelts + ARRAY_LEN(extra_resolver_options) + @@ -1214,11 +1225,10 @@ build_prop_conflict_options(resolver_opt } /* Ask the user what to do about the conflicted property PROPNAME described - * by CONFLICT and return the answer in *OPTION_ID. + * by CONFLICT and return the corresponding resolution option in *OPTION. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * -handle_one_prop_conflict(svn_client_conflict_option_id_t *option_id, - const svn_string_t **merged_value, +handle_one_prop_conflict(svn_client_conflict_option_t **option, svn_boolean_t *quit, const char *path_prefix, svn_cmdline_prompt_baton_t *pb, @@ -1226,6 +1236,7 @@ handle_one_prop_conflict(svn_client_conf apr_hash_t *config, svn_client_conflict_t *conflict, const char *propname, + svn_client_ctx_t *ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -1236,10 +1247,9 @@ handle_one_prop_conflict(svn_client_conf const svn_string_t *base_propval; const svn_string_t *my_propval; const svn_string_t *their_propval; + apr_array_header_t *resolution_options; resolver_option_t *prop_conflict_options; - *option_id = svn_client_conflict_option_unspecified; - SVN_ERR(svn_client_conflict_prop_get_propvals(NULL, &my_propval, &base_propval, &their_propval, conflict, propname, @@ -1257,7 +1267,11 @@ handle_one_prop_conflict(svn_client_conf scratch_pool, scratch_pool)); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", description)); - SVN_ERR(build_prop_conflict_options(&prop_conflict_options, conflict, + SVN_ERR(svn_client_conflict_prop_get_resolution_options(&resolution_options, + conflict, ctx, + result_pool, + scratch_pool)); + SVN_ERR(build_prop_conflict_options(&prop_conflict_options, conflict, ctx, scratch_pool, scratch_pool)); iterpool = svn_pool_create(scratch_pool); while (TRUE) @@ -1286,7 +1300,8 @@ handle_one_prop_conflict(svn_client_conf if (strcmp(opt->code, "q") == 0) { - *option_id = opt->choice; + *option = svn_client_conflict_option_find_by_id(resolution_options, + opt->choice); *quit = TRUE; break; } @@ -1315,13 +1330,17 @@ handle_one_prop_conflict(svn_client_conf continue; } - *merged_value = merged_propval; - *option_id = svn_client_conflict_option_merged_text; + *option = svn_client_conflict_option_find_by_id( + resolution_options, + svn_client_conflict_option_merged_text); + svn_client_conflict_option_set_merged_propval(*option, + merged_propval); break; } else if (opt->choice != svn_client_conflict_option_undefined) { - *option_id = opt->choice; + *option = svn_client_conflict_option_find_by_id(resolution_options, + opt->choice); break; } } @@ -1361,23 +1380,29 @@ handle_prop_conflicts(svn_boolean_t *res for (i = 0; i < props_conflicted->nelts; i++) { const char *propname = APR_ARRAY_IDX(props_conflicted, i, const char *); + svn_client_conflict_option_t *option; svn_client_conflict_option_id_t option_id; - const svn_string_t *merged_propval = NULL; svn_pool_clear(iterpool); - SVN_ERR(handle_one_prop_conflict(&option_id, &merged_propval, - quit, path_prefix, pb, + SVN_ERR(handle_one_prop_conflict(&option, quit, path_prefix, pb, editor_cmd, config, conflict, propname, + ctx, iterpool, iterpool)); + option_id = svn_client_conflict_option_get_id(option); if (option_id != svn_client_conflict_option_unspecified && option_id != svn_client_conflict_option_postpone) { - SVN_ERR(mark_conflict_resolved(conflict, option_id, - FALSE, propname, FALSE, - path_prefix, conflict_stats, - ctx, iterpool)); + const char *local_relpath = + svn_cl__local_style_skip_ancestor( + path_prefix, svn_client_conflict_get_local_abspath(conflict), + iterpool); + + SVN_ERR(svn_client_conflict_prop_resolve(conflict, propname, option, + ctx, iterpool)); + svn_cl__conflict_stats_resolved(conflict_stats, local_relpath, + svn_wc_conflict_kind_property); nresolved++; *postponed = FALSE; } @@ -1397,10 +1422,14 @@ handle_prop_conflicts(svn_boolean_t *res /* Set *OPTIONS to an array of resolution options for CONFLICT. */ static svn_error_t * -build_tree_conflict_options(resolver_option_t **options, - svn_client_conflict_t *conflict, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +build_tree_conflict_options( + resolver_option_t **options, + apr_array_header_t **possible_moved_to_repos_relpaths, + apr_array_header_t **possible_moved_to_abspaths, + svn_client_conflict_t *conflict, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { resolver_option_t *opt; const resolver_option_t *o; @@ -1410,12 +1439,14 @@ build_tree_conflict_options(resolver_opt apr_pool_t *iterpool; SVN_ERR(svn_client_conflict_tree_get_resolution_options(&builtin_options, - conflict, + conflict, ctx, scratch_pool, scratch_pool)); - nopt = builtin_options->nelts + ARRAY_LEN(extra_resolver_options) + - ARRAY_LEN(extra_resolver_options_tree); + nopt = builtin_options->nelts + ARRAY_LEN(extra_resolver_options_tree) + + ARRAY_LEN(extra_resolver_options); *options = apr_pcalloc(result_pool, sizeof(*opt) * (nopt + 1)); + *possible_moved_to_abspaths = NULL; + *possible_moved_to_repos_relpaths = NULL; opt = *options; iterpool = svn_pool_create(scratch_pool); @@ -1443,19 +1474,147 @@ build_tree_conflict_options(resolver_opt opt->accept_arg = known_option->accept_arg; opt++; - } + if (id == svn_client_conflict_option_incoming_move_file_text_merge || + id == svn_client_conflict_option_incoming_move_dir_merge) + { + SVN_ERR( + svn_client_conflict_option_get_moved_to_repos_relpath_candidates( + possible_moved_to_repos_relpaths, builtin_option, + result_pool, iterpool)); + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + possible_moved_to_abspaths, builtin_option, + result_pool, iterpool)); + } + } svn_pool_destroy(iterpool); - for (o = extra_resolver_options; o->code; o++) - *opt++ = *o; for (o = extra_resolver_options_tree; o->code; o++) + { + /* Add move target choice options only if there are multiple + * move targets to choose from. */ + if (strcmp(o->code, "d") == 0 && + (*possible_moved_to_repos_relpaths == NULL || + (*possible_moved_to_repos_relpaths)->nelts <= 1)) + continue; + if (strcmp(o->code, "w") == 0 && + (*possible_moved_to_abspaths == NULL || + (*possible_moved_to_abspaths)->nelts <= 1)) + continue; + + *opt++ = *o; + } + for (o = extra_resolver_options; o->code; o++) *opt++ = *o; return SVN_NO_ERROR; } +/* Make the user select a move target path for the moved-away VICTIM_ABSPATH. */ +static svn_error_t * +prompt_move_target_path(int *preferred_move_target_idx, + apr_array_header_t *possible_moved_to_paths, + svn_boolean_t paths_are_local, + svn_cmdline_prompt_baton_t *pb, + const char *victim_abspath, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + const char *move_targets_prompt = ""; + const char *move_targets_list = ""; + const char *wcroot_abspath; + const char *victim_relpath; + int i; + apr_int64_t idx; + apr_pool_t *iterpool; + + SVN_ERR(svn_client_get_wc_root(&wcroot_abspath, victim_abspath, + ctx, scratch_pool, scratch_pool)); + victim_relpath = svn_cl__local_style_skip_ancestor(wcroot_abspath, + victim_abspath, + scratch_pool), + iterpool = svn_pool_create(scratch_pool); + + /* Build the prompt. */ + for (i = 0; i < possible_moved_to_paths->nelts; i++) + { + svn_pool_clear(iterpool); + + if (paths_are_local) + { + const char *moved_to_abspath; + const char *moved_to_relpath; + + moved_to_abspath = APR_ARRAY_IDX(possible_moved_to_paths, i, + const char *); + moved_to_relpath = svn_cl__local_style_skip_ancestor( + wcroot_abspath, moved_to_abspath, iterpool), + move_targets_list = apr_psprintf(scratch_pool, "%s (%d): '%s'\n", + move_targets_list, i + 1, + moved_to_relpath); + } + else + { + const char *moved_to_repos_relpath; + + moved_to_repos_relpath = APR_ARRAY_IDX(possible_moved_to_paths, i, + const char *); + move_targets_list = apr_psprintf(scratch_pool, "%s (%d): '^/%s'\n", + move_targets_list, i + 1, + moved_to_repos_relpath); + } + } + if (paths_are_local) + move_targets_prompt = + apr_psprintf(scratch_pool, + _("Possible working copy destinations for moved-away '%s' " + "are:\n%s" + "Only one destination can be a move; the others are " + "copies.\n" + "Specify the correct move target path by number: "), + victim_relpath, move_targets_list); + else + move_targets_prompt = + apr_psprintf(scratch_pool, + _("Possible repository destinations for moved-away '%s' " + "are:\n%s" + "Only one destination can be a move; the others are " + "copies.\n" + "Specify the correct move target path by number: "), + victim_relpath, move_targets_list); + + /* Keep asking the user until we got a valid choice. */ + while (1) + { + const char *answer; + svn_error_t *err; + + svn_pool_clear(iterpool); + + SVN_ERR(svn_cmdline_prompt_user2(&answer, move_targets_prompt, + pb, iterpool)); + err = svn_cstring_strtoi64(&idx, answer, 1, + possible_moved_to_paths->nelts, 10); + if (err) + { + char buf[1024]; + + svn_cmdline_fprintf(stderr, iterpool, "%s\n", + svn_err_best_message(err, buf, sizeof(buf))); + svn_error_clear(err); + continue; + } + + break; + } + + svn_pool_destroy(iterpool); + + *preferred_move_target_idx = (idx - 1); + return SVN_NO_ERROR; +} + /* Ask the user what to do about the tree conflict described by CONFLICT * and either resolve the conflict accordingly or postpone resolution. * SCRATCH_POOL is used for temporary allocations. */ @@ -1474,18 +1633,22 @@ handle_tree_conflict(svn_boolean_t *reso apr_pool_t *iterpool; resolver_option_t *tree_conflict_options; svn_client_conflict_option_id_t option_id; + const char *local_abspath; const char *conflict_description; const char *local_change_description; const char *incoming_change_description; + apr_array_header_t *possible_moved_to_repos_relpaths; + apr_array_header_t *possible_moved_to_abspaths; option_id = svn_client_conflict_option_unspecified; + local_abspath = svn_client_conflict_get_local_abspath(conflict); /* Always show the best possible conflict description and options. */ - SVN_ERR(svn_client_conflict_tree_get_details(conflict, scratch_pool)); + SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, scratch_pool)); SVN_ERR(svn_client_conflict_tree_get_description( &incoming_change_description, &local_change_description, - conflict, scratch_pool, scratch_pool)); + conflict, ctx, scratch_pool, scratch_pool)); conflict_description = apr_psprintf(scratch_pool, "%s\n%s", incoming_change_description, local_change_description); @@ -1493,12 +1656,13 @@ handle_tree_conflict(svn_boolean_t *reso SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, _("Tree conflict on '%s':\n%s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, - svn_client_conflict_get_local_abspath(conflict), - scratch_pool), + path_prefix, local_abspath, scratch_pool), conflict_description)); - SVN_ERR(build_tree_conflict_options(&tree_conflict_options, conflict, + SVN_ERR(build_tree_conflict_options(&tree_conflict_options, + &possible_moved_to_repos_relpaths, + &possible_moved_to_abspaths, + conflict, ctx, scratch_pool, scratch_pool)); iterpool = svn_pool_create(scratch_pool); while (1) @@ -1508,8 +1672,7 @@ handle_tree_conflict(svn_boolean_t *reso svn_pool_clear(iterpool); SVN_ERR(prompt_user(&opt, tree_conflict_options, NULL, - *printed_description ? NULL : conflict_description, - pb, iterpool)); + conflict_description, pb, iterpool)); *printed_description = TRUE; if (! opt) continue; @@ -1520,6 +1683,91 @@ handle_tree_conflict(svn_boolean_t *reso *quit = TRUE; break; } + else if (strcmp(opt->code, "d") == 0) + { + int preferred_move_target_idx; + apr_array_header_t *options; + svn_client_conflict_option_t *conflict_option; + + SVN_ERR(prompt_move_target_path(&preferred_move_target_idx, + possible_moved_to_repos_relpaths, + FALSE, + pb, local_abspath, ctx, iterpool)); + + /* Update preferred move target path. */ + SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, + conflict, + ctx, + iterpool, + iterpool)); + conflict_option = + svn_client_conflict_option_find_by_id( + options, + svn_client_conflict_option_incoming_move_file_text_merge); + if (conflict_option == NULL) + { + conflict_option = + svn_client_conflict_option_find_by_id( + options, svn_client_conflict_option_incoming_move_dir_merge); + } + + if (conflict_option) + { + SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath( + conflict_option, preferred_move_target_idx, iterpool)); + + /* Update option description. */ + SVN_ERR(build_tree_conflict_options( + &tree_conflict_options, + &possible_moved_to_repos_relpaths, + &possible_moved_to_abspaths, + conflict, ctx, + scratch_pool, scratch_pool)); + } + continue; + } + else if (strcmp(opt->code, "w") == 0) + { + int preferred_move_target_idx; + apr_array_header_t *options; + svn_client_conflict_option_t *conflict_option; + + SVN_ERR(prompt_move_target_path(&preferred_move_target_idx, + possible_moved_to_abspaths, TRUE, + pb, local_abspath, ctx, iterpool)); + + /* Update preferred move target path. */ + SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, + conflict, + ctx, + iterpool, + iterpool)); + conflict_option = + svn_client_conflict_option_find_by_id( + options, + svn_client_conflict_option_incoming_move_file_text_merge); + if (conflict_option == NULL) + { + conflict_option = + svn_client_conflict_option_find_by_id( + options, svn_client_conflict_option_incoming_move_dir_merge); + } + + if (conflict_option) + { + SVN_ERR(svn_client_conflict_option_set_moved_to_abspath( + conflict_option, preferred_move_target_idx, ctx, iterpool)); + + /* Update option description. */ + SVN_ERR(build_tree_conflict_options( + &tree_conflict_options, + &possible_moved_to_repos_relpaths, + &possible_moved_to_abspaths, + conflict, ctx, + scratch_pool, scratch_pool)); + } + continue; + } else if (opt->choice != svn_client_conflict_option_undefined) { option_id = opt->choice; Modified: subversion/branches/authzperf/subversion/svn/merge-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/merge-cmd.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/merge-cmd.c (original) +++ subversion/branches/authzperf/subversion/svn/merge-cmd.c Thu Oct 13 15:25:15 2016 @@ -123,6 +123,11 @@ run_merge(svn_boolean_t two_sources_spec _("Merge sources must both be " "either paths or URLs")); + if (svn_path_is_url(targetpath)) + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Merge target '%s' must be a local path " + "but looks like a URL"), targetpath); + if (opt_state->verbose) SVN_ERR(svn_cmdline_printf(scratch_pool, _("--- Merging\n"))); merge_err = svn_client_merge5(sourcepath1, Modified: subversion/branches/authzperf/subversion/svn/notify.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/notify.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/notify.c (original) +++ subversion/branches/authzperf/subversion/svn/notify.c Thu Oct 13 15:25:15 2016 @@ -472,6 +472,21 @@ notify_body(struct notify_baton *nb, path_local)); break; + case svn_wc_notify_begin_search_tree_conflict_details: + SVN_ERR(svn_cmdline_printf(pool, + _("Searching tree conflict details for '%s' " + "in repository:\n"), + path_local)); + break; + + case svn_wc_notify_tree_conflict_details_progress: + SVN_ERR(svn_cmdline_printf(pool, _("\rChecking r%ld..."), n->revision)); + break; + + case svn_wc_notify_end_search_tree_conflict_details: + SVN_ERR(svn_cmdline_printf(pool, _(" done\n"))); + break; + case svn_wc_notify_add: /* We *should* only get the MIME_TYPE if PATH is a file. If we do get it, and the mime-type is not textual, note that this Modified: subversion/branches/authzperf/subversion/svn/svn.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/svn.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/svn.c (original) +++ subversion/branches/authzperf/subversion/svn/svn.c Thu Oct 13 15:25:15 2016 @@ -143,6 +143,7 @@ typedef enum svn_cl__longopt_t { opt_show_passwords, opt_pin_externals, opt_show_item, + opt_adds_as_modification, } svn_cl__longopt_t; @@ -449,6 +450,15 @@ const apr_getopt_option_t svn_cl__option " " " 'wc-root' root of TARGET's working copy")}, + {"adds-as-modification", opt_adds_as_modification, 0, + N_("Local additions are merged with incoming additions " + " " + "instead of causing a tree conflict. Use of this\n" + " " + "option is not recommended! Use 'svn resolve' to\n" + " " + "resolve tree conflicts instead.")}, + /* Long-opt Aliases * * These have NULL desriptions, but an option code that matches some @@ -1761,7 +1771,7 @@ const svn_opt_subcommand_desc2_t svn_cl_ " targets of this operation.\n"), {'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_force, opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept, - opt_parents}, + opt_parents, opt_adds_as_modification}, { {opt_force, N_("handle unversioned obstructions as changes")} } }, @@ -2431,6 +2441,9 @@ sub_main(int *exit_code, int argc, const SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); opt_state.show_item = utf8_opt_arg; break; + case opt_adds_as_modification: + opt_state.adds_as_modification = TRUE; + break; default: /* Hmmm. Perhaps this would be a good place to squirrel away opts that commands like svn diff might need. Hmmm indeed. */ Modified: subversion/branches/authzperf/subversion/svn/update-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svn/update-cmd.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svn/update-cmd.c (original) +++ subversion/branches/authzperf/subversion/svn/update-cmd.c Thu Oct 13 15:25:15 2016 @@ -170,7 +170,8 @@ svn_cl__update(apr_getopt_t *os, &(opt_state->start_revision), depth, depth_is_sticky, opt_state->ignore_externals, - opt_state->force, TRUE /* adds_as_modification */, + opt_state->force, + opt_state->adds_as_modification, opt_state->parents, ctx, scratch_pool)); Modified: subversion/branches/authzperf/subversion/svnmucc/svnmucc.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnmucc/svnmucc.c?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/svnmucc/svnmucc.c (original) +++ subversion/branches/authzperf/subversion/svnmucc/svnmucc.c Thu Oct 13 15:25:15 2016 @@ -74,6 +74,7 @@ check_lib_versions(void) return svn_ver_check_list2(&my_version, checklist, svn_ver_equal); } +/* Implements svn_commit_callback2_t */ static svn_error_t * commit_callback(const svn_commit_info_t *commit_info, void *baton, @@ -84,6 +85,15 @@ commit_callback(const svn_commit_info_t (commit_info->author ? commit_info->author : "(no author)"), commit_info->date)); + + /* Writing to stdout, as there maybe systems that consider the + * presence of stderr as an indication of commit failure. + * OTOH, this is only of informational nature to the user as + * the commit has succeeded. */ + if (commit_info->post_commit_err) + SVN_ERR(svn_cmdline_printf(pool, _("\nWarning: %s\n"), + commit_info->post_commit_err)); + return SVN_NO_ERROR; } Modified: subversion/branches/authzperf/subversion/tests/cmdline/depth_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/depth_tests.py?rev=1764707&r1=1764706&r2=1764707&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/tests/cmdline/depth_tests.py (original) +++ subversion/branches/authzperf/subversion/tests/cmdline/depth_tests.py Thu Oct 13 15:25:15 2016 @@ -2897,6 +2897,66 @@ def commit_excluded(sbox): [], False, "--set-depth=infinity", wc_dir) +@Issue(4636) +@XFail() +def fold_tree_with_deleted_moved_items(sbox): + "deleted & moved items left untouched" + ign_a, ign_b, ign_c, wc_dir = set_up_depthy_working_copies(sbox, + infinity=True) + + A_path = sbox.ospath('A') + + # Delete file lambda, move file pi and directory C + sbox.simple_rm('A/B/lambda') + sbox.simple_move('A/D/G/pi', 'A/D/G/pi_moved') + sbox.simple_move('A/C', 'A/C_moved') + + # Fold the A dir to empty, expect the deleted & moved items ones left + # and visible in status, rather than gone without a trace. + + # Directories B and D won't be deleted, because that would remove their + # local modifications. Their unmodified descendants are deleted though. + expected_output = svntest.wc.State(wc_dir, { + 'A/B/E' : Item(status='D '), + 'A/B/F' : Item(status='D '), + 'A/D/G/rho' : Item(status='D '), + 'A/D/G/tau' : Item(status='D '), + 'A/D/H' : Item(status='D '), + 'A/D/gamma' : Item(status='D '), + 'A/mu' : Item(status='D '), + }) + expected_status = svntest.wc.State(wc_dir, { + '' : Item(status=' ', wc_rev=1), + 'iota' : Item(status=' ', wc_rev=1), + 'A' : Item(status=' ', wc_rev=1), + 'A/B' : Item(status=' ', wc_rev=1), + 'A/B/lambda' : Item(status='D ', wc_rev=1), + 'A/C' : Item(status='D ', wc_rev=1, moved_to='A/C_moved'), + 'A/C_moved' : Item(status='A ', wc_rev='-', copied='+', + moved_from='A/C'), + 'A/D' : Item(status=' ', wc_rev=1), + 'A/D/G' : Item(status=' ', wc_rev=1), + 'A/D/G/pi' : Item(status='D ', wc_rev=1, moved_to='A/D/G/pi_moved'), + 'A/D/G/pi_moved' : Item(status='A ', wc_rev='-', copied='+', + moved_from='A/D/G/pi'), + }) + expected_disk = svntest.wc.State('', { + 'iota' : Item(contents="This is the file 'iota'.\n"), + 'A' : Item(contents=None), + 'A/B' : Item(contents=None), + 'A/C_moved' : Item(contents=None), + 'A/D' : Item(contents=None), + 'A/D/G' : Item(contents=None), + 'A/D/G/pi_moved' : Item(contents="This is the file 'pi'.\n"), + }) + svntest.actions.run_and_verify_update(wc_dir, + expected_output, + expected_disk, + expected_status, + [], False, + '--set-depth', 'empty', A_path) + verify_depth(None, "empty", A_path) + #---------------------------------------------------------------------- # list all tests here, starting with None: test_list = [ None, @@ -2948,6 +3008,7 @@ test_list = [ None, revert_depth_files, spurious_nodes_row, commit_excluded, + fold_tree_with_deleted_moved_items, ] if __name__ == "__main__":
