--- a/CHANGELOG Thu Nov 30 21:31:14 2017 -0800
+++ b/CHANGELOG Thu Nov 30 12:14:36 2017 -0500
@@ -1,6 +1,16 @@
Changelog
=========
+7.1.0 - in progress
+-------------------
+
+ * verbosity: respect --quiet for prev, next and summary
+
+topic (0.6.0)
+
+ * add a new 'serverminitopic' extension for minimal server support
+ (see `hg help -e serverminitopic` for details)
+
7.0.1 -- 2017-11-14
-------------------
--- a/hgext3rd/evolve/__init__.py Thu Nov 30 21:31:14 2017 -0800
+++ b/hgext3rd/evolve/__init__.py Thu Nov 30 12:14:36 2017 -0500
@@ -831,17 +831,10 @@
raise
def summaryhook(ui, repo):
- def write(fmt, count):
- s = fmt % count
- if count:
- ui.write(s)
- else:
- ui.note(s)
-
state = _evolvestateread(repo)
if state is not None:
# i18n: column positioning for "hg summary"
- ui.write(_('evolve: (evolve --continue)\n'))
+ ui.status(_('evolve: (evolve --continue)\n'))
@eh.extsetup
def obssummarysetup(ui):
@@ -2031,7 +2024,8 @@
finally:
lockmod.release(tr, lock)
- displayer.show(target)
+ if not repo.ui.quiet:
+ displayer.show(target)
def _findprevtarget(repo, displayer, movebookmark=False, topic=True):
target = bookmark = None
@@ -2174,7 +2168,8 @@
tr.close()
finally:
lockmod.release(tr, lock)
- displayer.show(c)
+ if not ui.quiet:
+ displayer.show(c)
result = 0
elif children:
ui.warn(_("ambigious next changeset:\n"))
--- a/hgext3rd/evolve/metadata.py Thu Nov 30 21:31:14 2017 -0800
+++ b/hgext3rd/evolve/metadata.py Thu Nov 30 12:14:36 2017 -0500
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-__version__ = '7.0.2.dev'
+__version__ = '7.1.0.dev'
testedwith = '4.1.3 4.2.3 4.3.2 4.4.1'
minimumhgversion = '4.1'
buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obshistory.py Thu Nov 30 21:31:14 2017 -0800
+++ b/hgext3rd/evolve/obshistory.py Thu Nov 30 12:14:36 2017 -0500
@@ -787,8 +787,15 @@
verb = 'split'
return {'verb': verb}
+# Use a more advanced version of obsfateverb that uses effect-flag
+if util.safehasattr(obsutil, 'obsfateverb'):
+
+ @eh.wrapfunction(obsutil, 'obsfateverb')
+ def obsfateverb(orig, *args, **kwargs):
+ return _successorsetverb(*args, **kwargs)['verb']
+
# Hijack callers of successorsetverb
-if util.safehasattr(obsutil, 'obsfateprinter'):
+elif util.safehasattr(obsutil, 'obsfateprinter'):
@eh.wrapfunction(obsutil, 'obsfateprinter')
def obsfateprinter(orig, successors, markers, ui):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/serverminitopic.py Thu Nov 30 12:14:36 2017 -0500
@@ -0,0 +1,226 @@
+"""enable a minimal verison of topic for server
+
+Non publishing repository will see topic as "branch:topic" in the branch field.
+
+In addition to adding the extensions, the feature must be manually enabled in the config:
+
+ [experimental]
+ server-mini-topic = yes
+"""
+import hashlib
+import contextlib
+
+from mercurial import (
+ branchmap,
+ context,
+ encoding,
+ extensions,
+ node,
+ registrar,
+ util,
+ wireproto,
+)
+
+if util.safehasattr(registrar, 'configitem'):
+
+ configtable = {}
+ configitem = registrar.configitem(configtable)
+ configitem('experimental', 'server-mini-topic',
+ default=False,
+ )
+
+def hasminitopic(repo):
+ """true if minitopic is enabled on the repository
+
+ (The value is cached on the repository)
+ """
+ enabled = getattr(repo, '_hasminitopic', None)
+ if enabled is None:
+ enabled = (repo.ui.configbool('experimental', 'server-mini-topic')
+ and not repo.publishing())
+ repo._hasminitopic = enabled
+ return enabled
+
+### make topic visible though "ctx.branch()"
+
+class topicchangectx(context.changectx):
+ """a sunclass of changectx that add topic to the branch name"""
+
+ def branch(self):
+ branch = super(topicchangectx, self).branch()
+ if hasminitopic(self._repo) and self.phase():
+ topic = self._changeset.extra.get('topic')
+ if topic is not None:
+ topic = encoding.tolocal(topic)
+ branch = '%s:%s' % (branch, topic)
+ return branch
+
+### avoid caching topic data in rev-branch-cache
+
+class revbranchcacheoverlay(object):
+ """revbranch mixin that don't use the cache for non public changeset"""
+
+ def _init__(self, *args, **kwargs):
+ super(revbranchcacheoverlay, self).__init__(*args, **kwargs)
+ if 'branchinfo' in vars(self):
+ del self.branchinfo
+
+ def branchinfo(self, rev):
+ """return branch name and close flag for rev, using and updating
+ persistent cache."""
+ phase = self._repo._phasecache.phase(self, rev)
+ if phase:
+ ctx = self._repo[rev]
+ return ctx.branch(), ctx.closesbranch()
+ return super(revbranchcacheoverlay, self).branchinfo(rev)
+
+def reposetup(ui, repo):
+ """install a repo class with a special revbranchcache"""
+
+ if hasminitopic(repo):
+ repo = repo.unfiltered()
+
+ class minitopicrepo(repo.__class__):
+ """repository subclass that install the modified cache"""
+
+ def revbranchcache(self):
+ if self._revbranchcache is None:
+ cache = super(minitopicrepo, self).revbranchcache()
+
+ class topicawarerbc(revbranchcacheoverlay, cache.__class__):
+ pass
+ cache.__class__ = topicawarerbc
+ if 'branchinfo' in vars(cache):
+ del cache.branchinfo
+ self._revbranchcache = cache
+ return self._revbranchcache
+
+ repo.__class__ = minitopicrepo
+
+### topic aware branch head cache
+
+def _phaseshash(repo, maxrev):
+ """uniq ID for a phase matching a set of rev"""
+ revs = set()
+ cl = repo.changelog
+ fr = cl.filteredrevs
+ nm = cl.nodemap
+ for roots in repo._phasecache.phaseroots[1:]:
+ for n in roots:
+ r = nm.get(n)
+ if r not in fr and r < maxrev:
+ revs.add(r)
+ key = node.nullid
+ revs = sorted(revs)
+ if revs:
+ s = hashlib.sha1()
+ for rev in revs:
+ s.update('%s;' % rev)
+ key = s.digest()
+ return key
+
+# needed to prevent reference used for 'super()' call using in branchmap.py to
+# no go into cycle. (yes, URG)
+_oldbranchmap = branchmap.branchcache
+
+@contextlib.contextmanager
+def oldbranchmap():
+ previous = branchmap.branchcache
+ try:
+ branchmap.branchcache = _oldbranchmap
+ yield
+ finally:
+ branchmap.branchcache = previous
+
+_publiconly = set([
+ 'base',
+ 'immutable',
+])
+
+def mighttopic(repo):
+ return hasminitopic(repo) and repo.filtername not in _publiconly
+
+class _topiccache(branchmap.branchcache): # combine me with branchmap.branchcache
+
+ def __init__(self, *args, **kwargs):
+ # super() call may fail otherwise
+ with oldbranchmap():
+ super(_topiccache, self).__init__(*args, **kwargs)
+ self.phaseshash = None
+
+ def copy(self):
+ """return an deep copy of the branchcache object"""
+ new = self.__class__(self, self.tipnode, self.tiprev, self.filteredhash,
+ self._closednodes)
+ new.phaseshash = self.phaseshash
+ return new
+
+ def validfor(self, repo):
+ """Is the cache content valid regarding a repo
+
+ - False when cached tipnode is unknown or if we detect a strip.
+ - True when cache is up to date or a subset of current repo."""
+ valid = super(_topiccache, self).validfor(repo)
+ if not valid:
+ return False
+ elif not mighttopic(repo) and self.phaseshash is None:
+ # phasehash at None means this is a branchmap
+ # coming from a public only set
+ return True
+ else:
+ try:
+ valid = self.phaseshash == _phaseshash(repo, self.tiprev)
+ return valid
+ except IndexError:
+ return False
+
+ def write(self, repo):
+ # we expect (hope) mutable set to be small enough to be that computing
+ # it all the time will be fast enough
+ if not mighttopic(repo):
+ super(_topiccache, self).write(repo)
+
+ def update(self, repo, revgen):
+ """Given a branchhead cache, self, that may have extra nodes or be
+ missing heads, and a generator of nodes that are strictly a superset of
+ heads missing, this function updates self to be correct.
+ """
+ super(_topiccache, self).update(repo, revgen)
+ if mighttopic(repo):
+ self.phaseshash = _phaseshash(repo, self.tiprev)
+
+def wrapread(orig, repo):
+ # Avoiding to write cache for filter where topic applies is a good step,
+ # but we need to also avoid reading it. Existing branchmap cache might
+ # exists before the turned the feature on.
+ if mighttopic(repo):
+ return None
+ return orig(repo)
+
+# advertise topic capabilities
+
+def wireprotocaps(orig, repo, proto):
+ caps = orig(repo, proto)
+ if hasminitopic(repo):
+ caps.append('topics')
+ return caps
+
+# wrap the necessary bit
+
+def wrapclass(container, oldname, new):
+ old = getattr(container, oldname)
+ if not issubclass(old, new):
+ targetclass = new
+ # check if someone else already wrapped the class and handle that
+ if not issubclass(new, old):
+ class targetclass(new, old):
+ pass
+ setattr(container, oldname, targetclass)
+ current = getattr(container, oldname)
+ assert issubclass(current, new), (current, new, targetclass)
+
+def uisetup(ui):
+ wrapclass(context, 'changectx', topicchangectx)
+ wrapclass(branchmap, 'branchcache', _topiccache)
+ extensions.wrapfunction(branchmap, 'read', wrapread)
+ extensions.wrapfunction(wireproto, '_capabilities', wireprotocaps)
--- a/hgext3rd/topic/__init__.py Thu Nov 30 21:31:14 2017 -0800
+++ b/hgext3rd/topic/__init__.py Thu Nov 30 12:14:36 2017 -0500
@@ -174,7 +174,7 @@
'topic.active': 'green',
}
-__version__ = '0.5.2.dev'
+__version__ = '0.6.0.dev'
testedwith = '4.1.3 4.2.3 4.3.3 4.4.1'
minimumhgversion = '4.1'
--- a/setup.py Thu Nov 30 21:31:14 2017 -0800
+++ b/setup.py Thu Nov 30 12:14:36 2017 -0500
@@ -19,6 +19,7 @@
return get_metadata()['minimumhgversion']
py_modules = [
+ 'hgext3rd.serverminitopic',
]
py_packages = [
'hgext3rd',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-minitopic.t Thu Nov 30 12:14:36 2017 -0500
@@ -0,0 +1,238 @@
+ $ . $TESTDIR/testlib/common.sh
+
+setup
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > share=
+ > blackbox=
+ > [web]
+ > allow_push = *
+ > push_ssl = no
+ > [phases]
+ > publish = False
+ > [paths]
+ > enabled = http://localhost:$HGPORT/
+ > disabled = http://localhost:$HGPORT2/
+ > EOF
+
+ $ hg init ./server-enabled
+ $ cat >> server-enabled/.hg/hgrc << EOF
+ > [extensions]
+ > serverminitopic=
+ > [experimental]
+ > server-mini-topic = yes
+ > EOF
+
+ $ hg share ./server-enabled ./server-disabled
+ updating working directory
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat >> server-disabled/.hg/hgrc << EOF
+ > [extensions]
+ > serverminitopic=
+ > [experimental]
+ > server-mini-topic = no
+ > EOF
+
+ $ hg init client-disabled
+ $ hg init client-enabled
+ $ cat >> client-enabled/.hg/hgrc << EOF
+ > [extensions]
+ > topic=
+ > EOF
+
+ $ hg serve -R server-enabled -p $HGPORT -d --pid-file hg1.pid --errorlog hg1.error
+ $ cat hg1.pid > $DAEMON_PIDS
+ $ hg serve -R server-disabled -p $HGPORT2 -d --pid-file hg2.pid --errorlog hg2.error
+ $ cat hg2.pid >> $DAEMON_PIDS
+
+ $ curl --silent http://localhost:$HGPORT/?cmd=capabilities | grep -o topics
+ topics
+ $ curl --silent http://localhost:$HGPORT2/?cmd=capabilities | grep -o topics
+ [1]
+
+Pushing first changesets to the servers
+--------------------------------------
+
+ $ cd client-enabled
+ $ mkcommit c_A0
+ $ hg push enabled
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ mkcommit c_B0
+ $ hg push disabled
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+ $ cat $TESTTMP/hg1.error
+ $ cat $TESTTMP/hg2.error
+
+Pushing new head
+----------------
+
+ $ hg up 'desc("c_A0")'
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ mkcommit c_C0
+ created new head
+ $ hg push enabled
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: push creates new remote head 22c9514ed811!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push disabled
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ abort: push creates new remote head 22c9514ed811!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+
+ $ curl --silent http://localhost:$HGPORT/?cmd=branchmap | sort
+ default 0ab6d544d0efd629fda056601cfe95e73d1af210
+ $ curl --silent http://localhost:$HGPORT2/?cmd=branchmap | sort
+ default 0ab6d544d0efd629fda056601cfe95e73d1af210
+ $ cat $TESTTMP/hg1.error
+ $ cat $TESTTMP/hg2.error
+
+Pushing new topic
+-----------------
+
+ $ hg merge
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ mkcommit c_D0
+ $ hg log -G
+ @ changeset: 3:9c660cf97499
+ |\ tag: tip
+ | | parent: 2:22c9514ed811
+ | | parent: 1:0ab6d544d0ef
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c_D0
+ | |
+ | o changeset: 2:22c9514ed811
+ | | parent: 0:14faebcf9752
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c_C0
+ | |
+ o | changeset: 1:0ab6d544d0ef
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c_B0
+ |
+ o changeset: 0:14faebcf9752
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c_A0
+
+ $ hg push enabled
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 2 changesets with 2 changes to 2 files
+ $ hg up 'desc("c_C0")'
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg topic topic_A
+ marked working directory as topic: topic_A
+ $ mkcommit c_E0
+ active topic 'topic_A' grew its first changeset
+ $ hg push disabled
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ abort: push creates new remote head f31af349535e!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push enabled
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files (+1 heads)
+
+ $ curl --silent http://localhost:$HGPORT/?cmd=branchmap | sort
+ default 9c660cf97499ae01ccb6894880455c6ffa4b19cf
+ default%3Atopic_A f31af349535e413b6023f11b51a6afccf4139180
+ $ curl --silent http://localhost:$HGPORT2/?cmd=branchmap | sort
+ default 9c660cf97499ae01ccb6894880455c6ffa4b19cf f31af349535e413b6023f11b51a6afccf4139180
+ $ cat $TESTTMP/hg1.error
+ $ cat $TESTTMP/hg2.error
+
+Pushing new head to a topic
+---------------------------
+
+ $ hg up 'desc("c_D0")'
+ 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg topic topic_A
+ marked working directory as topic: topic_A
+ $ mkcommit c_F0
+ $ hg log -G
+ @ changeset: 5:82c5842e0472
+ | tag: tip
+ | topic: topic_A
+ | parent: 3:9c660cf97499
+ | user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c_F0
+ |
+ | o changeset: 4:f31af349535e
+ | | topic: topic_A
+ | | parent: 2:22c9514ed811
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c_E0
+ | |
+ o | changeset: 3:9c660cf97499
+ |\| parent: 2:22c9514ed811
+ | | parent: 1:0ab6d544d0ef
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c_D0
+ | |
+ | o changeset: 2:22c9514ed811
+ | | parent: 0:14faebcf9752
+ | | user: test
+ | | date: Thu Jan 01 00:00:00 1970 +0000
+ | | summary: c_C0
+ | |
+ o | changeset: 1:0ab6d544d0ef
+ |/ user: test
+ | date: Thu Jan 01 00:00:00 1970 +0000
+ | summary: c_B0
+ |
+ o changeset: 0:14faebcf9752
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: c_A0
+
+ $ hg push enabled
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: push creates new remote head 82c5842e0472 on branch 'default:topic_A'!
+ (merge or see 'hg help push' for details about pushing new heads)
+ [255]
+ $ hg push disabled
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+ $ curl --silent http://localhost:$HGPORT/?cmd=branchmap | sort
+ default 9c660cf97499ae01ccb6894880455c6ffa4b19cf
+ default%3Atopic_A f31af349535e413b6023f11b51a6afccf4139180 82c5842e047215160763f81ae93ae42c65b20a63
+ $ curl --silent http://localhost:$HGPORT2/?cmd=branchmap | sort
+ default f31af349535e413b6023f11b51a6afccf4139180 82c5842e047215160763f81ae93ae42c65b20a63
+ $ cat $TESTTMP/hg1.error
+ $ cat $TESTTMP/hg2.error
--- a/tests/test-prev-next.t Thu Nov 30 21:31:14 2017 -0800
+++ b/tests/test-prev-next.t Thu Nov 30 12:14:36 2017 -0500
@@ -3,7 +3,7 @@
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
-hg prev -B should move active bookmark
+hg prev & next move to parent/child
$ hg init test-repo
$ cd test-repo
$ touch a
@@ -12,6 +12,18 @@
$ touch b
$ hg add b
$ hg commit -m 'added b'
+ $ hg prev
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ [0] added a
+ $ hg next
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ [1] added b
+
+hg prev & next respect --quiet
+ $ hg prev -q
+ $ hg next -q
+
+hg prev -B should move active bookmark
$ hg bookmark mark
$ hg bookmarks
* mark 1:6e742c9127b3
--- a/tests/test-topic-stack.t Thu Nov 30 21:31:14 2017 -0800
+++ b/tests/test-topic-stack.t Thu Nov 30 12:14:36 2017 -0500
@@ -864,13 +864,13 @@
| rewritten(parent, content) as dde94df880e9, e7ea874afbd5 by test (Thu Jan 01 00:00:00 1970 +0000)
|
x 907f7d3c2333 (18) c_G
- | rewritten as b24bab30ac12 by test (Thu Jan 01 00:00:00 1970 +0000)
+ | rewritten(content) as b24bab30ac12 by test (Thu Jan 01 00:00:00 1970 +0000)
|
x 3ab2eedae500 (13) c_G
- | rewritten as 907f7d3c2333 by test (Thu Jan 01 00:00:00 1970 +0000)
+ | rewritten(parent) as 907f7d3c2333 by test (Thu Jan 01 00:00:00 1970 +0000)
|
x c7d60a180d05 (6) c_G
- rewritten as 3ab2eedae500 by test (Thu Jan 01 00:00:00 1970 +0000)
+ rewritten(user) as 3ab2eedae500 by test (Thu Jan 01 00:00:00 1970 +0000)
$ hg export .
# HG changeset patch