diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -1074,6 +1074,11 @@ ) coreconfigitem( b'experimental', + b'sharesafe-auto-upgrade-shares', + default=False, +) +coreconfigitem( + b'experimental', b'single-head-per-branch', default=False, ) diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -582,12 +582,19 @@ elif shared: sourcerequires = _readrequires(sharedvfs, False) if requirementsmod.SHARESAFE_REQUIREMENT in sourcerequires: - ui.warn( - _( - b'warning: source repository supports share-safe functionality.' - b' Reshare to upgrade.\n' + if ui.configbool(b'experimental', b'sharesafe-auto-upgrade-shares'): + # prevent cyclic import localrepo -> upgrade -> localrepo + from . import upgrade + requirements = upgrade.upgrade_share_to_safe( + ui, hgvfs, storevfs, requirements, ) - ) + else: + ui.warn( + _( + b'warning: source repository supports share-safe functionality.' + b' Reshare to upgrade.\n' + ) + ) # The .hg/hgrc file may load extensions or contain config options # that influence repository construction. Attempt to load it and diff --git a/mercurial/upgrade.py b/mercurial/upgrade.py --- a/mercurial/upgrade.py +++ b/mercurial/upgrade.py @@ -12,7 +12,10 @@ error, hg, localrepo, + lock as lockmod, pycompat, + requirements as requirementsmod, + scmutil, ) from .upgrade_utils import ( @@ -20,6 +23,10 @@ engine as upgrade_engine, ) +from .utils import ( + stringutil, +) + allformatvariant = upgrade_actions.allformatvariant # search without '-' to support older form on newer client. @@ -268,3 +275,35 @@ b' be reshared.\n' ) ) + + +def upgrade_share_to_safe(ui, hgvfs, storevfs, current_requirements): + """Upgrades a share to use share-safe mechanism + + The upgrade will change the requirement of current repository that we are + loading. It may also fails to upgrade if we fails to get a lock. Hence + we need to update the caller about new set of repository requirements. + Therefore returns the set of new repository requirement. + """ + wlock = None + try: + wlock = lockmod.trylock(ui, hgvfs, b'wlock', 0, 0) + store_requirements = localrepo._readrequires(storevfs, False) + # after upgrade, store requires will be shared, so lets find + # the requirements which are not present in store and + # write them to share's .hg/requires + diffrequires = current_requirements - store_requirements + # add share-safe requirement as it will mark the share as share-safe + diffrequires.add(requirementsmod.SHARESAFE_REQUIREMENT) + scmutil.writerequires(hgvfs, diffrequires) + current_requirements.add(requirementsmod.SHARESAFE_REQUIREMENT) + ui.warn(_(b'repository upgraded to use share-safe mode\n')) + except error.LockError as e: + ui.warn( + _(b'failed to upgrade share, got error: %s\n') + % stringutil.forcebytestr(e.strerror) + ) + finally: + if wlock: + wlock.release() + return current_requirements diff --git a/tests/test-share-safe.t b/tests/test-share-safe.t --- a/tests/test-share-safe.t +++ b/tests/test-share-safe.t @@ -479,8 +479,63 @@ | o f3ba8b99bb6f897c87bbc1c07b75c6ddf43a4f77: added foo - $ hg unshare -R ../nss-share $ hg log -GT "{node}: {desc}\n" -R ../ss-share abort: share source does not support exp-sharesafe requirement [255] + + +Testing automatic upgrade of shares when config is set + + $ hg debugupgraderepo -q --run --config format.exp-share-safe=True + upgrade will perform the following actions: + + requirements + preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store + added: exp-sharesafe + + processed revlogs: + - all-filelogs + - changelog + - manifest + + repository upgraded to share safe mode, existing shares will still work in old non-safe mode. Re-share existing shares to use them in safe mode New shares will be created in safe mode. + $ hg debugrequirements + dotencode + exp-sharesafe + fncache + generaldelta + revlogv1 + sparserevlog + store + $ hg log -GT "{node}: {desc}\n" -R ../nss-share + warning: source repository supports share-safe functionality. Reshare to upgrade. + @ f63db81e6dde1d9c78814167f77fb1fb49283f4f: added bar + | + o f3ba8b99bb6f897c87bbc1c07b75c6ddf43a4f77: added foo + + +Check that if lock is taken, upgrade fails but read operation are successful + $ touch ../nss-share/.hg/wlock + $ hg log -GT "{node}: {desc}\n" -R ../nss-share --config experimental.sharesafe-auto-upgrade-shares=true + failed to upgrade share, got error: Lock held + @ f63db81e6dde1d9c78814167f77fb1fb49283f4f: added bar + | + o f3ba8b99bb6f897c87bbc1c07b75c6ddf43a4f77: added foo + + $ rm ../nss-share/.hg/wlock + $ hg log -GT "{node}: {desc}\n" -R ../nss-share --config experimental.sharesafe-auto-upgrade-shares=true + repository upgraded to use share-safe mode + @ f63db81e6dde1d9c78814167f77fb1fb49283f4f: added bar + | + o f3ba8b99bb6f897c87bbc1c07b75c6ddf43a4f77: added foo + + +Test that unshare works + + $ hg unshare -R ../nss-share + $ hg log -GT "{node}: {desc}\n" -R ../nss-share + @ f63db81e6dde1d9c78814167f77fb1fb49283f4f: added bar + | + o f3ba8b99bb6f897c87bbc1c07b75c6ddf43a4f77: added foo +