From 4ff0279f0865f3e0eb65d10426c2648c83c18a84 Mon Sep 17 00:00:00 2001 From: Liubov Dmitrieva Date: Tue, 26 Jun 2018 12:34:42 -0700 Subject: [PATCH] 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 --- hgext/commitcloud/commitcloudcommands.py | 72 +++++++++++++++++++++--- hgext/commitcloud/commitcloudutil.py | 6 ++ hgext/commitcloud/state.py | 14 +---- tests/test-fb-hgext-commitcloud-sync.t | 54 ++++++++++++++++++ 4 files changed, 127 insertions(+), 19 deletions(-) diff --git a/hgext/commitcloud/commitcloudcommands.py b/hgext/commitcloud/commitcloudcommands.py index f321576e02..ae42375af8 100644 --- a/hgext/commitcloud/commitcloudcommands.py +++ b/hgext/commitcloud/commitcloudcommands.py @@ -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) diff --git a/hgext/commitcloud/commitcloudutil.py b/hgext/commitcloud/commitcloudutil.py index 5764350b2f..58b815c929 100644 --- a/hgext/commitcloud/commitcloudutil.py +++ b/hgext/commitcloud/commitcloudutil.py @@ -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() diff --git a/hgext/commitcloud/state.py b/hgext/commitcloud/state.py index 13aedf8305..c8b2d12826 100644 --- a/hgext/commitcloud/state.py +++ b/hgext/commitcloud/state.py @@ -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 diff --git a/tests/test-fb-hgext-commitcloud-sync.t b/tests/test-fb-hgext-commitcloud-sync.t index eddae44b0b..c55b63dadd 100644 --- a/tests/test-fb-hgext-commitcloud-sync.t +++ b/tests/test-fb-hgext-commitcloud-sync.t @@ -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' + +