2018-01-03 22:51:20 +03:00
|
|
|
# no-check-code -- see T24862348
|
|
|
|
|
2019-05-21 19:06:46 +03:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
2010-01-26 19:36:13 +03:00
|
|
|
import errno
|
2008-10-08 07:13:14 +04:00
|
|
|
import os
|
2009-05-15 21:18:43 +04:00
|
|
|
import random
|
2009-05-28 06:40:58 +04:00
|
|
|
import shutil
|
2008-10-30 05:15:36 +03:00
|
|
|
import socket
|
2008-11-10 03:08:35 +03:00
|
|
|
import subprocess
|
2018-07-06 03:45:27 +03:00
|
|
|
import sys
|
2008-10-30 05:15:36 +03:00
|
|
|
import time
|
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
import test_hgsubversion_util
|
2019-01-30 03:25:33 +03:00
|
|
|
from edenscm.hgext.hgsubversion import compathacks, util
|
|
|
|
from edenscm.mercurial import commands, context, hg, node, revlog, util as hgutil
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-10-08 07:13:14 +04:00
|
|
|
|
2018-01-17 14:23:44 +03:00
|
|
|
class PushTests(test_hgsubversion_util.TestBase):
|
2013-08-09 21:30:25 +04:00
|
|
|
obsolete_mode_tests = True
|
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def setUp(self):
|
2018-01-17 14:23:44 +03:00
|
|
|
test_hgsubversion_util.TestBase.setUp(self)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.repo_path = self.load_and_fetch("simple_branch.svndump")[1]
|
2008-10-08 07:13:14 +04:00
|
|
|
|
2009-03-29 01:50:00 +03:00
|
|
|
def test_cant_push_empty_ctx(self):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2009-03-29 01:50:00 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
2009-03-29 01:50:00 +03:00
|
|
|
raise IOError()
|
2018-07-06 03:45:27 +03:00
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
[],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
|
|
|
old_tip = repo["tip"].node()
|
2009-03-29 01:50:00 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2009-03-29 01:50:00 +03:00
|
|
|
self.assertEqual(tip.node(), old_tip)
|
|
|
|
|
2013-07-16 18:09:55 +04:00
|
|
|
def test_push_add_of_added_upstream_gives_sane_error(self):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2013-07-16 18:09:55 +04:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
2013-07-16 18:09:55 +04:00
|
|
|
raise IOError()
|
2018-07-06 03:45:27 +03:00
|
|
|
|
|
|
|
p1 = repo["default"].node()
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(p1, node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
|
|
|
old_tip = repo["tip"].node()
|
2013-07-16 18:09:55 +04:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2013-07-16 18:09:55 +04:00
|
|
|
self.assertNotEqual(tip.node(), old_tip)
|
|
|
|
|
|
|
|
# This node adds the same file as the first one we added, and
|
|
|
|
# will be refused by the server for adding a file that already
|
|
|
|
# exists. We should respond with an error suggesting the user
|
|
|
|
# rebase.
|
2018-07-06 03:45:27 +03:00
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(p1, node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
|
|
|
old_tip = repo["tip"].node()
|
2013-07-16 18:09:55 +04:00
|
|
|
try:
|
2018-07-06 03:45:27 +03:00
|
|
|
self.pushrevisions()
|
|
|
|
except hgutil.Abort as e:
|
|
|
|
assert "pull again and rebase" in str(e)
|
|
|
|
tip = self.repo["tip"]
|
2013-07-16 18:09:55 +04:00
|
|
|
self.assertEqual(tip.node(), old_tip)
|
|
|
|
|
2009-07-19 05:44:33 +04:00
|
|
|
def test_cant_push_with_changes(self):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2009-07-19 05:44:33 +04:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2009-07-19 05:44:33 +04:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2009-07-19 05:44:33 +04:00
|
|
|
# Touch an existing file
|
2018-07-06 03:45:27 +03:00
|
|
|
repo.wwrite("beta", "something else", "")
|
2009-07-19 05:44:33 +04:00
|
|
|
try:
|
|
|
|
self.pushrevisions()
|
|
|
|
except hgutil.Abort:
|
|
|
|
pass
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2009-07-19 05:44:33 +04:00
|
|
|
self.assertEqual(new_hash, tip.node())
|
|
|
|
|
2019-06-03 13:23:14 +03:00
|
|
|
def _get_free_address_port(self):
|
|
|
|
host = socket.gethostname()
|
|
|
|
for attempt in range(5):
|
|
|
|
port = random.randint(socket.IPPORT_USERRESERVED, 65535)
|
|
|
|
|
|
|
|
# The `svnserve` binary appears to use the obsolete
|
|
|
|
# `gethostbyname(3)` function, which always returns an IPv4
|
|
|
|
# address, even on hosts that support and expect IPv6. As a
|
|
|
|
# workaround, resolve the hostname within the test harness
|
|
|
|
# with `getaddrinfo(3)` to ensure that the client and server
|
|
|
|
# both use the same IPv4 or IPv6 address.
|
|
|
|
try:
|
|
|
|
addrinfo = socket.getaddrinfo(host, port)
|
|
|
|
except socket.gaierror:
|
|
|
|
# gethostname() can give a hostname that doesn't
|
|
|
|
# resolve. Seems bad, but let's fall back to `localhost`
|
|
|
|
# in that case and hope for the best.
|
|
|
|
host = "localhost"
|
|
|
|
addrinfo = socket.getaddrinfo(host, port)
|
|
|
|
# On macOS svn seems to have issues with IPv6 at least some
|
|
|
|
# of the time, so try and bias towards IPv4. This works
|
|
|
|
# because AF_INET is less than AF_INET6 on all platforms
|
|
|
|
# I've checked. Hopefully any platform where that's not true
|
|
|
|
# will be fine with IPv6 all the time. :)
|
|
|
|
selected = sorted(addrinfo)[0]
|
|
|
|
# Check the port is free for use by attempting to bind it.
|
|
|
|
# `svnserve` sets `SO_REUSEADDR`, so as long as nothing binds the
|
|
|
|
# same port in the time between us closing the port and svnserve
|
|
|
|
# binding it, we should be fine.
|
|
|
|
try:
|
|
|
|
s = socket.socket(selected[0], selected[1])
|
|
|
|
s.bind((selected[4][0], selected[4][1]))
|
|
|
|
s.close()
|
|
|
|
return selected
|
|
|
|
except Exception:
|
|
|
|
pass
|
|
|
|
assert False, "Could not get a free port after 5 attempts"
|
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
def internal_push_over_svnserve(self, subdir="", commit=True):
|
|
|
|
repo_path = self.load_svndump("simple_branch.svndump")
|
|
|
|
open(os.path.join(repo_path, "conf", "svnserve.conf"), "w").write(
|
|
|
|
"[general]\nanon-access=write\n[sasl]\n"
|
|
|
|
)
|
2019-06-03 13:23:14 +03:00
|
|
|
addrinfo = self._get_free_address_port()
|
|
|
|
self.host = addrinfo[4][0]
|
|
|
|
self.port = addrinfo[4][1]
|
2017-04-11 02:58:28 +03:00
|
|
|
|
|
|
|
# If we're connecting via IPv6 the need to put brackets around the
|
|
|
|
# hostname in the URL.
|
2019-06-03 13:23:14 +03:00
|
|
|
ipv6 = addrinfo[0] == socket.AF_INET6
|
2017-05-29 19:50:55 +03:00
|
|
|
|
|
|
|
# Ditch any interface information since that's not helpful in
|
|
|
|
# a URL
|
2018-07-06 03:45:27 +03:00
|
|
|
if ipv6 and ":" in self.host and "%" in self.host:
|
|
|
|
self.host = self.host.rsplit("%", 1)[0]
|
|
|
|
|
|
|
|
urlfmt = "svn://[%s]:%d/%s" if ipv6 else "svn://%s:%d/%s"
|
|
|
|
|
|
|
|
args = [
|
|
|
|
"svnserve",
|
|
|
|
"--daemon",
|
|
|
|
"--foreground",
|
|
|
|
"--listen-port=%d" % self.port,
|
|
|
|
"--listen-host=%s" % self.host,
|
|
|
|
"--root=%s" % repo_path,
|
|
|
|
]
|
|
|
|
|
|
|
|
svnserve = subprocess.Popen(
|
|
|
|
args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
|
|
|
)
|
2009-05-19 13:43:49 +04:00
|
|
|
self.svnserve_pid = svnserve.pid
|
2009-05-13 19:22:18 +04:00
|
|
|
try:
|
|
|
|
time.sleep(2)
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2009-05-14 06:39:39 +04:00
|
|
|
shutil.rmtree(self.wc_path)
|
2018-07-06 03:45:27 +03:00
|
|
|
commands.clone(
|
|
|
|
self.ui(),
|
|
|
|
urlfmt % (self.host, self.port, subdir),
|
|
|
|
self.wc_path,
|
|
|
|
noupdate=True,
|
|
|
|
)
|
2009-05-13 19:22:18 +04:00
|
|
|
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
old_tip = repo["tip"].node()
|
|
|
|
expected_parent = repo["default"].node()
|
|
|
|
|
2009-05-13 19:22:18 +04:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
parents=(repo["default"].node(), node.nullid),
|
|
|
|
text="automated test",
|
|
|
|
files=["adding_file"],
|
|
|
|
filectxfn=file_callback,
|
|
|
|
user="an_author",
|
|
|
|
date="2008-10-07 20:59:48 -0500",
|
|
|
|
extra={"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2009-05-13 19:22:18 +04:00
|
|
|
if not commit:
|
2018-07-06 03:45:27 +03:00
|
|
|
return # some tests use this test as an extended setup.
|
|
|
|
hg.update(repo, repo["tip"].node())
|
|
|
|
oldauthor = repo["tip"].user()
|
2009-05-13 19:22:18 +04:00
|
|
|
commands.push(repo.ui, repo)
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2009-05-13 19:22:18 +04:00
|
|
|
self.assertNotEqual(oldauthor, tip.user())
|
|
|
|
self.assertNotEqual(tip.node(), old_tip)
|
|
|
|
self.assertEqual(tip.parents()[0].node(), expected_parent)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["adding_file"].data(), "foo")
|
2009-05-22 15:42:51 +04:00
|
|
|
# unintended behaviour:
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertNotEqual("an_author", tip.user())
|
|
|
|
self.assertEqual("(no author)", tip.user().rsplit("@", 1)[0])
|
2009-05-13 19:22:18 +04:00
|
|
|
finally:
|
2018-07-06 03:45:27 +03:00
|
|
|
if sys.version_info >= (2, 6):
|
2012-04-12 17:39:17 +04:00
|
|
|
svnserve.kill()
|
2012-05-17 17:24:54 +04:00
|
|
|
else:
|
2018-01-17 14:23:44 +03:00
|
|
|
test_hgsubversion_util.kill_process(svnserve)
|
2009-03-29 01:50:00 +03:00
|
|
|
|
2010-07-28 16:47:44 +04:00
|
|
|
def test_push_over_svnserve(self):
|
|
|
|
self.internal_push_over_svnserve()
|
|
|
|
|
|
|
|
def test_push_over_svnserve_with_subdir(self):
|
2018-07-06 03:45:27 +03:00
|
|
|
self.internal_push_over_svnserve(subdir="///branches////the_branch/////")
|
2010-07-28 16:47:44 +04:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def test_push_to_default(self, commit=True):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
old_tip = repo["tip"].node()
|
|
|
|
expected_parent = repo["default"].node()
|
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2008-11-01 20:23:07 +03:00
|
|
|
if not commit:
|
2018-07-06 03:45:27 +03:00
|
|
|
return # some tests use this test as an extended setup.
|
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), old_tip)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(node.hex(tip.parents()[0].node()), node.hex(expected_parent))
|
|
|
|
self.assertEqual(tip["adding_file"].data(), "foo")
|
2008-12-23 06:21:11 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def test_push_two_revs(self):
|
|
|
|
# set up some work for us
|
|
|
|
self.test_push_to_default(commit=False)
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
old_tip = repo["tip"].node()
|
|
|
|
expected_parent = repo["tip"].parents()[0].node()
|
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file2":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo2",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file2"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2008-10-07 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), old_tip)
|
|
|
|
self.assertNotEqual(tip.parents()[0].node(), old_tip)
|
|
|
|
self.assertEqual(tip.parents()[0].parents()[0].node(), expected_parent)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["adding_file2"].data(), "foo2")
|
|
|
|
self.assertEqual(tip["adding_file"].data(), "foo")
|
|
|
|
self.assertEqual(tip.parents()[0]["adding_file"].data(), "foo")
|
2008-11-01 20:23:07 +03:00
|
|
|
try:
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip.parents()[0]["adding_file2"].data(), "foo")
|
|
|
|
assert (
|
|
|
|
False
|
|
|
|
), "this is impossible, adding_file2 should not be in this manifest."
|
2018-01-03 22:51:00 +03:00
|
|
|
except revlog.LookupError:
|
2008-11-01 20:23:07 +03:00
|
|
|
pass
|
2008-10-30 05:15:36 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def test_delete_file(self):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2014-09-17 03:03:31 +04:00
|
|
|
return compathacks.filectxfn_deleted(memctx, path)
|
2018-07-06 03:45:27 +03:00
|
|
|
|
|
|
|
old_files = set(repo["default"].manifest().keys())
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["alpha"],
|
|
|
|
file_callback,
|
|
|
|
"an author",
|
|
|
|
"2008-10-29 21:26:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
|
|
|
self.assertEqual(old_files, set(tip.manifest().keys() + ["alpha"]))
|
|
|
|
self.assert_("alpha" not in tip.manifest())
|
2008-10-30 05:15:36 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def test_push_executable_file(self):
|
|
|
|
self.test_push_to_default(commit=True)
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "gamma":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=False,
|
|
|
|
isexec=True,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["tip"].node(), node.nullid),
|
|
|
|
"message",
|
|
|
|
["gamma"],
|
|
|
|
file_callback,
|
|
|
|
"author",
|
|
|
|
"2008-10-29 21:26:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2008-11-01 20:23:07 +03:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.clean(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), new_hash)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assert_("@" in self.repo["tip"].user())
|
|
|
|
self.assertEqual(tip["gamma"].flags(), "x")
|
|
|
|
self.assertEqual(tip["gamma"].data(), "foo")
|
|
|
|
self.assertEqual(
|
|
|
|
sorted([x for x in tip.manifest().keys() if "x" not in tip[x].flags()]),
|
|
|
|
["adding_file", "alpha", "beta"],
|
|
|
|
)
|
2008-10-30 06:58:52 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def test_push_symlink_file(self):
|
|
|
|
self.test_push_to_default(commit=True)
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "gamma":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=True,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["tip"].node(), node.nullid),
|
|
|
|
"message",
|
|
|
|
["gamma"],
|
|
|
|
file_callback,
|
|
|
|
"author",
|
|
|
|
"2008-10-29 21:26:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2008-11-01 20:23:07 +03:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
# grab a new repo instance (self.repo is an @property functions)
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), new_hash)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["gamma"].flags(), "l")
|
|
|
|
self.assertEqual(tip["gamma"].data(), "foo")
|
|
|
|
self.assertEqual(
|
|
|
|
sorted([x for x in tip.manifest().keys() if "l" not in tip[x].flags()]),
|
|
|
|
["adding_file", "alpha", "beta"],
|
|
|
|
)
|
2008-11-01 20:23:07 +03:00
|
|
|
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
def file_callback2(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "gamma":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="a" * 129,
|
|
|
|
islink=True,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["tip"].node(), node.nullid),
|
|
|
|
"message",
|
|
|
|
["gamma"],
|
|
|
|
file_callback2,
|
|
|
|
"author",
|
|
|
|
"2014-08-08 20:11:41 -0700",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
self.pushrevisions()
|
|
|
|
# grab a new repo instance (self.repo is an @property functions)
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = repo["tip"]
|
|
|
|
self.assertEqual(tip["gamma"].flags(), "l")
|
|
|
|
self.assertEqual(tip["gamma"].data(), "a" * 129)
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
|
|
|
|
def file_callback3(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "gamma":
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="a" * 64 + "b" * 65,
|
|
|
|
islink=True,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["tip"].node(), node.nullid),
|
|
|
|
"message",
|
|
|
|
["gamma"],
|
|
|
|
file_callback3,
|
|
|
|
"author",
|
|
|
|
"2014-08-08 20:16:25 -0700",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
self.pushrevisions()
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = repo["tip"]
|
|
|
|
self.assertEqual(tip["gamma"].flags(), "l")
|
|
|
|
self.assertEqual(tip["gamma"].data(), "a" * 64 + "b" * 65)
|
pushmod: prepend "link " to base text for links
http://svn.apache.org/viewvc?view=revision&revision=1223036 exposes
what is arguably a bug in hgsubversion push code. Specifically, when
we are receiving text from the server in an editor, we prepend a "link
" to the text of symlinks when opening a file and strip it when
closing a file. We don't, however, prepend "link " to the base we use
when sending text changes to the server.
This was working before because prior to that revision, the first
thing subversion did was to check whether the entirety of the before
text or the entirety of the after text was less than 64 bytes. In
that case, it just sent the entirety of the after text as a single
insert operation. I'd expect most, but not all symlinks to fit under
the 64 byte limit, including the leading "link " text on the
subversion end.
After the change, the first thing subversion does is check for a
leading match that is more than 4 bytes long, or that is the full
length of the after text. In this case, it sends a copy operation for
the leading match, and then goes into the if < 64 bytes remaining send
the whole thing behavior. It also looks for trailing matches of more
than 4 bytes even in the <64 byte case, but that's not what breaks the
tests.
Incidentally, changing the destination of long symlinks was broken
even before this subversion change. This diff includes test additions
that cover that breakage.
2014-08-08 06:30:26 +04:00
|
|
|
|
2008-11-06 18:07:13 +03:00
|
|
|
def test_push_existing_file_newly_symlink(self):
|
2018-07-06 03:45:27 +03:00
|
|
|
self.test_push_existing_file_newly_execute(
|
|
|
|
execute=False, link=True, expected_flags="l"
|
|
|
|
)
|
2008-11-06 18:07:13 +03:00
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
def test_push_existing_file_newly_execute(
|
|
|
|
self, execute=True, link=False, expected_flags="x"
|
|
|
|
):
|
2008-11-01 20:23:07 +03:00
|
|
|
self.test_push_to_default()
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-01 20:23:07 +03:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="foo",
|
|
|
|
islink=link,
|
|
|
|
isexec=execute,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"message",
|
|
|
|
["alpha"],
|
|
|
|
file_callback,
|
|
|
|
"author",
|
|
|
|
"2008-1-1 00:00:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2008-11-01 20:23:07 +03:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), new_hash)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["alpha"].data(), "foo")
|
|
|
|
self.assertEqual(tip.parents()[0]["alpha"].flags(), "")
|
|
|
|
self.assertEqual(tip["alpha"].flags(), expected_flags)
|
2008-11-01 20:23:07 +03:00
|
|
|
# while we're here, double check pushing an already-executable file
|
|
|
|
# works
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-22 01:21:19 +03:00
|
|
|
def file_callback2(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="bar",
|
|
|
|
islink=link,
|
|
|
|
isexec=execute,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"mutate already-special file alpha",
|
|
|
|
["alpha"],
|
|
|
|
file_callback2,
|
|
|
|
"author",
|
|
|
|
"2008-1-1 00:00:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2008-11-01 20:23:07 +03:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-01 20:23:07 +03:00
|
|
|
self.assertNotEqual(tip.node(), new_hash)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["alpha"].data(), "bar")
|
|
|
|
self.assertEqual(tip.parents()[0]["alpha"].flags(), expected_flags)
|
|
|
|
self.assertEqual(tip["alpha"].flags(), expected_flags)
|
2008-11-06 18:24:33 +03:00
|
|
|
# now test removing the property entirely
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
|
2008-11-22 01:21:19 +03:00
|
|
|
def file_callback3(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data="bar",
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"convert alpha back to regular file",
|
|
|
|
["alpha"],
|
|
|
|
file_callback3,
|
|
|
|
"author",
|
|
|
|
"2008-01-01 00:00:00 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2008-11-06 18:24:33 +03:00
|
|
|
new_hash = repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2008-11-10 03:08:35 +03:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2008-11-06 18:24:33 +03:00
|
|
|
self.assertNotEqual(tip.node(), new_hash)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["alpha"].data(), "bar")
|
|
|
|
self.assertEqual(tip.parents()[0]["alpha"].flags(), expected_flags)
|
|
|
|
self.assertEqual(tip["alpha"].flags(), "")
|
2008-10-30 06:58:52 +03:00
|
|
|
|
2009-04-25 05:31:17 +04:00
|
|
|
def test_push_outdated_base_text(self):
|
|
|
|
self.test_push_two_revs()
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("adding_file", "adding_file", "different_content")]
|
|
|
|
par = self.repo["tip"].rev()
|
2010-09-08 12:42:53 +04:00
|
|
|
self.commitchanges(changes, parent=par)
|
2009-04-25 05:31:17 +04:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("adding_file", "adding_file", "even_more different_content")]
|
2010-09-08 12:42:53 +04:00
|
|
|
self.commitchanges(changes, parent=par)
|
2009-04-25 05:31:17 +04:00
|
|
|
try:
|
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
assert False, "This should have aborted!"
|
|
|
|
except hgutil.Abort as e:
|
|
|
|
self.assertEqual(
|
|
|
|
e.args[0],
|
|
|
|
"Outgoing changesets parent is not at subversion "
|
2018-11-01 00:00:12 +03:00
|
|
|
"HEAD (svn error 160028)\n"
|
2018-07-06 03:45:27 +03:00
|
|
|
"(pull again and rebase on a newer revision)",
|
|
|
|
)
|
2012-05-17 17:24:54 +04:00
|
|
|
# verify that any pending transactions on the server got cleaned up
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(
|
|
|
|
[],
|
|
|
|
os.listdir(
|
|
|
|
os.path.join(self.tmpdir, "testrepo-1", "db", "transactions")
|
|
|
|
),
|
|
|
|
)
|
2008-10-08 07:13:14 +04:00
|
|
|
|
2012-09-09 16:54:43 +04:00
|
|
|
def test_push_encoding(self):
|
|
|
|
self.test_push_two_revs()
|
|
|
|
# Writing then rebasing UTF-8 filenames in a cp1252 windows console
|
|
|
|
# used to fail because hg internal encoding was being changed during
|
|
|
|
# the interactions with subversion, *and during the rebase*, which
|
|
|
|
# confused the dirstate and made it believe the file was deleted.
|
2018-07-06 03:45:27 +03:00
|
|
|
fn = "pi\xc3\xa8ce/test"
|
|
|
|
changes = [(fn, fn, "a")]
|
|
|
|
par = self.repo["tip"].rev()
|
2012-09-09 16:54:43 +04:00
|
|
|
self.commitchanges(changes, parent=par)
|
|
|
|
self.pushrevisions()
|
|
|
|
|
2012-09-09 18:12:28 +04:00
|
|
|
def test_push_emptying_changeset(self):
|
2018-07-06 03:45:27 +03:00
|
|
|
self.repo["tip"]
|
|
|
|
changes = [("alpha", None, None), ("beta", None, None)]
|
|
|
|
parent = self.repo["tip"].rev()
|
2012-09-09 18:12:28 +04:00
|
|
|
self.commitchanges(changes, parent=parent)
|
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(len(self.repo["tip"].manifest()), 0)
|
2012-09-09 18:12:28 +04:00
|
|
|
|
|
|
|
# Try to re-add a file after emptying the branch
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("alpha", "alpha", "alpha")]
|
|
|
|
self.commitchanges(changes, parent=self.repo["tip"].rev())
|
2012-09-09 18:12:28 +04:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(["alpha"], list(self.repo["tip"].manifest()))
|
2012-09-09 18:12:28 +04:00
|
|
|
|
2013-01-03 05:51:07 +04:00
|
|
|
def test_push_without_pushing_children(self):
|
2018-07-06 03:45:27 +03:00
|
|
|
"""
|
2013-01-03 05:51:07 +04:00
|
|
|
Verify that a push of a nontip node, keeps the tip child
|
|
|
|
on top of the pushed commit.
|
2018-07-06 03:45:27 +03:00
|
|
|
"""
|
2013-01-03 05:51:07 +04:00
|
|
|
|
2018-01-17 14:23:44 +03:00
|
|
|
oldlen = test_hgsubversion_util.repolen(self.repo)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.repo["default"].node()
|
2013-01-03 05:51:07 +04:00
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("gamma", "gamma", "sometext")]
|
2013-01-03 05:51:07 +04:00
|
|
|
newhash1 = self.commitchanges(changes)
|
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("delta", "delta", "sometext")]
|
2018-01-03 22:51:00 +03:00
|
|
|
self.commitchanges(changes)
|
2013-01-03 05:51:07 +04:00
|
|
|
|
|
|
|
# push only the first commit
|
|
|
|
repo = self.repo
|
|
|
|
hg.update(repo, newhash1)
|
|
|
|
commands.push(repo.ui, repo)
|
2018-01-17 14:23:44 +03:00
|
|
|
self.assertEqual(test_hgsubversion_util.repolen(self.repo), oldlen + 2)
|
2013-01-03 05:51:07 +04:00
|
|
|
|
|
|
|
# verify that the first commit is pushed, and the second is not
|
2018-07-06 03:45:27 +03:00
|
|
|
commit2 = self.repo["tip"]
|
2019-02-06 02:48:52 +03:00
|
|
|
self.assertEqual(commit2.files(), ("delta",))
|
2013-08-05 22:27:31 +04:00
|
|
|
self.assertEqual(util.getsvnrev(commit2), None)
|
2013-01-03 05:51:07 +04:00
|
|
|
commit1 = commit2.parents()[0]
|
2019-02-06 02:48:52 +03:00
|
|
|
self.assertEqual(commit1.files(), ("gamma",))
|
2018-07-06 03:45:27 +03:00
|
|
|
prefix = "svn:" + self.repo.svnmeta().uuid
|
|
|
|
self.assertEqual(util.getsvnrev(commit1), prefix + "/branches/the_branch@5")
|
2013-01-03 05:51:07 +04:00
|
|
|
|
2013-01-03 05:54:30 +04:00
|
|
|
def test_push_two_that_modify_same_file(self):
|
2018-07-06 03:45:27 +03:00
|
|
|
"""
|
2013-01-03 05:54:30 +04:00
|
|
|
Push performs a rebase if two commits touch the same file.
|
|
|
|
This test verifies that code path works.
|
2018-07-06 03:45:27 +03:00
|
|
|
"""
|
2013-01-03 05:54:30 +04:00
|
|
|
|
2018-01-17 14:23:44 +03:00
|
|
|
oldlen = test_hgsubversion_util.repolen(self.repo)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.repo["default"].node()
|
2013-01-03 05:54:30 +04:00
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [("gamma", "gamma", "sometext")]
|
2013-01-03 05:54:30 +04:00
|
|
|
newhash = self.commitchanges(changes)
|
2018-07-06 03:45:27 +03:00
|
|
|
changes = [
|
|
|
|
("gamma", "gamma", "sometext\n moretext"),
|
|
|
|
("delta", "delta", "sometext\n moretext"),
|
|
|
|
]
|
2013-01-03 05:54:30 +04:00
|
|
|
newhash = self.commitchanges(changes)
|
|
|
|
|
|
|
|
repo = self.repo
|
|
|
|
hg.update(repo, newhash)
|
|
|
|
commands.push(repo.ui, repo)
|
2018-01-17 14:23:44 +03:00
|
|
|
self.assertEqual(test_hgsubversion_util.repolen(self.repo), oldlen + 2)
|
2013-01-03 05:54:30 +04:00
|
|
|
|
|
|
|
# verify that both commits are pushed
|
2018-07-06 03:45:27 +03:00
|
|
|
commit1 = self.repo["tip"]
|
2019-02-06 02:48:52 +03:00
|
|
|
self.assertEqual(commit1.files(), ("delta", "gamma"))
|
2013-08-05 22:27:31 +04:00
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
prefix = "svn:" + self.repo.svnmeta().uuid
|
|
|
|
self.assertEqual(util.getsvnrev(commit1), prefix + "/branches/the_branch@6")
|
2013-01-03 05:54:30 +04:00
|
|
|
commit2 = commit1.parents()[0]
|
2019-02-06 02:48:52 +03:00
|
|
|
self.assertEqual(commit2.files(), ("gamma",))
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(util.getsvnrev(commit2), prefix + "/branches/the_branch@5")
|
2013-01-03 05:54:30 +04:00
|
|
|
|
2013-01-18 05:01:45 +04:00
|
|
|
def test_push_in_subdir(self, commit=True):
|
|
|
|
repo = self.repo
|
2018-07-06 03:45:27 +03:00
|
|
|
old_tip = repo["tip"].node()
|
|
|
|
|
2013-01-18 05:01:45 +04:00
|
|
|
def file_callback(repo, memctx, path):
|
2018-07-06 03:45:27 +03:00
|
|
|
if path == "adding_file" or path == "newdir/new_file":
|
|
|
|
testData = "fooFirstFile"
|
|
|
|
if path == "newdir/new_file":
|
|
|
|
testData = "fooNewFile"
|
|
|
|
return compathacks.makememfilectx(
|
|
|
|
repo,
|
|
|
|
memctx=memctx,
|
|
|
|
path=path,
|
|
|
|
data=testData,
|
|
|
|
islink=False,
|
|
|
|
isexec=False,
|
|
|
|
copied=False,
|
|
|
|
)
|
|
|
|
raise IOError(errno.EINVAL, "Invalid operation: " + path)
|
|
|
|
|
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["adding_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2012-12-13 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2013-01-18 05:01:45 +04:00
|
|
|
p = os.path.join(repo.root, "newdir")
|
|
|
|
os.mkdir(p)
|
2018-07-06 03:45:27 +03:00
|
|
|
ctx = context.memctx(
|
|
|
|
repo,
|
|
|
|
(repo["default"].node(), node.nullid),
|
|
|
|
"automated test",
|
|
|
|
["newdir/new_file"],
|
|
|
|
file_callback,
|
|
|
|
"an_author",
|
|
|
|
"2012-12-13 20:59:48 -0500",
|
|
|
|
{"branch": "default"},
|
|
|
|
)
|
2018-01-03 22:51:00 +03:00
|
|
|
repo.commitctx(ctx)
|
2018-07-06 03:45:27 +03:00
|
|
|
hg.update(repo, repo["tip"].node())
|
2013-01-18 05:01:45 +04:00
|
|
|
self.pushrevisions()
|
2018-07-06 03:45:27 +03:00
|
|
|
tip = self.repo["tip"]
|
2013-01-18 05:01:45 +04:00
|
|
|
self.assertNotEqual(tip.node(), old_tip)
|
2018-07-06 03:45:27 +03:00
|
|
|
self.assertEqual(tip["adding_file"].data(), "fooFirstFile")
|
|
|
|
self.assertEqual(tip["newdir/new_file"].data(), "fooNewFile")
|
|
|
|
|
2018-01-17 14:23:44 +03:00
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
if __name__ == "__main__":
|
2018-01-17 14:23:44 +03:00
|
|
|
import silenttestrunner
|
|
|
|
|
2018-07-06 03:45:27 +03:00
|
|
|
silenttestrunner.main(__name__)
|