📄 update_editor.c
字号:
if (eb->notify_func) { svn_wc_notify_t *notify = svn_wc_create_notify(db->path, svn_wc_notify_update_add, pool); notify->kind = svn_node_dir; (*eb->notify_func)(eb->notify_baton, notify, pool); } return SVN_NO_ERROR;}static svn_error_t *open_directory(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **child_baton){ struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; svn_wc_entry_t tmp_entry; apr_uint32_t flags = SVN_WC__ENTRY_MODIFY_REVISION | SVN_WC__ENTRY_MODIFY_URL | SVN_WC__ENTRY_MODIFY_INCOMPLETE; svn_wc_adm_access_t *adm_access; /* kff todo: check that the dir exists locally, find it somewhere if its not there? Yes, all this and more... And ancestor_url and ancestor_revision need to get used. */ struct dir_baton *db = make_dir_baton(path, eb, pb, FALSE, pool); *child_baton = db; /* Mark directory as being at target_revision and URL, but incomplete. */ tmp_entry.revision = *(eb->target_revision); tmp_entry.url = db->new_URL; /* In some situations, the URL of this directory does not have the same repository root as the anchor of the update; we can't just blindly use the that repository root here, so make sure it is really an ancestor. */ if (eb->repos && svn_path_is_ancestor(eb->repos, db->new_URL)) { tmp_entry.repos = eb->repos; flags |= SVN_WC__ENTRY_MODIFY_REPOS; } tmp_entry.incomplete = TRUE; SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access, db->path, pool)); SVN_ERR(svn_wc__entry_modify(adm_access, NULL /* THIS_DIR */, &tmp_entry, flags, TRUE /* immediate write */, pool)); return SVN_NO_ERROR;}static svn_error_t *change_dir_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool){ svn_prop_t *propchange; struct dir_baton *db = dir_baton; propchange = apr_array_push(db->propchanges); propchange->name = apr_pstrdup(db->pool, name); propchange->value = value ? svn_string_dup(value, db->pool) : NULL; return SVN_NO_ERROR;}/* If any of the svn_prop_t objects in PROPCHANGES represents a change to the SVN_PROP_EXTERNALS property, return that change, else return null. If PROPCHANGES contains more than one such change, return the first. */static const svn_prop_t *externals_prop_changed(apr_array_header_t *propchanges){ int i; for (i = 0; i < propchanges->nelts; i++) { const svn_prop_t *p = &(APR_ARRAY_IDX(propchanges, i, svn_prop_t)); if (strcmp(p->name, SVN_PROP_EXTERNALS) == 0) return p; } return NULL;}static svn_error_t *close_directory(void *dir_baton, apr_pool_t *pool){ struct dir_baton *db = dir_baton; svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown; apr_array_header_t *entry_props, *wc_props, *regular_props; svn_wc_adm_access_t *adm_access; SVN_ERR(svn_categorize_props(db->propchanges, &entry_props, &wc_props, ®ular_props, pool)); SVN_ERR(svn_wc_adm_retrieve(&adm_access, db->edit_baton->adm_access, db->path, db->pool)); /* If this directory has property changes stored up, now is the time to deal with them. */ if (regular_props->nelts || entry_props->nelts || wc_props->nelts) { /* to hold log messages: */ svn_stringbuf_t *entry_accum = svn_stringbuf_create("", db->pool); if (regular_props->nelts) { /* If recording traversal info, then see if the SVN_PROP_EXTERNALS property on this directory changed, and record before and after for the change. */ if (db->edit_baton->traversal_info) { svn_wc_traversal_info_t *ti = db->edit_baton->traversal_info; const svn_prop_t *change = externals_prop_changed(regular_props); if (change) { const svn_string_t *new_val_s = change->value; const svn_string_t *old_val_s; SVN_ERR(svn_wc_prop_get (&old_val_s, SVN_PROP_EXTERNALS, db->path, adm_access, db->pool)); if ((new_val_s == NULL) && (old_val_s == NULL)) ; /* No value before, no value after... so do nothing. */ else if (new_val_s && old_val_s && (svn_string_compare(old_val_s, new_val_s))) ; /* Value did not change... so do nothing. */ else /* something changed, record the change */ { /* We can't assume that ti came pre-loaded with the old values of the svn:externals property. Yes, most callers will have already initialized ti by sending it through svn_wc_crawl_revisions, but we shouldn't count on that here -- so we set both the old and new values again. */ if (old_val_s) apr_hash_set(ti->externals_old, apr_pstrdup(ti->pool, db->path), APR_HASH_KEY_STRING, apr_pstrmemdup(ti->pool, old_val_s->data, old_val_s->len)); if (new_val_s) apr_hash_set(ti->externals_new, apr_pstrdup(ti->pool, db->path), APR_HASH_KEY_STRING, apr_pstrmemdup(ti->pool, new_val_s->data, new_val_s->len)); } } } /* Merge pending properties into temporary files (ignoring conflicts). */ SVN_ERR_W(svn_wc__merge_props(&prop_state, adm_access, NULL, NULL /* use baseprops */, regular_props, TRUE, FALSE, db->pool, &entry_accum), _("Couldn't do property merge")); } SVN_ERR(accumulate_entry_props(entry_accum, NULL, adm_access, SVN_WC_ENTRY_THIS_DIR, entry_props, pool)); SVN_ERR(accumulate_wcprops(entry_accum, adm_access, SVN_WC_ENTRY_THIS_DIR, wc_props, pool)); /* Write our accumulation of log entries into a log file */ SVN_ERR(svn_wc__write_log(adm_access, db->log_number, entry_accum, pool)); } /* Run the log. */ SVN_ERR(svn_wc__run_log(adm_access, db->edit_baton->diff3_cmd, db->pool)); db->log_number = 0; /* We're done with this directory, so remove one reference from the bump information. This may trigger a number of actions. See maybe_bump_dir_info() for more information. */ SVN_ERR(maybe_bump_dir_info(db->edit_baton, db->bump_info, db->pool)); /* Notify of any prop changes on this directory -- but do nothing if it's an added directory, because notification has already happened in that case. */ if ((! db->added) && (db->edit_baton->notify_func)) { svn_wc_notify_t *notify = svn_wc_create_notify(db->path, svn_wc_notify_update_update, pool); notify->kind = svn_node_dir; notify->prop_state = prop_state; (*db->edit_baton->notify_func)(db->edit_baton->notify_baton, notify, pool); } return SVN_NO_ERROR;}/* Common code for 'absent_file' and 'absent_directory'. */static svn_error_t *absent_file_or_dir(const char *path, svn_node_kind_t kind, void *parent_baton, apr_pool_t *pool){ const char *name = svn_path_basename(path, pool); struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; svn_wc_adm_access_t *adm_access; apr_hash_t *entries; const svn_wc_entry_t *ent; svn_wc_entry_t tmp_entry; /* Extra check: an item by this name may not exist, but there may still be one scheduled for addition. That's a genuine tree-conflict. */ SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access, pb->path, pool)); SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool)); ent = apr_hash_get(entries, name, APR_HASH_KEY_STRING); if (ent && (ent->schedule == svn_wc_schedule_add)) return svn_error_createf (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, _("Failed to mark '%s' absent: item of the same name is already " "scheduled for addition"), svn_path_local_style(path, pool)); /* Immediately create an entry for the new item in the parent. Note that the parent must already be either added or opened, and thus it's in an 'incomplete' state just like the new item. */ tmp_entry.kind = kind; /* Note that there may already exist a 'ghost' entry in the parent with the same name, in a 'deleted' state. If so, it's fine to overwrite it... but we need to make sure we get rid of the 'deleted' flag when doing so: */ tmp_entry.deleted = FALSE; /* Post-update processing knows to leave this entry if its revision is equal to the target revision of the overall update. */ tmp_entry.revision = *(eb->target_revision); /* And, of course, marking as absent is the whole point. */ tmp_entry.absent = TRUE; SVN_ERR(svn_wc__entry_modify(adm_access, name, &tmp_entry, (SVN_WC__ENTRY_MODIFY_KIND | SVN_WC__ENTRY_MODIFY_REVISION | SVN_WC__ENTRY_MODIFY_DELETED | SVN_WC__ENTRY_MODIFY_ABSENT), TRUE /* immediate write */, pool)); return SVN_NO_ERROR;}static svn_error_t *absent_file(const char *path, void *parent_baton, apr_pool_t *pool){ return absent_file_or_dir(path, svn_node_file, parent_baton, pool);}static svn_error_t *absent_directory(const char *path, void *parent_baton, apr_pool_t *pool){ return absent_file_or_dir(path, svn_node_dir, parent_baton, pool);}/* Common code for add_file() and open_file(). */static svn_error_t *add_or_open_file(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_rev, void **file_baton, svn_boolean_t adding, /* 0 if replacing */ apr_pool_t *pool){ struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct file_baton *fb; const svn_wc_entry_t *entry; svn_node_kind_t kind; svn_wc_adm_access_t *adm_access; /* the file_pool can stick around for a *long* time, so we want to use a subpool for any temporary allocations. */ apr_pool_t *subpool = svn_pool_create(pool); /* ### kff todo: if file is marked as removed by user, then flag a conflict in the entry and proceed. Similarly if it has changed kind. see issuezilla task #398. */ fb = make_file_baton(pb, path, adding, pool); /* It is interesting to note: everything below is just validation. We aren't actually doing any "work" or fetching any persistent data. */ SVN_ERR(svn_io_check_path(fb->path, &kind, subpool)); SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access, pb->path, subpool)); SVN_ERR(svn_wc_entry(&entry, fb->path, adm_access, FALSE, subpool)); /* Sanity checks. */ /* If adding, there should be nothing with this name. */ if (adding && (kind != svn_node_none)) return svn_error_createf (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, _("Failed to add file '%s': object of the same name already exists"), svn_path_local_style(fb->path, pool)); /* sussman sez: If we're trying to add a file that's already in `entries' (but not on disk), that's okay. It's probably because the user deleted the working version and ran 'svn up' as a means of getting the file back. It certainly doesn't hurt to re-add the file. We can't possibly get the entry showing up twice in `entries', since it's a hash; and we know that we won't lose any local mods. Let the existing entry be overwritten. sussman follows up to himself, many months later: the above scenario is fine, as long as the pre-existing entry isn't scheduled for addition. that's a genuine tree-conflict, regardless of whether the working file still exists. */ if (adding && entry && entry->schedule == svn_wc_schedule_add) return svn_error_createf (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, _("Failed to add file '%s': object of the same name is already " "scheduled for addition"), svn_path_local_style(fb->path, pool)); /* If replacing, make sure the .svn entry already exists. */ if ((! adding) && (! entry)) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("File '%s' in directory '%s' " "is not a versioned resource"), fb->name, svn_path_local_style(pb->path, pool)); /* ### todo: right now the incoming copyfrom* args are being completely ignored! Someday the editor-driver may expect us to support this optimization; when that happens, this func needs to -copy- the specified existing wc file to this location. From there, the driver can apply_textdelta on it, etc. */ svn_pool_destroy(subpool); *file_baton = fb; return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -