summaryrefslogtreecommitdiff
path: root/subversion/libsvn_client/shelve.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_client/shelve.c')
-rw-r--r--subversion/libsvn_client/shelve.c560
1 files changed, 0 insertions, 560 deletions
diff --git a/subversion/libsvn_client/shelve.c b/subversion/libsvn_client/shelve.c
deleted file mode 100644
index 4eeb4dd..0000000
--- a/subversion/libsvn_client/shelve.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * shelve.c: implementation of the 'shelve' commands
- *
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- */
-
-/* ==================================================================== */
-
-/* We define this here to remove any further warnings about the usage of
- experimental functions in this file. */
-#define SVN_EXPERIMENTAL
-
-#include "svn_client.h"
-#include "svn_wc.h"
-#include "svn_pools.h"
-#include "svn_dirent_uri.h"
-#include "svn_path.h"
-#include "svn_hash.h"
-#include "svn_utf.h"
-#include "svn_ctype.h"
-
-#include "client.h"
-#include "private/svn_client_private.h"
-#include "private/svn_wc_private.h"
-#include "svn_private_config.h"
-
-
-static svn_error_t *
-shelf_name_encode(char **encoded_name_p,
- const char *name,
- apr_pool_t *result_pool)
-{
- char *encoded_name
- = apr_palloc(result_pool, strlen(name) * 2 + 1);
- char *out_pos = encoded_name;
-
- if (name[0] == '\0')
- return svn_error_create(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
- _("Shelf name cannot be the empty string"));
-
- while (*name)
- {
- apr_snprintf(out_pos, 3, "%02x", (unsigned char)(*name++));
- out_pos += 2;
- }
- *encoded_name_p = encoded_name;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-shelf_name_decode(char **decoded_name_p,
- const char *codename,
- apr_pool_t *result_pool)
-{
- svn_stringbuf_t *sb
- = svn_stringbuf_create_ensure(strlen(codename) / 2, result_pool);
- const char *input = codename;
-
- while (*input)
- {
- int c;
- int nchars;
- int nitems = sscanf(input, "%02x%n", &c, &nchars);
-
- if (nitems != 1 || nchars != 2)
- return svn_error_createf(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
- _("Shelve: Bad encoded name '%s'"), codename);
- svn_stringbuf_appendbyte(sb, c);
- input += 2;
- }
- *decoded_name_p = sb->data;
- return SVN_NO_ERROR;
-}
-
-/* Set *NAME to the shelf name from FILENAME. */
-static svn_error_t *
-shelf_name_from_filename(char **name,
- const char *filename,
- apr_pool_t *result_pool)
-{
- size_t len = strlen(filename);
-
- if (len > 6 && strcmp(filename + len - 6, ".patch") == 0)
- {
- char *codename = apr_pstrndup(result_pool, filename, len - 6);
- SVN_ERR(shelf_name_decode(name, codename, result_pool));
- }
- return SVN_NO_ERROR;
-}
-
-/* Set *PATCH_ABSPATH to the abspath of the patch file for shelved change
- * NAME, no matter whether it exists.
- */
-static svn_error_t *
-get_patch_abspath(char **patch_abspath,
- const char *name,
- const char *wc_root_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- char *dir;
- char *filename;
-
- SVN_ERR(svn_wc__get_shelves_dir(&dir, ctx->wc_ctx, wc_root_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(shelf_name_encode(&filename, name, scratch_pool));
- filename = apr_pstrcat(scratch_pool, filename, ".patch", SVN_VA_NULL);
- *patch_abspath = svn_dirent_join(dir, filename, result_pool);
- return SVN_NO_ERROR;
-}
-
-/** Write local changes to a patch file for shelved change @a name.
- *
- * @a message: An optional log message.
- *
- * @a wc_root_abspath: The WC root dir.
- *
- * @a overwrite_existing: If a file at @a patch_abspath exists, overwrite it.
- *
- * @a paths, @a depth, @a changelists: The selection of local paths to diff.
- */
-static svn_error_t *
-shelf_write_patch(const char *name,
- const char *message,
- const char *wc_root_abspath,
- svn_boolean_t overwrite_existing,
- const apr_array_header_t *paths,
- svn_depth_t depth,
- const apr_array_header_t *changelists,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- char *patch_abspath;
- apr_int32_t flag;
- apr_file_t *outfile;
- svn_stream_t *outstream;
- svn_stream_t *errstream;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- int i;
- svn_opt_revision_t peg_revision = {svn_opt_revision_unspecified, {0}};
- svn_opt_revision_t start_revision = {svn_opt_revision_base, {0}};
- svn_opt_revision_t end_revision = {svn_opt_revision_working, {0}};
-
- SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
- ctx, scratch_pool, scratch_pool));
-
- /* Get streams for the output and any error output of the diff. */
- /* ### svn_stream_open_writable() doesn't work here: the buffering
- goes wrong so that diff headers appear after their hunks.
- For now, fix by opening the file without APR_BUFFERED. */
- flag = APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE;
- if (! overwrite_existing)
- flag |= APR_FOPEN_EXCL;
- SVN_ERR(svn_io_file_open(&outfile, patch_abspath,
- flag, APR_FPROT_OS_DEFAULT, scratch_pool));
- outstream = svn_stream_from_aprfile2(outfile, FALSE /*disown*/, scratch_pool);
- SVN_ERR(svn_stream_for_stderr(&errstream, scratch_pool));
-
- /* Write the patch file header (log message, etc.) */
- if (message)
- {
- SVN_ERR(svn_stream_printf(outstream, scratch_pool, "%s\n",
- message));
- }
- SVN_ERR(svn_stream_printf(outstream, scratch_pool,
- "--This line, and those below, will be ignored--\n\n"));
- SVN_ERR(svn_stream_printf(outstream, scratch_pool,
- "--This patch was generated by 'svn shelve'--\n\n"));
-
- for (i = 0; i < paths->nelts; i++)
- {
- const char *path = APR_ARRAY_IDX(paths, i, const char *);
- apr_hash_t *old_config;
- svn_error_t *err;
-
- if (svn_path_is_url(path))
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' is not a local path"), path);
- SVN_ERR(svn_dirent_get_absolute(&path, path, scratch_pool));
-
- /* Ensure we use internal diff, not any configured external diff-cmd. */
- old_config = ctx->config;
- ctx->config = NULL;
- err = svn_client_diff_peg6(
- NULL /*options*/,
- path,
- &peg_revision,
- &start_revision,
- &end_revision,
- wc_root_abspath,
- depth,
- TRUE /*notice_ancestry*/,
- FALSE /*no_diff_added*/,
- FALSE /*no_diff_deleted*/,
- TRUE /*show_copies_as_adds*/,
- FALSE /*ignore_content_type: FALSE -> omit binary files*/,
- FALSE /*ignore_properties*/,
- FALSE /*properties_only*/,
- FALSE /*use_git_diff_format*/,
- SVN_APR_LOCALE_CHARSET,
- outstream,
- errstream,
- changelists,
- ctx, iterpool);
- ctx->config = old_config;
- SVN_ERR(err);
- }
-
- SVN_ERR(svn_stream_close(outstream));
- SVN_ERR(svn_stream_close(errstream));
-
- return SVN_NO_ERROR;
-}
-
-/** Apply the patch file for shelved change @a name to the WC.
- *
- * @a wc_root_abspath: The WC root dir.
- *
- * @a reverse: Apply the patch in reverse.
- *
- * @a dry_run: Don't really apply the changes, just notify what would be done.
- */
-static svn_error_t *
-shelf_apply_patch(const char *name,
- const char *wc_root_abspath,
- svn_boolean_t reverse,
- svn_boolean_t dry_run,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- char *patch_abspath;
-
- SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
- ctx, scratch_pool, scratch_pool));
- SVN_ERR(svn_client_patch(patch_abspath, wc_root_abspath,
- dry_run, 0 /*strip*/,
- reverse,
- FALSE /*ignore_whitespace*/,
- TRUE /*remove_tempfiles*/, NULL, NULL,
- ctx, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/** Delete the patch file for shelved change @a name.
- *
- * @a wc_root_abspath: The WC root dir.
- */
-static svn_error_t *
-shelf_delete_patch(const char *name,
- const char *wc_root_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- char *patch_abspath, *to_abspath;
-
- SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
- ctx, scratch_pool, scratch_pool));
- to_abspath = apr_pstrcat(scratch_pool, patch_abspath, ".bak", SVN_VA_NULL);
-
- /* remove any previous backup */
- SVN_ERR(svn_io_remove_file2(to_abspath, TRUE /*ignore_enoent*/,
- scratch_pool));
-
- /* move the patch to a backup file */
- SVN_ERR(svn_io_file_rename2(patch_abspath, to_abspath, FALSE /*flush_to_disk*/,
- scratch_pool));
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelve(const char *name,
- const apr_array_header_t *paths,
- svn_depth_t depth,
- const apr_array_header_t *changelists,
- svn_boolean_t keep_local,
- svn_boolean_t dry_run,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- const char *local_abspath;
- const char *wc_root_abspath;
- const char *message = "";
- svn_error_t *err;
-
- /* ### TODO: check all paths are in same WC; for now use first path */
- SVN_ERR(svn_dirent_get_absolute(&local_abspath,
- APR_ARRAY_IDX(paths, 0, char *), pool));
- SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
- local_abspath, ctx, pool, pool));
-
- /* Fetch the log message and any other revprops */
- if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
- {
- const char *tmp_file;
- apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(void *));
-
- SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items,
- ctx, pool));
- if (! message)
- return SVN_NO_ERROR;
- }
-
- err = shelf_write_patch(name, message, wc_root_abspath,
- FALSE /*overwrite_existing*/,
- paths, depth, changelists,
- ctx, pool);
- if (err && APR_STATUS_IS_EEXIST(err->apr_err))
- {
- return svn_error_quick_wrapf(err,
- "Shelved change '%s' already exists",
- name);
- }
- else
- SVN_ERR(err);
-
- if (!keep_local)
- {
- /* Reverse-apply the patch. This should be a safer way to remove those
- changes from the WC than running a 'revert' operation. */
- SVN_ERR(shelf_apply_patch(name, wc_root_abspath,
- TRUE /*reverse*/, dry_run,
- ctx, pool));
- }
-
- if (dry_run)
- {
- SVN_ERR(shelf_delete_patch(name, wc_root_abspath,
- ctx, pool));
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_unshelve(const char *name,
- const char *local_abspath,
- svn_boolean_t keep,
- svn_boolean_t dry_run,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- const char *wc_root_abspath;
- svn_error_t *err;
-
- SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
- local_abspath, ctx, pool, pool));
-
- /* Apply the patch. */
- err = shelf_apply_patch(name, wc_root_abspath,
- FALSE /*reverse*/, dry_run,
- ctx, pool);
- if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
- {
- return svn_error_quick_wrapf(err,
- "Shelved change '%s' not found",
- name);
- }
- else
- SVN_ERR(err);
-
- /* Remove the patch. */
- if (! keep && ! dry_run)
- {
- SVN_ERR(shelf_delete_patch(name, wc_root_abspath,
- ctx, pool));
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelves_delete(const char *name,
- const char *local_abspath,
- svn_boolean_t dry_run,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- const char *wc_root_abspath;
-
- SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
- local_abspath, ctx, pool, pool));
-
- /* Remove the patch. */
- if (! dry_run)
- {
- svn_error_t *err;
-
- err = shelf_delete_patch(name, wc_root_abspath,
- ctx, pool);
- if (err && APR_STATUS_IS_ENOENT(err->apr_err))
- {
- return svn_error_quick_wrapf(err,
- "Shelved change '%s' not found",
- name);
- }
- else
- SVN_ERR(err);
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelf_get_paths(apr_hash_t **affected_paths,
- const char *name,
- const char *local_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *wc_root_abspath;
- char *patch_abspath;
- svn_patch_file_t *patch_file;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- apr_hash_t *paths = apr_hash_make(result_pool);
-
- SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
- local_abspath, ctx, scratch_pool, scratch_pool));
- SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
- ctx, scratch_pool, scratch_pool));
- SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, result_pool));
-
- while (1)
- {
- svn_patch_t *patch;
-
- svn_pool_clear(iterpool);
- SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
- FALSE /*reverse*/,
- FALSE /*ignore_whitespace*/,
- iterpool, iterpool));
- if (! patch)
- break;
- svn_hash_sets(paths,
- apr_pstrdup(result_pool, patch->old_filename),
- apr_pstrdup(result_pool, patch->new_filename));
- }
- SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool));
- svn_pool_destroy(iterpool);
-
- *affected_paths = paths;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelf_has_changes(svn_boolean_t *has_changes,
- const char *name,
- const char *local_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *patch_paths;
-
- SVN_ERR(svn_client_shelf_get_paths(&patch_paths, name, local_abspath,
- ctx, scratch_pool, scratch_pool));
- *has_changes = (apr_hash_count(patch_paths) != 0);
- return SVN_NO_ERROR;
-}
-
-/* Set *LOGMSG to the log message stored in the file PATCH_ABSPATH.
- *
- * ### Currently just reads the first line.
- */
-static svn_error_t *
-read_logmsg_from_patch(const char **logmsg,
- const char *patch_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- apr_file_t *file;
- svn_stream_t *stream;
- svn_boolean_t eof;
- svn_stringbuf_t *line;
-
- SVN_ERR(svn_io_file_open(&file, patch_abspath,
- APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, scratch_pool));
- stream = svn_stream_from_aprfile2(file, FALSE /*disown*/, scratch_pool);
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
- SVN_ERR(svn_stream_close(stream));
- *logmsg = line->data;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelves_list(apr_hash_t **shelved_patch_infos,
- const char *local_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- char *shelves_dir;
- apr_hash_t *dirents;
- apr_hash_index_t *hi;
-
- SVN_ERR(svn_wc__get_shelves_dir(&shelves_dir, ctx->wc_ctx, local_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_io_get_dirents3(&dirents, shelves_dir, FALSE /*only_check_type*/,
- result_pool, scratch_pool));
-
- *shelved_patch_infos = apr_hash_make(result_pool);
-
- /* Remove non-shelves */
- for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
- {
- const char *filename = apr_hash_this_key(hi);
- svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
- char *name = NULL;
-
- svn_error_clear(shelf_name_from_filename(&name, filename, result_pool));
- if (name && dirent->kind == svn_node_file)
- {
- svn_client_shelved_patch_info_t *info
- = apr_palloc(result_pool, sizeof(*info));
-
- info->dirent = dirent;
- info->mtime = info->dirent->mtime;
- info->patch_path
- = svn_dirent_join(shelves_dir, filename, result_pool);
- SVN_ERR(read_logmsg_from_patch(&info->message, info->patch_path,
- result_pool, scratch_pool));
-
- svn_hash_sets(*shelved_patch_infos, name, info);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_shelves_any(svn_boolean_t *any_shelved,
- const char *local_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *shelved_patch_infos;
-
- SVN_ERR(svn_client_shelves_list(&shelved_patch_infos, local_abspath,
- ctx, scratch_pool, scratch_pool));
- *any_shelved = apr_hash_count(shelved_patch_infos) != 0;
- return SVN_NO_ERROR;
-}