Skip to content

Commit

Permalink
Move WebDAV HTTP push under remote-curl
Browse files Browse the repository at this point in the history
The remote helper interface now supports the push capability,
which can be used to ask the implementation to push one or more
specs to the remote repository.  For remote-curl we implement this
by calling the existing WebDAV based git-http-push executable.

Internally the helper interface uses the push_refs transport hook
so that the complexity of the refspec parsing and matching can be
reused between remote implementations.  When possible however the
helper protocol uses source ref name rather than the source SHA-1,
thereby allowing the helper to access this name if it is useful.

>From Clemens Buchacher <drizzd@aon.at>:
 update http tests according to remote-curl capabilities

 o Pushing packed refs is now fixed.

 o The transport helper fails if refs are already up-to-date. Add
   a test for that.

 o The transport helper will notice if refs are already
   up-to-date. We therefore need to update server info in the
   unpacked-refs test.

 o The transport helper will purge deleted branches automatically.

 o Use a variable ($ORIG_HEAD) instead of full SHA-1 name.

Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
Signed-off-by: Clemens Buchacher <drizzd@aon.at>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: Daniel Barkalow <barkalow@iabervon.org>
CC: Mike Hommey <mh@glandium.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Shawn O. Pearce authored and Junio C Hamano committed Oct 31, 2009
1 parent ef08ef9 commit ae4efe1
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 54 deletions.
33 changes: 32 additions & 1 deletion Documentation/git-remote-helpers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Commands are given by the caller on the helper's standard input, one per line.
value of the ref. A space-separated list of attributes follows
the name; unrecognized attributes are ignored. After the
complete list, outputs a blank line.
+
If 'push' is supported this may be called as 'list for-push'
to obtain the current refs prior to sending one or more 'push'
commands to the helper.

'option' <name> <value>::
Set the transport helper option <name> to <value>. Outputs a
Expand All @@ -59,6 +63,22 @@ suitably updated.
+
Supported if the helper has the "fetch" capability.

'push' +<src>:<dst>::
Pushes the given <src> commit or branch locally to the
remote branch described by <dst>. A batch sequence of
one or more push commands is terminated with a blank line.
+
Zero or more protocol options may be entered after the last 'push'
command, before the batch's terminating blank line.
+
When the push is complete, outputs one or more 'ok <dst>' or
'error <dst> <why>?' lines to indicate success or failure of
each pushed ref. The status report output is terminated by
a blank line. The option field <why> may be quoted in a C
style string if it contains an LF.
+
Supported if the helper has the "push" capability.

If a fatal error occurs, the program writes the error message to
stderr and exits. The caller should expect that a suitable error
message has been printed if the child closes the connection without
Expand All @@ -76,10 +96,16 @@ CAPABILITIES
'option'::
This helper supports the option command.

'push'::
This helper supports the 'push' command.

REF LIST ATTRIBUTES
-------------------

None are defined yet, but the caller must accept any which are supplied.
'for-push'::
The caller wants to use the ref list to prepare push
commands. A helper might chose to acquire the ref list by
opening a different type of connection to the destination.

OPTIONS
-------
Expand All @@ -106,6 +132,11 @@ OPTIONS
ask for the tag specifically. Some helpers may be able to
use this option to avoid a second network connection.

'option dry-run' \{'true'|'false'\}:
If true, pretend the operation completed successfully,
but don't actually change any repository data. For most
helpers this only applies to the 'push', if supported.

Documentation
-------------
Documentation by Daniel Barkalow.
Expand Down
29 changes: 27 additions & 2 deletions http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static int push_verbosely;
static int push_all = MATCH_REFS_NONE;
static int force_all;
static int dry_run;
static int helper_status;

static struct object_list *objects;

Expand Down Expand Up @@ -1813,6 +1814,10 @@ int main(int argc, char **argv)
dry_run = 1;
continue;
}
if (!strcmp(arg, "--helper-status")) {
helper_status = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
push_verbosely = 1;
http_is_verbose = 1;
Expand Down Expand Up @@ -1911,9 +1916,12 @@ int main(int argc, char **argv)

/* Remove a remote branch if -d or -D was specified */
if (delete_branch) {
if (delete_remote_branch(refspec[0], force_delete) == -1)
if (delete_remote_branch(refspec[0], force_delete) == -1) {
fprintf(stderr, "Unable to delete remote branch %s\n",
refspec[0]);
if (helper_status)
printf("error %s cannot remove\n", refspec[0]);
}
goto cleanup;
}

Expand All @@ -1925,6 +1933,8 @@ int main(int argc, char **argv)
}
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
if (helper_status)
printf("error null no match\n");
rc = 0;
goto cleanup;
}
Expand All @@ -1942,15 +1952,21 @@ int main(int argc, char **argv)
if (is_null_sha1(ref->peer_ref->new_sha1)) {
if (delete_remote_branch(ref->name, 1) == -1) {
error("Could not remove %s", ref->name);
if (helper_status)
printf("error %s cannot remove\n", ref->name);
rc = -4;
}
else if (helper_status)
printf("ok %s\n", ref->name);
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);
if (helper_status)
printf("ok %s up to date\n", ref->name);
continue;
}

Expand All @@ -1974,6 +1990,8 @@ int main(int argc, char **argv)
"need to pull first?",
ref->name,
ref->peer_ref->name);
if (helper_status)
printf("error %s non-fast forward\n", ref->name);
rc = -2;
continue;
}
Expand All @@ -1987,14 +2005,19 @@ int main(int argc, char **argv)
if (strcmp(ref->name, ref->peer_ref->name))
fprintf(stderr, " using '%s'", ref->peer_ref->name);
fprintf(stderr, "\n from %s\n to %s\n", old_hex, new_hex);
if (dry_run)
if (dry_run) {
if (helper_status)
printf("ok %s\n", ref->name);
continue;
}

/* Lock remote branch ref */
ref_lock = lock_remote(ref->name, LOCK_TIME);
if (ref_lock == NULL) {
fprintf(stderr, "Unable to lock remote branch %s\n",
ref->name);
if (helper_status)
printf("error %s lock error\n", ref->name);
rc = 1;
continue;
}
Expand Down Expand Up @@ -2045,6 +2068,8 @@ int main(int argc, char **argv)

if (!rc)
fprintf(stderr, " done\n");
if (helper_status)
printf("%s %s\n", !rc ? "ok" : "error", ref->name);
unlock_remote(ref_lock);
check_locks();
}
Expand Down
97 changes: 85 additions & 12 deletions remote-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "walker.h"
#include "http.h"
#include "exec_cmd.h"
#include "run-command.h"

static struct remote *remote;
static const char *url;
Expand All @@ -13,7 +14,8 @@ struct options {
int verbosity;
unsigned long depth;
unsigned progress : 1,
followtags : 1;
followtags : 1,
dry_run : 1;
};
static struct options options;

Expand Down Expand Up @@ -59,6 +61,15 @@ static int set_option(const char *name, const char *value)
return -1;
return 1 /* TODO implement later */;
}
else if (!strcmp(name, "dry-run")) {
if (!strcmp(value, "true"))
options.dry_run = 1;
else if (!strcmp(value, "false"))
options.dry_run = 0;
else
return -1;
return 0;
}
else {
return 1 /* unsupported */;
}
Expand Down Expand Up @@ -136,6 +147,20 @@ static struct ref *get_refs(void)
return refs;
}

static void output_refs(struct ref *refs)
{
struct ref *posn;
for (posn = refs; posn; posn = posn->next) {
if (posn->symref)
printf("@%s %s\n", posn->symref, posn->name);
else
printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
}
printf("\n");
fflush(stdout);
free_refs(refs);
}

static int fetch_dumb(int nr_heads, struct ref **to_fetch)
{
char **targets = xmalloc(nr_heads * sizeof(char*));
Expand Down Expand Up @@ -211,6 +236,58 @@ static void parse_fetch(struct strbuf *buf)
strbuf_reset(buf);
}

static int push_dav(int nr_spec, char **specs)
{
const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
int argc = 0, i;

argv[argc++] = "http-push";
argv[argc++] = "--helper-status";
if (options.dry_run)
argv[argc++] = "--dry-run";
if (options.verbosity > 1)
argv[argc++] = "--verbose";
argv[argc++] = url;
for (i = 0; i < nr_spec; i++)
argv[argc++] = specs[i];
argv[argc++] = NULL;

if (run_command_v_opt(argv, RUN_GIT_CMD))
die("git-%s failed", argv[0]);
free(argv);
return 0;
}

static void parse_push(struct strbuf *buf)
{
char **specs = NULL;
int alloc_spec = 0, nr_spec = 0, i;

do {
if (!prefixcmp(buf->buf, "push ")) {
ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
specs[nr_spec++] = xstrdup(buf->buf + 5);
}
else
die("http transport does not support %s", buf->buf);

strbuf_reset(buf);
if (strbuf_getline(buf, stdin, '\n') == EOF)
return;
if (!*buf->buf)
break;
} while (1);

if (push_dav(nr_spec, specs))
exit(128); /* error already reported */
for (i = 0; i < nr_spec; i++)
free(specs[i]);
free(specs);

printf("\n");
fflush(stdout);
}

int main(int argc, const char **argv)
{
struct strbuf buf = STRBUF_INIT;
Expand Down Expand Up @@ -239,17 +316,12 @@ int main(int argc, const char **argv)
if (!prefixcmp(buf.buf, "fetch ")) {
parse_fetch(&buf);

} else if (!strcmp(buf.buf, "list")) {
struct ref *refs = get_refs();
struct ref *posn;
for (posn = refs; posn; posn = posn->next) {
if (posn->symref)
printf("@%s %s\n", posn->symref, posn->name);
else
printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
}
printf("\n");
fflush(stdout);
} else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) {
output_refs(get_refs());

} else if (!prefixcmp(buf.buf, "push ")) {
parse_push(&buf);

} else if (!prefixcmp(buf.buf, "option ")) {
char *name = buf.buf + strlen("option ");
char *value = strchr(name, ' ');
Expand All @@ -272,6 +344,7 @@ int main(int argc, const char **argv)
} else if (!strcmp(buf.buf, "capabilities")) {
printf("fetch\n");
printf("option\n");
printf("push\n");
printf("\n");
fflush(stdout);
} else {
Expand Down
14 changes: 9 additions & 5 deletions t/t5540-http-push.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ test_expect_success 'setup remote repository' '
cd test_repo.git &&
git --bare update-server-info &&
mv hooks/post-update.sample hooks/post-update &&
ORIG_HEAD=$(git rev-parse --verify HEAD) &&
cd - &&
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
'
Expand All @@ -45,7 +46,7 @@ test_expect_success 'clone remote repository' '
git clone $HTTPD_URL/test_repo.git test_repo_clone
'

test_expect_failure 'push to remote repository with packed refs' '
test_expect_success 'push to remote repository with packed refs' '
cd "$ROOT_PATH"/test_repo_clone &&
: >path2 &&
git add path2 &&
Expand All @@ -57,11 +58,15 @@ test_expect_failure 'push to remote repository with packed refs' '
test $HEAD = $(git rev-parse --verify HEAD))
'

test_expect_success ' push to remote repository with unpacked refs' '
test_expect_failure 'push already up-to-date' '
git push
'

test_expect_success 'push to remote repository with unpacked refs' '
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
rm packed-refs &&
git update-ref refs/heads/master \
0c973ae9bd51902a28466f3850b543fa66a6aaf4) &&
git update-ref refs/heads/master $ORIG_HEAD &&
git --bare update-server-info) &&
git push &&
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
test $HEAD = $(git rev-parse --verify HEAD))
Expand Down Expand Up @@ -113,7 +118,6 @@ test_expect_success 'create and delete remote branch' '
git push origin dev &&
git fetch &&
git push origin :dev &&
git branch -d -r origin/dev &&
git fetch &&
test_must_fail git show-ref --verify refs/remotes/origin/dev
'
Expand Down
Loading

0 comments on commit ae4efe1

Please sign in to comment.