📄 log.c
字号:
const svn_wc_entry_t *parentry;
svn_wc_entry_t tmp_entry;
SVN_ERR (svn_wc_remove_from_revision_control (loggy->adm_access,
name, FALSE, FALSE,
NULL, NULL,
pool));
/* If the parent entry's working rev 'lags' behind new_rev... */
SVN_ERR (svn_wc_entry (&parentry,
svn_wc_adm_access_path (loggy->adm_access),
loggy->adm_access,
TRUE, pool));
if (new_rev > parentry->revision)
{
/* ...then the parent's revision is now officially a
lie; therefore, it must remember the file as being
'deleted' for a while. Create a new, uninteresting
ghost entry: */
tmp_entry.kind = svn_node_file;
tmp_entry.deleted = TRUE;
tmp_entry.revision = new_rev;
SVN_ERR (svn_wc__entry_modify
(loggy->adm_access, name, &tmp_entry,
SVN_WC__ENTRY_MODIFY_REVISION
| SVN_WC__ENTRY_MODIFY_KIND
| SVN_WC__ENTRY_MODIFY_DELETED,
FALSE, pool));
loggy->entries_modified = TRUE;
}
return SVN_NO_ERROR;
}
}
/*** Mark the committed item committed-to-date ***/
/* If "this dir" has been replaced (delete + add), all its
immmediate children *must* be either scheduled for deletion (they
were children of "this dir" during the "delete" phase of its
replacement), added (they are new children of the replaced dir),
or replaced (they are new children of the replace dir that have
the same names as children that were present during the "delete"
phase of the replacement).
Children which are added or replaced will have been reported as
individual commit targets, and thus will be re-visited by
log_do_committed(). Children which were marked for deletion,
however, need to be outright removed from revision control. */
if ((entry->schedule == svn_wc_schedule_replace) && is_this_dir)
{
apr_hash_index_t *hi;
/* Loop over all children entries, look for items scheduled for
deletion. */
SVN_ERR (svn_wc_entries_read (&entries, loggy->adm_access, TRUE, pool));
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
const void *key;
apr_ssize_t klen;
void *val;
const svn_wc_entry_t *cur_entry;
svn_wc_adm_access_t *entry_access;
/* Get the next entry */
apr_hash_this (hi, &key, &klen, &val);
cur_entry = (svn_wc_entry_t *) val;
/* Skip each entry that isn't scheduled for deletion. */
if (cur_entry->schedule != svn_wc_schedule_delete)
continue;
/* Determine what arguments to hand to our removal function,
and let BASE_NAME double as an "ok" flag to run that function. */
base_name = NULL;
if (cur_entry->kind == svn_node_file)
{
pdir = svn_wc_adm_access_path (loggy->adm_access);
base_name = apr_pstrdup (pool, key);
entry_access = loggy->adm_access;
}
else if (cur_entry->kind == svn_node_dir)
{
pdir = svn_path_join (svn_wc_adm_access_path (loggy->adm_access),
key, pool);
base_name = SVN_WC_ENTRY_THIS_DIR;
SVN_ERR (svn_wc_adm_retrieve (&entry_access, loggy->adm_access,
pdir, pool));
}
/* ### We pass NULL, NULL for cancel_func and cancel_baton below.
### If they were available, it would be nice to use them. */
if (base_name)
SVN_ERR (svn_wc_remove_from_revision_control
(entry_access, base_name, FALSE, FALSE,
NULL, NULL, pool));
}
}
/* For file commit items, we need to "install" the user's working
file as the new `text-base' in the administrative area. A copy
of this file should have been dropped into our `tmp/text-base'
directory during the commit process. Part of this process
involves setting the textual timestamp for this entry. We'd like
to just use the timestamp of the working file, but it is possible that
at some point during the commit, the real working file might have
changed again. If that has happened, we'll use the timestamp of
the copy of this file in `tmp/text-base'. */
if (! is_this_dir)
{
const char *wf = full_path, *tmpf;
/* Make sure our working file copy is present in the temp area. */
tmpf = svn_wc__text_base_path (wf, 1, pool);
if ((err = svn_io_check_path (tmpf, &kind, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error checking existence of '%s'"), name);
if (kind == svn_node_file)
{
svn_boolean_t modified;
const char *chosen;
/* Verify that the working file is the same as the tmpf file. */
if ((err = svn_wc__versioned_file_modcheck (&modified, wf,
loggy->adm_access,
tmpf, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error comparing '%s' and '%s'"),
wf, tmpf);
/* If they are the same, use the working file's timestamp,
else use the tmpf file's timestamp. */
chosen = modified ? tmpf : wf;
/* Get the timestamp from our chosen file. */
if ((err = svn_io_file_affected_time (&text_time, chosen, pool)))
return svn_error_createf
(pick_error_code (loggy), err,
_("Error getting 'affected time' for '%s'"), chosen);
}
}
/* Now check for property commits. If a property commit occurred, a
copy of the "working" property file should have been dumped in
the admistrative `tmp' area. We'll let that tmpfile's existence
be a signal that we need to do post-commit property processing.
Also, we have to again decide which timestamp to use (see the
text-time case above). */
{
const char *wf, *tmpf, *basef;
/* Get property file pathnames (not from the `tmp' area) depending
on whether we're examining a file or THIS_DIR */
/* ### Logic check: if is_this_dir, then full_path is the same
as loggy->adm_access->path, I think. In which case we don't need the
inline conditionals below... */
SVN_ERR (svn_wc__prop_path
(&wf,
is_this_dir
? svn_wc_adm_access_path (loggy->adm_access) : full_path,
loggy->adm_access, FALSE, pool));
SVN_ERR (svn_wc__prop_base_path
(&basef,
is_this_dir
? svn_wc_adm_access_path (loggy->adm_access) : full_path,
loggy->adm_access, FALSE, pool));
/* If this file was replaced in the commit, then we definitely
need to begin by removing any old residual prop-base file. */
if (entry->schedule == svn_wc_schedule_replace)
{
svn_node_kind_t kinder;
SVN_ERR (svn_io_check_path (basef, &kinder, pool));
if (kinder == svn_node_file)
SVN_ERR (svn_io_remove_file (basef, pool));
}
SVN_ERR (svn_wc__prop_path
(&tmpf,
is_this_dir
? svn_wc_adm_access_path (loggy->adm_access) : full_path,
loggy->adm_access, TRUE, pool));
if ((err = svn_io_check_path (tmpf, &kind, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error checking existence of '%s'"), name);
if (kind == svn_node_file)
{
svn_boolean_t same;
const char *chosen;
/* We need to decide which prop-timestamp to use, just like we
did with text-time above. */
if ((err = svn_io_files_contents_same_p (&same, wf, tmpf, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error comparing '%s' and '%s'"),
wf, tmpf);
/* If they are the same, use the working file's timestamp,
else use the tmp_base file's timestamp. */
chosen = same ? wf : tmpf;
/* Get the timestamp of our chosen file. */
if ((err = svn_io_file_affected_time (&prop_time, chosen, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error getting 'affected time' of '%s'"),
chosen);
/* Examine propchanges here before installing the new
propbase. If the executable prop was -deleted-, then set a
flag that will remind us to run -x after our call to
install_committed_file(). */
if (! is_this_dir)
{
int i;
apr_array_header_t *propchanges;
SVN_ERR (svn_wc_get_prop_diffs (&propchanges, NULL,
full_path, loggy->adm_access,
pool));
for (i = 0; i < propchanges->nelts; i++)
{
svn_prop_t *propchange
= &APR_ARRAY_IDX (propchanges, i, svn_prop_t);
if ((! strcmp (propchange->name, SVN_PROP_EXECUTABLE))
&& (propchange->value == NULL))
{
remove_executable = TRUE;
break;
}
}
}
/* Make the tmp prop file the new pristine one. */
SVN_ERR (svn_wc__prep_file_for_replacement (basef, TRUE, pool));
SVN_ERR (svn_io_file_rename (tmpf, basef, pool));
SVN_ERR (svn_io_set_file_read_only (basef, FALSE, pool));
}
}
/* Timestamps have been decided on, and prop-base has been installed
if necessary. Now we install the new text-base (if present), and
possibly re-translate the working file. */
if (! is_this_dir)
{
/* Install the new file, which may involve expanding keywords. */
if ((err = install_committed_file
(&overwrote_working, loggy->adm_access, name, pool)))
return svn_error_createf
(pick_error_code (loggy), err,
_("Error replacing text-base of '%s'"), name);
/* The previous call will have run +x if the executable property
was added or already present. But if this property was
-removed-, (detected earlier), then run -x here on the new
working file. */
if (remove_executable)
{
SVN_ERR (svn_io_set_file_executable (full_path,
FALSE, /* chmod -x */
FALSE, pool));
overwrote_working = TRUE; /* entry needs wc-file's timestamp */
}
/* If the working file was overwritten (due to re-translation)
or touched (due to +x / -x), then use *that* textual
timestamp instead. */
if (overwrote_working)
if ((err = svn_io_file_affected_time (&text_time, full_path, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error getting 'affected time' of '%s'"),
full_path);
}
/* Files have been moved, and timestamps have been found. It is now
fime for The Big Entry Modification. */
entry->revision = SVN_STR_TO_REV (rev);
entry->kind = is_this_dir ? svn_node_dir : svn_node_file;
entry->schedule = svn_wc_schedule_normal;
entry->copied = FALSE;
entry->deleted = FALSE;
entry->text_time = text_time;
entry->prop_time = prop_time;
entry->conflict_old = NULL;
entry->conflict_new = NULL;
entry->conflict_wrk = NULL;
entry->prejfile = NULL;
entry->copyfrom_url = NULL;
entry->copyfrom_rev = SVN_INVALID_REVNUM;
if ((err = svn_wc__entry_modify (loggy->adm_access, name, entry,
(SVN_WC__ENTRY_MODIFY_REVISION
| SVN_WC__ENTRY_MODIFY_SCHEDULE
| SVN_WC__ENTRY_MODIFY_COPIED
| SVN_WC__ENTRY_MODIFY_DELETED
| SVN_WC__ENTRY_MODIFY_COPYFROM_URL
| SVN_WC__ENTRY_MODIFY_COPYFROM_REV
| SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
| SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
| SVN_WC__ENTRY_MODIFY_CONFLICT_WRK
| SVN_WC__ENTRY_MODIFY_PREJFILE
| (text_time
? SVN_WC__ENTRY_MODIFY_TEXT_TIME
: 0)
| (prop_time
? SVN_WC__ENTRY_MODIFY_PROP_TIME
: 0)
| SVN_WC__ENTRY_MODIFY_FORCE),
FALSE, pool)))
return svn_error_createf
(pick_error_code (loggy), err,
_("Error modifying entry of '%s'"), name);
loggy->entries_modified = TRUE;
/* If we aren't looking at "this dir" (meaning we are looking at a
file), we are finished. From here on out, it's all about a
directory's entry in its parent. */
if (! is_this_dir)
return SVN_NO_ERROR;
/* For directories, we also have to reset the state in the parent's
entry for this directory, unless the current directory is a `WC
root' (meaning, our parent directory on disk is not our parent in
Version Control Land), in which case we're all finished here. */
SVN_ERR (svn_wc_is_wc_root (&wc_root,
svn_wc_adm_access_path (loggy->adm_access),
loggy->adm_access,
pool));
if (wc_root)
return SVN_NO_ERROR;
/* Make sure our entry exists in the parent. */
{
svn_wc_adm_access_t *paccess;
svn_boolean_t unassociated = FALSE;
svn_path_split (svn_wc_adm_access_path (loggy->adm_access), &pdir,
&base_name, pool);
err = svn_wc_adm_retrieve (&paccess, loggy->adm_access, pdir, pool);
if (err && (err->apr_err == SVN_ERR_WC_NOT_LOCKED))
{
svn_error_clear (err);
SVN_ERR (svn_wc_adm_open2 (&paccess, NULL, pdir, TRUE, 0, pool));
unassociated = TRUE;
}
else if (err)
return err;
SVN_ERR (svn_wc_entries_read (&entries, paccess, FALSE, pool));
if (apr_hash_get (entries, base_name, APR_HASH_KEY_STRING))
{
if ((err = svn_wc__entry_modify (paccess, base_name, entry,
(SVN_WC__ENTRY_MODIFY_SCHEDULE
| SVN_WC__ENTRY_MODIFY_COPIED
| SVN_WC__ENTRY_MODIFY_DELETED
| SVN_WC__ENTRY_MODIFY_FORCE),
TRUE, pool)))
return svn_error_createf (pick_error_code (loggy), err,
_("Error modifying entry of '%s'"), name);
}
if (unassociated)
SVN_ERR (svn_wc_adm_close (paccess));
}
return SVN_NO_ERROR;
}
/* See documentation for SVN_WC__LOG_MODIFY_WCPROP. */
static svn_error_t *
log_do_modify_wcprop (struct log_runner *loggy,
const char *name,
const char **atts)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -