From: "Shawn O. Pearce" <spearce@spearce.org>
To: Junio C Hamano <junkio@cox.net>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 4/4] Add 'filter' attribute and external filter driver definition.
Date: Sat, 21 Apr 2007 20:39:29 -0400 [thread overview]
Message-ID: <20070422003929.GD17480@spearce.org> (raw)
In-Reply-To: <11771520591703-git-send-email-junkio@cox.net>
Junio C Hamano <junkio@cox.net> wrote:
> The interface is similar to the custom low-level merge drivers.
...
> +static int filter_buffer(const char *path, const char *src,
> + unsigned long size, const char *cmd)
> +{
> + /*
> + * Spawn cmd and feed the buffer contents through its stdin.
> + */
...
ick. What about something like this on top? I moved the extra child
process for the input pipe down into the start_command routine,
where we can do something a little smarter on some systems, like
using a thread rather than a full process. Its also a shorter
patch and uses more of the run-command API.
Its not documented very well, but if you set child_process.{in,out}
to <0 we open the pipe for you, and close your side of the pipe
for you. That really simplifies the logic in the callers.
I did consider rewriting this as a select() based loop to feed the
input and read the output, but that might not port well onto a more
native Win32 based set of APIs.
---
diff --git a/convert.c b/convert.c
index 62d8cee..2ba7ea3 100644
--- a/convert.c
+++ b/convert.c
@@ -201,99 +201,37 @@ static char *crlf_to_worktree(const char *path, const char *src, unsigned long *
return buffer;
}
-static int filter_buffer(const char *path, const char *src,
- unsigned long size, const char *cmd)
-{
- /*
- * Spawn cmd and feed the buffer contents through its stdin.
- */
- struct child_process child_process;
- int pipe_feed[2];
- int write_err, status;
-
- memset(&child_process, 0, sizeof(child_process));
-
- if (pipe(pipe_feed) < 0) {
- error("cannot create pipe to run external filter %s", cmd);
- return 1;
- }
-
- child_process.pid = fork();
- if (child_process.pid < 0) {
- error("cannot fork to run external filter %s", cmd);
- close(pipe_feed[0]);
- close(pipe_feed[1]);
- return 1;
- }
- if (!child_process.pid) {
- dup2(pipe_feed[0], 0);
- close(pipe_feed[0]);
- close(pipe_feed[1]);
- execlp(cmd, cmd, NULL);
- return 1;
- }
- close(pipe_feed[0]);
-
- write_err = (write_in_full(pipe_feed[1], src, size) < 0);
- if (close(pipe_feed[1]))
- write_err = 1;
- if (write_err)
- error("cannot feed the input to external filter %s", cmd);
-
- status = finish_command(&child_process);
- if (status)
- error("external filter %s failed %d", cmd, -status);
- return (write_err || status);
-}
-
static char *apply_filter(const char *path, const char *src,
unsigned long *sizep, const char *cmd)
{
- /*
- * Create a pipeline to have the command filter the buffer's
- * contents.
- *
- * (child --> cmd) --> us
- */
const int SLOP = 4096;
- int pipe_feed[2];
+ struct child_process filter_process;
+ const char *filter_argv[] = {cmd, NULL};
int status;
char *dst;
unsigned long dstsize, dstalloc;
- struct child_process child_process;
if (!cmd)
return NULL;
- memset(&child_process, 0, sizeof(child_process));
-
- if (pipe(pipe_feed) < 0) {
- error("cannot create pipe to run external filter %s", cmd);
- return NULL;
- }
-
- child_process.pid = fork();
- if (child_process.pid < 0) {
- error("cannot fork to run external filter %s", cmd);
- close(pipe_feed[0]);
- close(pipe_feed[1]);
+ memset(&filter_process, 0, sizeof(filter_process));
+ filter_process.in_bufptr = src;
+ filter_process.in_buflen = *sizep;
+ filter_process.out = -1;
+ filter_process.argv = filter_argv;
+ status = start_command(&filter_process);
+ if (status) {
+ error("external filter %s failed %d", cmd, -status);
return NULL;
}
- if (!child_process.pid) {
- dup2(pipe_feed[1], 1);
- close(pipe_feed[0]);
- close(pipe_feed[1]);
- exit(filter_buffer(path, src, *sizep, cmd));
- }
- close(pipe_feed[1]);
dstalloc = *sizep;
dst = xmalloc(dstalloc);
dstsize = 0;
while (1) {
- ssize_t numread = xread(pipe_feed[0], dst + dstsize,
- dstalloc - dstsize);
+ ssize_t numread = xread(filter_process.out,
+ dst + dstsize, dstalloc - dstsize);
if (numread <= 0) {
if (!numread)
@@ -310,7 +248,7 @@ static char *apply_filter(const char *path, const char *src,
}
}
- status = finish_command(&child_process);
+ status = finish_command(&filter_process);
if (status) {
error("external filter %s failed %d", cmd, -status);
free(dst);
diff --git a/run-command.c b/run-command.c
index eff523e..72887f8 100644
--- a/run-command.c
+++ b/run-command.c
@@ -20,12 +20,29 @@ int start_command(struct child_process *cmd)
int need_in, need_out;
int fdin[2], fdout[2];
- need_in = !cmd->no_stdin && cmd->in < 0;
+ need_in = !cmd->no_stdin && (cmd->in_bufptr || cmd->in < 0);
if (need_in) {
if (pipe(fdin) < 0)
return -ERR_RUN_COMMAND_PIPE;
- cmd->in = fdin[1];
- cmd->close_in = 1;
+ if (cmd->in_bufptr) {
+ pid_t in_feeder = fork();
+ if (in_feeder < 0) {
+ close_pair(fdin);
+ return -ERR_RUN_COMMAND_PIPE;
+ }
+ if (!in_feeder) {
+ close(fdin[0]);
+ if (write_in_full(fdin[1],
+ cmd->in_bufptr,
+ cmd->in_buflen) != cmd->in_buflen)
+ die("'%s' did not read all input", cmd->argv[0]);
+ exit(0);
+ }
+ close(fdin[1]);
+ } else {
+ cmd->in = fdin[1];
+ cmd->close_in = 1;
+ }
}
need_out = !cmd->no_stdout
diff --git a/run-command.h b/run-command.h
index 3680ef9..7632843 100644
--- a/run-command.h
+++ b/run-command.h
@@ -13,6 +13,8 @@ enum {
struct child_process {
const char **argv;
+ const char *in_bufptr;
+ size_t in_buflen;
pid_t pid;
int in;
int out;
--
1.5.1.1.135.gf948
--
Shawn.
next prev parent reply other threads:[~2007-04-22 0:39 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-21 10:40 [PATCH 0/4] External 'filter' attributes and drivers Junio C Hamano
[not found] ` <11771520591703-gi t-send-email-junkio@cox.net>
2007-04-21 10:40 ` [PATCH 1/4] Simplify calling of CR/LF conversion routines Junio C Hamano
2007-04-21 10:40 ` [PATCH 2/4] convert.c: restructure the attribute checking part Junio C Hamano
2007-04-21 10:40 ` [PATCH 3/4] lockfile: record the primary process Junio C Hamano
2007-04-21 10:40 ` [PATCH 4/4] Add 'filter' attribute and external filter driver definition Junio C Hamano
2007-04-22 0:39 ` Shawn O. Pearce [this message]
2007-04-22 2:15 ` Junio C Hamano
2007-04-22 3:00 ` Shawn O. Pearce
2007-04-22 1:33 ` David Lang
2007-04-22 6:33 ` Junio C Hamano
2007-04-22 9:09 ` David Lang
2007-04-22 9:20 ` David Lang
2007-04-22 17:42 ` Junio C Hamano
2007-04-22 21:05 ` David Lang
2007-04-22 18:11 ` Nicolas Pitre
2007-04-22 20:27 ` [PATCH 4/4] Add 'filter' attribute and external filter driverdefinition David Lang
2007-04-22 5:47 ` [PATCH 4/4] Add 'filter' attribute and external filter driver definition Linus Torvalds
2007-04-22 6:12 ` Junio C Hamano
2007-04-21 20:03 ` [PATCH 0/4] External 'filter' attributes and drivers Alex Riesen
2007-04-22 1:19 ` David Lang
2007-04-22 5:20 ` Shawn O. Pearce
2007-04-22 9:01 ` David Lang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070422003929.GD17480@spearce.org \
--to=spearce@spearce.org \
--cc=git@vger.kernel.org \
--cc=junkio@cox.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.