📄 mucc.c
字号:
/* Multiple URL Command Client Combine a list of mv, cp and rm commands on URLs into a single commit. Copyright 2005 Philip Martin <philip@codematters.co.uk> Licenced under the same terms as Subversion. How it works: the command line arguments are parsed into an array of action structures. The action structures are interpreted to build a tree of operation structures. The tree of operation structures is used to drive an RA commit editor to produce a single commit. */#include "svn_cmdline.h"#include "svn_client.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_path.h"#include "svn_ra.h"#include <apr_lib.h>#include <stdio.h>#include <string.h>static void handle_error(svn_error_t *err, apr_pool_t *pool){ if (err) svn_handle_error2(err, stderr, FALSE, "mucc: "); svn_error_clear(err); if (pool) svn_pool_destroy(pool); exit(EXIT_FAILURE);}static apr_pool_t *init(const char *application){ apr_allocator_t *allocator; apr_pool_t *pool; svn_error_t *err; const svn_version_checklist_t checklist[] = { {"svn_client", svn_client_version}, {"svn_subr", svn_subr_version}, {"svn_ra", svn_ra_version}, {NULL, NULL} }; SVN_VERSION_DEFINE(my_version); if (svn_cmdline_init(application, stderr) || apr_allocator_create(&allocator)) exit(EXIT_FAILURE); err = svn_ver_check_list(&my_version, checklist); if (err) handle_error(err, NULL); apr_allocator_max_free_set(allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE); pool = svn_pool_create_ex(NULL, allocator); apr_allocator_owner_set(allocator, pool); return pool;}static svn_error_t *prompt_for_creds(const char **username, const char **password, const char *realm, apr_pool_t *pool){ char buffer[100]; svn_boolean_t prompt_with_username; if (realm) SVN_ERR(svn_cmdline_printf(pool, "Authentication realm: %s\n", realm)); if (! *username) { SVN_ERR(svn_cmdline_printf(pool, "Username: ")); if (! fgets(buffer, sizeof(buffer), stdin)) return svn_error_createf(0, NULL, "failed to get username"); if (strlen(buffer) > 0 && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; *username = buffer; prompt_with_username = FALSE; } else prompt_with_username = TRUE; *username = apr_pstrdup(pool, *username); if (password) { apr_size_t sz = sizeof(buffer); const char *prompt = (prompt_with_username ? apr_psprintf(pool, "Password for %s: ", *username) : "Password: "); apr_status_t status = apr_password_get(prompt, buffer, &sz); if (status) return svn_error_wrap_apr(status, "failed to get password"); *password = apr_pstrdup(pool, buffer); } return SVN_NO_ERROR;}static svn_error_t *simple_prompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool){ const char *password; SVN_ERR(prompt_for_creds(&username, &password, realm, pool)); *cred = apr_palloc(pool, sizeof(**cred)); (*cred)->username = username; (*cred)->password = password; return SVN_NO_ERROR;}static svn_error_t *username_prompt(svn_auth_cred_username_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool){ const char *username = NULL; SVN_ERR(prompt_for_creds(&username, NULL, realm, pool)); *cred = apr_palloc(pool, sizeof(**cred)); (*cred)->username = username; return SVN_NO_ERROR;}static svn_ra_callbacks_t *ra_callbacks(apr_pool_t *pool){ apr_array_header_t *providers; svn_ra_callbacks_t *callbacks; svn_auth_provider_object_t *provider; providers = apr_array_make(pool, 2, sizeof(svn_auth_provider_object_t *)); svn_client_get_simple_prompt_provider(&provider, simple_prompt, NULL, 2, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; svn_client_get_username_prompt_provider(&provider, username_prompt, NULL, 2, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; callbacks = apr_palloc(pool, sizeof(*callbacks)); svn_auth_open(&callbacks->auth_baton, providers, pool); callbacks->open_tmp_file = NULL; callbacks->get_wc_prop = NULL; callbacks->set_wc_prop = NULL; callbacks->push_wc_prop = NULL; callbacks->invalidate_wc_props = NULL; return callbacks;}static svn_error_t *commit_callback(svn_revnum_t revision, const char *date, const char *author, void *baton){ apr_pool_t *pool = baton; SVN_ERR(svn_cmdline_printf(pool, "r%ld committed by %s at %s\n", revision, author ? author : "(no author)", date)); return SVN_NO_ERROR;}struct operation { enum { OP_OPEN, OP_DELETE, OP_ADD, OP_REPLACE } operation; svn_node_kind_t kind; /* to copy, valid for add and replace */ svn_revnum_t rev; /* to copy, valid for add and replace */ const char *url; /* to copy, valid for add and replace */ apr_hash_t *children; /* key: const char *path, value: struct operation * */ void *baton; /* as returned by the commit editor */};static svn_error_t *drive(struct operation *operation, svn_revnum_t head, const svn_delta_editor_t *editor, apr_pool_t *pool){ apr_pool_t *subpool = svn_pool_create(pool); apr_hash_index_t *hi; for (hi = apr_hash_first(pool, operation->children); hi; hi = apr_hash_next(hi)) { const void *key; void *val; struct operation *child; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); child = val; if (child->operation == OP_DELETE || child->operation == OP_REPLACE) { SVN_ERR(editor->delete_entry(key, head, operation->baton, subpool)); } if (child->operation == OP_OPEN) { SVN_ERR(editor->open_directory(key, operation->baton, head, subpool, &child->baton)); } if (child->operation == OP_ADD || child->operation == OP_REPLACE) { if (child->kind == svn_node_dir) { SVN_ERR(editor->add_directory(key, operation->baton, child->url, child->rev, subpool, &child->baton)); } else { void *file_baton; SVN_ERR(editor->add_file(key, operation->baton, child->url, child->rev, subpool, &file_baton)); SVN_ERR(editor->close_file(file_baton, NULL, subpool)); } } if (child->operation == OP_OPEN || ((child->operation == OP_ADD || child->operation == OP_REPLACE) && child->kind == svn_node_dir)) { SVN_ERR(drive(child, head, editor, subpool)); SVN_ERR(editor->close_directory(child->baton, subpool)); } } svn_pool_destroy(subpool); return SVN_NO_ERROR;}static struct operation *get_operation(const char *path, struct operation *operation, apr_pool_t *pool){ struct operation *child = apr_hash_get(operation->children, path, APR_HASH_KEY_STRING); if (! child) { child = apr_palloc(pool, sizeof(*child)); child->children = apr_hash_make(pool); child->operation = OP_OPEN; apr_hash_set(operation->children, path, APR_HASH_KEY_STRING, child); } return child;}static const char *subtract_anchor(const char *anchor, const char *url, apr_pool_t *pool){ if (! strcmp(url, anchor)) return ""; else return svn_path_uri_decode(svn_path_is_child(anchor, url, pool), pool);}/* Add PATH to the operations tree rooted at OPERATION, creating any intermediate nodes that are required. If URL is null then PATH will be deleted, otherwise URL@REV is the source to be copied to create PATH. Node type information is obtained for any copy source (to determine whether to create a file or directory) and for any deleted path (to ensure it exists since svn_delta_editor_t->delete_entry doesn't return an error on non-existent nodes). */static svn_error_t *build(const char *path, const char *url, svn_revnum_t rev, svn_revnum_t head, const char *anchor, svn_ra_session_t *session, struct operation *operation, apr_pool_t *pool){ apr_array_header_t *path_bits = svn_path_decompose(path, pool); const char *path_so_far = ""; const char *copy_src = NULL; svn_revnum_t copy_rev = SVN_INVALID_REVNUM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -