diff options
Diffstat (limited to 'subversion/libsvn_client')
| -rw-r--r-- | subversion/libsvn_client/commit_util.c | 118 | ||||
| -rw-r--r-- | subversion/libsvn_client/export.c | 5 | ||||
| -rw-r--r-- | subversion/libsvn_client/merge.c | 159 | ||||
| -rw-r--r-- | subversion/libsvn_client/prop_commands.c | 18 | 
4 files changed, 196 insertions, 104 deletions
diff --git a/subversion/libsvn_client/commit_util.c b/subversion/libsvn_client/commit_util.c index 1e2c50cd9e61..a32ec5d3ef80 100644 --- a/subversion/libsvn_client/commit_util.c +++ b/subversion/libsvn_client/commit_util.c @@ -892,7 +892,7 @@ harvest_status_callback(void *status_baton,    if (matches_changelists        && (is_harvest_root || baton->changelists)        && state_flags -      && is_added +      && (is_added || (is_deleted && is_op_root && status->copied))        && baton->danglers)      {        /* If a node is added, its parent must exist in the repository at the @@ -966,17 +966,19 @@ struct handle_descendants_baton    void *cancel_baton;    svn_client__check_url_kind_t check_url_func;    void *check_url_baton; +  svn_client__committables_t *committables;  };  /* Helper for the commit harvesters */  static svn_error_t *  handle_descendants(void *baton, -                       const void *key, apr_ssize_t klen, void *val, -                       apr_pool_t *pool) +                   const void *key, apr_ssize_t klen, void *val, +                   apr_pool_t *pool)  {    struct handle_descendants_baton *hdb = baton;    apr_array_header_t *commit_items = val;    apr_pool_t *iterpool = svn_pool_create(pool); +  const char *repos_root_url = key;    int i;    for (i = 0; i < commit_items->nelts; i++) @@ -1002,32 +1004,64 @@ handle_descendants(void *baton,        for (j = 0; j < absent_descendants->nelts; j++)          { -          int k; -          svn_boolean_t found_item = FALSE;            svn_node_kind_t kind; +          svn_client_commit_item3_t *desc_item;            const char *relpath = APR_ARRAY_IDX(absent_descendants, j,                                                const char *);            const char *local_abspath = svn_dirent_join(item->path, relpath,                                                        iterpool); -          /* If the path has a commit operation, we do nothing. -             (It will be deleted by the operation) */ -          for (k = 0; k < commit_items->nelts; k++) +          /* ### Need a sub-iterpool? */ + + +          /* We found a 'not present' descendant during a copy (at op_depth>0), +             this is most commonly caused by copying some mixed revision tree. + +             In this case not present can imply that the node does not exist +             in the parent revision, or that the node does. But we want to copy +             the working copy state in which it does not exist, but might be +             replaced. */ + +          desc_item = svn_hash_gets(hdb->committables->by_path, local_abspath); + +          /* If the path has a commit operation (possibly at an higher +             op_depth, we might want to turn an add in a replace. */ +          if (desc_item)              { -              svn_client_commit_item3_t *cmt_item = -                 APR_ARRAY_IDX(commit_items, k, svn_client_commit_item3_t *); +              const char *dir; +              svn_boolean_t found_intermediate = FALSE; + +              if (desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) +                continue; /* We already have a delete or replace */ +              else if (!(desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) +                continue; /* Not a copy/add, just a modification */ -              if (! strcmp(cmt_item->path, local_abspath)) +              dir = svn_dirent_dirname(local_abspath, iterpool); + +              while (strcmp(dir, item->path))                  { -                  found_item = TRUE; -                  break; +                  svn_client_commit_item3_t *i_item; + +                  i_item = svn_hash_gets(hdb->committables->by_path, dir); + +                  if (i_item) +                    { +                      if ((i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) +                          || (i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) +                        { +                          found_intermediate = TRUE; +                          break; +                        } +                    } +                  dir = svn_dirent_dirname(dir, iterpool);                  } -            } -          if (found_item) -            continue; /* We have an explicit delete or replace for this path */ +              if (found_intermediate) +                continue; /* Some intermediate ancestor is an add or delete */ -          /* ### Need a sub-iterpool? */ +              /* Fall through to detect if we need to turn the add in a +                 replace. */ +            }            if (hdb->check_url_func)              { @@ -1045,25 +1079,35 @@ handle_descendants(void *baton,            else              kind = svn_node_unknown; /* 'Ok' for a delete of something */ -          { -            /* Add a new commit item that describes the delete */ -            apr_pool_t *result_pool = commit_items->pool; -            svn_client_commit_item3_t *new_item -                  = svn_client_commit_item3_create(result_pool); - -            new_item->path = svn_dirent_join(item->path, relpath, -                                             result_pool); -            new_item->kind = kind; -            new_item->url = svn_path_url_add_component2(item->url, relpath, -                                                        result_pool); -            new_item->revision = SVN_INVALID_REVNUM; -            new_item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE; -            new_item->incoming_prop_changes = apr_array_make(result_pool, 1, -                                                 sizeof(svn_prop_t *)); - -            APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) -                  = new_item; -          } +          if (desc_item) +            { +              /* Extend the existing add/copy item to create a replace */ +              desc_item->state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE; +              continue; +            } + +          /* Add a new commit item that describes the delete */ + +          SVN_ERR(add_committable(hdb->committables, +                                  svn_dirent_join(item->path, relpath, +                                                  iterpool), +                                  kind, +                                  repos_root_url, +                                  svn_uri_skip_ancestor( +                                        repos_root_url, +                                        svn_path_url_add_component2(item->url, +                                                                    relpath, +                                                                    iterpool), +                                        iterpool), +                                  SVN_INVALID_REVNUM, +                                  NULL /* copyfrom_relpath */, +                                  SVN_INVALID_REVNUM, +                                  NULL /* moved_from_abspath */, +                                  SVN_CLIENT_COMMIT_ITEM_DELETE, +                                  NULL /* lock tokens */, +                                  NULL /* lock */, +                                  commit_items->pool, +                                  iterpool));          }        } @@ -1181,6 +1225,7 @@ svn_client__harvest_committables(svn_client__committables_t **committables,    hdb.cancel_baton = ctx->cancel_baton;    hdb.check_url_func = check_url_func;    hdb.check_url_baton = check_url_baton; +  hdb.committables = *committables;    SVN_ERR(svn_iter_apr_hash(NULL, (*committables)->by_repository,                              handle_descendants, &hdb, iterpool)); @@ -1274,6 +1319,7 @@ harvest_copy_committables(void *baton, void *item, apr_pool_t *pool)    hdb.cancel_baton = btn->ctx->cancel_baton;    hdb.check_url_func = btn->check_url_func;    hdb.check_url_baton = btn->check_url_baton; +  hdb.committables = btn->committables;    SVN_ERR(svn_iter_apr_hash(NULL, btn->committables->by_repository,                              handle_descendants, &hdb, pool)); diff --git a/subversion/libsvn_client/export.c b/subversion/libsvn_client/export.c index d6022ed68f29..c14a5f0bc017 100644 --- a/subversion/libsvn_client/export.c +++ b/subversion/libsvn_client/export.c @@ -267,7 +267,9 @@ export_node(void *baton,                                                        scratch_pool));      } -  if (status->file_external) +  /* Skip file externals if they are a descendant of the export, +     BUT NOT if we are explictly exporting the file external. */ +  if (status->file_external && strcmp(eib->origin_abspath, local_abspath) != 0)      return SVN_NO_ERROR;    /* Produce overwrite errors for the export root */ @@ -1587,3 +1589,4 @@ svn_client_export5(svn_revnum_t *result_rev,    return SVN_NO_ERROR;  } + diff --git a/subversion/libsvn_client/merge.c b/subversion/libsvn_client/merge.c index cb07f8303c2b..b314e8409b2a 100644 --- a/subversion/libsvn_client/merge.c +++ b/subversion/libsvn_client/merge.c @@ -322,6 +322,10 @@ typedef struct merge_cmd_baton_t {    const char *diff3_cmd;    const apr_array_header_t *merge_options; +  /* Array of file extension patterns to preserve as extensions in +     generated conflict files. */ +  const apr_array_header_t *ext_patterns; +    /* RA sessions used throughout a merge operation.  Opened/re-parented       as needed. @@ -2023,17 +2027,36 @@ merge_file_changed(const char *relpath,      {        svn_boolean_t has_local_mods;        enum svn_wc_merge_outcome_t content_outcome; +      const char *target_label; +      const char *left_label; +      const char *right_label; +      const char *path_ext = ""; + +      if (merge_b->ext_patterns && merge_b->ext_patterns->nelts) +        { +          svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool); +          if (! (*path_ext +                 && svn_cstring_match_glob_list(path_ext, +                                                merge_b->ext_patterns))) +            { +              path_ext = ""; +            } +        }        /* xgettext: the '.working', '.merge-left.r%ld' and           '.merge-right.r%ld' strings are used to tag onto a file           name in case of a merge conflict */ -      const char *target_label = _(".working"); -      const char *left_label = apr_psprintf(scratch_pool, -                                            _(".merge-left.r%ld"), -                                            left_source->revision); -      const char *right_label = apr_psprintf(scratch_pool, -                                             _(".merge-right.r%ld"), -                                             right_source->revision); + +      target_label = apr_psprintf(scratch_pool, _(".working%s%s"), +                                  *path_ext ? "." : "", path_ext); +      left_label = apr_psprintf(scratch_pool, +                                _(".merge-left.r%ld%s%s"), +                                left_source->revision, +                                *path_ext ? "." : "", path_ext); +      right_label = apr_psprintf(scratch_pool, +                                 _(".merge-right.r%ld%s%s"), +                                 right_source->revision, +                                 *path_ext ? "." : "", path_ext);        SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx,                                        local_abspath, FALSE, scratch_pool)); @@ -3062,7 +3085,6 @@ merge_dir_deleted(const char *relpath,    struct merge_dir_baton_t *db = dir_baton;    const char *local_abspath = svn_dirent_join(merge_b->target->abspath,                                                relpath, scratch_pool); -  struct dir_delete_baton_t *delb;    svn_boolean_t same;    apr_hash_t *working_props; @@ -3093,66 +3115,69 @@ merge_dir_deleted(const char *relpath,                              scratch_pool, scratch_pool));    if (merge_b->force_delete) -    same = TRUE; +    { +      /* In this legacy mode we just assume that a directory delete +         matches any directory. db->delete_state is NULL */ +      same = TRUE; +    }    else      { +      struct dir_delete_baton_t *delb; +        /* Compare the properties */        SVN_ERR(properties_same_p(&same, left_props, working_props,                                  scratch_pool)); -    } +      delb = db->delete_state; +      assert(delb != NULL); -  delb = db->delete_state; -  assert(delb != NULL); - -  if (! same) -    { -      delb->found_edit = TRUE; -    } -  else -    { -      store_path(delb->compared_abspaths, local_abspath); -    } +      if (! same) +        { +          delb->found_edit = TRUE; +        } +      else +        { +          store_path(delb->compared_abspaths, local_abspath); +        } -  if (delb->del_root != db) -    return SVN_NO_ERROR; +      if (delb->del_root != db) +        return SVN_NO_ERROR; -  if (delb->found_edit) -    same = FALSE; -  else if (merge_b->force_delete) -    same = TRUE; -  else -    { -      apr_array_header_t *ignores; -      svn_error_t *err; -      same = TRUE; +      if (delb->found_edit) +        same = FALSE; +      else +        { +          apr_array_header_t *ignores; +          svn_error_t *err; +          same = TRUE; -      SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, -                                         scratch_pool)); +          SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, +                                             scratch_pool)); -      /* None of the descendants was modified, but maybe there are -         descendants we haven't walked? - -         Note that we aren't interested in changes, as we already verified -         changes in the paths touched by the merge. And the existance of -         other paths is enough to mark the directory edited */ -      err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, -                               svn_depth_infinity, TRUE /* get-all */, -                               FALSE /* no-ignore */, -                               TRUE /* ignore-text-mods */, ignores, -                               verify_touched_by_del_check, delb, -                               merge_b->ctx->cancel_func, -                               merge_b->ctx->cancel_baton, -                               scratch_pool); +          /* None of the descendants was modified, but maybe there are +             descendants we haven't walked? + +             Note that we aren't interested in changes, as we already verified +             changes in the paths touched by the merge. And the existence of +             other paths is enough to mark the directory edited */ +          err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, +                                   svn_depth_infinity, TRUE /* get-all */, +                                   FALSE /* no-ignore */, +                                   TRUE /* ignore-text-mods */, ignores, +                                   verify_touched_by_del_check, delb, +                                   merge_b->ctx->cancel_func, +                                   merge_b->ctx->cancel_baton, +                                   scratch_pool); + +          if (err) +            { +              if (err->apr_err != SVN_ERR_CEASE_INVOCATION) +                return svn_error_trace(err); -      if (err) -        { -          if (err->apr_err != SVN_ERR_CEASE_INVOCATION) -            return svn_error_trace(err); +              svn_error_clear(err); +            } -          svn_error_clear(err); +          same = ! delb->found_edit;          } - -      same = ! delb->found_edit;      }    if (same && !merge_b->dry_run) @@ -9668,6 +9693,7 @@ do_merge(apr_hash_t **modified_subtrees,    merge_cmd_baton_t merge_cmd_baton = { 0 };    svn_config_t *cfg;    const char *diff3_cmd; +  const char *preserved_exts_str;    int i;    svn_boolean_t checked_mergeinfo_capability = FALSE;    svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL; @@ -9728,6 +9754,11 @@ do_merge(apr_hash_t **modified_subtrees,    if (diff3_cmd != NULL)      SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool)); +    /* See which files the user wants to preserve the extension of when +     conflict files are made. */ +  svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY, +                 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, ""); +    /* Build the merge context baton (or at least the parts of it that       don't need to be reset for each merge source).  */    merge_cmd_baton.force_delete = force_delete; @@ -9743,6 +9774,11 @@ do_merge(apr_hash_t **modified_subtrees,    merge_cmd_baton.pool = iterpool;    merge_cmd_baton.merge_options = merge_options;    merge_cmd_baton.diff3_cmd = diff3_cmd; +  merge_cmd_baton.ext_patterns = *preserved_exts_str +                          ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", +                                              FALSE, scratch_pool) +                          : NULL; +    merge_cmd_baton.use_sleep = use_sleep;    /* Do we already know the specific subtrees with mergeinfo we want @@ -10447,15 +10483,10 @@ merge_locked(conflict_report_t **conflict_report,      }    else      { -      merge_source_t source; - -      source.loc1 = source1_loc; -      source.loc2 = source2_loc; -      source.ancestral = FALSE; -        /* Build a single-item merge_source_t array. */        merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); -      APR_ARRAY_PUSH(merge_sources, merge_source_t *) = &source; +      APR_ARRAY_PUSH(merge_sources, merge_source_t *) +        = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool);      }    err = do_merge(NULL, NULL, conflict_report, &use_sleep, @@ -10761,7 +10792,7 @@ log_find_operative_revs(void *baton,     UNMERGED_CATALOG represents the history (as mergeinfo) from     TARGET_LOC that is not represented in SOURCE_LOC's     explicit/inherited mergeinfo as represented by MERGED_CATALOG. -   MERGEINFO_CATALOG may be empty if the source has no explicit or inherited +   MERGED_CATALOG may be empty if the source has no explicit or inherited     mergeinfo.     Check that all of the unmerged revisions in UNMERGED_CATALOG's @@ -11464,7 +11495,7 @@ find_reintegrate_merge(merge_source_t **source_p,           prefix. */        svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool); -      SVN_ERR(find_unsynced_ranges(source_loc, yc_ancestor, +      SVN_ERR(find_unsynced_ranges(source_loc, &target->loc,                                     unmerged_to_source_mergeinfo_catalog,                                     merged_to_source_mergeinfo_catalog,                                     final_unmerged_catalog, diff --git a/subversion/libsvn_client/prop_commands.c b/subversion/libsvn_client/prop_commands.c index a3e59c866813..06c4d21dc1e0 100644 --- a/subversion/libsvn_client/prop_commands.c +++ b/subversion/libsvn_client/prop_commands.c @@ -890,8 +890,14 @@ svn_client_propget5(apr_hash_t **props,            const char *copy_root_abspath;            svn_boolean_t is_copy; -          SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, -                                          scratch_pool)); +          /* Avoid assertion on the next line when somebody accidentally asks for +             a working copy revision on a URL */ +          if (svn_path_is_url(target)) +            return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, +                                    NULL, NULL); + +          SVN_ERR_ASSERT(svn_dirent_is_absolute(target)); +          local_abspath = target;            if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))              { @@ -1232,7 +1238,7 @@ recursive_proplist_receiver(void *baton,           Report iprops anyway */        SVN_ERR(b->wrapped_receiver(b->wrapped_receiver_baton, -                                  b->anchor ? b->anchor : local_abspath, +                                  b->anchor ? b->anchor : b->anchor_abspath,                                    NULL /* prop_hash */,                                    b->iprops,                                    scratch_pool)); @@ -1293,6 +1299,12 @@ get_remote_props(const char *path_or_url,        const char *copy_root_abspath;        svn_boolean_t is_copy; +      /* Avoid assertion on the next line when somebody accidentally asks for +         a working copy revision on a URL */ +      if (svn_path_is_url(path_or_url)) +        return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, +                                NULL, NULL); +        SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,                                        scratch_pool));  | 
