3 #include "run-command.h"
6 static const char usage_msg
[] =
7 "git remote-ext <remote> <url>";
11 * 'command [arg1 [arg2 [...]]]' Invoke command with given arguments.
13 * '% ': Literal space in argument.
14 * '%%': Literal percent sign.
15 * '%S': Name of service (git-upload-pack/git-upload-archive/
17 * '%s': Same as \s, but with possible git- prefix stripped.
18 * '%G': Only allowed as first 'character' of argument. Do not pass this
19 * Argument to command, instead send this as name of repository
20 * in in-line git://-style request (also activates sending this
22 * '%V': Only allowed as first 'character' of argument. Used in
23 * conjunction with '%G': Do not pass this argument to command,
24 * instead send this as vhost in git://-style request (note: does
25 * not activate sending git:// style request).
29 static char *git_req_vhost
;
31 static char *strip_escapes(const char *str
, const char *service
,
37 const char *service_noprefix
= service
;
38 struct strbuf ret
= STRBUF_INIT
;
40 skip_prefix(service_noprefix
, "git-", &service_noprefix
);
42 /* Pass the service to command. */
43 setenv("GIT_EXT_SERVICE", service
, 1);
44 setenv("GIT_EXT_SERVICE_NOPREFIX", service_noprefix
, 1);
46 /* Scan the length of argument. */
47 while (str
[rpos
] && (escape
|| str
[rpos
] != ' ')) {
60 /* Fall-through to error. */
62 die("Bad remote-ext placeholder '%%%c'.",
67 escape
= (str
[rpos
] == '%');
70 if (escape
&& !str
[rpos
])
71 die("remote-ext command has incomplete placeholder");
74 ++*next
; /* Skip over space */
77 * Do the actual placeholder substitution. The string will be short
78 * enough not to overflow integers.
80 rpos
= special
? 2 : 0; /* Skip first 2 bytes in specials. */
82 while (str
[rpos
] && (escape
|| str
[rpos
] != ' ')) {
87 strbuf_addch(&ret
, str
[rpos
]);
90 strbuf_addstr(&ret
, service_noprefix
);
93 strbuf_addstr(&ret
, service
);
103 strbuf_addch(&ret
, str
[rpos
]);
110 git_req
= strbuf_detach(&ret
, NULL
);
113 git_req_vhost
= strbuf_detach(&ret
, NULL
);
116 return strbuf_detach(&ret
, NULL
);
120 static void parse_argv(struct argv_array
*out
, const char *arg
, const char *service
)
123 char *expanded
= strip_escapes(arg
, service
, &arg
);
125 argv_array_push(out
, expanded
);
130 static void send_git_request(int stdin_fd
, const char *serv
, const char *repo
,
134 packet_write_fmt(stdin_fd
, "%s %s%c", serv
, repo
, 0);
136 packet_write_fmt(stdin_fd
, "%s %s%chost=%s%c", serv
, repo
, 0,
140 static int run_child(const char *arg
, const char *service
)
143 struct child_process child
= CHILD_PROCESS_INIT
;
148 parse_argv(&child
.args
, arg
, service
);
150 if (start_command(&child
) < 0)
151 die("Can't run specified command");
154 send_git_request(child
.in
, service
, git_req
, git_req_vhost
);
156 r
= bidirectional_transfer_loop(child
.out
, child
.in
);
158 r
= finish_command(&child
);
160 finish_command(&child
);
164 #define MAXCOMMAND 4096
166 static int command_loop(const char *child
)
168 char buffer
[MAXCOMMAND
];
172 if (!fgets(buffer
, MAXCOMMAND
- 1, stdin
)) {
174 die("Command input error");
177 /* Strip end of line characters. */
179 while (i
> 0 && isspace(buffer
[i
- 1]))
182 if (!strcmp(buffer
, "capabilities")) {
183 printf("*connect\n\n");
185 } else if (!strncmp(buffer
, "connect ", 8)) {
188 return run_child(child
, buffer
+ 8);
190 fprintf(stderr
, "Bad command");
196 int cmd_remote_ext(int argc
, const char **argv
, const char *prefix
)
201 return command_loop(argv
[2]);