From: Junio C Hamano Date: Tue, 18 Mar 2014 20:49:32 +0000 (-0700) Subject: Merge branch 'fc/transport-helper-fixes' X-Git-Tag: v2.0.0-rc0~99 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/90e6255a6d01760d13d8ac635cca5819b0b4dbc5?ds=inline;hp=-c Merge branch 'fc/transport-helper-fixes' Updates transport-helper, fast-import and fast-export to allow the ref mapping and ref deletion in a way similar to the natively supported transports. * fc/transport-helper-fixes: remote-bzr: support the new 'force' option test-hg.sh: tests are now expected to pass transport-helper.c: do not overwrite forced bit transport-helper: check for 'forced update' message transport-helper: add 'force' to 'export' helpers transport-helper: don't update refs in dry-run transport-helper: mismerge fix --- 90e6255a6d01760d13d8ac635cca5819b0b4dbc5 diff --combined Documentation/gitremote-helpers.txt index c2908db763,e75699ce1f..64f7ad26b4 --- a/Documentation/gitremote-helpers.txt +++ b/Documentation/gitremote-helpers.txt @@@ -437,13 -437,10 +437,17 @@@ set by Git if the remote helper has th 'option check-connectivity' \{'true'|'false'\}:: Request the helper to check connectivity of a clone. + 'option force' \{'true'|'false'\}:: + Request the helper to perform a force update. Defaults to + 'false'. + +'option cloning \{'true'|'false'\}:: + Notify the helper this is a clone request (i.e. the current + repository is guaranteed empty). + +'option update-shallow \{'true'|'false'\}:: + Allow to extend .git/shallow if the new refs require it. + SEE ALSO -------- linkgit:git-remote[1] diff --combined contrib/remote-helpers/git-remote-bzr index 332aba784b,f1ba477fb8..5f4b2e3e16 --- a/contrib/remote-helpers/git-remote-bzr +++ b/contrib/remote-helpers/git-remote-bzr @@@ -44,8 -44,8 +44,8 @@@ import StringI import atexit, shutil, hashlib, urlparse, subprocess NAME_RE = re.compile('^([^<>]+)') -AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$') -EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)') +AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)') +EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)') RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)') def die(msg, *args): @@@ -193,7 -193,8 +193,7 @@@ def fixup_user(user) else: m = EMAIL_RE.match(user) if m: - name = m.group(1) - mail = m.group(2) + mail = m.group(1) else: m = NAME_RE.match(user) if m: @@@ -684,7 -685,8 +684,8 @@@ def do_export(parser) peer = bzrlib.branch.Branch.open(peers[name], possible_transports=transports) try: - peer.bzrdir.push_branch(branch, revision_id=revid) + peer.bzrdir.push_branch(branch, revision_id=revid, + overwrite=force) except bzrlib.errors.DivergedBranches: print "error %s non-fast forward" % ref continue @@@ -718,8 -720,32 +719,32 @@@ def do_capabilities(parser) print "*import-marks %s" % path print "*export-marks %s" % path + print "option" print + class InvalidOptionValue(Exception): + pass + + def get_bool_option(val): + if val == 'true': + return True + elif val == 'false': + return False + else: + raise InvalidOptionValue() + + def do_option(parser): + global force + opt, val = parser[1:3] + try: + if opt == 'force': + force = get_bool_option(val) + print 'ok' + else: + print 'unsupported' + except InvalidOptionValue: + print "error '%s' is not a valid value for option '%s'" % (val, opt) + def ref_is_valid(name): return not True in [c in name for c in '~^: \\'] @@@ -882,17 -908,8 +907,18 @@@ def main(args) global is_tmp global branches, peers global transports + global force + marks = None + is_tmp = False + gitdir = os.environ.get('GIT_DIR', None) + + if len(args) < 3: + die('Not enough arguments.') + + if not gitdir: + die('GIT_DIR not set') + alias = args[1] url = args[2] @@@ -901,15 -918,20 +927,16 @@@ blob_marks = {} parsed_refs = {} files_cache = {} - marks = None branches = {} peers = {} transports = [] + force = False if alias[5:] == url: is_tmp = True alias = hashlib.sha1(alias).hexdigest() - else: - is_tmp = False prefix = 'refs/bzr/%s' % alias - gitdir = os.environ['GIT_DIR'] dirname = os.path.join(gitdir, 'bzr', alias) if not is_tmp: @@@ -936,6 -958,8 +963,8 @@@ do_import(parser) elif parser.check('export'): do_export(parser) + elif parser.check('option'): + do_option(parser) else: die('unhandled command: %s' % line) sys.stdout.flush() diff --combined contrib/remote-helpers/test-bzr.sh index 1e53ff9a58,ae26dbb2e9..4f379c2ab4 --- a/contrib/remote-helpers/test-bzr.sh +++ b/contrib/remote-helpers/test-bzr.sh @@@ -5,8 -5,7 +5,8 @@@ test_description='Test remote-bzr' -. ./test-lib.sh +test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t +. "$TEST_DIRECTORY"/test-lib.sh if ! test_have_prereq PYTHON then @@@ -66,13 -65,33 +66,33 @@@ test_expect_success 'pushing' test_cmp expected actual ' + test_expect_success 'forced pushing' ' + ( + cd gitrepo && + echo three-new >content && + git commit -a --amend -m three-new && + git push -f + ) && + + ( + cd bzrrepo && + # the forced update overwrites the bzr branch but not the bzr + # working directory (it tries to merge instead) + bzr revert + ) && + + echo three-new >expected && + cat bzrrepo/content >actual && + test_cmp expected actual + ' + test_expect_success 'roundtrip' ' ( cd gitrepo && git pull && git log --format="%s" -1 origin/master >actual ) && - echo three >expected && + echo three-new >expected && test_cmp expected actual && (cd gitrepo && git push && git pull) && @@@ -379,7 -398,7 +399,7 @@@ test_expect_success 'export utf-8 autho git add content && git commit -m one && git remote add bzr "bzr::../bzrrepo" && - git push bzr + git push bzr master ) && ( diff --combined contrib/remote-helpers/test-hg.sh index 5d128a5da9,aacd8a9528..a933b1e30c --- a/contrib/remote-helpers/test-hg.sh +++ b/contrib/remote-helpers/test-hg.sh @@@ -8,8 -8,7 +8,8 @@@ test_description='Test remote-hg' -. ./test-lib.sh +test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t +. "$TEST_DIRECTORY"/test-lib.sh if ! test_have_prereq PYTHON then @@@ -54,14 -53,14 +54,14 @@@ check_bookmark () } check_push () { - local expected_ret=$1 ret=0 ref_ret=0 IFS=':' + expected_ret=$1 ret=0 ref_ret=0 shift git push origin "$@" 2>error ret=$? cat error - while read branch kind + while IFS=':' read branch kind do case "$kind" in 'new') @@@ -83,7 -82,7 +83,7 @@@ test $ref_ret -ne 0 && echo "match for '$branch' failed" && break done - if test $expected_ret -ne $ret -o $ref_ret -ne 0 + if test $expected_ret -ne $ret || test $ref_ret -ne 0 then return 1 fi @@@ -206,17 -205,16 +206,17 @@@ test_expect_success 'authors' >../expected && author_test alpha "" "H G Wells " && - author_test beta "test" "test " && - author_test beta "test (comment)" "test " && - author_test gamma "" "Unknown " && - author_test delta "name" "name " && - author_test epsilon "name " && - author_test zeta " test " "test " && - author_test eta "test < test@example.com >" "test " && - author_test theta "test >test@example.com>" "test " && - author_test iota "test < test example com>" "test " && - author_test kappa "test@example.com" "Unknown " + author_test beta "beta" "beta " && + author_test gamma "gamma (comment)" "gamma " && + author_test delta "" "Unknown " && + author_test epsilon "epsilon" "epsilon " && + author_test zeta "zeta " && + author_test eta " eta " "eta " && + author_test theta "theta < test@example.com >" "theta " && + author_test iota "iota >test@example.com>" "iota " && + author_test kappa "kappa < test example com>" "kappa " && + author_test lambda "lambda@example.com" "Unknown " && + author_test mu "mu.mu@example.com" "Unknown " ) && git clone "hg::hgrepo" gitrepo && @@@ -337,17 -335,6 +337,17 @@@ test_expect_success 'remote cloning' check gitrepo HEAD zero ' +test_expect_success 'moving remote clone' ' + test_when_finished "rm -rf gitrepo*" && + + ( + git clone "hg::hgrepo" gitrepo && + mv gitrepo gitrepo2 && + cd gitrepo2 && + git fetch + ) +' + test_expect_success 'remote update bookmark' ' test_when_finished "rm -rf gitrepo*" && @@@ -455,74 -442,6 +455,74 @@@ test_expect_success 'remote new bookmar # cleanup previous stuff rm -rf hgrepo +test_expect_success 'fetch special filenames' ' + test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" && + + LC_ALL=en_US.UTF-8 + export LC_ALL + + ( + hg init hgrepo && + cd hgrepo && + + echo test >> "æ rø" && + hg add "æ rø" && + echo test >> "ø~?" && + hg add "ø~?" && + hg commit -m add-utf-8 && + echo test >> "æ rø" && + hg commit -m test-utf-8 && + hg rm "ø~?" && + hg mv "æ rø" "ø~?" && + hg commit -m hg-mv-utf-8 + ) && + + ( + git clone "hg::hgrepo" gitrepo && + cd gitrepo && + git -c core.quotepath=false ls-files > ../actual + ) && + echo "ø~?" > expected && + test_cmp expected actual +' + +test_expect_success 'push special filenames' ' + test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" && + + mkdir -p tmp && cd tmp && + + LC_ALL=en_US.UTF-8 + export LC_ALL + + ( + hg init hgrepo && + cd hgrepo && + + echo one >> content && + hg add content && + hg commit -m one + ) && + + ( + git clone "hg::hgrepo" gitrepo && + cd gitrepo && + + echo test >> "æ rø" && + git add "æ rø" && + git commit -m utf-8 && + + git push + ) && + + (cd hgrepo && + hg update && + hg manifest > ../actual + ) && + + printf "content\næ rø\n" > expected && + test_cmp expected actual +' + setup_big_push () { ( hg init hgrepo && @@@ -680,7 -599,7 +680,7 @@@ test_expect_success 'remote big push fe ) ' - test_expect_failure 'remote big push force' ' + test_expect_success 'remote big push force' ' test_when_finished "rm -rf hgrepo gitrepo*" && setup_big_push @@@ -710,7 -629,7 +710,7 @@@ check_bookmark hgrepo new_bmark six ' - test_expect_failure 'remote big push dry-run' ' + test_expect_success 'remote big push dry-run' ' test_when_finished "rm -rf hgrepo gitrepo*" && setup_big_push diff --combined transport-helper.c index ad72fbd53c,705dce7e04..86e1679c1e --- a/transport-helper.c +++ b/transport-helper.c @@@ -190,7 -190,7 +190,7 @@@ static struct child_process *get_helper data->export = 1; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity = 1; - else if (!data->refspecs && !prefixcmp(capname, "refspec ")) { + else if (!data->refspecs && starts_with(capname, "refspec ")) { ALLOC_GROW(refspecs, refspec_nr + 1, refspec_alloc); @@@ -199,17 -199,17 +199,17 @@@ data->connect = 1; } else if (!strcmp(capname, "signed-tags")) { data->signed_tags = 1; - } else if (!prefixcmp(capname, "export-marks ")) { + } else if (starts_with(capname, "export-marks ")) { struct strbuf arg = STRBUF_INIT; strbuf_addstr(&arg, "--export-marks="); strbuf_addstr(&arg, capname + strlen("export-marks ")); data->export_marks = strbuf_detach(&arg, NULL); - } else if (!prefixcmp(capname, "import-marks")) { + } else if (starts_with(capname, "import-marks")) { struct strbuf arg = STRBUF_INIT; strbuf_addstr(&arg, "--import-marks="); strbuf_addstr(&arg, capname + strlen("import-marks ")); data->import_marks = strbuf_detach(&arg, NULL); - } else if (!prefixcmp(capname, "no-private-update")) { + } else if (starts_with(capname, "no-private-update")) { data->no_private_update = 1; } else if (mandatory) { die("Unknown mandatory capability %s. This remote " @@@ -269,7 -269,6 +269,7 @@@ static const char *unsupported_options[ TRANS_OPT_THIN, TRANS_OPT_KEEP }; + static const char *boolean_options[] = { TRANS_OPT_THIN, TRANS_OPT_KEEP, @@@ -311,7 -310,7 +311,7 @@@ static int set_helper_option(struct tra if (!strcmp(buf.buf, "ok")) ret = 0; - else if (!prefixcmp(buf.buf, "error")) { + else if (starts_with(buf.buf, "error")) { ret = -1; } else if (!strcmp(buf.buf, "unsupported")) ret = 1; @@@ -360,12 -359,6 +360,12 @@@ static int fetch_with_fetch(struct tran data->transport_options.check_self_contained_and_connected) set_helper_option(transport, "check-connectivity", "true"); + if (transport->cloning) + set_helper_option(transport, "cloning", "true"); + + if (data->transport_options.update_shallow) + set_helper_option(transport, "update-shallow", "true"); + for (i = 0; i < nr_heads; i++) { const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) @@@ -381,7 -374,7 +381,7 @@@ while (1) { recvline(data, &buf); - if (!prefixcmp(buf.buf, "lock ")) { + if (starts_with(buf.buf, "lock ")) { const char *name = buf.buf + 5; if (transport->pack_lockfile) warning("%s also locked %s", data->name, name); @@@ -650,12 -643,12 +650,12 @@@ static int push_update_ref_status(struc struct ref *remote_refs) { char *refname, *msg; - int status; + int status, forced = 0; - if (!prefixcmp(buf->buf, "ok ")) { + if (starts_with(buf->buf, "ok ")) { status = REF_STATUS_OK; refname = buf->buf + 3; - } else if (!prefixcmp(buf->buf, "error ")) { + } else if (starts_with(buf->buf, "error ")) { status = REF_STATUS_REMOTE_REJECT; refname = buf->buf + 6; } else @@@ -708,6 -701,11 +708,11 @@@ free(msg); msg = NULL; } + else if (!strcmp(msg, "forced update")) { + forced = 1; + free(msg); + msg = NULL; + } } if (*ref) @@@ -729,12 -727,14 +734,14 @@@ } (*ref)->status = status; + (*ref)->forced_update |= forced; (*ref)->remote_status = msg; return !(status == REF_STATUS_OK); } static void push_update_refs_status(struct helper_data *data, - struct ref *remote_refs) + struct ref *remote_refs, + int flags) { struct strbuf buf = STRBUF_INIT; struct ref *ref = remote_refs; @@@ -748,7 -748,7 +755,7 @@@ if (push_update_ref_status(&buf, &ref, remote_refs)) continue; - if (!data->refspecs || data->no_private_update) + if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update) continue; /* propagate back the update to the remote namespace */ @@@ -839,7 -839,7 +846,7 @@@ static int push_refs_with_push(struct t sendline(data, &buf); strbuf_release(&buf); - push_update_refs_status(data, remote_refs); + push_update_refs_status(data, remote_refs, flags); return 0; } @@@ -860,6 -860,11 +867,11 @@@ static int push_refs_with_export(struc die("helper %s does not support dry-run", data->name); } + if (flags & TRANSPORT_PUSH_FORCE) { + if (set_helper_option(transport, "force", "true") != 0) + warning("helper %s does not support 'force'", data->name); + } + helper = get_helper(transport); write_constant(helper->in, "export\n"); @@@ -881,9 -886,6 +893,6 @@@ } free(private); - if (ref->deletion) - die("remote-helpers do not support ref deletion"); - if (ref->peer_ref) { if (strcmp(ref->peer_ref->name, ref->name)) die("remote-helpers do not support old:new syntax"); @@@ -896,7 -898,7 +905,7 @@@ if (finish_command(&exporter)) die("Error while running fast-export"); - push_update_refs_status(data, remote_refs); + push_update_refs_status(data, remote_refs, flags); return 0; } @@@ -1135,8 -1137,9 +1144,8 @@@ static int udt_do_write(struct unidirec return 0; /* Nothing to write. */ transfer_debug("%s is writable", t->dest_name); - bytes = write(t->dest, t->buf, t->bufuse); - if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN && - errno != EINTR) { + bytes = xwrite(t->dest, t->buf, t->bufuse); + if (bytes < 0 && errno != EWOULDBLOCK) { error("write(%s) failed: %s", t->dest_name, strerror(errno)); return -1; } else if (bytes > 0) {