Merge branch 'jc/am-state-fix'

Recent reimplementation of "git am" changed the format of state
files kept in $GIT_DIR/rebase-apply/ without meaning to do so,
primarily because write_file() API was cumbersome to use and it was
easy to mistakenly make text files with incomplete lines.  Update
write_file() interface to make it harder to misuse.

* jc/am-state-fix:
  write_file(): drop caller-supplied LF from calls to create a one-liner file
  write_file_v(): do not leave incomplete line at the end
  write_file(): drop "fatal" parameter
  builtin/am: make sure state files are text
  builtin/am: introduce write_state_*() helper functions
This commit is contained in:
Junio C Hamano 2015-08-31 15:39:01 -07:00
commit d75bb73bcf
10 changed files with 80 additions and 44 deletions

View File

@ -194,6 +194,27 @@ static inline const char *am_path(const struct am_state *state, const char *path
return mkpath("%s/%s", state->dir, path);
}
/**
* For convenience to call write_file()
*/
static int write_state_text(const struct am_state *state,
const char *name, const char *string)
{
return write_file(am_path(state, name), "%s", string);
}
static int write_state_count(const struct am_state *state,
const char *name, int value)
{
return write_file(am_path(state, name), "%d", value);
}
static int write_state_bool(const struct am_state *state,
const char *name, int value)
{
return write_state_text(state, name, value ? "t" : "f");
}
/**
* If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline
* at the end.
@ -363,7 +384,7 @@ static void write_author_script(const struct am_state *state)
sq_quote_buf(&sb, state->author_date);
strbuf_addch(&sb, '\n');
write_file(am_path(state, "author-script"), 1, "%s", sb.buf);
write_state_text(state, "author-script", sb.buf);
strbuf_release(&sb);
}
@ -1001,13 +1022,10 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
if (state->rebasing)
state->threeway = 1;
write_file(am_path(state, "threeway"), 1, state->threeway ? "t" : "f");
write_file(am_path(state, "quiet"), 1, state->quiet ? "t" : "f");
write_file(am_path(state, "sign"), 1, state->signoff ? "t" : "f");
write_file(am_path(state, "utf8"), 1, state->utf8 ? "t" : "f");
write_state_bool(state, "threeway", state->threeway);
write_state_bool(state, "quiet", state->quiet);
write_state_bool(state, "sign", state->signoff);
write_state_bool(state, "utf8", state->utf8);
switch (state->keep) {
case KEEP_FALSE:
@ -1023,9 +1041,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
die("BUG: invalid value for state->keep");
}
write_file(am_path(state, "keep"), 1, "%s", str);
write_file(am_path(state, "messageid"), 1, state->message_id ? "t" : "f");
write_state_text(state, "keep", str);
write_state_bool(state, "messageid", state->message_id);
switch (state->scissors) {
case SCISSORS_UNSET:
@ -1040,24 +1057,23 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
default:
die("BUG: invalid value for state->scissors");
}
write_file(am_path(state, "scissors"), 1, "%s", str);
write_state_text(state, "scissors", str);
sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
write_file(am_path(state, "apply-opt"), 1, "%s", sb.buf);
write_state_text(state, "apply-opt", sb.buf);
if (state->rebasing)
write_file(am_path(state, "rebasing"), 1, "%s", "");
write_state_text(state, "rebasing", "");
else
write_file(am_path(state, "applying"), 1, "%s", "");
write_state_text(state, "applying", "");
if (!get_sha1("HEAD", curr_head)) {
write_file(am_path(state, "abort-safety"), 1, "%s", sha1_to_hex(curr_head));
write_state_text(state, "abort-safety", sha1_to_hex(curr_head));
if (!state->rebasing)
update_ref("am", "ORIG_HEAD", curr_head, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
} else {
write_file(am_path(state, "abort-safety"), 1, "%s", "");
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
delete_ref("ORIG_HEAD", NULL, 0);
}
@ -1067,9 +1083,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
* session is in progress, they should be written last.
*/
write_file(am_path(state, "next"), 1, "%d", state->cur);
write_file(am_path(state, "last"), 1, "%d", state->last);
write_state_count(state, "next", state->cur);
write_state_count(state, "last", state->last);
strbuf_release(&sb);
}
@ -1102,12 +1117,12 @@ static void am_next(struct am_state *state)
unlink(am_path(state, "original-commit"));
if (!get_sha1("HEAD", head))
write_file(am_path(state, "abort-safety"), 1, "%s", sha1_to_hex(head));
write_state_text(state, "abort-safety", sha1_to_hex(head));
else
write_file(am_path(state, "abort-safety"), 1, "%s", "");
write_state_text(state, "abort-safety", "");
state->cur++;
write_file(am_path(state, "next"), 1, "%d", state->cur);
write_state_count(state, "next", state->cur);
}
/**
@ -1480,8 +1495,7 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
write_commit_patch(state, commit);
hashcpy(state->orig_commit, commit_sha1);
write_file(am_path(state, "original-commit"), 1, "%s",
sha1_to_hex(commit_sha1));
write_state_text(state, "original-commit", sha1_to_hex(commit_sha1));
return 0;
}
@ -1783,7 +1797,7 @@ static void am_run(struct am_state *state, int resume)
refresh_and_write_cache();
if (index_has_changes(&sb)) {
write_file(am_path(state, "dirtyindex"), 1, "t");
write_state_bool(state, "dirtyindex", 1);
die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf);
}

View File

@ -776,7 +776,7 @@ static int edit_branch_description(const char *branch_name)
" %s\n"
"Lines starting with '%c' will be stripped.\n",
branch_name, comment_line_char);
if (write_file(git_path(edit_description), 0, "%s", buf.buf)) {
if (write_file_gently(git_path(edit_description), "%s", buf.buf)) {
strbuf_release(&buf);
return error(_("could not write branch description template: %s"),
strerror(errno));

View File

@ -378,7 +378,7 @@ static void separate_git_dir(const char *git_dir)
die_errno(_("unable to move %s to %s"), src, git_dir);
}
write_file(git_link, 1, "gitdir: %s\n", git_dir);
write_file(git_link, "gitdir: %s", git_dir);
}
int init_db(const char *template_dir, unsigned int flags)

View File

@ -238,7 +238,7 @@ static int add_worktree(const char *path, const char *refname,
* after the preparation is over.
*/
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
write_file(sb.buf, 1, "initializing\n");
write_file(sb.buf, "initializing");
strbuf_addf(&sb_git, "%s/.git", path);
if (safe_create_leading_directories_const(sb_git.buf))
@ -248,8 +248,8 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
write_file(sb.buf, "%s", real_path(sb_git.buf));
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
real_path(get_git_common_dir()), name);
/*
* This is to keep resolve_ref() happy. We need a valid HEAD
@ -260,10 +260,10 @@ static int add_worktree(const char *path, const char *refname,
*/
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
write_file(sb.buf, 1, "0000000000000000000000000000000000000000\n");
write_file(sb.buf, "0000000000000000000000000000000000000000");
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, 1, "../..\n");
write_file(sb.buf, "../..");
fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name);

View File

@ -1577,8 +1577,9 @@ static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
}
__attribute__((format (printf, 3, 4)))
extern int write_file(const char *path, int fatal, const char *fmt, ...);
extern int write_file(const char *path, const char *fmt, ...);
extern int write_file_gently(const char *path, const char *fmt, ...);
/* pager.c */
extern void setup_pager(void);

View File

@ -1376,7 +1376,7 @@ int main(int argc, char **argv)
sanitize_stdfds();
if (pid_file)
write_file(pid_file, 1, "%"PRIuMAX"\n", (uintmax_t) getpid());
write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
/* prepare argv for serving-processes */
cld_argv = xmalloc(sizeof (char *) * (argc + 2));

View File

@ -404,7 +404,7 @@ static void update_linked_gitdir(const char *gitfile, const char *gitdir)
strbuf_addf(&path, "%s/gitfile", gitdir);
if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
write_file(path.buf, 0, "%s\n", gitfile);
write_file_gently(path.buf, "%s", gitfile);
strbuf_release(&path);
}

View File

@ -1033,7 +1033,7 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
/* Update gitfile */
strbuf_addf(&file_name, "%s/.git", work_tree);
write_file(file_name.buf, 1, "gitdir: %s\n",
write_file(file_name.buf, "gitdir: %s",
relative_path(git_dir, real_work_tree, &rel_path));
/* Update core.worktree setting */

View File

@ -291,7 +291,7 @@ static int write_one_ref(const char *name, const struct object_id *oid,
strbuf_addstr(buf, name);
if (safe_create_leading_directories(buf->buf) ||
write_file(buf->buf, 0, "%s\n", oid_to_hex(oid)))
write_file_gently(buf->buf, "%s", oid_to_hex(oid)))
return error("problems writing temporary file %s: %s",
buf->buf, strerror(errno));
strbuf_setlen(buf, len);

View File

@ -621,19 +621,18 @@ char *xgetcwd(void)
return strbuf_detach(&sb, NULL);
}
int write_file(const char *path, int fatal, const char *fmt, ...)
static int write_file_v(const char *path, int fatal,
const char *fmt, va_list params)
{
struct strbuf sb = STRBUF_INIT;
va_list params;
int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
if (fatal)
die_errno(_("could not open %s for writing"), path);
return -1;
}
va_start(params, fmt);
strbuf_vaddf(&sb, fmt, params);
va_end(params);
strbuf_complete_line(&sb);
if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
int err = errno;
close(fd);
@ -652,6 +651,28 @@ int write_file(const char *path, int fatal, const char *fmt, ...)
return 0;
}
int write_file(const char *path, const char *fmt, ...)
{
int status;
va_list params;
va_start(params, fmt);
status = write_file_v(path, 1, fmt, params);
va_end(params);
return status;
}
int write_file_gently(const char *path, const char *fmt, ...)
{
int status;
va_list params;
va_start(params, fmt);
status = write_file_v(path, 0, fmt, params);
va_end(params);
return status;
}
void sleep_millisec(int millisec)
{
poll(NULL, 0, millisec);