4 * Based on git-am.sh by Junio C Hamano.
9 #include "parse-options.h"
13 /* state directory path */
16 /* current and last patch numbers, 1-indexed */
22 * Initializes am_state with the default values. The state directory is set to
25 static void am_state_init(struct am_state
*state
, const char *dir
)
27 memset(state
, 0, sizeof(*state
));
30 state
->dir
= xstrdup(dir
);
34 * Releases memory allocated by an am_state.
36 static void am_state_release(struct am_state
*state
)
42 * Returns path relative to the am_state directory.
44 static inline const char *am_path(const struct am_state
*state
, const char *path
)
46 return mkpath("%s/%s", state
->dir
, path
);
50 * Returns 1 if there is an am session in progress, 0 otherwise.
52 static int am_in_progress(const struct am_state
*state
)
56 if (lstat(state
->dir
, &st
) < 0 || !S_ISDIR(st
.st_mode
))
58 if (lstat(am_path(state
, "last"), &st
) || !S_ISREG(st
.st_mode
))
60 if (lstat(am_path(state
, "next"), &st
) || !S_ISREG(st
.st_mode
))
66 * Reads the contents of `file` in the `state` directory into `sb`. Returns the
67 * number of bytes read on success, -1 if the file does not exist. If `trim` is
68 * set, trailing whitespace will be removed.
70 static int read_state_file(struct strbuf
*sb
, const struct am_state
*state
,
71 const char *file
, int trim
)
75 if (strbuf_read_file(sb
, am_path(state
, file
), 0) >= 0) {
85 die_errno(_("could not read '%s'"), am_path(state
, file
));
89 * Loads state from disk.
91 static void am_load(struct am_state
*state
)
93 struct strbuf sb
= STRBUF_INIT
;
95 if (read_state_file(&sb
, state
, "next", 1) < 0)
96 die("BUG: state file 'next' does not exist");
97 state
->cur
= strtol(sb
.buf
, NULL
, 10);
99 if (read_state_file(&sb
, state
, "last", 1) < 0)
100 die("BUG: state file 'last' does not exist");
101 state
->last
= strtol(sb
.buf
, NULL
, 10);
107 * Removes the am_state directory, forcefully terminating the current am
110 static void am_destroy(const struct am_state
*state
)
112 struct strbuf sb
= STRBUF_INIT
;
114 strbuf_addstr(&sb
, state
->dir
);
115 remove_dir_recursively(&sb
, 0);
120 * Setup a new am session for applying patches
122 static void am_setup(struct am_state
*state
)
124 if (mkdir(state
->dir
, 0777) < 0 && errno
!= EEXIST
)
125 die_errno(_("failed to create directory '%s'"), state
->dir
);
128 * NOTE: Since the "next" and "last" files determine if an am_state
129 * session is in progress, they should be written last.
132 write_file(am_path(state
, "next"), 1, "%d", state
->cur
);
134 write_file(am_path(state
, "last"), 1, "%d", state
->last
);
138 * Increments the patch pointer, and cleans am_state for the application of the
141 static void am_next(struct am_state
*state
)
144 write_file(am_path(state
, "next"), 1, "%d", state
->cur
);
148 * Applies all queued mail.
150 static void am_run(struct am_state
*state
)
152 while (state
->cur
<= state
->last
) {
154 /* NEEDSWORK: Patch application not implemented yet */
162 int cmd_am(int argc
, const char **argv
, const char *prefix
)
164 struct am_state state
;
166 const char * const usage
[] = {
167 N_("git am [options] [(<mbox>|<Maildir>)...]"),
171 struct option options
[] = {
176 * NEEDSWORK: Once all the features of git-am.sh have been
177 * re-implemented in builtin/am.c, this preamble can be removed.
179 if (!getenv("_GIT_USE_BUILTIN_AM")) {
180 const char *path
= mkpath("%s/git-am", git_exec_path());
182 if (sane_execvp(path
, (char **)argv
) < 0)
183 die_errno("could not exec %s", path
);
185 prefix
= setup_git_directory();
186 trace_repo_setup(prefix
);
190 git_config(git_default_config
, NULL
);
192 am_state_init(&state
, git_path("rebase-apply"));
194 argc
= parse_options(argc
, argv
, prefix
, options
, usage
, 0);
196 if (am_in_progress(&state
))
203 am_state_release(&state
);