* read-tree. Non-scripted Porcelain is not required to use these messages
* and in fact are encouraged to reword them to better suit their particular
* situation better. See how "git checkout" and "git merge" replaces
- * them using set_porcelain_error_msgs(), for example.
+ * them using setup_unpack_trees_porcelain(), for example.
*/
const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
/* ERROR_WOULD_OVERWRITE */
? ((o)->msgs[(type)]) \
: (unpack_plumbing_errors[(type)]) )
+void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
+ const char *cmd)
+{
+ int i;
+ const char **msgs = opts->msgs;
+ const char *msg;
+ char *tmp;
+ const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
+ if (advice_commit_before_merge)
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
+ "Please, commit your changes or stash them before you can %s.";
+ else
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
+ sprintf(tmp, msg, cmd, cmd2);
+ msgs[ERROR_WOULD_OVERWRITE] = tmp;
+ msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
+
+ msgs[ERROR_NOT_UPTODATE_DIR] =
+ "Updating the following directories would lose untracked files in it:\n%s";
+
+ if (advice_commit_before_merge)
+ msg = "The following untracked working tree files would be %s by %s:\n%%s"
+ "Please move or remove them before you can %s.";
+ else
+ msg = "The following untracked working tree files would be %s by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "removed", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "overwritten", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
+
+ /*
+ * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
+ * cannot easily display it as a list.
+ */
+ msgs[ERROR_BIND_OVERLAP] = "Entry '%s' overlaps with '%s'. Cannot bind.";
+
+ msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
+ "Cannot update sparse checkout: the following entries are not up-to-date:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
+ "The following Working tree files would be overwritten by sparse checkout update:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
+ "The following Working tree files would be removed by sparse checkout update:\n%s";
+
+ opts->show_all_errors = 1;
+ /* rejected paths may not have a static buffer */
+ for (i = 0; i < ARRAY_SIZE(opts->unpack_rejects); i++)
+ opts->unpack_rejects[i].strdup_strings = 1;
+}
+
static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
{
enum unpack_trees_error_types e,
const char *path)
{
- struct rejected_paths_list *newentry;
- int porcelain = o && (o)->msgs[e];
- /*
- * simply display the given error message if in plumbing mode
- */
- if (!porcelain)
- o->show_all_errors = 0;
if (!o->show_all_errors)
return error(ERRORMSG(o, e), path);
* Otherwise, insert in a list for future display by
* display_error_msgs()
*/
- newentry = xmalloc(sizeof(struct rejected_paths_list));
- newentry->path = (char *)path;
- newentry->next = o->unpack_rejects[e];
- o->unpack_rejects[e] = newentry;
+ string_list_append(&o->unpack_rejects[e], path);
return -1;
}
-/*
- * free all the structures allocated for the error <e>
- */
-static void free_rejected_paths(struct unpack_trees_options *o,
- enum unpack_trees_error_types e)
-{
- while (o->unpack_rejects[e]) {
- struct rejected_paths_list *del = o->unpack_rejects[e];
- o->unpack_rejects[e] = o->unpack_rejects[e]->next;
- free(del);
- }
- free(o->unpack_rejects[e]);
-}
-
/*
* display all the error messages stored in a nice way
*/
static void display_error_msgs(struct unpack_trees_options *o)
{
- int e;
+ int e, i;
int something_displayed = 0;
for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
- if (o->unpack_rejects[e]) {
- struct rejected_paths_list *rp;
+ struct string_list *rejects = &o->unpack_rejects[e];
+ if (rejects->nr > 0) {
struct strbuf path = STRBUF_INIT;
something_displayed = 1;
- for (rp = o->unpack_rejects[e]; rp; rp = rp->next)
- strbuf_addf(&path, "\t%s\n", rp->path);
+ for (i = 0; i < rejects->nr; i++)
+ strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
error(ERRORMSG(o, e), path.buf);
strbuf_release(&path);
- free_rejected_paths(o, e);
}
+ string_list_clear(rejects, 0);
}
if (something_displayed)
printf("Aborting\n");
*/
static void unlink_entry(struct cache_entry *ce)
{
- if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+ if (!check_leading_path(ce->name, ce_namelen(ce)))
return;
if (remove_or_warn(ce->ce_mode, ce->name))
return;
* See if we can find a case-insensitive match in the index that also
* matches the stat information, and assume it's that other file!
*/
-static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst, struct stat *st)
+static int icase_exists(struct unpack_trees_options *o, const char *name, int len, struct stat *st)
{
struct cache_entry *src;
- src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);
+ src = index_name_exists(o->src_index, name, len, 1);
return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
}
+static int check_ok_to_remove(const char *name, int len, int dtype,
+ struct cache_entry *ce, struct stat *st,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *result;
+
+ /*
+ * It may be that the 'lstat()' succeeded even though
+ * target 'ce' was absent, because there is an old
+ * entry that is different only in case..
+ *
+ * Ignore that lstat() if it matches.
+ */
+ if (ignore_case && icase_exists(o, name, len, st))
+ return 0;
+
+ if (o->dir && excluded(o->dir, name, &dtype))
+ /*
+ * ce->name is explicitly excluded, so it is Ok to
+ * overwrite it.
+ */
+ return 0;
+ if (S_ISDIR(st->st_mode)) {
+ /*
+ * We are checking out path "foo" and
+ * found "foo/." in the working tree.
+ * This is tricky -- if we have modified
+ * files that are in "foo/" we would lose
+ * them.
+ */
+ if (verify_clean_subdirectory(ce, error_type, o) < 0)
+ return -1;
+ return 0;
+ }
+
+ /*
+ * The previous round may already have decided to
+ * delete this path, which is in a subdirectory that
+ * is being replaced with a blob.
+ */
+ result = index_name_exists(&o->result, name, len, 0);
+ if (result) {
+ if (result->ce_flags & CE_REMOVE)
+ return 0;
+ }
+
+ return o->gently ? -1 :
+ add_rejected_path(o, error_type, name);
+}
+
/*
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
+ int len;
struct stat st;
if (o->index_only || o->reset || !o->update)
return 0;
- if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+ len = check_leading_path(ce->name, ce_namelen(ce));
+ if (!len)
return 0;
+ else if (len > 0) {
+ char path[PATH_MAX + 1];
+ memcpy(path, ce->name, len);
+ path[len] = 0;
+ lstat(path, &st);
+
+ return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
+ error_type, o);
+ } else if (!lstat(ce->name, &st))
+ return check_ok_to_remove(ce->name, ce_namelen(ce),
+ ce_to_dtype(ce), ce, &st,
+ error_type, o);
- if (!lstat(ce->name, &st)) {
- int dtype = ce_to_dtype(ce);
- struct cache_entry *result;
-
- /*
- * It may be that the 'lstat()' succeeded even though
- * target 'ce' was absent, because there is an old
- * entry that is different only in case..
- *
- * Ignore that lstat() if it matches.
- */
- if (ignore_case && icase_exists(o, ce, &st))
- return 0;
-
- if (o->dir && excluded(o->dir, ce->name, &dtype))
- /*
- * ce->name is explicitly excluded, so it is Ok to
- * overwrite it.
- */
- return 0;
- if (S_ISDIR(st.st_mode)) {
- /*
- * We are checking out path "foo" and
- * found "foo/." in the working tree.
- * This is tricky -- if we have modified
- * files that are in "foo/" we would lose
- * them.
- */
- if (verify_clean_subdirectory(ce, error_type, o) < 0)
- return -1;
- return 0;
- }
-
- /*
- * The previous round may already have decided to
- * delete this path, which is in a subdirectory that
- * is being replaced with a blob.
- */
- result = index_name_exists(&o->result, ce->name, ce_namelen(ce), 0);
- if (result) {
- if (result->ce_flags & CE_REMOVE)
- return 0;
- }
-
- return o->gently ? -1 :
- add_rejected_path(o, error_type, ce->name);
- }
return 0;
}
+
static int verify_absent(struct cache_entry *ce,
enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)