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] != ' ')) {
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 strvec *out, const char *arg, const char *service)
123
char *expanded = strip_escapes(arg, service, &arg);
125
strvec_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];
174
if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
176
die("Command input error");
179
/* Strip end of line characters. */
181
while (i > 0 && isspace(buffer[i - 1]))
184
if (!strcmp(buffer, "capabilities")) {
185
printf("*connect\n\n");
187
} else if (skip_prefix(buffer, "connect ", &arg)) {
190
return run_child(child, arg);
192
fprintf(stderr, "Bad command");
198
int cmd_remote_ext(int argc, const char **argv, const char *prefix)
200
BUG_ON_NON_EMPTY_PREFIX(prefix);
205
return command_loop(argv[2]);