📄 commit.c
字号:
/* * commit.c : entry point for commit RA functions for ra_serf * * ==================================================================== * Copyright (c) 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 <apr_uri.h>#include <expat.h>#include <serf.h>#include "svn_pools.h"#include "svn_ra.h"#include "svn_dav.h"#include "svn_xml.h"#include "../libsvn_ra/ra_loader.h"#include "svn_config.h"#include "svn_delta.h"#include "svn_base64.h"#include "svn_version.h"#include "svn_path.h"#include "svn_private_config.h"#include "ra_serf.h"/* Structure associated with a CHECKOUT request. */typedef struct { apr_pool_t *pool; const char *activity_url; apr_size_t activity_url_len; const char *checkout_url; const char *resource_url; svn_ra_serf__simple_request_context_t progress;} checkout_context_t;/* Baton passed back with the commit editor. */typedef struct { /* Pool for our commit. */ apr_pool_t *pool; svn_ra_serf__session_t *session; svn_ra_serf__connection_t *conn; svn_string_t *log_msg; svn_commit_callback2_t callback; void *callback_baton; apr_hash_t *lock_tokens; svn_boolean_t keep_locks; const char *uuid; const char *activity_url; apr_size_t activity_url_len; /* The checkout for the baseline. */ checkout_context_t *baseline; /* The checked-in root to base CHECKOUTs from */ const char *checked_in_url; /* The root baseline collection */ const char *baseline_url; /* Deleted files - so we can detect delete+add (replace) ops. */ apr_hash_t *deleted_entries; /* Copied entries - so we do not checkout these resources. */ apr_hash_t *copied_entries;} commit_context_t;/* Structure associated with a PROPPATCH request. */typedef struct { apr_pool_t *pool; const char *name; const char *path; commit_context_t *commit; /* Changed and removed properties. */ apr_hash_t *changed_props; apr_hash_t *removed_props; svn_ra_serf__simple_request_context_t progress;} proppatch_context_t;typedef struct { const char *path; svn_revnum_t revision; const char *lock_token; apr_hash_t *lock_token_hash; svn_boolean_t keep_locks; svn_ra_serf__simple_request_context_t progress;} delete_context_t;/* Represents a directory. */typedef struct dir_context_t { /* Pool for our directory. */ apr_pool_t *pool; /* The root commit we're in progress for. */ commit_context_t *commit; /* The checked out context for this directory. * * May be NULL; if so call checkout_dir() first. */ checkout_context_t *checkout; /* Our URL to CHECKOUT */ const char *checked_in_url; /* How many pending changes we have left in this directory. */ unsigned int ref_count; /* Our parent */ struct dir_context_t *parent_dir; /* The directory name; if NULL, we're the 'root' */ const char *name; /* The base revision of the dir. */ svn_revnum_t base_revision; const char *copy_path; svn_revnum_t copy_revision; /* Changed and removed properties */ apr_hash_t *changed_props; apr_hash_t *removed_props;} dir_context_t;/* Represents a file to be committed. */typedef struct { /* Pool for our file. */ apr_pool_t *pool; /* The root commit we're in progress for. */ commit_context_t *commit; dir_context_t *parent_dir; const char *name; /* The checked out context for this file. */ checkout_context_t *checkout; /* The base revision of the file. */ svn_revnum_t base_revision; /* Copy path and revision */ const char *copy_path; svn_revnum_t copy_revision; /* stream */ svn_stream_t *stream; /* Temporary file containing the svndiff. */ apr_file_t *svndiff; /* Our base checksum as reported by the WC. */ const char *base_checksum; /* Our resulting checksum as reported by the WC. */ const char *result_checksum; /* Changed and removed properties. */ apr_hash_t *changed_props; apr_hash_t *removed_props; /* URL to PUT the file at. */ const char *put_url;} file_context_t;/* Setup routines and handlers for various requests we'll invoke. */static svn_error_t *return_response_err(svn_ra_serf__handler_t *handler, svn_ra_serf__simple_request_context_t *ctx){ SVN_ERR(ctx->server_error.error); return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, "%s of '%s': %d %s", handler->method, handler->path, ctx->status, ctx->reason);}#define CHECKOUT_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:checkout xmlns:D=\"DAV:\"><D:activity-set><D:href>" #define CHECKOUT_TRAILER "</D:href></D:activity-set></D:checkout>"static serf_bucket_t *create_checkout_body(void *baton, serf_bucket_alloc_t *alloc, apr_pool_t *pool){ checkout_context_t *ctx = baton; serf_bucket_t *body_bkt, *tmp_bkt; body_bkt = serf_bucket_aggregate_create(alloc); tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(CHECKOUT_HEADER, sizeof(CHECKOUT_HEADER) - 1, alloc); serf_bucket_aggregate_append(body_bkt, tmp_bkt); tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(ctx->activity_url, ctx->activity_url_len, alloc); serf_bucket_aggregate_append(body_bkt, tmp_bkt); tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(CHECKOUT_TRAILER, sizeof(CHECKOUT_TRAILER) - 1, alloc); serf_bucket_aggregate_append(body_bkt, tmp_bkt); return body_bkt;}static apr_status_thandle_checkout(serf_request_t *request, serf_bucket_t *response, void *handler_baton, apr_pool_t *pool){ checkout_context_t *ctx = handler_baton; apr_status_t status; status = svn_ra_serf__handle_status_only(request, response, &ctx->progress, pool); /* Get the resulting location. */ if (ctx->progress.done && ctx->progress.status == 201) { serf_bucket_t *hdrs; apr_uri_t uri; const char *location; hdrs = serf_bucket_response_get_headers(response); location = serf_bucket_headers_get(hdrs, "Location"); if (!location) { abort(); } apr_uri_parse(pool, location, &uri); ctx->resource_url = apr_pstrdup(ctx->pool, uri.path); } return status;}static svn_error_t *checkout_dir(dir_context_t *dir){ checkout_context_t *checkout_ctx; svn_ra_serf__handler_t *handler; if (dir->checkout) { return SVN_NO_ERROR; } if (dir->parent_dir) { /* Is our parent a copy? If so, we're already implicitly checked out. */ if (apr_hash_get(dir->commit->copied_entries, dir->parent_dir->name, APR_HASH_KEY_STRING)) { /* Implicitly checkout this dir now. */ dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout)); dir->checkout->pool = dir->pool; dir->checkout->activity_url = dir->commit->activity_url; dir->checkout->activity_url_len = dir->commit->activity_url_len; dir->checkout->resource_url = svn_path_url_add_component(dir->parent_dir->checkout->resource_url, svn_path_basename(dir->name, dir->pool), dir->pool); apr_hash_set(dir->commit->copied_entries, apr_pstrdup(dir->commit->pool, dir->name), APR_HASH_KEY_STRING, (void*)1); return SVN_NO_ERROR; } } /* Checkout our directory into the activity URL now. */ handler = apr_pcalloc(dir->pool, sizeof(*handler)); handler->session = dir->commit->session; handler->conn = dir->commit->conn; checkout_ctx = apr_pcalloc(dir->pool, sizeof(*checkout_ctx)); checkout_ctx->pool = dir->pool; checkout_ctx->activity_url = dir->commit->activity_url; checkout_ctx->activity_url_len = dir->commit->activity_url_len; /* We could be called twice for the root: once to checkout the baseline; * once to checkout the directory itself if we need to do so. */ if (!dir->parent_dir && !dir->commit->baseline) { checkout_ctx->checkout_url = dir->commit->baseline_url; dir->commit->baseline = checkout_ctx; } else { checkout_ctx->checkout_url = dir->checked_in_url; dir->checkout = checkout_ctx; } handler->body_delegate = create_checkout_body; handler->body_delegate_baton = checkout_ctx; handler->body_type = "text/xml"; handler->response_handler = handle_checkout; handler->response_baton = checkout_ctx; handler->method = "CHECKOUT"; handler->path = checkout_ctx->checkout_url; svn_ra_serf__request_create(handler); SVN_ERR(svn_ra_serf__context_run_wait(&checkout_ctx->progress.done, dir->commit->session, dir->pool)); if (checkout_ctx->progress.status != 201) { if (checkout_ctx->progress.status == 404) { return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, return_response_err(handler, &checkout_ctx->progress), _("Path '%s' not present"), dir->name); } return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, return_response_err(handler, &checkout_ctx->progress), _("Your file or directory '%s' is probably out-of-date"), svn_path_local_style(dir->name, dir->pool)); } return SVN_NO_ERROR;}static svn_error_t *checkout_file(file_context_t *file){ svn_ra_serf__handler_t *handler; /* Checkout our file into the activity URL now. */ handler = apr_pcalloc(file->pool, sizeof(*handler)); handler->session = file->commit->session; handler->conn = file->commit->conn; file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout)); file->checkout->pool = file->pool; file->checkout->activity_url = file->commit->activity_url; file->checkout->activity_url_len = file->commit->activity_url_len; /* Append our file name to the baseline to get the resulting checkout. */ file->checkout->checkout_url = svn_path_url_add_component(file->commit->checked_in_url, file->name, file->pool); handler->body_delegate = create_checkout_body; handler->body_delegate_baton = file->checkout; handler->body_type = "text/xml"; handler->response_handler = handle_checkout; handler->response_baton = file->checkout; handler->method = "CHECKOUT"; handler->path = file->checkout->checkout_url; svn_ra_serf__request_create(handler); /* There's no need to wait here as we only need this when we start the * PROPPATCH or PUT of the file. */ SVN_ERR(svn_ra_serf__context_run_wait(&file->checkout->progress.done, file->commit->session, file->pool)); if (file->checkout->progress.status != 201) { if (file->checkout->progress.status == 404) { return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, return_response_err(handler, &file->checkout->progress), _("Path '%s' not present"), file->name); } return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, return_response_err(handler, &file->checkout->progress), _("Your file or directory '%s' is probably out-of-date"), svn_path_local_style(file->name, file->pool)); } return SVN_NO_ERROR;}static svn_error_t *get_version_url(dir_context_t *dir){ svn_ra_serf__session_t *session = dir->commit->session; const char *root_checkout; if (dir->commit->session->wc_callbacks->get_wc_prop) { const svn_string_t *current_version; SVN_ERR(session->wc_callbacks->get_wc_prop(session->wc_callback_baton, dir->name, SVN_RA_SERF__WC_CHECKED_IN_URL, ¤t_version, dir->pool)); if (current_version) { dir->checked_in_url = current_version->data; return SVN_NO_ERROR; } } if (dir->commit->checked_in_url) { root_checkout = dir->commit->checked_in_url; } else { svn_ra_serf__propfind_context_t *propfind_ctx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -