/* * repos_diff_summarize.c -- The diff summarize editor for summarizing * the differences of two repository versions * * ==================================================================== * Copyright (c) 2005-2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */ #include "svn_props.h" #include "svn_pools.h" #include "client.h" /* Overall crawler editor baton. */ struct edit_baton { /* The summarize callback passed down from the API */ svn_client_diff_summarize_func_t summarize_func; /* The summarize callback baton */ void *summarize_func_baton; /* An RA session used to check the kind of deleted paths */ svn_ra_session_t *ra_session; /* The start revision for the comparison */ svn_revnum_t revision; }; /* Item baton. */ struct item_baton { /* The overall crawler editor baton */ struct edit_baton *edit_baton; /* The summarize filled by the editor calls, NULL if this item hasn't been modified (yet) */ svn_client_diff_summarize_t *summarize; /* The path of the file or directory within the repository */ const char *path; /* The kind of this item */ svn_node_kind_t node_kind; /* The file/directory pool */ apr_pool_t *item_pool; }; /* Create an item baton, with the fields initialized to EDIT_BATON, PATH, * NODE_KIND and POOL, respectively. Allocate the returned structure in POOL. */ static struct item_baton * create_item_baton(struct edit_baton *edit_baton, const char *path, svn_node_kind_t node_kind, apr_pool_t *pool) { struct item_baton *b = apr_pcalloc(pool, sizeof(*b)); b->edit_baton = edit_baton; b->path = apr_pstrdup(pool, path); b->node_kind = node_kind; b->item_pool = pool; return b; } /* Make sure that this item baton contains a summarize struct. * If it doesn't before this call, allocate a new struct in the item's pool, * initializing the diff kind to normal. * All other fields are also initialized from IB to to NULL/invalid values. */ static void ensure_summarize(struct item_baton *ib) { svn_client_diff_summarize_t *sum; if (ib->summarize) return; sum = apr_pcalloc(ib->item_pool, sizeof(*sum)); sum->node_kind = ib->node_kind; sum->summarize_kind = svn_client_diff_summarize_kind_normal; sum->path = ib->path; ib->summarize = sum; } /* An editor function. The root of the comparison hierarchy */ static svn_error_t * open_root(void *edit_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **root_baton) { struct item_baton *ib = create_item_baton(edit_baton, "", svn_node_dir, pool);; *root_baton = ib; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * delete_entry(const char *path, svn_revnum_t base_revision, void *parent_baton, apr_pool_t *pool) { struct item_baton *ib = parent_baton; struct edit_baton *eb = ib->edit_baton; svn_client_diff_summarize_t *sum; svn_node_kind_t kind; /* We need to know if this is a directory or a file */ SVN_ERR(svn_ra_check_path(eb->ra_session, path, eb->revision, &kind, pool)); sum = apr_pcalloc(pool, sizeof(*sum)); sum->summarize_kind = svn_client_diff_summarize_kind_deleted; sum->path = path; sum->node_kind = kind; SVN_ERR(eb->summarize_func(sum, eb->summarize_func_baton, pool)); return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * add_directory(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_rev, apr_pool_t *pool, void **child_baton) { struct item_baton *pb = parent_baton; struct item_baton *cb; cb = create_item_baton(pb->edit_baton, path, svn_node_dir, pool); ensure_summarize(cb); cb->summarize->summarize_kind = svn_client_diff_summarize_kind_added; *child_baton = cb; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * open_directory(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **child_baton) { struct item_baton *pb = parent_baton; struct item_baton *cb; cb = create_item_baton(pb->edit_baton, path, svn_node_dir, pool); *child_baton = cb; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * close_directory(void *dir_baton, apr_pool_t *pool) { struct item_baton *ib = dir_baton; struct edit_baton *eb = ib->edit_baton; if (ib->summarize) SVN_ERR(eb->summarize_func(ib->summarize, eb->summarize_func_baton, pool)); return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * add_file(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_rev, apr_pool_t *pool, void **file_baton) { struct item_baton *pb = parent_baton; struct item_baton *cb; cb = create_item_baton(pb->edit_baton, path, svn_node_file, pool); ensure_summarize(cb); cb->summarize->summarize_kind = svn_client_diff_summarize_kind_added; *file_baton = cb; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * open_file(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **file_baton) { struct item_baton *pb = parent_baton; struct item_baton *cb; cb = create_item_baton(pb->edit_baton, path, svn_node_file, pool); *file_baton = cb; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton) { struct item_baton *ib = file_baton; ensure_summarize(ib); if (ib->summarize->summarize_kind == svn_client_diff_summarize_kind_normal) ib->summarize->summarize_kind = svn_client_diff_summarize_kind_modified; *handler = svn_delta_noop_window_handler; *handler_baton = NULL; return SVN_NO_ERROR; } /* An editor function. */ static svn_error_t * close_file(void *file_baton, const char *text_checksum, apr_pool_t *pool) { struct item_baton *fb = file_baton; struct edit_baton *eb = fb->edit_baton; if (fb->summarize) SVN_ERR(eb->summarize_func(fb->summarize, eb->summarize_func_baton, pool)); return SVN_NO_ERROR; } /* An editor function, implementing both change_file_prop and * change_dir_prop. */ static svn_error_t * change_prop(void *entry_baton, const char *name, const svn_string_t *value, apr_pool_t *pool) { struct item_baton *ib = entry_baton; if (svn_property_kind(NULL, name) == svn_prop_regular_kind) { ensure_summarize(ib); ib->summarize->prop_changed = TRUE; } return SVN_NO_ERROR; } /* Create a repository diff summarize editor and baton. */ svn_error_t * svn_client__get_diff_summarize_editor(const char *target, svn_client_diff_summarize_func_t summarize_func, void *item_baton, svn_ra_session_t *ra_session, svn_revnum_t revision, svn_cancel_func_t cancel_func, void *cancel_baton, const svn_delta_editor_t **editor, void **edit_baton, apr_pool_t *pool) { svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool); struct edit_baton *eb = apr_palloc(pool, sizeof(*eb)); eb->summarize_func = summarize_func; eb->summarize_func_baton = item_baton; eb->ra_session = ra_session; eb->revision = revision; tree_editor->open_root = open_root; tree_editor->delete_entry = delete_entry; tree_editor->add_directory = add_directory; tree_editor->open_directory = open_directory; tree_editor->change_dir_prop = change_prop; tree_editor->close_directory = close_directory; tree_editor->add_file = add_file; tree_editor->open_file = open_file; tree_editor->apply_textdelta = apply_textdelta; tree_editor->change_file_prop = change_prop; tree_editor->close_file = close_file; SVN_ERR(svn_delta_get_cancellation_editor (cancel_func, cancel_baton, tree_editor, eb, editor, edit_baton, pool)); return SVN_NO_ERROR; }