Skip to content

Commit ae4efe1

Browse files
spearcegitster
authored andcommitted
Move WebDAV HTTP push under remote-curl
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 <[email protected]>: 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 <[email protected]> Signed-off-by: Clemens Buchacher <[email protected]> Signed-off-by: Shawn O. Pearce <[email protected]> CC: Daniel Barkalow <[email protected]> CC: Mike Hommey <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ef08ef9 commit ae4efe1

File tree

6 files changed

+287
-54
lines changed

6 files changed

+287
-54
lines changed

Documentation/git-remote-helpers.txt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Commands are given by the caller on the helper's standard input, one per line.
3434
value of the ref. A space-separated list of attributes follows
3535
the name; unrecognized attributes are ignored. After the
3636
complete list, outputs a blank line.
37+
+
38+
If 'push' is supported this may be called as 'list for-push'
39+
to obtain the current refs prior to sending one or more 'push'
40+
commands to the helper.
3741

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

66+
'push' +<src>:<dst>::
67+
Pushes the given <src> commit or branch locally to the
68+
remote branch described by <dst>. A batch sequence of
69+
one or more push commands is terminated with a blank line.
70+
+
71+
Zero or more protocol options may be entered after the last 'push'
72+
command, before the batch's terminating blank line.
73+
+
74+
When the push is complete, outputs one or more 'ok <dst>' or
75+
'error <dst> <why>?' lines to indicate success or failure of
76+
each pushed ref. The status report output is terminated by
77+
a blank line. The option field <why> may be quoted in a C
78+
style string if it contains an LF.
79+
+
80+
Supported if the helper has the "push" capability.
81+
6282
If a fatal error occurs, the program writes the error message to
6383
stderr and exits. The caller should expect that a suitable error
6484
message has been printed if the child closes the connection without
@@ -76,10 +96,16 @@ CAPABILITIES
7696
'option'::
7797
This helper supports the option command.
7898

99+
'push'::
100+
This helper supports the 'push' command.
101+
79102
REF LIST ATTRIBUTES
80103
-------------------
81104

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

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

135+
'option dry-run' \{'true'|'false'\}:
136+
If true, pretend the operation completed successfully,
137+
but don't actually change any repository data. For most
138+
helpers this only applies to the 'push', if supported.
139+
109140
Documentation
110141
-------------
111142
Documentation by Daniel Barkalow.

http-push.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static int push_verbosely;
7878
static int push_all = MATCH_REFS_NONE;
7979
static int force_all;
8080
static int dry_run;
81+
static int helper_status;
8182

8283
static struct object_list *objects;
8384

@@ -1813,6 +1814,10 @@ int main(int argc, char **argv)
18131814
dry_run = 1;
18141815
continue;
18151816
}
1817+
if (!strcmp(arg, "--helper-status")) {
1818+
helper_status = 1;
1819+
continue;
1820+
}
18161821
if (!strcmp(arg, "--verbose")) {
18171822
push_verbosely = 1;
18181823
http_is_verbose = 1;
@@ -1911,9 +1916,12 @@ int main(int argc, char **argv)
19111916

19121917
/* Remove a remote branch if -d or -D was specified */
19131918
if (delete_branch) {
1914-
if (delete_remote_branch(refspec[0], force_delete) == -1)
1919+
if (delete_remote_branch(refspec[0], force_delete) == -1) {
19151920
fprintf(stderr, "Unable to delete remote branch %s\n",
19161921
refspec[0]);
1922+
if (helper_status)
1923+
printf("error %s cannot remove\n", refspec[0]);
1924+
}
19171925
goto cleanup;
19181926
}
19191927

@@ -1925,6 +1933,8 @@ int main(int argc, char **argv)
19251933
}
19261934
if (!remote_refs) {
19271935
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
1936+
if (helper_status)
1937+
printf("error null no match\n");
19281938
rc = 0;
19291939
goto cleanup;
19301940
}
@@ -1942,15 +1952,21 @@ int main(int argc, char **argv)
19421952
if (is_null_sha1(ref->peer_ref->new_sha1)) {
19431953
if (delete_remote_branch(ref->name, 1) == -1) {
19441954
error("Could not remove %s", ref->name);
1955+
if (helper_status)
1956+
printf("error %s cannot remove\n", ref->name);
19451957
rc = -4;
19461958
}
1959+
else if (helper_status)
1960+
printf("ok %s\n", ref->name);
19471961
new_refs++;
19481962
continue;
19491963
}
19501964

19511965
if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
19521966
if (push_verbosely || 1)
19531967
fprintf(stderr, "'%s': up-to-date\n", ref->name);
1968+
if (helper_status)
1969+
printf("ok %s up to date\n", ref->name);
19541970
continue;
19551971
}
19561972

@@ -1974,6 +1990,8 @@ int main(int argc, char **argv)
19741990
"need to pull first?",
19751991
ref->name,
19761992
ref->peer_ref->name);
1993+
if (helper_status)
1994+
printf("error %s non-fast forward\n", ref->name);
19771995
rc = -2;
19781996
continue;
19791997
}
@@ -1987,14 +2005,19 @@ int main(int argc, char **argv)
19872005
if (strcmp(ref->name, ref->peer_ref->name))
19882006
fprintf(stderr, " using '%s'", ref->peer_ref->name);
19892007
fprintf(stderr, "\n from %s\n to %s\n", old_hex, new_hex);
1990-
if (dry_run)
2008+
if (dry_run) {
2009+
if (helper_status)
2010+
printf("ok %s\n", ref->name);
19912011
continue;
2012+
}
19922013

19932014
/* Lock remote branch ref */
19942015
ref_lock = lock_remote(ref->name, LOCK_TIME);
19952016
if (ref_lock == NULL) {
19962017
fprintf(stderr, "Unable to lock remote branch %s\n",
19972018
ref->name);
2019+
if (helper_status)
2020+
printf("error %s lock error\n", ref->name);
19982021
rc = 1;
19992022
continue;
20002023
}
@@ -2045,6 +2068,8 @@ int main(int argc, char **argv)
20452068

20462069
if (!rc)
20472070
fprintf(stderr, " done\n");
2071+
if (helper_status)
2072+
printf("%s %s\n", !rc ? "ok" : "error", ref->name);
20482073
unlock_remote(ref_lock);
20492074
check_locks();
20502075
}

remote-curl.c

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "walker.h"
55
#include "http.h"
66
#include "exec_cmd.h"
7+
#include "run-command.h"
78

89
static struct remote *remote;
910
static const char *url;
@@ -13,7 +14,8 @@ struct options {
1314
int verbosity;
1415
unsigned long depth;
1516
unsigned progress : 1,
16-
followtags : 1;
17+
followtags : 1,
18+
dry_run : 1;
1719
};
1820
static struct options options;
1921

@@ -59,6 +61,15 @@ static int set_option(const char *name, const char *value)
5961
return -1;
6062
return 1 /* TODO implement later */;
6163
}
64+
else if (!strcmp(name, "dry-run")) {
65+
if (!strcmp(value, "true"))
66+
options.dry_run = 1;
67+
else if (!strcmp(value, "false"))
68+
options.dry_run = 0;
69+
else
70+
return -1;
71+
return 0;
72+
}
6273
else {
6374
return 1 /* unsupported */;
6475
}
@@ -136,6 +147,20 @@ static struct ref *get_refs(void)
136147
return refs;
137148
}
138149

150+
static void output_refs(struct ref *refs)
151+
{
152+
struct ref *posn;
153+
for (posn = refs; posn; posn = posn->next) {
154+
if (posn->symref)
155+
printf("@%s %s\n", posn->symref, posn->name);
156+
else
157+
printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
158+
}
159+
printf("\n");
160+
fflush(stdout);
161+
free_refs(refs);
162+
}
163+
139164
static int fetch_dumb(int nr_heads, struct ref **to_fetch)
140165
{
141166
char **targets = xmalloc(nr_heads * sizeof(char*));
@@ -211,6 +236,58 @@ static void parse_fetch(struct strbuf *buf)
211236
strbuf_reset(buf);
212237
}
213238

239+
static int push_dav(int nr_spec, char **specs)
240+
{
241+
const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
242+
int argc = 0, i;
243+
244+
argv[argc++] = "http-push";
245+
argv[argc++] = "--helper-status";
246+
if (options.dry_run)
247+
argv[argc++] = "--dry-run";
248+
if (options.verbosity > 1)
249+
argv[argc++] = "--verbose";
250+
argv[argc++] = url;
251+
for (i = 0; i < nr_spec; i++)
252+
argv[argc++] = specs[i];
253+
argv[argc++] = NULL;
254+
255+
if (run_command_v_opt(argv, RUN_GIT_CMD))
256+
die("git-%s failed", argv[0]);
257+
free(argv);
258+
return 0;
259+
}
260+
261+
static void parse_push(struct strbuf *buf)
262+
{
263+
char **specs = NULL;
264+
int alloc_spec = 0, nr_spec = 0, i;
265+
266+
do {
267+
if (!prefixcmp(buf->buf, "push ")) {
268+
ALLOC_GROW(specs, nr_spec + 1, alloc_spec);
269+
specs[nr_spec++] = xstrdup(buf->buf + 5);
270+
}
271+
else
272+
die("http transport does not support %s", buf->buf);
273+
274+
strbuf_reset(buf);
275+
if (strbuf_getline(buf, stdin, '\n') == EOF)
276+
return;
277+
if (!*buf->buf)
278+
break;
279+
} while (1);
280+
281+
if (push_dav(nr_spec, specs))
282+
exit(128); /* error already reported */
283+
for (i = 0; i < nr_spec; i++)
284+
free(specs[i]);
285+
free(specs);
286+
287+
printf("\n");
288+
fflush(stdout);
289+
}
290+
214291
int main(int argc, const char **argv)
215292
{
216293
struct strbuf buf = STRBUF_INIT;
@@ -239,17 +316,12 @@ int main(int argc, const char **argv)
239316
if (!prefixcmp(buf.buf, "fetch ")) {
240317
parse_fetch(&buf);
241318

242-
} else if (!strcmp(buf.buf, "list")) {
243-
struct ref *refs = get_refs();
244-
struct ref *posn;
245-
for (posn = refs; posn; posn = posn->next) {
246-
if (posn->symref)
247-
printf("@%s %s\n", posn->symref, posn->name);
248-
else
249-
printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name);
250-
}
251-
printf("\n");
252-
fflush(stdout);
319+
} else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) {
320+
output_refs(get_refs());
321+
322+
} else if (!prefixcmp(buf.buf, "push ")) {
323+
parse_push(&buf);
324+
253325
} else if (!prefixcmp(buf.buf, "option ")) {
254326
char *name = buf.buf + strlen("option ");
255327
char *value = strchr(name, ' ');
@@ -272,6 +344,7 @@ int main(int argc, const char **argv)
272344
} else if (!strcmp(buf.buf, "capabilities")) {
273345
printf("fetch\n");
274346
printf("option\n");
347+
printf("push\n");
275348
printf("\n");
276349
fflush(stdout);
277350
} else {

t/t5540-http-push.sh

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ test_expect_success 'setup remote repository' '
3636
cd test_repo.git &&
3737
git --bare update-server-info &&
3838
mv hooks/post-update.sample hooks/post-update &&
39+
ORIG_HEAD=$(git rev-parse --verify HEAD) &&
3940
cd - &&
4041
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
4142
'
@@ -45,7 +46,7 @@ test_expect_success 'clone remote repository' '
4546
git clone $HTTPD_URL/test_repo.git test_repo_clone
4647
'
4748

48-
test_expect_failure 'push to remote repository with packed refs' '
49+
test_expect_success 'push to remote repository with packed refs' '
4950
cd "$ROOT_PATH"/test_repo_clone &&
5051
: >path2 &&
5152
git add path2 &&
@@ -57,11 +58,15 @@ test_expect_failure 'push to remote repository with packed refs' '
5758
test $HEAD = $(git rev-parse --verify HEAD))
5859
'
5960

60-
test_expect_success ' push to remote repository with unpacked refs' '
61+
test_expect_failure 'push already up-to-date' '
62+
git push
63+
'
64+
65+
test_expect_success 'push to remote repository with unpacked refs' '
6166
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
6267
rm packed-refs &&
63-
git update-ref refs/heads/master \
64-
0c973ae9bd51902a28466f3850b543fa66a6aaf4) &&
68+
git update-ref refs/heads/master $ORIG_HEAD &&
69+
git --bare update-server-info) &&
6570
git push &&
6671
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
6772
test $HEAD = $(git rev-parse --verify HEAD))
@@ -113,7 +118,6 @@ test_expect_success 'create and delete remote branch' '
113118
git push origin dev &&
114119
git fetch &&
115120
git push origin :dev &&
116-
git branch -d -r origin/dev &&
117121
git fetch &&
118122
test_must_fail git show-ref --verify refs/remotes/origin/dev
119123
'

0 commit comments

Comments
 (0)