cloud rejoin command

Summary:
this command will be use in fbclone

it does sync and join if a person has been used already the commit cloud workspace in that repo

Reviewed By: markbt

Differential Revision: D8640667

fbshipit-source-id: 9c8d96497cf7930b995a49c8bdaebe7048e0c1e8
This commit is contained in:
Liubov Dmitrieva 2018-06-26 12:34:42 -07:00 committed by Facebook Github Bot
parent 6bd246ce84
commit 4ff0279f08
4 changed files with 127 additions and 19 deletions

View File

@ -95,6 +95,50 @@ def cloudjoin(ui, repo, **opts):
cloudsync(ui, repo, **opts)
@subcmd("rejoin|reconnect", [])
def cloudrejoin(ui, repo, **opts):
"""reconnect the local repository to commit cloud
Reconnect only happens if the machine has been registered with Commit Cloud,
and the workspace has been already used for this repo
Use `hg cloud sync` to trigger a new synchronization.
Use `hg cloud connect` to connect to commit cloud for the first time.
"""
token = commitcloudutil.TokenLocator(ui).token
if token:
try:
serv = service.get(ui, token)
serv.check()
reponame, workspace = getdefaultrepoworkspace(ui, repo)
highlightstatus(
ui,
_("trying to reconnect to the '%s' workspace for the '%s' repo\n")
% (workspace, reponame),
)
cloudrefs = serv.getreferences(reponame, workspace, 0)
if cloudrefs.version == 0:
highlightstatus(
ui,
_(
"unable to reconnect: this workspace has been never connected to commit cloud for this repo\n"
),
)
else:
commitcloudutil.WorkspaceManager(repo).setworkspace(workspace)
highlightstatus(ui, _("the repository is now reconnected\n"))
cloudsync(ui, repo, cloudrefs, **opts)
return
except commitcloudcommon.RegistrationError:
pass
highlightstatus(
ui, _("unable to reconnect: not authenticated with commit cloud on this host\n")
)
@subcmd("leave|disconnect")
def cloudleave(ui, repo, **opts):
"""disconnect the local repository from commit cloud
@ -195,6 +239,17 @@ def getrepoworkspace(ui, repo):
return reponame, workspace
def getdefaultrepoworkspace(ui, repo):
"""get default workspace identity
repo may be not joined to this workspace yet
"""
workspacemanager = commitcloudutil.WorkspaceManager(repo)
reponame = workspacemanager.reponame
if not reponame:
raise commitcloudcommon.ConfigurationError(ui, _("unknown repo"))
return reponame, workspacemanager.defaultworkspace
@subcmd(
"sync",
[
@ -229,7 +284,7 @@ def getrepoworkspace(ui, repo):
),
],
)
def cloudsync(ui, repo, **opts):
def cloudsync(ui, repo, cloudrefs=None, **opts):
"""synchronize commits with the commit cloud service"""
repo.ignoreautobackup = True
if opts.get("use_bgssh"):
@ -246,7 +301,7 @@ def cloudsync(ui, repo, **opts):
srcrepo = shareutil.getsrcrepo(repo)
with lockmod.lock(srcrepo.vfs, _backuplockname, timeout=timeout):
currentnode = repo["."].node()
_docloudsync(ui, repo, **opts)
_docloudsync(ui, repo, cloudrefs, **opts)
return _maybeupdateworkingcopy(ui, repo, currentnode)
except error.LockHeld as e:
if e.errno == errno.ETIMEDOUT:
@ -263,14 +318,14 @@ def cloudsync(ui, repo, **opts):
raise
def _docloudsync(ui, repo, **opts):
def _docloudsync(ui, repo, cloudrefs=None, **opts):
start = time.time()
# external services can run cloud sync and require to check if
# auto sync is enabled
if opts.get("check_autosync_enabled") and not autosyncenabled(ui, repo):
highlightstatus(
ui, _("automatic backup and synchronization " "is currently disabled\n")
ui, _("automatic backup and synchronization is currently disabled\n")
)
return 0
@ -279,7 +334,7 @@ def _docloudsync(ui, repo, **opts):
serv = service.get(ui, tokenlocator.token)
highlightstatus(ui, _("synchronizing '%s' with '%s'\n") % (reponame, workspace))
lastsyncstate = state.SyncState(repo)
lastsyncstate = state.SyncState(repo, workspace)
# external services can run cloud sync and know the lasest version
version = opts.get("workspace_version")
@ -287,7 +342,9 @@ def _docloudsync(ui, repo, **opts):
highlightstatus(ui, _("this version has been already synchronized\n"))
return 0
cloudrefs = serv.getreferences(reponame, workspace, lastsyncstate.version)
# cloudrefs are passed in cloud rejoin
if cloudrefs is None:
cloudrefs = serv.getreferences(reponame, workspace, lastsyncstate.version)
synced = False
pushfailures = set()
@ -424,7 +481,8 @@ def cloudrecover(ui, repo, **opts):
the repository from scratch.
"""
highlightstatus(ui, "clearing local commit cloud cache\n")
state.SyncState.erasestate(repo)
_, workspace = getrepoworkspace(ui, repo)
state.SyncState.erasestate(repo, workspace)
cloudsync(ui, repo, **opts)

View File

@ -241,8 +241,14 @@ class WorkspaceManager(object):
os.path.basename(self.ui.config("paths", "default")),
)
@property
def defaultworkspace(self):
"""Default workspace name"""
return self._getdefaultworkspacename()
@property
def workspace(self):
"""Current connected workspace (reads commitcloudrc file)"""
if self.repo.svfs.exists(self.filename):
with self.repo.svfs.open(self.filename, r"rb") as f:
workspaceconfig = config.config()

View File

@ -33,22 +33,12 @@ class SyncState(object):
)
@classmethod
def erasestate(cls, repo):
# get current workspace
workspace = commitcloudutil.getworkspacename(repo)
if not workspace:
raise commitcloudcommon.WorkspaceError(repo.ui, _("undefined workspace"))
def erasestate(cls, repo, workspace):
filename = cls._filename(workspace)
# clean up the current state in force recover mode
repo.svfs.tryunlink(filename)
def __init__(self, repo):
# get current workspace
workspace = commitcloudutil.getworkspacename(repo)
if not workspace:
raise commitcloudcommon.WorkspaceError(repo.ui, _("undefined workspace"))
def __init__(self, repo, workspace):
self.filename = self._filename(workspace)
repo = shareutil.getsrcrepo(repo)
self.repo = repo

View File

@ -1121,3 +1121,57 @@ Check subscription when join/leave and also scm service health check
repo_name=server
repo_root=$TESTTMP/client1/.hg
$ cd ..
Rejoin
$ rm -rf client2
$ mkdir client2
$ mkdir $TESTTMP/otherservicelocation
$ mkdir $TESTTMP/othertokenlocation
$ hg clone ssh://user@dummy/server client2 -q
$ cd client2
$ cat ../shared.rc >> .hg/hgrc
$ hg cloud reconnect --config "commitcloud.user_token_path=$TESTTMP/othertokenlocation" # invalid token
#commitcloud unable to reconnect: not authenticated with commit cloud on this host
$ hg cloud reconnect --config "commitcloud.servicelocation=$TESTTMP/otherservicelocation" # token is valid but server is different
#commitcloud trying to reconnect to the 'user/test/default' workspace for the 'server' repo
#commitcloud unable to reconnect: this workspace has been never connected to commit cloud for this repo
$ hg cloud reconnect # should be able to reconnect
#commitcloud trying to reconnect to the 'user/test/default' workspace for the 'server' repo
#commitcloud the repository is now reconnected
#commitcloud synchronizing 'server' with 'user/test/default'
pulling from ssh://user@dummy/server
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files (+1 heads)
adding changesets
adding manifests
adding file changes
added 2 changesets with 3 changes to 3 files
new changesets 3597ff85ead0:af621240884f
(run 'hg heads' to see heads, 'hg merge' to merge)
#commitcloud commits synchronized
$ hg trglog
o af621240884f 'stack 1 second'
|
o 81cd67693e59 'stack 1 first'
|
| o 799d22972c4e 'stack 2 second'
| |
| o 3597ff85ead0 'stack 2 first'
| |
@ | 97250524560a 'public 2' default/publicbookmark2 default/default
| |
o | acd5b9e8c656 'public' default/publicbookmark1
|/
o d20a80d4def3 'base'