Skip to content

Commit

Permalink
Allow stream-switching when re-using a client on new host (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
ca-johnson authored Sep 21, 2020
1 parent 12dcab4 commit b3d41e7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
Binary file modified python/fixture/server.zip
Binary file not shown.
19 changes: 18 additions & 1 deletion python/perforce.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ def insert_clientname(mapping):
return '%s //%s/%s' % (depot, clientname, local)
return [insert_clientname(mapping) for mapping in view]

def _flush_to_previous_client(self, current_client, prev_clientname):
"""Flush a new client to match existing workspace data from a previous client"""
prev_client = self.perforce.fetch_client(prev_clientname)
stream_switch = self.stream and prev_client._stream != self.stream
if stream_switch:
self.perforce.logger.info("previous client stream %s does not match %s, switching stream temporarily to flush" % (prev_client._stream, self.stream))
current_client._stream = prev_client._stream
self.perforce.save_client(current_client)

self.perforce.run_flush(['//...@%s' % prev_clientname])

if stream_switch:
self.perforce.logger.info("switching stream back to %s" % self.stream)
current_client._stream = self.stream
self.perforce.save_client(current_client)

def _setup_client(self):
"""Creates or re-uses the client workspace for this machine"""
# pylint: disable=protected-access
Expand Down Expand Up @@ -107,7 +123,8 @@ def _setup_client(self):
if line.startswith('P4CLIENT='))
if prev_clientname != clientname:
self.perforce.logger.warning("p4config last client was %s, flushing workspace to match" % prev_clientname)
self.perforce.run_flush(['//...@%s' % prev_clientname])
self._flush_to_previous_client(client, prev_clientname)

elif 'Update' in client: # client was accessed previously
self.perforce.logger.warning("p4config missing for previously accessed client workspace. flushing to revision zero")
self.perforce.run_flush(['//...@0'])
Expand Down
41 changes: 37 additions & 4 deletions python/test_perforce.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def test_fixture(capsys, server):
assert depotfile_to_content == {
"//depot/file.txt": "Hello World\n",
"//stream-depot/main/file.txt": "Hello Stream World\n",
"//stream-depot/main/file_2.txt": "file_2\n",
"//stream-depot/dev/file.txt": "Hello Stream World (dev)\n",
}

Expand Down Expand Up @@ -143,6 +144,11 @@ def test_fixture(capsys, server):
'action': ['edit'],
'depotFile': ['//stream-depot/dev/file.txt'],
'desc': 'Update contents of //stream-depot/dev/file.txt\n'
},
'9': {
'action': ['add'],
'depotFile': ['//stream-depot/main/file_2.txt'],
'desc': 'file_2.txt - exists in main but not dev\n'
}
}

Expand Down Expand Up @@ -188,11 +194,12 @@ def test_fixture(capsys, server):

def test_head(server, tmpdir):
"""Test resolve of HEAD changelist"""
repo = P4Repo(root=tmpdir)
assert repo.head() == "@6", "Unexpected global HEAD revision"
# workspace with no changes in view defaults to global view
repo = P4Repo(root=tmpdir, view="//depot/empty_dir/... empty_dir/...")
assert repo.head() == "@9", "Unexpected global HEAD revision"

repo = P4Repo(root=tmpdir, stream='//stream-depot/main')
assert repo.head() == "@2", "Unexpected HEAD revision for stream"
repo = P4Repo(root=tmpdir, stream='//stream-depot/dev')
assert repo.head() == "@8", "Unexpected HEAD revision for stream"

repo = P4Repo(root=tmpdir, stream='//stream-depot/idontexist')
with pytest.raises(Exception, match=r"Stream '//stream-depot/idontexist' doesn't exist."):
Expand Down Expand Up @@ -413,16 +420,42 @@ def test_stream_switching(server, tmpdir):
repo = P4Repo(root=tmpdir, stream='//stream-depot/main')
synced = repo.sync()
assert len(synced) > 0, "Didn't sync any files"
assert set(os.listdir(tmpdir)) == set([
"file.txt", "file_2.txt", "p4config"])
with open(os.path.join(tmpdir, "file.txt")) as content:
assert content.read() == "Hello Stream World\n", "Unexpected content in workspace file"

# Re-use the same checkout directory, but switch streams
repo = P4Repo(root=tmpdir, stream='//stream-depot/dev')
repo.sync()
assert len(synced) > 0, "Didn't sync any files"
assert set(os.listdir(tmpdir)) == set([
"file.txt", "p4config"]) # file_2.txt was de-synced
with open(os.path.join(tmpdir, "file.txt")) as content:
assert content.read() == "Hello Stream World (dev)\n", "Unexpected content in workspace file"

def test_stream_switching_migration(server, tmpdir):
"""Test stream-switching and client migration simultaneously"""
repo = P4Repo(root=tmpdir, stream='//stream-depot/main')
synced = repo.sync()
assert len(synced) > 0, "Didn't sync any files"
assert set(os.listdir(tmpdir)) == set([
"file.txt", "file_2.txt", "p4config"])
with open(os.path.join(tmpdir, "file.txt")) as content:
assert content.read() == "Hello Stream World\n", "Unexpected content in workspace file"

with tempfile.TemporaryDirectory(prefix="bk-p4-test-") as second_client:
copytree(tmpdir, second_client)
# Client names include path on disk, so this creates a new unique client
# Re-use the same checkout directory and switch streams at the same time
repo = P4Repo(root=second_client, stream='//stream-depot/dev')
repo.sync()
assert len(synced) > 0, "Didn't sync any files"
assert set(os.listdir(second_client)) == set([
"file.txt", "p4config"]) # file_2.txt was de-synced
with open(os.path.join(second_client, "file.txt")) as content:
assert content.read() == "Hello Stream World (dev)\n", "Unexpected content in workspace file"


# def test_live_server():
# """Reproduce production issues quickly by writing tests which run against a real server"""
Expand Down

0 comments on commit b3d41e7

Please sign in to comment.