Documentation/git-checkout: Update summary to reflect current abilities
[gitweb.git] / http-push.c
index af00ea10b96ffe6c2a29d69603d48093dd12e441..5b230380ccd33d8b04f8dfce24050237ae9206ad 100644 (file)
@@ -664,8 +664,7 @@ static void release_request(struct transfer_request *request)
                close(request->local_fileno);
        if (request->local_stream)
                fclose(request->local_stream);
-       if (request->url != NULL)
-               free(request->url);
+       free(request->url);
        free(request);
 }
 
@@ -1067,88 +1066,6 @@ static int fetch_indices(void)
        return 0;
 }
 
-static inline int needs_quote(int ch)
-{
-       if (((ch >= 'A') && (ch <= 'Z'))
-                       || ((ch >= 'a') && (ch <= 'z'))
-                       || ((ch >= '0') && (ch <= '9'))
-                       || (ch == '/')
-                       || (ch == '-')
-                       || (ch == '.'))
-               return 0;
-       return 1;
-}
-
-static inline int hex(int v)
-{
-       if (v < 10) return '0' + v;
-       else return 'A' + v - 10;
-}
-
-static char *quote_ref_url(const char *base, const char *ref)
-{
-       const char *cp;
-       char *dp, *qref;
-       int len, baselen, ch;
-
-       baselen = strlen(base);
-       len = baselen + 1;
-       for (cp = ref; (ch = *cp) != 0; cp++, len++)
-               if (needs_quote(ch))
-                       len += 2; /* extra two hex plus replacement % */
-       qref = xmalloc(len);
-       memcpy(qref, base, baselen);
-       for (cp = ref, dp = qref + baselen; (ch = *cp) != 0; cp++) {
-               if (needs_quote(ch)) {
-                       *dp++ = '%';
-                       *dp++ = hex((ch >> 4) & 0xF);
-                       *dp++ = hex(ch & 0xF);
-               }
-               else
-                       *dp++ = ch;
-       }
-       *dp = 0;
-
-       return qref;
-}
-
-int fetch_ref(char *ref, unsigned char *sha1)
-{
-       char *url;
-       struct strbuf buffer = STRBUF_INIT;
-       char *base = remote->url;
-       struct active_request_slot *slot;
-       struct slot_results results;
-       int ret;
-
-       url = quote_ref_url(base, ref);
-       slot = get_active_slot();
-       slot->results = &results;
-       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
-       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
-       if (start_active_slot(slot)) {
-               run_active_slot(slot);
-               if (results.curl_result == CURLE_OK) {
-                       strbuf_rtrim(&buffer);
-                       if (buffer.len == 40)
-                               ret = get_sha1_hex(buffer.buf, sha1);
-                       else
-                               ret = 1;
-               } else {
-                       ret = error("Couldn't get %s for %s\n%s",
-                                   url, ref, curl_errorstr);
-               }
-       } else {
-               ret = error("Unable to start request");
-       }
-
-       strbuf_release(&buffer);
-       free(url);
-       return ret;
-}
-
 static void one_remote_object(const char *hex)
 {
        unsigned char sha1[20];
@@ -1365,10 +1282,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        strbuf_release(&in_buffer);
 
        if (lock->token == NULL || lock->timeout <= 0) {
-               if (lock->token != NULL)
-                       free(lock->token);
-               if (lock->owner != NULL)
-                       free(lock->owner);
+               free(lock->token);
+               free(lock->owner);
                free(url);
                free(lock);
                lock = NULL;
@@ -1426,8 +1341,7 @@ static int unlock_remote(struct remote_lock *lock)
                        prev->next = prev->next->next;
        }
 
-       if (lock->owner != NULL)
-               free(lock->owner);
+       free(lock->owner);
        free(lock->url);
        free(lock->token);
        free(lock);
@@ -1645,9 +1559,17 @@ static int locking_available(void)
                                lock_flags = 0;
                        }
                        XML_ParserFree(parser);
+                       if (!lock_flags)
+                               error("Error: no DAV locking support on %s",
+                                     remote->url);
+
+               } else {
+                       error("Cannot access URL %s, return code %d",
+                             remote->url, results.curl_result);
+                       lock_flags = 0;
                }
        } else {
-               fprintf(stderr, "Unable to start PROPFIND request\n");
+               error("Unable to start PROPFIND request on %s", remote->url);
        }
 
        strbuf_release(&out_buffer.buf);
@@ -1708,12 +1630,19 @@ static struct object_list **process_tree(struct tree *tree,
 
        init_tree_desc(&desc, tree->buffer, tree->size);
 
-       while (tree_entry(&desc, &entry)) {
-               if (S_ISDIR(entry.mode))
+       while (tree_entry(&desc, &entry))
+               switch (object_type(entry.mode)) {
+               case OBJ_TREE:
                        p = process_tree(lookup_tree(entry.sha1), p, &me, name);
-               else
+                       break;
+               case OBJ_BLOB:
                        p = process_blob(lookup_blob(entry.sha1), p, &me, name);
-       }
+                       break;
+               default:
+                       /* Subproject commit - not in this repository */
+                       break;
+               }
+
        free(tree->buffer);
        tree->buffer = NULL;
        return p;
@@ -1834,7 +1763,8 @@ static void one_remote_ref(char *refname)
        struct object *obj;
        int len = strlen(refname) + 1;
 
-       if (fetch_ref(refname, remote_sha1) != 0) {
+       if (http_fetch_ref(remote->url, refname + 5 /* "refs/" */,
+                          remote_sha1) != 0) {
                fprintf(stderr,
                        "Unable to fetch ref %s from %s\n",
                        refname, remote->url);
@@ -1966,7 +1896,8 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
        int len;
        char *ref_info;
 
-       if (fetch_ref(ls->dentry_name, remote_sha1) != 0) {
+       if (http_fetch_ref(remote->url, ls->dentry_name + 5 /* "refs/" */,
+                          remote_sha1) != 0) {
                fprintf(stderr,
                        "Unable to fetch ref %s from %s\n",
                        ls->dentry_name, remote->url);
@@ -2059,7 +1990,6 @@ static int remote_exists(const char *path)
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               free(url);
                if (results.http_code == 404)
                        ret = 0;
                else if (results.curl_result == CURLE_OK)
@@ -2067,7 +1997,6 @@ static int remote_exists(const char *path)
                else
                        fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code);
        } else {
-               free(url);
                fprintf(stderr, "Unable to start HEAD request\n");
        }
 
@@ -2102,8 +2031,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        }
        free(url);
 
-       if (*symref != NULL)
-               free(*symref);
+       free(*symref);
        *symref = NULL;
        hashclr(sha1);
 
@@ -2205,6 +2133,8 @@ static int delete_remote_branch(char *pattern, int force)
 
        /* Send delete request */
        fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
+       if (dry_run)
+               return 0;
        url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1);
        sprintf(url, "%s%s", remote->url, remote_ref->name);
        slot = get_active_slot();
@@ -2243,6 +2173,7 @@ int main(int argc, char **argv)
        int i;
        int new_refs;
        struct ref *ref;
+       char *rewritten_url = NULL;
 
        setup_git_directory();
 
@@ -2294,6 +2225,10 @@ int main(int argc, char **argv)
                break;
        }
 
+#ifndef USE_CURL_MULTI
+       die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
+#endif
+
        if (!remote->url)
                usage(http_push_usage);
 
@@ -2302,13 +2237,20 @@ int main(int argc, char **argv)
 
        memset(remote_dir_exists, -1, 256);
 
-       http_init();
+       http_init(NULL);
 
        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
 
+       if (remote->url && remote->url[strlen(remote->url)-1] != '/') {
+               rewritten_url = malloc(strlen(remote->url)+2);
+               strcpy(rewritten_url, remote->url);
+               strcat(rewritten_url, "/");
+               remote->url = rewritten_url;
+               ++remote->path_len;
+       }
+
        /* Verify DAV compliance/lock support */
        if (!locking_available()) {
-               fprintf(stderr, "Error: no DAV locking support on remote repo %s\n", remote->url);
                rc = 1;
                goto cleanup;
        }
@@ -2321,6 +2263,11 @@ int main(int argc, char **argv)
                info_ref_lock = lock_remote("info/refs", LOCK_TIME);
                if (info_ref_lock)
                        remote->can_update_info_refs = 1;
+               else {
+                       fprintf(stderr, "Error: cannot lock existing info/refs\n");
+                       rc = 1;
+                       goto cleanup;
+               }
        }
        if (remote->has_info_packs)
                fetch_indices();
@@ -2342,11 +2289,14 @@ int main(int argc, char **argv)
        if (!remote_tail)
                remote_tail = &remote_refs;
        if (match_refs(local_refs, remote_refs, &remote_tail,
-                      nr_refspec, (const char **) refspec, push_all))
-               return -1;
+                      nr_refspec, (const char **) refspec, push_all)) {
+               rc = -1;
+               goto cleanup;
+       }
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
-               return 0;
+               rc = 0;
+               goto cleanup;
        }
 
        new_refs = 0;
@@ -2358,6 +2308,16 @@ int main(int argc, char **argv)
 
                if (!ref->peer_ref)
                        continue;
+
+               if (is_zero_sha1(ref->peer_ref->new_sha1)) {
+                       if (delete_remote_branch(ref->name, 1) == -1) {
+                               error("Could not remove %s", ref->name);
+                               rc = -4;
+                       }
+                       new_refs++;
+                       continue;
+               }
+
                if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
                        if (push_verbosely || 1)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
@@ -2389,11 +2349,6 @@ int main(int argc, char **argv)
                        }
                }
                hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
-               if (is_zero_sha1(ref->new_sha1)) {
-                       error("cannot happen anymore");
-                       rc = -3;
-                       continue;
-               }
                new_refs++;
                strcpy(old_hex, sha1_to_hex(ref->old_sha1));
                new_hex = sha1_to_hex(ref->new_sha1);
@@ -2437,7 +2392,8 @@ int main(int argc, char **argv)
 
                /* Generate a list of objects that need to be pushed */
                pushing = 0;
-               prepare_revision_walk(&revs);
+               if (prepare_revision_walk(&revs))
+                       die("revision walk setup failed");
                mark_edges_uninteresting(revs.commits);
                objects_to_send = get_delta(&revs, ref_lock);
                finish_all_active_slots();
@@ -2452,15 +2408,17 @@ int main(int argc, char **argv)
                fill_active_slots();
                add_fill_function(NULL, fill_active_slot);
 #endif
-               finish_all_active_slots();
+               do {
+                       finish_all_active_slots();
+#ifdef USE_CURL_MULTI
+                       fill_active_slots();
+#endif
+               } while (request_queue_head && !aborted);
 
                /* Update the remote branch if all went well */
-               if (aborted || !update_remote(ref->new_sha1, ref_lock)) {
+               if (aborted || !update_remote(ref->new_sha1, ref_lock))
                        rc = 1;
-                       goto unlock;
-               }
 
-       unlock:
                if (!rc)
                        fprintf(stderr, "    done\n");
                unlock_remote(ref_lock);
@@ -2477,10 +2435,11 @@ int main(int argc, char **argv)
                        fprintf(stderr, "Unable to update server info\n");
                }
        }
-       if (info_ref_lock)
-               unlock_remote(info_ref_lock);
 
  cleanup:
+       free(rewritten_url);
+       if (info_ref_lock)
+               unlock_remote(info_ref_lock);
        free(remote);
 
        curl_slist_free_all(no_pragma_header);