| /* |
| * update.c: wrappers around wc update functionality |
| * |
| * ==================================================================== |
| * Copyright (c) 2000-2002 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/. |
| * ==================================================================== |
| */ |
| |
| /* ==================================================================== */ |
| |
| |
| |
| /*** Includes. ***/ |
| |
| #include <assert.h> |
| |
| #include "svn_wc.h" |
| #include "svn_client.h" |
| #include "svn_string.h" |
| #include "svn_error.h" |
| #include "svn_path.h" |
| #include "client.h" |
| |
| |
| |
| /*** Code. ***/ |
| |
| /* Perform an update of PATH (part of a working copy), providing pre- |
| and post-checkout hook editors and batons (BEFORE_EDITOR, |
| BEFORE_EDIT_BATON / AFTER_EDITOR, AFTER_EDIT_BATON). |
| |
| If XML_SRC is NULL, then the update will come from the repository |
| that PATH was originally checked-out from. An invalid REVISION |
| will cause the PATH to be updated to the "latest" revision, while a |
| valid REVISION will update to a specific tree. Alternatively, a |
| time TM can be used to implicitly select a revision. TM cannot be |
| used at the same time as REVISION. |
| |
| If XML_SRC is non-NULL, it is an xml file to update from. An |
| invalid REVISION implies that the revision *must* be present in the |
| <delta-pkg> tag, while a valid REVISION will be simply be stored in |
| the wc. (Note: a <delta-pkg> revision will *always* override the |
| one passed in.) |
| |
| This operation will use the provided memory POOL. */ |
| svn_error_t * |
| svn_client_update (const svn_delta_editor_t *before_editor, |
| void *before_edit_baton, |
| const svn_delta_editor_t *after_editor, |
| void *after_edit_baton, |
| svn_client_auth_baton_t *auth_baton, |
| svn_stringbuf_t *path, |
| svn_stringbuf_t *xml_src, |
| const svn_client_revision_t *revision, |
| svn_boolean_t recurse, |
| svn_wc_notify_func_t notify_func, |
| void *notify_baton, |
| apr_pool_t *pool) |
| { |
| const svn_delta_editor_t *update_editor; |
| void *update_edit_baton; |
| const svn_delta_editor_t *wrap_editor; |
| void *wrap_edit_baton; |
| const svn_delta_edit_fns_t *wrapped_old_editor; |
| void *wrapped_old_edit_baton; |
| const svn_ra_reporter_t *reporter; |
| void *report_baton; |
| svn_wc_entry_t *entry; |
| svn_stringbuf_t *URL; |
| svn_stringbuf_t *anchor, *target; |
| svn_error_t *err; |
| svn_revnum_t revnum; |
| |
| /* Sanity check. Without this, the update is meaningless. */ |
| assert (path != NULL); |
| assert (path->len > 0); |
| |
| /* Use PATH to get the update's anchor and targets. */ |
| SVN_ERR (svn_wc_get_actual_target (path, &anchor, &target, pool)); |
| |
| /* Get full URL from the ANCHOR. */ |
| SVN_ERR (svn_wc_entry (&entry, anchor, pool)); |
| if (! entry) |
| return svn_error_createf |
| (SVN_ERR_WC_OBSTRUCTED_UPDATE, 0, NULL, pool, |
| "svn_client_update: %s is not under revision control", anchor->data); |
| if (! entry->url) |
| return svn_error_createf |
| (SVN_ERR_ENTRY_MISSING_URL, 0, NULL, pool, |
| "svn_client_update: entry '%s' has no URL", anchor->data); |
| URL = svn_stringbuf_dup (entry->url, pool); |
| |
| /* Get revnum set to something meaningful, so we can fetch the |
| update editor. */ |
| if (revision->kind == svn_client_revision_number) |
| revnum = revision->value.number; /* do the trivial conversion manually */ |
| else |
| revnum = SVN_INVALID_REVNUM; /* no matter, do real conversion later */ |
| |
| /* Fetch the update editor. If REVISION is invalid, that's okay; |
| either the RA or XML driver will call editor->set_target_revision |
| later on. */ |
| SVN_ERR (svn_wc_get_update_editor (anchor, |
| target, |
| revnum, |
| recurse, |
| &update_editor, |
| &update_edit_baton, |
| pool)); |
| |
| |
| /* Wrap it up with outside editors. */ |
| svn_delta_wrap_editor (&wrap_editor, &wrap_edit_baton, |
| before_editor, before_edit_baton, |
| update_editor, update_edit_baton, |
| after_editor, after_edit_baton, pool); |
| |
| /* ### todo: This is a TEMPORARY wrapper around our editor so we |
| can use it with an old driver. */ |
| svn_delta_compat_wrap (&wrapped_old_editor, &wrapped_old_edit_baton, |
| wrap_editor, wrap_edit_baton, pool); |
| |
| /* Using an RA layer */ |
| if (! xml_src) |
| { |
| void *ra_baton, *session; |
| svn_ra_plugin_t *ra_lib; |
| |
| /* Get the RA vtable that matches URL. */ |
| SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool)); |
| SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL->data, pool)); |
| |
| /* Open an RA session for the URL */ |
| SVN_ERR (svn_client__open_ra_session (&session, ra_lib, URL, anchor, |
| NULL, TRUE, TRUE, TRUE, |
| auth_baton, pool)); |
| |
| /* ### todo: shouldn't svn_client__get_revision_number be able |
| to take a url as easily as a local path? */ |
| SVN_ERR (svn_client__get_revision_number |
| (&revnum, ra_lib, session, revision, anchor->data, pool)); |
| |
| /* Tell RA to do a update of URL+TARGET to REVISION; if we pass an |
| invalid revnum, that means RA will use the latest revision. */ |
| SVN_ERR (ra_lib->do_update (session, |
| &reporter, &report_baton, |
| revnum, |
| target, |
| recurse, |
| wrapped_old_editor, wrapped_old_edit_baton)); |
| |
| /* Drive the reporter structure, describing the revisions within |
| PATH. When we call reporter->finish_report, the |
| update_editor will be driven by svn_repos_dir_delta. */ |
| err = svn_wc_crawl_revisions (path, reporter, report_baton, |
| TRUE, recurse, |
| notify_func, notify_baton, pool); |
| |
| /* Sleep for one second to ensure timestamp integrity. */ |
| apr_sleep (APR_USEC_PER_SEC * 1); |
| |
| if (err) |
| return err; |
| |
| /* Close the RA session. */ |
| SVN_ERR (ra_lib->close (session)); |
| } |
| |
| /* Else we're checking out from xml */ |
| else |
| { |
| apr_status_t apr_err; |
| apr_file_t *in = NULL; |
| |
| /* Open xml file. */ |
| apr_err = apr_file_open (&in, xml_src->data, (APR_READ | APR_CREATE), |
| APR_OS_DEFAULT, pool); |
| if (apr_err) |
| return svn_error_createf (apr_err, 0, NULL, pool, |
| "unable to open %s", xml_src->data); |
| |
| /* Do an update by xml-parsing the stream. An invalid revnum |
| means that there will be a revision number in the <delta-pkg> |
| tag. Otherwise, a valid revnum will be stored in the wc, |
| assuming there's no <delta-pkg> tag to override it. */ |
| err = svn_delta_xml_auto_parse (svn_stream_from_aprfile (in, pool), |
| wrapped_old_editor, |
| wrapped_old_edit_baton, |
| URL->data, |
| revnum, |
| pool); |
| |
| /* Sleep for one second to ensure timestamp integrity. */ |
| apr_sleep (APR_USEC_PER_SEC * 1); |
| |
| if (err) |
| return err; |
| |
| /* Close XML file. */ |
| apr_file_close (in); |
| } |
| |
| return SVN_NO_ERROR; |
| } |
| |
| |
| |
| /* |
| * local variables: |
| * eval: (load-file "../../tools/dev/svn-dev.el") |
| * end: */ |