blob: 733163576caf8f36cd1f34285f5a01db3d282a99 [file] [log] [blame]
/*
* add.c: wrappers around wc add/mkdir 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 <string.h>
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_string.h"
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_path.h"
#include "client.h"
/*** Code. ***/
static svn_error_t *
add_dir_recursive (const char *dirname,
svn_wc_notify_func_t notify_added,
void *notify_baton,
apr_pool_t *pool)
{
apr_dir_t *dir;
apr_finfo_t this_entry;
apr_status_t apr_err;
apr_pool_t *subpool;
apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
/* Add this directory to revision control. */
SVN_ERR (svn_wc_add (svn_stringbuf_create (dirname, pool),
NULL, SVN_INVALID_REVNUM,
notify_added, notify_baton, pool));
/* Create a subpool for iterative memory control. */
subpool = svn_pool_create (pool);
/* Read the directory entries one by one and add those things to
revision control. */
apr_err = apr_dir_open (&dir, dirname, pool);
for (apr_err = apr_dir_read (&this_entry, flags, dir);
APR_STATUS_IS_SUCCESS (apr_err);
apr_err = apr_dir_read (&this_entry, flags, dir))
{
svn_stringbuf_t *fullpath;
/* Skip over SVN admin directories. */
if (strcmp (this_entry.name, SVN_WC_ADM_DIR_NAME) == 0)
continue;
/* Skip entries for this dir and its parent. */
if ((strcmp (this_entry.name, ".") == 0)
|| (strcmp (this_entry.name, "..") == 0))
continue;
/* Construct the full path of the entry. */
fullpath = svn_stringbuf_create (dirname, subpool);
svn_path_add_component
(fullpath,
svn_stringbuf_create (this_entry.name, subpool));
if (this_entry.filetype == APR_DIR)
/* Recurse. */
SVN_ERR (add_dir_recursive (fullpath->data,
notify_added, notify_baton,
subpool));
else if (this_entry.filetype == APR_REG)
SVN_ERR (svn_wc_add (fullpath, NULL, SVN_INVALID_REVNUM,
notify_added, notify_baton, subpool));
/* Clean out the per-iteration pool. */
svn_pool_clear (subpool);
}
/* Destroy the per-iteration pool. */
svn_pool_destroy (subpool);
/* Check that the loop exited cleanly. */
if (! (APR_STATUS_IS_ENOENT (apr_err)))
{
return svn_error_createf
(apr_err, 0, NULL, subpool, "error during recursive add of `%s'",
dirname);
}
else /* Yes, it exited cleanly, so close the dir. */
{
apr_err = apr_dir_close (dir);
if (! (APR_STATUS_IS_SUCCESS (apr_err)))
return svn_error_createf
(apr_err, 0, NULL, subpool, "error closing dir `%s'", dirname);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_add (svn_stringbuf_t *path,
svn_boolean_t recursive,
svn_wc_notify_func_t notify_func,
void *notify_baton,
apr_pool_t *pool)
{
enum svn_node_kind kind;
svn_error_t *err = NULL;
SVN_ERR (svn_io_check_path (path->data, &kind, pool));
if ((kind == svn_node_dir) && (recursive))
err = add_dir_recursive (path->data, notify_func, notify_baton, pool);
else
err = svn_wc_add (path, NULL, SVN_INVALID_REVNUM,
notify_func, notify_baton, pool);
if (err && (err->apr_err == SVN_ERR_ENTRY_EXISTS))
return svn_error_quick_wrap
(err, "svn warning: Cannot add because entry already exists.");
return err;
}
svn_error_t *
svn_client_mkdir (svn_client_commit_info_t **commit_info,
svn_stringbuf_t *path,
svn_client_auth_baton_t *auth_baton,
svn_client_get_commit_log_t log_msg_func,
void *log_msg_baton,
svn_wc_notify_func_t notify_func,
void *notify_baton,
apr_pool_t *pool)
{
svn_string_t path_str;
apr_status_t apr_err;
path_str.data = path->data;
path_str.len = path->len;
/* If this is a URL, we want to drive a commit editor to create this
directory. */
if (svn_path_is_url (&path_str))
{
/* This is a remote directory creation. */
void *ra_baton, *session;
svn_ra_plugin_t *ra_lib;
svn_stringbuf_t *anchor, *target;
const svn_delta_editor_t *editor;
void *edit_baton;
void *root_baton, *dir_baton;
svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
const char *committed_date = NULL;
const char *committed_author = NULL;
svn_stringbuf_t *message;
*commit_info = NULL;
/* Create a new commit item and add it to the array. */
if (log_msg_func)
{
svn_client_commit_item_t *item;
apr_array_header_t *commit_items
= apr_array_make (pool, 1, sizeof (item));
item = apr_pcalloc (pool, sizeof (*item));
item->url = svn_stringbuf_dup (path, pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
(*((svn_client_commit_item_t **) apr_array_push (commit_items)))
= item;
SVN_ERR ((*log_msg_func) (&message, commit_items,
log_msg_baton, pool));
if (! message)
return SVN_NO_ERROR;
}
else
message = svn_stringbuf_create ("", pool);
/* Split the new directory name from its parent URL. */
svn_path_split (path, &anchor, &target, pool);
/* 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, anchor->data, pool));
/* Open a repository session to the URL. Note that we do not have a
base directory, do not want to store auth data, and do not
(necessarily) have an admin area for temp files. */
SVN_ERR (svn_client__open_ra_session (&session, ra_lib, anchor, NULL,
NULL, FALSE, FALSE, TRUE,
auth_baton, pool));
/* Fetch RA commit editor */
SVN_ERR (ra_lib->get_commit_editor (session, &editor, &edit_baton,
&committed_rev,
&committed_date,
&committed_author,
message));
/* Drive the editor to create the TARGET. */
SVN_ERR (editor->open_root (edit_baton, SVN_INVALID_REVNUM, pool,
&root_baton));
SVN_ERR (editor->add_directory (target->data, root_baton, NULL,
SVN_INVALID_REVNUM, pool, &dir_baton));
SVN_ERR (editor->close_directory (dir_baton));
SVN_ERR (editor->close_directory (root_baton));
SVN_ERR (editor->close_edit (edit_baton));
/* Fill in the commit_info structure. */
*commit_info = svn_client__make_commit_info (committed_rev,
committed_author,
committed_date,
pool);
/* Free the RA session. */
SVN_ERR (ra_lib->close (session));
return SVN_NO_ERROR;
}
/* This is a regular "mkdir" + "svn add" */
apr_err = apr_dir_make (path->data, APR_OS_DEFAULT, pool);
if (apr_err)
return svn_error_create (apr_err, 0, NULL, pool, path->data);
return svn_wc_add (path, NULL, SVN_INVALID_REVNUM,
notify_func, notify_baton, pool);
}
/*
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end: */