Merge branch 'ss/pull-rebase-preserve' into maint
[gitweb.git] / remote-curl.c
index 13c639c632eb96ed559aee97239b387eccc5f9e3..696a5ecf05d116bb24847079b5741fffe905a2f3 100644 (file)
@@ -25,7 +25,8 @@ struct options {
                update_shallow : 1,
                followtags : 1,
                dry_run : 1,
-               thin : 1;
+               thin : 1,
+               push_cert : 1;
 };
 static struct options options;
 static struct string_list cas_options = STRING_LIST_INIT_DUP;
@@ -106,6 +107,14 @@ static int set_option(const char *name, const char *value)
                else
                        return -1;
                return 0;
+       } else if (!strcmp(name, "pushcert")) {
+               if (!strcmp(value, "true"))
+                       options.push_cert = 1;
+               else if (!strcmp(value, "false"))
+                       options.push_cert = 0;
+               else
+                       return -1;
+               return 0;
        } else {
                return 1 /* unsupported */;
        }
@@ -194,19 +203,19 @@ static void free_discovery(struct discovery *d)
        }
 }
 
-static int show_http_message(struct strbuf *type, struct strbuf *msg)
+static int show_http_message(struct strbuf *type, struct strbuf *charset,
+                            struct strbuf *msg)
 {
        const char *p, *eol;
 
        /*
         * We only show text/plain parts, as other types are likely
         * to be ugly to look at on the user's terminal.
-        *
-        * TODO should handle "; charset=XXX", and re-encode into
-        * logoutputencoding
         */
-       if (strcasecmp(type->buf, "text/plain"))
+       if (strcmp(type->buf, "text/plain"))
                return -1;
+       if (charset->len)
+               strbuf_reencode(msg, charset->buf, get_log_output_encoding());
 
        strbuf_trim(msg);
        if (!msg->len)
@@ -221,10 +230,11 @@ static int show_http_message(struct strbuf *type, struct strbuf *msg)
        return 0;
 }
 
-static struct discoverydiscover_refs(const char *service, int for_push)
+static struct discovery *discover_refs(const char *service, int for_push)
 {
        struct strbuf exp = STRBUF_INIT;
        struct strbuf type = STRBUF_INIT;
+       struct strbuf charset = STRBUF_INIT;
        struct strbuf buffer = STRBUF_INIT;
        struct strbuf refs_url = STRBUF_INIT;
        struct strbuf effective_url = STRBUF_INIT;
@@ -249,6 +259,7 @@ static struct discovery* discover_refs(const char *service, int for_push)
 
        memset(&options, 0, sizeof(options));
        options.content_type = &type;
+       options.charset = &charset;
        options.effective_url = &effective_url;
        options.base_url = &url;
        options.no_cache = 1;
@@ -259,13 +270,13 @@ static struct discovery* discover_refs(const char *service, int for_push)
        case HTTP_OK:
                break;
        case HTTP_MISSING_TARGET:
-               show_http_message(&type, &buffer);
+               show_http_message(&type, &charset, &buffer);
                die("repository '%s' not found", url.buf);
        case HTTP_NOAUTH:
-               show_http_message(&type, &buffer);
+               show_http_message(&type, &charset, &buffer);
                die("Authentication failed for '%s'", url.buf);
        default:
-               show_http_message(&type, &buffer);
+               show_http_message(&type, &charset, &buffer);
                die("unable to access '%s': %s", url.buf, curl_errorstr);
        }
 
@@ -310,6 +321,7 @@ static struct discovery* discover_refs(const char *service, int for_push)
        strbuf_release(&refs_url);
        strbuf_release(&exp);
        strbuf_release(&type);
+       strbuf_release(&charset);
        strbuf_release(&effective_url);
        strbuf_release(&buffer);
        last_discovery = last;
@@ -396,7 +408,7 @@ static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
                        rpc->pos = 0;
                        return CURLIOE_OK;
                }
-               fprintf(stderr, "Unable to rewind rpc post data - try increasing http.postBuffer\n");
+               error("unable to rewind rpc post data - try increasing http.postBuffer");
                return CURLIOE_FAILRESTART;
 
        default:
@@ -619,10 +631,9 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
        const char *svc = rpc->service_name;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf *preamble = rpc->stdin_preamble;
-       struct child_process client;
+       struct child_process client = CHILD_PROCESS_INIT;
        int err = 0;
 
-       memset(&client, 0, sizeof(client));
        client.in = -1;
        client.out = -1;
        client.git_cmd = 1;
@@ -705,7 +716,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
                free(targets[i]);
        free(targets);
 
-       return ret ? error("Fetch failed.") : 0;
+       return ret ? error("fetch failed.") : 0;
 }
 
 static int fetch_git(struct discovery *heads,
@@ -748,7 +759,7 @@ static int fetch_git(struct discovery *heads,
 
        for (i = 0; i < nr_heads; i++) {
                struct ref *ref = to_fetch[i];
-               if (!ref->name || !*ref->name)
+               if (!*ref->name)
                        die("cannot fetch by sha1 over smart http");
                packet_buf_write(&preamble, "%s %s\n",
                                 sha1_to_hex(ref->old_sha1), ref->name);
@@ -787,9 +798,9 @@ static void parse_fetch(struct strbuf *buf)
        int alloc_heads = 0, nr_heads = 0;
 
        do {
-               if (starts_with(buf->buf, "fetch ")) {
-                       char *p = buf->buf + strlen("fetch ");
-                       char *name;
+               const char *p;
+               if (skip_prefix(buf->buf, "fetch ", &p)) {
+                       const char *name;
                        struct ref *ref;
                        unsigned char old_sha1[20];
 
@@ -859,6 +870,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
        int i, err;
        struct argv_array args;
        struct string_list_item *cas_option;
+       struct strbuf preamble = STRBUF_INIT;
 
        argv_array_init(&args);
        argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
@@ -868,6 +880,8 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
                argv_array_push(&args, "--thin");
        if (options.dry_run)
                argv_array_push(&args, "--dry-run");
+       if (options.push_cert)
+               argv_array_push(&args, "--signed");
        if (options.verbosity == 0)
                argv_array_push(&args, "--quiet");
        else if (options.verbosity > 1)
@@ -876,17 +890,22 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
        for_each_string_list_item(cas_option, &cas_options)
                argv_array_push(&args, cas_option->string);
        argv_array_push(&args, url.buf);
+
+       argv_array_push(&args, "--stdin");
        for (i = 0; i < nr_spec; i++)
-               argv_array_push(&args, specs[i]);
+               packet_buf_write(&preamble, "%s\n", specs[i]);
+       packet_buf_flush(&preamble);
 
        memset(&rpc, 0, sizeof(rpc));
        rpc.service_name = "git-receive-pack",
        rpc.argv = args.argv;
+       rpc.stdin_preamble = &preamble;
 
        err = rpc_service(&rpc, heads);
        if (rpc.result.len)
                write_or_die(1, rpc.result.buf, rpc.result.len);
        strbuf_release(&rpc.result);
+       strbuf_release(&preamble);
        argv_array_clear(&args);
        return err;
 }
@@ -945,7 +964,7 @@ int main(int argc, const char **argv)
        git_extract_argv0_path(argv[0]);
        setup_git_directory_gently(&nongit);
        if (argc < 2) {
-               fprintf(stderr, "Remote needed\n");
+               error("remote-curl: usage: git remote-curl <remote> [<url>]");
                return 1;
        }
 
@@ -964,18 +983,18 @@ int main(int argc, const char **argv)
        http_init(remote, url.buf, 0);
 
        do {
+               const char *arg;
+
                if (strbuf_getline(&buf, stdin, '\n') == EOF) {
                        if (ferror(stdin))
-                               fprintf(stderr, "Error reading command stream\n");
-                       else
-                               fprintf(stderr, "Unexpected end of command stream\n");
+                               error("remote-curl: error reading command stream from git");
                        return 1;
                }
                if (buf.len == 0)
                        break;
                if (starts_with(buf.buf, "fetch ")) {
                        if (nongit)
-                               die("Fetch attempted without a local repo");
+                               die("remote-curl: fetch attempted without a local repo");
                        parse_fetch(&buf);
 
                } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) {
@@ -985,9 +1004,8 @@ int main(int argc, const char **argv)
                } else if (starts_with(buf.buf, "push ")) {
                        parse_push(&buf);
 
-               } else if (starts_with(buf.buf, "option ")) {
-                       char *name = buf.buf + strlen("option ");
-                       char *value = strchr(name, ' ');
+               } else if (skip_prefix(buf.buf, "option ", &arg)) {
+                       char *value = strchr(arg, ' ');
                        int result;
 
                        if (value)
@@ -995,7 +1013,7 @@ int main(int argc, const char **argv)
                        else
                                value = "true";
 
-                       result = set_option(name, value);
+                       result = set_option(arg, value);
                        if (!result)
                                printf("ok\n");
                        else if (result < 0)
@@ -1012,7 +1030,7 @@ int main(int argc, const char **argv)
                        printf("\n");
                        fflush(stdout);
                } else {
-                       fprintf(stderr, "Unknown command '%s'\n", buf.buf);
+                       error("remote-curl: unknown command '%s' from git", buf.buf);
                        return 1;
                }
                strbuf_reset(&buf);