svn_error_t * svn_client__can_delete(const char *path, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { svn_opt_revision_t revision; svn_node_kind_t external_kind; const char *defining_abspath; const char* local_abspath; revision.kind = svn_opt_revision_unspecified; SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); /* A file external should not be deleted since the file external is implemented as a switched file and it would delete the file the file external is switched to, which is not the behavior the user would probably want. */ SVN_ERR(svn_wc__read_external_info(&external_kind, &defining_abspath, NULL, NULL, NULL, ctx->wc_ctx, local_abspath, local_abspath, TRUE, scratch_pool, scratch_pool)); if (external_kind != svn_node_none) return svn_error_createf(SVN_ERR_WC_CANNOT_DELETE_FILE_EXTERNAL, NULL, _("Cannot remove the external at '%s'; " "please edit or delete the svn:externals " "property on '%s'"), svn_dirent_local_style(local_abspath, scratch_pool), svn_dirent_local_style(defining_abspath, scratch_pool)); /* Use an infinite-depth status check to see if there's anything in or under PATH which would make it unsafe for deletion. The status callback function find_undeletables() makes the determination, returning an error if it finds anything that shouldn't be deleted. */ return svn_error_trace(svn_client_status5(NULL, ctx, path, &revision, svn_depth_infinity, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, find_undeletables, NULL, scratch_pool)); }
QString QSvn::urlFromPath(const QString &path) { QString ret; svn_error_t *err = nullptr; QSvnPool localpool(pool); svn_opt_revision_t rev; rev.kind = svn_opt_revision_working; rev.value.number = 0; err = svn_client_status5(nullptr, ctx, path.toUtf8().constData(), &rev, svn_depth_empty, true, false, true, true, false, nullptr, [](void *baton, const char *path, const svn_client_status_t *status, apr_pool_t *scratch_pool) -> svn_error_t * { Q_UNUSED(path); Q_UNUSED(status); Q_UNUSED(scratch_pool); QString *ret = (QString *)baton; *ret = QString::fromUtf8(status->repos_root_url); if (strlen(status->repos_relpath) > 0) { *ret += "/" + QString::fromUtf8(status->repos_relpath); } return SVN_NO_ERROR; }, (void *)&ret, localpool); if (err) { emit error(err->message); } return ret; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__status(apr_getopt_t *os, void *baton, apr_pool_t *scratch_pool) { svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; apr_pool_t *iterpool; apr_hash_t *master_cl_hash = apr_hash_make(scratch_pool); int i; svn_opt_revision_t rev; struct status_baton sb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, scratch_pool); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); /* We want our -u statuses to be against HEAD. */ rev.kind = svn_opt_revision_head; sb.had_print_error = FALSE; if (opt_state->xml) { /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("status", scratch_pool)); } else { if (opt_state->incremental) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'incremental' option only valid in XML " "mode")); } sb.suppress_externals_placeholders = (opt_state->quiet && (! opt_state->verbose)); sb.detailed = (opt_state->verbose || opt_state->update); sb.show_last_committed = opt_state->verbose; sb.skip_unrecognized = opt_state->quiet; sb.repos_locks = opt_state->update; sb.xml_mode = opt_state->xml; sb.cached_changelists = master_cl_hash; sb.cl_pool = scratch_pool; sb.text_conflicts = 0; sb.prop_conflicts = 0; sb.tree_conflicts = 0; sb.ctx = ctx; SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_revnum_t repos_rev = SVN_INVALID_REVNUM; svn_pool_clear(iterpool); SVN_ERR(svn_dirent_get_absolute(&(sb.target_abspath), target, scratch_pool)); sb.target_path = target; SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); if (opt_state->xml) SVN_ERR(print_start_target_xml(svn_dirent_local_style(target, iterpool), iterpool)); /* Retrieve a hash of status structures with the information requested by the user. */ SVN_ERR(svn_cl__try(svn_client_status5(&repos_rev, ctx, target, &rev, opt_state->depth, opt_state->verbose, opt_state->update, opt_state->no_ignore, opt_state->ignore_externals, FALSE /* depth_as_sticky */, opt_state->changelists, print_status, &sb, iterpool), NULL, opt_state->quiet, /* not versioned: */ SVN_ERR_WC_NOT_WORKING_COPY, SVN_ERR_WC_PATH_NOT_FOUND, SVN_NO_ERROR)); if (opt_state->xml) SVN_ERR(print_finish_target_xml(repos_rev, iterpool)); } /* If any paths were cached because they were associatied with changelists, we can now display them as grouped changelists. */ if (apr_hash_count(master_cl_hash) > 0) { apr_hash_index_t *hi; svn_stringbuf_t *buf; if (opt_state->xml) buf = svn_stringbuf_create_empty(scratch_pool); for (hi = apr_hash_first(scratch_pool, master_cl_hash); hi; hi = apr_hash_next(hi)) { const char *changelist_name = svn__apr_hash_index_key(hi); apr_array_header_t *path_array = svn__apr_hash_index_val(hi); int j; /* ### TODO: For non-XML output, we shouldn't print the ### leading \n on the first changelist if there were no ### non-changelist entries. */ if (opt_state->xml) { svn_stringbuf_setempty(buf); svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "changelist", "name", changelist_name, NULL); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } else SVN_ERR(svn_cmdline_printf(scratch_pool, _("\n--- Changelist '%s':\n"), changelist_name)); for (j = 0; j < path_array->nelts; j++) { struct status_cache *scache = APR_ARRAY_IDX(path_array, j, struct status_cache *); sb.target_abspath = scache->target_abspath; sb.target_path = scache->target_path; SVN_ERR(print_status_normal_or_xml(&sb, scache->path, scache->status, scratch_pool)); } if (opt_state->xml) { svn_stringbuf_setempty(buf); svn_xml_make_close_tag(&buf, scratch_pool, "changelist"); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } } }
bool CCachedDirectory::SvnUpdateMembersStatus() { if (InterlockedExchange(&m_FetchingStatus, TRUE)) return false; svn_opt_revision_t revision; revision.kind = svn_opt_revision_unspecified; SVNPool subPool(CSVNStatusCache::Instance().m_svnHelp.Pool()); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": stat for %s\n"), m_directoryPath.GetWinPath()); const char * svnapipath = m_directoryPath.GetSVNApiPath(subPool); if ((svnapipath == 0)||(svnapipath[0] == 0)) { InterlockedExchange(&m_FetchingStatus, FALSE); m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; CSVNStatusCache::Instance().BlockPath(m_directoryPath, true, 5); return false; } m_pCtx = CSVNStatusCache::Instance().m_svnHelp.ClientContext(subPool); svn_error_t * pErr = nullptr; if (m_pCtx) { pErr = svn_client_status5 ( NULL, m_pCtx, svnapipath, &revision, svn_depth_immediates, TRUE, // get all FALSE, // update TRUE, // no ignores FALSE, // ignore externals TRUE, // depth as sticky NULL, // changelists GetStatusCallback, this, subPool ); svn_wc_context_destroy(m_pCtx->wc_ctx); m_pCtx->wc_ctx = NULL; m_pCtx = NULL; } else { CTraceToOutputDebugString::Instance()(__FUNCTION__ ": error creating client context!\n"); m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; // Since we only assume a none status here due to the fact that we couldn't get a client context, // make sure that this status times out soon. CSVNStatusCache::Instance().m_folderCrawler.BlockPath(m_directoryPath, 20); CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath); } InterlockedExchange(&m_FetchingStatus, FALSE); if (pErr) { // Handle an error // The most likely error on a folder is that it's not part of a WC // In most circumstances, this will have been caught earlier, // but in some situations, we'll get this error. // If we allow ourselves to fall on through, then folders will be asked // for their own status, and will set themselves as unversioned, for the // benefit of future requests CTraceToOutputDebugString::Instance()(__FUNCTION__ ": svn_cli_stat error '%s'\n", pErr->message); // No assert here! Since we _can_ get here, an assertion is not an option! // Reasons to get here: // - renaming a folder with many sub folders --> results in "not a working copy" if the revert // happens between our checks and the svn_client_status() call. // - reverting a move/copy --> results in "not a working copy" (as above) switch (pErr->apr_err) { case SVN_ERR_WC_NOT_WORKING_COPY: { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; CSVNStatusCache::Instance().BlockPath(m_directoryPath, true); } break; case SVN_ERR_WC_PATH_NOT_FOUND: case SVN_ERR_WC_NOT_FILE: case SVN_ERR_WC_CORRUPT: case SVN_ERR_WC_CORRUPT_TEXT_BASE: case SVN_ERR_WC_UNSUPPORTED_FORMAT: case SVN_ERR_WC_DB_ERROR: case SVN_ERR_WC_MISSING: case SVN_ERR_WC_PATH_UNEXPECTED_STATUS: case SVN_ERR_WC_UPGRADE_REQUIRED: case SVN_ERR_WC_CLEANUP_REQUIRED: { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; } break; default: { // Since we only assume a none status here due to svn_client_status() // returning an error, make sure that this status times out soon. CSVNStatusCache::Instance().m_folderCrawler.BlockPath(m_directoryPath, 20); CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath); } break; } svn_error_clear(pErr); return false; } RefreshMostImportant(false); return true; }