--- a/Makefile Thu Nov 15 11:27:30 2012 -0600
+++ b/Makefile Fri Nov 16 10:20:32 2012 -0600
@@ -34,7 +34,7 @@
local:
$(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_hgexe -i build_mo
- $(PYTHON) hg version
+ env HGRCPATH= $(PYTHON) hg version
build:
$(PYTHON) setup.py $(PURE) build
--- a/hgext/convert/git.py Thu Nov 15 11:27:30 2012 -0600
+++ b/hgext/convert/git.py Fri Nov 16 10:20:32 2012 -0600
@@ -6,12 +6,24 @@
# GNU General Public License version 2 or any later version.
import os
-from mercurial import util
+from mercurial import util, config
from mercurial.node import hex, nullid
from mercurial.i18n import _
from common import NoRepo, commit, converter_source, checktool
+class submodule(object):
+ def __init__(self, path, node, url):
+ self.path = path
+ self.node = node
+ self.url = url
+
+ def hgsub(self):
+ return "%s = [git]%s" % (self.path, self.url)
+
+ def hgsubstate(self):
+ return "%s %s" % (self.node, self.path)
+
class convert_git(converter_source):
# Windows does not support GIT_DIR= construct while other systems
# cannot remove environment variable. Just assume none have
@@ -55,6 +67,7 @@
checktool('git', 'git')
self.path = path
+ self.submodules = []
def getheads(self):
if not self.rev:
@@ -76,16 +89,57 @@
return data
def getfile(self, name, rev):
- data = self.catfile(rev, "blob")
- mode = self.modecache[(name, rev)]
+ if name == '.hgsub':
+ data = '\n'.join([m.hgsub() for m in self.submoditer()])
+ mode = ''
+ elif name == '.hgsubstate':
+ data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
+ mode = ''
+ else:
+ data = self.catfile(rev, "blob")
+ mode = self.modecache[(name, rev)]
return data, mode
+ def submoditer(self):
+ null = hex(nullid)
+ for m in sorted(self.submodules, key=lambda p: p.path):
+ if m.node != null:
+ yield m
+
+ def parsegitmodules(self, content):
+ """Parse the formatted .gitmodules file, example file format:
+ [submodule "sub"]\n
+ \tpath = sub\n
+ \turl = git://giturl\n
+ """
+ self.submodules = []
+ c = config.config()
+ # Each item in .gitmodules starts with \t that cant be parsed
+ c.parse('.gitmodules', content.replace('\t',''))
+ for sec in c.sections():
+ s = c[sec]
+ if 'url' in s and 'path' in s:
+ self.submodules.append(submodule(s['path'], '', s['url']))
+
+ def retrievegitmodules(self, version):
+ modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
+ if ret:
+ raise util.Abort(_('cannot read submodules config file in %s') %
+ version)
+ self.parsegitmodules(modules)
+ for m in self.submodules:
+ node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
+ if ret:
+ continue
+ m.node = node.strip()
+
def getchanges(self, version):
self.modecache = {}
fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
changes = []
seen = set()
entry = None
+ subexists = False
for l in fh.read().split('\x00'):
if not entry:
if not l.startswith(':'):
@@ -97,15 +151,24 @@
seen.add(f)
entry = entry.split()
h = entry[3]
- if entry[1] == '160000':
- raise util.Abort('git submodules are not supported!')
p = (entry[1] == "100755")
s = (entry[1] == "120000")
- self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
- changes.append((f, h))
+
+ if f == '.gitmodules':
+ subexists = True
+ changes.append(('.hgsub', ''))
+ elif entry[1] == '160000' or entry[0] == ':160000':
+ subexists = True
+ else:
+ self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
+ changes.append((f, h))
entry = None
if fh.close():
raise util.Abort(_('cannot read changes in %s') % version)
+
+ if subexists:
+ self.retrievegitmodules(version)
+ changes.append(('.hgsubstate', ''))
return (changes, {})
def getcommit(self, version):
--- a/hgext/convert/hg.py Thu Nov 15 11:27:30 2012 -0600
+++ b/hgext/convert/hg.py Fri Nov 16 10:20:32 2012 -0600
@@ -219,9 +219,10 @@
return
self.ui.status(_("updating bookmarks\n"))
+ destmarks = self.repo._bookmarks
for bookmark in updatedbookmark:
- self.repo._bookmarks[bookmark] = bin(updatedbookmark[bookmark])
- bookmarks.write(self.repo)
+ destmarks[bookmark] = bin(updatedbookmark[bookmark])
+ destmarks.write()
def hascommit(self, rev):
if rev not in self.repo and self.clonebranches:
--- a/hgext/histedit.py Thu Nov 15 11:27:30 2012 -0600
+++ b/hgext/histedit.py Fri Nov 16 10:20:32 2012 -0600
@@ -144,7 +144,6 @@
import pickle
import os
-from mercurial import bookmarks
from mercurial import cmdutil
from mercurial import discovery
from mercurial import error
@@ -740,12 +739,13 @@
# nothing to move
moves.append((bk, new[-1]))
if moves:
+ marks = repo._bookmarks
for mark, new in moves:
- old = repo._bookmarks[mark]
+ old = marks[mark]
ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
% (mark, node.short(old), node.short(new)))
- repo._bookmarks[mark] = new
- bookmarks.write(repo)
+ marks[mark] = new
+ marks.write()
def cleanupnode(ui, repo, name, nodes):
"""strip a group of nodes from the repository
--- a/hgext/mq.py Thu Nov 15 11:27:30 2012 -0600
+++ b/hgext/mq.py Fri Nov 16 10:20:32 2012 -0600
@@ -63,7 +63,7 @@
from mercurial.node import bin, hex, short, nullid, nullrev
from mercurial.lock import release
from mercurial import commands, cmdutil, hg, scmutil, util, revset
-from mercurial import repair, extensions, error, phases, bookmarks
+from mercurial import repair, extensions, error, phases
from mercurial import patch as patchmod
import os, re, errno, shutil
@@ -1675,9 +1675,10 @@
patchf.write(chunk)
patchf.close()
+ marks = repo._bookmarks
for bm in bmlist:
- repo._bookmarks[bm] = n
- bookmarks.write(repo)
+ marks[bm] = n
+ marks.write()
self.applied.append(statusentry(n, patchfn))
except: # re-raises
@@ -2999,7 +3000,7 @@
revs.update(set(rsrevs))
if not revs:
del marks[mark]
- repo._writebookmarks(mark)
+ marks.write()
ui.write(_("bookmark '%s' deleted\n") % mark)
if not revs:
@@ -3049,7 +3050,7 @@
if opts.get('bookmark'):
del marks[mark]
- repo._writebookmarks(marks)
+ marks.write()
ui.write(_("bookmark '%s' deleted\n") % mark)
repo.mq.strip(repo, revs, backup=backup, update=update,
--- a/hgext/rebase.py Thu Nov 15 11:27:30 2012 -0600
+++ b/hgext/rebase.py Fri Nov 16 10:20:32 2012 -0600
@@ -479,13 +479,14 @@
def updatebookmarks(repo, nstate, originalbookmarks, **opts):
'Move bookmarks to their correct changesets'
+ marks = repo._bookmarks
for k, v in originalbookmarks.iteritems():
if v in nstate:
if nstate[v] != nullmerge:
# update the bookmarks for revs that have moved
- repo._bookmarks[k] = nstate[v]
+ marks[k] = nstate[v]
- bookmarks.write(repo)
+ marks.write()
def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
external):
--- a/mercurial/bookmarks.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/bookmarks.py Fri Nov 16 10:20:32 2012 -0600
@@ -7,35 +7,75 @@
from mercurial.i18n import _
from mercurial.node import hex
-from mercurial import encoding, error, util, obsolete, phases
+from mercurial import encoding, error, util, obsolete
import errno, os
-def read(repo):
- '''Parse .hg/bookmarks file and return a dictionary
+class bmstore(dict):
+ """Storage for bookmarks.
+
+ This object should do all bookmark reads and writes, so that it's
+ fairly simple to replace the storage underlying bookmarks without
+ having to clone the logic surrounding bookmarks.
+
+ This particular bmstore implementation stores bookmarks as
+ {hash}\s{name}\n (the same format as localtags) in
+ .hg/bookmarks. The mapping is stored as {name: nodeid}.
+
+ This class does NOT handle the "current" bookmark state at this
+ time.
+ """
- Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
- in the .hg/bookmarks file.
- Read the file and return a (name=>nodeid) dictionary
- '''
- bookmarks = {}
- try:
- for line in repo.opener('bookmarks'):
- line = line.strip()
- if not line:
- continue
- if ' ' not in line:
- repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
- continue
- sha, refspec = line.split(' ', 1)
- refspec = encoding.tolocal(refspec)
+ def __init__(self, repo):
+ dict.__init__(self)
+ self._repo = repo
+ try:
+ for line in repo.vfs('bookmarks'):
+ line = line.strip()
+ if not line:
+ continue
+ if ' ' not in line:
+ repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
+ % line)
+ continue
+ sha, refspec = line.split(' ', 1)
+ refspec = encoding.tolocal(refspec)
+ try:
+ self[refspec] = repo.changelog.lookup(sha)
+ except LookupError:
+ pass
+ except IOError, inst:
+ if inst.errno != errno.ENOENT:
+ raise
+
+ def write(self):
+ '''Write bookmarks
+
+ Write the given bookmark => hash dictionary to the .hg/bookmarks file
+ in a format equal to those of localtags.
+
+ We also store a backup of the previous state in undo.bookmarks that
+ can be copied back on rollback.
+ '''
+ repo = self._repo
+ if repo._bookmarkcurrent not in self:
+ setcurrent(repo, None)
+
+ wlock = repo.wlock()
+ try:
+
+ file = repo.vfs('bookmarks', 'w', atomictemp=True)
+ for name, node in self.iteritems():
+ file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
+ file.close()
+
+ # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
try:
- bookmarks[refspec] = repo.changelog.lookup(sha)
- except LookupError:
+ os.utime(repo.sjoin('00changelog.i'), None)
+ except OSError:
pass
- except IOError, inst:
- if inst.errno != errno.ENOENT:
- raise
- return bookmarks
+
+ finally:
+ wlock.release()
def readcurrent(repo):
'''Get the current bookmark
@@ -60,37 +100,6 @@
file.close()
return mark
-def write(repo):
- '''Write bookmarks
-
- Write the given bookmark => hash dictionary to the .hg/bookmarks file
- in a format equal to those of localtags.
-
- We also store a backup of the previous state in undo.bookmarks that
- can be copied back on rollback.
- '''
- refs = repo._bookmarks
-
- if repo._bookmarkcurrent not in refs:
- setcurrent(repo, None)
-
- wlock = repo.wlock()
- try:
-
- file = repo.opener('bookmarks', 'w', atomictemp=True)
- for refspec, node in refs.iteritems():
- file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
- file.close()
-
- # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
- try:
- os.utime(repo.sjoin('00changelog.i'), None)
- except OSError:
- pass
-
- finally:
- wlock.release()
-
def setcurrent(repo, mark):
'''Set the name of the bookmark that we are currently on
@@ -152,7 +161,7 @@
if mark != cur:
del marks[mark]
if update:
- repo._writebookmarks(marks)
+ marks.write()
return update
def listbookmarks(repo):
@@ -179,7 +188,7 @@
if new not in repo:
return False
marks[key] = repo[new].node()
- write(repo)
+ marks.write()
return True
finally:
w.release()
@@ -188,16 +197,17 @@
ui.debug("checking for updated bookmarks\n")
rb = remote.listkeys('bookmarks')
changed = False
+ localmarks = repo._bookmarks
for k in rb.keys():
- if k in repo._bookmarks:
- nr, nl = rb[k], repo._bookmarks[k]
+ if k in localmarks:
+ nr, nl = rb[k], localmarks[k]
if nr in repo:
cr = repo[nr]
cl = repo[nl]
if cl.rev() >= cr.rev():
continue
if validdest(repo, cl, cr):
- repo._bookmarks[k] = cr.node()
+ localmarks[k] = cr.node()
changed = True
ui.status(_("updating bookmark %s\n") % k)
else:
@@ -208,7 +218,7 @@
# find a unique @ suffix
for x in range(1, 100):
n = '%s@%d' % (kd, x)
- if n not in repo._bookmarks:
+ if n not in localmarks:
break
# try to use an @pathalias suffix
# if an @pathalias already exists, we overwrite (update) it
@@ -216,17 +226,17 @@
if path == u:
n = '%s@%s' % (kd, p)
- repo._bookmarks[n] = cr.node()
+ localmarks[n] = cr.node()
changed = True
ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
elif rb[k] in repo:
# add remote bookmarks for changes we already have
- repo._bookmarks[k] = repo[rb[k]].node()
+ localmarks[k] = repo[rb[k]].node()
changed = True
ui.status(_("adding remote bookmark %s\n") % k)
if changed:
- write(repo)
+ localmarks.write()
def diff(ui, dst, src):
ui.status(_("searching for changed bookmarks\n"))
@@ -263,14 +273,10 @@
while len(validdests) != plen:
plen = len(validdests)
succs = set(c.node() for c in validdests)
- for c in validdests:
- if c.phase() > phases.public:
- # obsolescence marker does not apply to public changeset
- succs.update(obsolete.allsuccessors(repo.obsstore,
- [c.node()]))
+ mutable = [c.node() for c in validdests if c.mutable()]
+ succs.update(obsolete.allsuccessors(repo.obsstore, mutable))
known = (n for n in succs if n in nm)
validdests = set(repo.set('%ln::', known))
- validdests.remove(old)
return new in validdests
else:
return old.descendant(new)
--- a/mercurial/bundlerepo.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/bundlerepo.py Fri Nov 16 10:20:32 2012 -0600
@@ -33,6 +33,7 @@
self.basemap = {}
n = len(self)
chain = None
+ self.bundlenodes = []
while True:
chunkdata = bundle.deltachunk(chain)
if not chunkdata:
@@ -48,6 +49,7 @@
start = bundle.tell() - size
link = linkmapper(cs)
+ self.bundlenodes.append(node)
if node in self.nodemap:
# this can happen if two branches make the same change
chain = node
--- a/mercurial/cmdutil.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/cmdutil.py Fri Nov 16 10:20:32 2012 -0600
@@ -10,7 +10,7 @@
import os, sys, errno, re, tempfile
import util, scmutil, templater, patch, error, templatekw, revlog, copies
import match as matchmod
-import subrepo, context, repair, bookmarks, graphmod, revset, phases, obsolete
+import subrepo, context, repair, graphmod, revset, phases, obsolete
import changelog
import lock as lockmod
@@ -1759,9 +1759,10 @@
# Move bookmarks from old parent to amend commit
bms = repo.nodebookmarks(old.node())
if bms:
+ marks = repo._bookmarks
for bm in bms:
- repo._bookmarks[bm] = newid
- bookmarks.write(repo)
+ marks[bm] = newid
+ marks.write()
#commit the whole amend process
if obsolete._enabled and newid != old.node():
# mark the new changeset as successor of the rewritten one
--- a/mercurial/commands.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/commands.py Fri Nov 16 10:20:32 2012 -0600
@@ -821,7 +821,7 @@
if mark == repo._bookmarkcurrent:
bookmarks.setcurrent(repo, None)
del marks[mark]
- bookmarks.write(repo)
+ marks.write()
elif rename:
if mark is None:
@@ -834,7 +834,7 @@
if repo._bookmarkcurrent == rename and not inactive:
bookmarks.setcurrent(repo, mark)
del marks[rename]
- bookmarks.write(repo)
+ marks.write()
elif mark is not None:
mark = checkformat(mark)
@@ -848,7 +848,7 @@
marks[mark] = cur
if not inactive and cur == marks[mark]:
bookmarks.setcurrent(repo, mark)
- bookmarks.write(repo)
+ marks.write()
# Same message whether trying to deactivate the current bookmark (-i
# with no NAME) or listing bookmarks
@@ -1321,11 +1321,12 @@
elif marks:
ui.debug('moving bookmarks %r from %s to %s\n' %
(marks, old.hex(), hex(node)))
+ newmarks = repo._bookmarks
for bm in marks:
- repo._bookmarks[bm] = node
+ newmarks[bm] = node
if bm == current:
bookmarks.setcurrent(repo, bm)
- bookmarks.write(repo)
+ newmarks.write()
else:
e = cmdutil.commiteditor
if opts.get('force_editor'):
@@ -4206,6 +4207,9 @@
Returns 0 on success.
"""
+
+ fm = ui.formatter('manifest', opts)
+
if opts.get('all'):
if rev or node:
raise util.Abort(_("can't specify a revision with --all"))
@@ -4223,7 +4227,9 @@
finally:
lock.release()
for f in res:
- ui.write("%s\n" % f)
+ fm.startitem()
+ fm.write("path", '%s\n', f)
+ fm.end()
return
if rev and node:
@@ -4232,14 +4238,17 @@
if not node:
node = rev
- decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
+ char = {'l': '@', 'x': '*', '': ''}
+ mode = {'l': '644', 'x': '755', '': '644'}
ctx = scmutil.revsingle(repo, node)
+ mf = ctx.manifest()
for f in ctx:
- if ui.debugflag:
- ui.write("%40s " % hex(ctx.manifest()[f]))
- if ui.verbose:
- ui.write(decor[ctx.flags(f)])
- ui.write("%s\n" % f)
+ fm.startitem()
+ fl = ctx[f].flags()
+ fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
+ fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
+ fm.write('path', '%s\n', f)
+ fm.end()
@command('^merge',
[('f', 'force', None, _('force a merge with outstanding changes')),
@@ -4665,11 +4674,12 @@
# update specified bookmarks
if opts.get('bookmark'):
+ marks = repo._bookmarks
for b in opts['bookmark']:
# explicit pull overrides local bookmark if any
ui.status(_("importing bookmark %s\n") % b)
- repo._bookmarks[b] = repo[rb[b]].node()
- bookmarks.write(repo)
+ marks[b] = repo[rb[b]].node()
+ marks.write()
return ret
@@ -5426,17 +5436,16 @@
copy = copies.pathcopies(repo[node1], repo[node2])
fm = ui.formatter('status', opts)
- format = '%s %s' + end
- if opts.get('no_status'):
- format = '%.0s%s' + end
+ fmt = '%s' + end
+ showchar = not opts.get('no_status')
for state, char, files in changestates:
if state in show:
label = 'status.' + state
for f in files:
fm.startitem()
- fm.write("status path", format, char,
- repo.pathto(f, cwd), label=label)
+ fm.condwrite(showchar, 'status', '%s ', char, label=label)
+ fm.write('path', fmt, repo.pathto(f, cwd), label=label)
if f in copy:
fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
label='status.copied')
@@ -5742,7 +5751,7 @@
release(lock, wlock)
@command('tags', [], '')
-def tags(ui, repo):
+def tags(ui, repo, **opts):
"""list repository tags
This lists both regular and local tags. When the -v/--verbose
@@ -5751,27 +5760,27 @@
Returns 0 on success.
"""
+ fm = ui.formatter('tags', opts)
hexfunc = ui.debugflag and hex or short
tagtype = ""
for t, n in reversed(repo.tagslist()):
- if ui.quiet:
- ui.write("%s\n" % t, label='tags.normal')
- continue
-
hn = hexfunc(n)
- r = "%5d:%s" % (repo.changelog.rev(n), hn)
- rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
- spaces = " " * (30 - encoding.colwidth(t))
-
- tag = ui.label(t, 'tags.normal')
- if ui.verbose:
- if repo.tagtype(t) == 'local':
- tagtype = " local"
- tag = ui.label(t, 'tags.local')
- else:
- tagtype = ""
- ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
+ label = 'tags.normal'
+ tagtype = ''
+ if repo.tagtype(t) == 'local':
+ label = 'tags.local'
+ tagtype = 'local'
+
+ fm.startitem()
+ fm.write('tag', '%s', t, label=label)
+ fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
+ fm.condwrite(not ui.quiet, 'rev id', fmt,
+ repo.changelog.rev(n), hn, label=label)
+ fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
+ tagtype, label=label)
+ fm.plain('\n')
+ fm.end()
@command('tip',
[('p', 'patch', None, _('show patch')),
--- a/mercurial/formatter.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/formatter.py Fri Nov 16 10:20:32 2012 -0600
@@ -31,6 +31,10 @@
'''do default text output while assigning data to item'''
for k, v in zip(fields.split(), fielddata):
self._item[k] = v
+ def condwrite(self, cond, fields, deftext, *fielddata, **opts):
+ '''do conditional write (primarily for plain formatter)'''
+ for k, v in zip(fields.split(), fielddata):
+ self._item[k] = v
def plain(self, text, **opts):
'''show raw text for non-templated mode'''
pass
@@ -51,6 +55,10 @@
pass
def write(self, fields, deftext, *fielddata, **opts):
self._ui.write(deftext % fielddata, **opts)
+ def condwrite(self, cond, fields, deftext, *fielddata, **opts):
+ '''do conditional write'''
+ if cond:
+ self._ui.write(deftext % fielddata, **opts)
def plain(self, text, **opts):
self._ui.write(text, **opts)
def end(self):
--- a/mercurial/help/config.txt Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/help/config.txt Fri Nov 16 10:20:32 2012 -0600
@@ -1295,6 +1295,10 @@
(DEPRECATED) Whether to allow .zip downloading of repository
revisions. Default is False. This feature creates temporary files.
+``archivesubrepos``
+ Whether to recurse into subrepositories when archiving. Default is
+ False.
+
``baseurl``
Base URL to use when publishing URLs in other locations, so
third-party tools like email notification hooks can construct
--- a/mercurial/hg.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/hg.py Fri Nov 16 10:20:32 2012 -0600
@@ -171,11 +171,14 @@
r = repository(ui, root)
default = srcrepo.ui.config('paths', 'default')
- if default:
- fp = r.opener("hgrc", "w", text=True)
- fp.write("[paths]\n")
- fp.write("default = %s\n" % default)
- fp.close()
+ if not default:
+ # set default to source for being able to clone subrepos
+ default = os.path.abspath(util.urllocalpath(origsource))
+ fp = r.opener("hgrc", "w", text=True)
+ fp.write("[paths]\n")
+ fp.write("default = %s\n" % default)
+ fp.close()
+ r.ui.setconfig('paths', 'default', default)
if update:
r.ui.status(_("updating working directory\n"))
@@ -391,14 +394,15 @@
destrepo = destpeer.local()
if destrepo and srcpeer.capable("pushkey"):
rb = srcpeer.listkeys('bookmarks')
+ marks = destrepo._bookmarks
for k, n in rb.iteritems():
try:
m = destrepo.lookup(n)
- destrepo._bookmarks[k] = m
+ marks[k] = m
except error.RepoLookupError:
pass
if rb:
- bookmarks.write(destrepo)
+ marks.write()
elif srcrepo and destpeer.capable("pushkey"):
for k, n in srcrepo._bookmarks.iteritems():
destpeer.pushkey('bookmarks', k, '', hex(n))
--- a/mercurial/hgweb/webcommands.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/hgweb/webcommands.py Fri Nov 16 10:20:32 2012 -0600
@@ -14,6 +14,7 @@
from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
from mercurial import graphmod, patch
from mercurial import help as helpmod
+from mercurial import scmutil
from mercurial.i18n import _
# __all__ is populated with the allowed commands. Be sure to add to it if
@@ -799,7 +800,11 @@
headers.append(('Content-Encoding', encoding))
req.header(headers)
req.respond(HTTP_OK)
- archival.archive(web.repo, req, cnode, artype, prefix=name)
+
+ ctx = webutil.changectx(web.repo, req)
+ archival.archive(web.repo, req, cnode, artype, prefix=name,
+ matchfn=scmutil.match(ctx, []),
+ subrepos=web.configbool("web", "archivesubrepos"))
return []
--- a/mercurial/localrepo.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/localrepo.py Fri Nov 16 10:20:32 2012 -0600
@@ -265,15 +265,12 @@
@filecache('bookmarks')
def _bookmarks(self):
- return bookmarks.read(self)
+ return bookmarks.bmstore(self)
@filecache('bookmarks.current')
def _bookmarkcurrent(self):
return bookmarks.readcurrent(self)
- def _writebookmarks(self, marks):
- bookmarks.write(self)
-
def bookmarkheads(self, bookmark):
name = bookmark.split('@', 1)[0]
heads = []
--- a/mercurial/mdiff.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/mdiff.py Fri Nov 16 10:20:32 2012 -0600
@@ -7,7 +7,7 @@
from i18n import _
import bdiff, mpatch, util
-import re, struct
+import re, struct, base85, zlib
def splitnewlines(text):
'''like str.splitlines, but only split on newlines.'''
@@ -142,20 +142,7 @@
yield s, type
yield s1, '='
-def diffline(revs, a, b, opts):
- parts = ['diff']
- if opts.git:
- parts.append('--git')
- if revs and not opts.git:
- parts.append(' '.join(["-r %s" % rev for rev in revs]))
- if opts.git:
- parts.append('a/%s' % a)
- parts.append('b/%s' % b)
- else:
- parts.append(a)
- return ' '.join(parts) + '\n'
-
-def unidiff(a, ad, b, bd, fn1, fn2, r=None, opts=defaultopts):
+def unidiff(a, ad, b, bd, fn1, fn2, opts=defaultopts):
def datetag(date, fn=None):
if not opts.git and not opts.nodates:
return '\t%s\n' % date
@@ -206,9 +193,6 @@
if l[ln][-1] != '\n':
l[ln] += "\n\ No newline at end of file\n"
- if r:
- l.insert(0, diffline(r, fn1, fn2, opts))
-
return "".join(l)
# creates a headerless unified diff
@@ -314,6 +298,41 @@
for x in yieldhunk(hunk):
yield x
+def b85diff(to, tn):
+ '''print base85-encoded binary diff'''
+ def fmtline(line):
+ l = len(line)
+ if l <= 26:
+ l = chr(ord('A') + l - 1)
+ else:
+ l = chr(l - 26 + ord('a') - 1)
+ return '%c%s\n' % (l, base85.b85encode(line, True))
+
+ def chunk(text, csize=52):
+ l = len(text)
+ i = 0
+ while i < l:
+ yield text[i:i + csize]
+ i += csize
+
+ if to is None:
+ to = ''
+ if tn is None:
+ tn = ''
+
+ if to == tn:
+ return ''
+
+ # TODO: deltas
+ ret = []
+ ret.append('GIT binary patch\n')
+ ret.append('literal %s\n' % len(tn))
+ for l in chunk(zlib.compress(tn)):
+ ret.append(fmtline(l))
+ ret.append('\n')
+
+ return ''.join(ret)
+
def patchtext(bin):
pos = 0
t = []
--- a/mercurial/patch.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/patch.py Fri Nov 16 10:20:32 2012 -0600
@@ -1514,44 +1514,6 @@
finally:
fp.close()
-def b85diff(to, tn):
- '''print base85-encoded binary diff'''
- def gitindex(text):
- if not text:
- return hex(nullid)
- l = len(text)
- s = util.sha1('blob %d\0' % l)
- s.update(text)
- return s.hexdigest()
-
- def fmtline(line):
- l = len(line)
- if l <= 26:
- l = chr(ord('A') + l - 1)
- else:
- l = chr(l - 26 + ord('a') - 1)
- return '%c%s\n' % (l, base85.b85encode(line, True))
-
- def chunk(text, csize=52):
- l = len(text)
- i = 0
- while i < l:
- yield text[i:i + csize]
- i += csize
-
- tohash = gitindex(to)
- tnhash = gitindex(tn)
- if tohash == tnhash:
- return ""
-
- # TODO: deltas
- ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
- (tohash, tnhash, len(tn))]
- for l in chunk(zlib.compress(tn)):
- ret.append(fmtline(l))
- ret.append('\n')
- return ''.join(ret)
-
class GitDiffRequired(Exception):
pass
@@ -1622,9 +1584,8 @@
return []
revs = None
- if not repo.ui.quiet:
- hexfunc = repo.ui.debugflag and hex or short
- revs = [hexfunc(node) for node in [node1, node2] if node]
+ hexfunc = repo.ui.debugflag and hex or short
+ revs = [hexfunc(node) for node in [node1, node2] if node]
copy = {}
if opts.git or opts.upgrade:
@@ -1690,18 +1651,46 @@
'''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
return difflabel(diff, *args, **kw)
-
-def _addmodehdr(header, omode, nmode):
- if omode != nmode:
- header.append('old mode %s\n' % omode)
- header.append('new mode %s\n' % nmode)
-
def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
copy, getfilectx, opts, losedatafn, prefix):
def join(f):
return os.path.join(prefix, f)
+ def addmodehdr(header, omode, nmode):
+ if omode != nmode:
+ header.append('old mode %s\n' % omode)
+ header.append('new mode %s\n' % nmode)
+
+ def addindexmeta(meta, revs):
+ if opts.git:
+ i = len(revs)
+ if i==2:
+ meta.append('index %s..%s\n' % tuple(revs))
+ elif i==3:
+ meta.append('index %s,%s..%s\n' % tuple(revs))
+
+ def gitindex(text):
+ if not text:
+ return hex(nullid)
+ l = len(text)
+ s = util.sha1('blob %d\0' % l)
+ s.update(text)
+ return s.hexdigest()
+
+ def diffline(a, b, revs):
+ if opts.git:
+ line = 'diff --git a/%s b/%s\n' % (a, b)
+ elif not repo.ui.quiet:
+ if revs:
+ revinfo = ' '.join(["-r %s" % rev for rev in revs])
+ line = 'diff %s %s\n' % (revinfo, a)
+ else:
+ line = 'diff %s\n' % a
+ else:
+ line = ''
+ return line
+
date1 = util.datestr(ctx1.date())
man1 = ctx1.manifest()
@@ -1733,7 +1722,7 @@
else:
a = copyto[f]
omode = gitmode[man1.flags(a)]
- _addmodehdr(header, omode, mode)
+ addmodehdr(header, omode, mode)
if a in removed and a not in gone:
op = 'rename'
gone.add(a)
@@ -1779,22 +1768,24 @@
nflag = ctx2.flags(f)
binary = util.binary(to) or util.binary(tn)
if opts.git:
- _addmodehdr(header, gitmode[oflag], gitmode[nflag])
+ addmodehdr(header, gitmode[oflag], gitmode[nflag])
if binary:
dodiff = 'binary'
elif binary or nflag != oflag:
losedatafn(f)
- if opts.git:
- header.insert(0, mdiff.diffline(revs, join(a), join(b), opts))
if dodiff:
+ if opts.git or revs:
+ header.insert(0, diffline(join(a), join(b), revs))
if dodiff == 'binary':
- text = b85diff(to, tn)
+ text = mdiff.b85diff(to, tn)
+ if text:
+ addindexmeta(header, [gitindex(to), gitindex(tn)])
else:
text = mdiff.unidiff(to, date1,
# ctx2 date may be dynamic
tn, util.datestr(ctx2.date()),
- join(a), join(b), revs, opts=opts)
+ join(a), join(b), opts=opts)
if header and (text or len(header) > 1):
yield ''.join(header)
if text:
--- a/mercurial/repair.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/repair.py Fri Nov 16 10:20:32 2012 -0600
@@ -6,7 +6,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-from mercurial import changegroup, bookmarks
+from mercurial import changegroup
from mercurial.node import short
from mercurial.i18n import _
import os
@@ -181,7 +181,7 @@
for m in updatebm:
bm[m] = repo[newbmtarget].node()
- bookmarks.write(repo)
+ bm.write()
except: # re-raises
if backupfile:
ui.warn(_("strip failed, full bundle stored in '%s'\n")
--- a/mercurial/revset.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/revset.py Fri Nov 16 10:20:32 2012 -0600
@@ -442,6 +442,19 @@
bumped = obsmod.getrevs(repo, 'bumped')
return [r for r in subset if r in bumped]
+def bundle(repo, subset, x):
+ """``bundle()``
+ Changesets in the bundle.
+
+ Bundle must be specified by the -R option."""
+
+ try:
+ bundlenodes = repo.changelog.bundlenodes
+ except AttributeError:
+ raise util.Abort(_("no bundle provided - specify with -R"))
+ revs = set(repo[n].rev() for n in bundlenodes)
+ return [r for r in subset if r in revs]
+
def checkstatus(repo, subset, pat, field):
m = None
s = []
@@ -1513,6 +1526,7 @@
"branch": branch,
"branchpoint": branchpoint,
"bumped": bumped,
+ "bundle": bundle,
"children": children,
"closed": closed,
"contains": contains,
--- a/mercurial/scmutil.py Thu Nov 15 11:27:30 2012 -0600
+++ b/mercurial/scmutil.py Fri Nov 16 10:20:32 2012 -0600
@@ -279,37 +279,38 @@
mode += "b" # for that other OS
nlink = -1
- dirname, basename = util.split(f)
- # If basename is empty, then the path is malformed because it points
- # to a directory. Let the posixfile() call below raise IOError.
- if basename and mode not in ('r', 'rb'):
- if atomictemp:
- if not os.path.isdir(dirname):
- util.makedirs(dirname, self.createmode)
- return util.atomictempfile(f, mode, self.createmode)
- try:
- if 'w' in mode:
- util.unlink(f)
+ if mode not in ('r', 'rb'):
+ dirname, basename = util.split(f)
+ # If basename is empty, then the path is malformed because it points
+ # to a directory. Let the posixfile() call below raise IOError.
+ if basename:
+ if atomictemp:
+ if not os.path.isdir(dirname):
+ util.makedirs(dirname, self.createmode)
+ return util.atomictempfile(f, mode, self.createmode)
+ try:
+ if 'w' in mode:
+ util.unlink(f)
+ nlink = 0
+ else:
+ # nlinks() may behave differently for files on Windows
+ # shares if the file is open.
+ fd = util.posixfile(f)
+ nlink = util.nlinks(f)
+ if nlink < 1:
+ nlink = 2 # force mktempcopy (issue1922)
+ fd.close()
+ except (OSError, IOError), e:
+ if e.errno != errno.ENOENT:
+ raise
nlink = 0
- else:
- # nlinks() may behave differently for files on Windows
- # shares if the file is open.
- fd = util.posixfile(f)
- nlink = util.nlinks(f)
- if nlink < 1:
- nlink = 2 # force mktempcopy (issue1922)
- fd.close()
- except (OSError, IOError), e:
- if e.errno != errno.ENOENT:
- raise
- nlink = 0
- if not os.path.isdir(dirname):
- util.makedirs(dirname, self.createmode)
- if nlink > 0:
- if self._trustnlink is None:
- self._trustnlink = nlink > 1 or util.checknlink(f)
- if nlink > 1 or not self._trustnlink:
- util.rename(util.mktempcopy(f), f)
+ if not os.path.isdir(dirname):
+ util.makedirs(dirname, self.createmode)
+ if nlink > 0:
+ if self._trustnlink is None:
+ self._trustnlink = nlink > 1 or util.checknlink(f)
+ if nlink > 1 or not self._trustnlink:
+ util.rename(util.mktempcopy(f), f)
fp = util.posixfile(f, mode)
if nlink == 0:
self._fixfilemode(f)
--- a/setup.py Thu Nov 15 11:27:30 2012 -0600
+++ b/setup.py Fri Nov 16 10:20:32 2012 -0600
@@ -151,6 +151,8 @@
if not e.startswith(b('Not trusting file')) \
and not e.startswith(b('warning: Not importing'))]
if err:
+ print >> sys.stderr, "stderr from '%s':" % (' '.join(cmd))
+ print >> sys.stderr, '\n'.join([' ' + e for e in err])
return ''
return out
--- a/tests/run-tests.py Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/run-tests.py Fri Nov 16 10:20:32 2012 -0600
@@ -55,6 +55,7 @@
import re
import threading
import killdaemons as killmod
+import cPickle as pickle
processlock = threading.Lock()
@@ -175,6 +176,8 @@
parser.add_option("-t", "--timeout", type="int",
help="kill errant tests after TIMEOUT seconds"
" (default: $%s or %d)" % defaults['timeout'])
+ parser.add_option("--time", action="store_true",
+ help="time how long each test takes")
parser.add_option("--tmpdir", type="string",
help="run tests in the given temporary directory"
" (implies --keep-tmpdir)")
@@ -263,6 +266,10 @@
sys.stderr.write(
'warning: --timeout option ignored with --debug\n')
options.timeout = 0
+ if options.time:
+ sys.stderr.write(
+ 'warning: --time option ignored with --debug\n')
+ options.time = False
if options.py3k_warnings:
if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
parser.error('--py3k-warnings can only be used on Python 2.6+')
@@ -447,6 +454,14 @@
fn = os.path.join(INST, '..', '.coverage')
os.environ['COVERAGE_FILE'] = fn
+def outputtimes(options):
+ vlog('# Producing time report')
+ times.sort(key=lambda t: (t[1], t[0]), reverse=True)
+ cols = '%7.3f %s'
+ print '\n%-7s %s' % ('Time', 'Test')
+ for test, timetaken in times:
+ print cols % (timetaken, test)
+
def outputcoverage(options):
vlog('# Producing coverage report')
@@ -891,7 +906,12 @@
replacements.append((re.escape(testtmp), '$TESTTMP'))
os.mkdir(testtmp)
+ if options.time:
+ starttime = time.time()
ret, out = runner(testpath, testtmp, options, replacements)
+ if options.time:
+ endtime = time.time()
+ times.append((test, endtime - starttime))
vlog("# Ret was:", ret)
mark = '.'
@@ -1056,29 +1076,30 @@
childopts += ['--tmpdir', childtmp]
cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
vlog(' '.join(cmdline))
- fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
+ fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'rb')
os.close(wfd)
signal.signal(signal.SIGINT, signal.SIG_IGN)
failures = 0
- tested, skipped, failed = 0, 0, 0
+ passed, skipped, failed = 0, 0, 0
skips = []
fails = []
while fps:
pid, status = os.wait()
fp = fps.pop(pid)
- l = fp.read().splitlines()
try:
- test, skip, fail = map(int, l[:3])
- except ValueError:
- test, skip, fail = 0, 0, 0
- split = -fail or len(l)
- for s in l[3:split]:
- skips.append(s.split(" ", 1))
- for s in l[split:]:
- fails.append(s.split(" ", 1))
- tested += test
- skipped += skip
- failed += fail
+ childresults = pickle.load(fp)
+ except pickle.UnpicklingError:
+ pass
+ else:
+ passed += len(childresults['p'])
+ skipped += len(childresults['s'])
+ failed += len(childresults['f'])
+ skips.extend(childresults['s'])
+ fails.extend(childresults['f'])
+ if options.time:
+ childtimes = pickle.load(fp)
+ times.extend(childtimes)
+
vlog('pid %d exited, status %d' % (pid, status))
failures |= status
print
@@ -1093,17 +1114,20 @@
_checkhglib("Tested")
print "# Ran %d tests, %d skipped, %d failed." % (
- tested, skipped, failed)
+ passed + failed, skipped, failed)
+ if options.time:
+ outputtimes(options)
if options.anycoverage:
outputcoverage(options)
sys.exit(failures != 0)
results = dict(p=[], f=[], s=[], i=[])
resultslock = threading.Lock()
+times = []
iolock = threading.Lock()
-def runqueue(options, tests, results):
+def runqueue(options, tests):
for test in tests:
ret = runone(options, test)
if options.first and ret is not None and not ret:
@@ -1129,7 +1153,7 @@
print "running all tests"
tests = orig
- runqueue(options, tests, results)
+ runqueue(options, tests)
failed = len(results['f'])
tested = len(results['p']) + failed
@@ -1137,12 +1161,10 @@
ignored = len(results['i'])
if options.child:
- fp = os.fdopen(options.child, 'w')
- fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
- for s in results['s']:
- fp.write("%s %s\n" % s)
- for s in results['f']:
- fp.write("%s %s\n" % s)
+ fp = os.fdopen(options.child, 'wb')
+ pickle.dump(results, fp, pickle.HIGHEST_PROTOCOL)
+ if options.time:
+ pickle.dump(times, fp, pickle.HIGHEST_PROTOCOL)
fp.close()
else:
print
@@ -1153,6 +1175,8 @@
_checkhglib("Tested")
print "# Ran %d tests, %d skipped, %d failed." % (
tested, skipped + ignored, failed)
+ if options.time:
+ outputtimes(options)
if options.anycoverage:
outputcoverage(options)
@@ -1170,9 +1194,9 @@
checktools()
- if len(args) == 0:
- args = os.listdir(".")
- args.sort()
+ if len(args) == 0:
+ args = os.listdir(".")
+ args.sort()
tests = args
--- a/tests/test-bundle.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-bundle.t Fri Nov 16 10:20:32 2012 -0600
@@ -444,6 +444,33 @@
added 1 changesets with 1 changes to 1 files
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+View full contents of the bundle
+ $ hg -R test bundle --base null -r 3 ../partial.hg
+ 4 changesets found
+ $ cd test
+ $ hg -R ../../partial.hg log -r "bundle()"
+ changeset: 0:f9ee2f85a263
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.0
+
+ changeset: 1:34c2bf6b0626
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.1
+
+ changeset: 2:e38ba6f5b7e0
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.2
+
+ changeset: 3:eebf5a27f8ca
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 0.3
+
+ $ cd ..
+
test for 540d1059c802
test for 540d1059c802
--- a/tests/test-convert-git.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-convert-git.t Fri Nov 16 10:20:32 2012 -0600
@@ -298,3 +298,50 @@
$ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
> grep 'abort:' | sed 's/abort:.*/abort:/g'
abort:
+
+test sub modules
+
+ $ mkdir git-repo5
+ $ cd git-repo5
+ $ git init-db >/dev/null 2>/dev/null
+ $ echo 'sub' >> foo
+ $ git add foo
+ $ commit -a -m 'addfoo'
+ $ BASE=${PWD}
+ $ cd ..
+ $ mkdir git-repo6
+ $ cd git-repo6
+ $ git init-db >/dev/null 2>/dev/null
+ $ git submodule add ${BASE} >/dev/null 2>/dev/null
+ $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
+ $ cd ..
+
+convert sub modules
+ $ hg convert git-repo6 git-repo6-hg
+ initializing destination git-repo6-hg repository
+ scanning source...
+ sorting...
+ converting...
+ 0 addsubmodule
+ updating bookmarks
+ $ hg -R git-repo6-hg log -v
+ changeset: 0:* (glob)
+ bookmark: master
+ tag: tip
+ user: nottest <test@example.org>
+ date: Mon Jan 01 00:00:23 2007 +0000
+ files: .hgsub .hgsubstate
+ description:
+ addsubmodule
+
+ committer: test <test@example.org>
+
+
+
+ $ cd git-repo6-hg
+ $ hg up >/dev/null 2>/dev/null
+ $ cat .hgsubstate
+ * git-repo5 (glob)
+ $ cd git-repo5
+ $ cat foo
+ sub
--- a/tests/test-eolfilename.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-eolfilename.t Fri Nov 16 10:20:32 2012 -0600
@@ -68,9 +68,9 @@
$ touch "$A"
$ touch "$B"
$ hg status --color=always
- \x1b[0;35;1;4m? foo\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
\x1b[0;35;1;4mbar\x1b[0m (esc)
- \x1b[0;35;1;4m? foo\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
\x1b[0;35;1;4mbar.baz\x1b[0m (esc)
$ cd ..
--- a/tests/test-mq.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-mq.t Fri Nov 16 10:20:32 2012 -0600
@@ -198,11 +198,11 @@
status --mq with color (issue2096)
$ hg status --mq --config extensions.color= --config color.mode=ansi --color=always
- \x1b[0;32;1mA .hgignore\x1b[0m (esc)
- \x1b[0;32;1mA A\x1b[0m (esc)
- \x1b[0;32;1mA B\x1b[0m (esc)
- \x1b[0;32;1mA series\x1b[0m (esc)
- \x1b[0;35;1;4m? flaf\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1m.hgignore\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mA\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mB\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mseries\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mflaf\x1b[0m (esc)
try the --mq option on a command provided by an extension
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-pathencode.py Fri Nov 16 10:20:32 2012 -0600
@@ -0,0 +1,193 @@
+# This is a randomized test that generates different pathnames every
+# time it is invoked, and tests the encoding of those pathnames.
+#
+# It uses a simple probabilistic model to generate valid pathnames
+# that have proven likely to expose bugs and divergent behaviour in
+# different encoding implementations.
+
+from mercurial import parsers
+from mercurial import store
+import binascii, itertools, math, os, random, sys, time
+import collections
+
+if sys.version_info[:2] < (2, 6):
+ sys.exit(0)
+
+def hybridencode(path):
+ return store._hybridencode(path, True)
+
+validchars = set(map(chr, range(0, 256)))
+alphanum = range(ord('A'), ord('Z'))
+
+for c in '\0/':
+ validchars.remove(c)
+
+winreserved = ('aux con prn nul'.split() +
+ ['com%d' % i for i in xrange(1, 10)] +
+ ['lpt%d' % i for i in xrange(1, 10)])
+
+def casecombinations(names):
+ '''Build all case-diddled combinations of names.'''
+
+ combos = set()
+
+ for r in names:
+ for i in xrange(len(r) + 1):
+ for c in itertools.combinations(xrange(len(r)), i):
+ d = r
+ for j in c:
+ d = ''.join((d[:j], d[j].upper(), d[j + 1:]))
+ combos.add(d)
+ return sorted(combos)
+
+def buildprobtable(fp, cmd='hg manifest tip'):
+ '''Construct and print a table of probabilities for path name
+ components. The numbers are percentages.'''
+
+ counts = collections.defaultdict(lambda: 0)
+ for line in os.popen(cmd).read().splitlines():
+ if line[-2:] in ('.i', '.d'):
+ line = line[:-2]
+ if line.startswith('data/'):
+ line = line[5:]
+ for c in line:
+ counts[c] += 1
+ for c in '\r/\n':
+ counts.pop(c, None)
+ t = sum(counts.itervalues()) / 100.0
+ fp.write('probtable = (')
+ for i, (k, v) in enumerate(sorted(counts.iteritems(), key=lambda x: x[1],
+ reverse=True)):
+ if (i % 5) == 0:
+ fp.write('\n ')
+ vt = v / t
+ if vt < 0.0005:
+ break
+ fp.write('(%r, %.03f), ' % (k, vt))
+ fp.write('\n )\n')
+
+# A table of character frequencies (as percentages), gleaned by
+# looking at filelog names from a real-world, very large repo.
+
+probtable = (
+ ('t', 9.828), ('e', 9.042), ('s', 8.011), ('a', 6.801), ('i', 6.618),
+ ('g', 5.053), ('r', 5.030), ('o', 4.887), ('p', 4.363), ('n', 4.258),
+ ('l', 3.830), ('h', 3.693), ('_', 3.659), ('.', 3.377), ('m', 3.194),
+ ('u', 2.364), ('d', 2.296), ('c', 2.163), ('b', 1.739), ('f', 1.625),
+ ('6', 0.666), ('j', 0.610), ('y', 0.554), ('x', 0.487), ('w', 0.477),
+ ('k', 0.476), ('v', 0.473), ('3', 0.336), ('1', 0.335), ('2', 0.326),
+ ('4', 0.310), ('5', 0.305), ('9', 0.302), ('8', 0.300), ('7', 0.299),
+ ('q', 0.298), ('0', 0.250), ('z', 0.223), ('-', 0.118), ('C', 0.095),
+ ('T', 0.087), ('F', 0.085), ('B', 0.077), ('S', 0.076), ('P', 0.076),
+ ('L', 0.059), ('A', 0.058), ('N', 0.051), ('D', 0.049), ('M', 0.046),
+ ('E', 0.039), ('I', 0.035), ('R', 0.035), ('G', 0.028), ('U', 0.026),
+ ('W', 0.025), ('O', 0.017), ('V', 0.015), ('H', 0.013), ('Q', 0.011),
+ ('J', 0.007), ('K', 0.005), ('+', 0.004), ('X', 0.003), ('Y', 0.001),
+ )
+
+for c, _ in probtable:
+ validchars.remove(c)
+validchars = list(validchars)
+
+def pickfrom(rng, table):
+ c = 0
+ r = rng.random() * sum(i[1] for i in table)
+ for i, p in table:
+ c += p
+ if c >= r:
+ return i
+
+reservedcombos = casecombinations(winreserved)
+
+# The first component of a name following a slash.
+
+firsttable = (
+ (lambda rng: pickfrom(rng, probtable), 90),
+ (lambda rng: rng.choice(validchars), 5),
+ (lambda rng: rng.choice(reservedcombos), 5),
+ )
+
+# Components of a name following the first.
+
+resttable = firsttable[:-1]
+
+# Special suffixes.
+
+internalsuffixcombos = casecombinations('.hg .i .d'.split())
+
+# The last component of a path, before a slash or at the end of a name.
+
+lasttable = resttable + (
+ (lambda rng: '', 95),
+ (lambda rng: rng.choice(internalsuffixcombos), 5),
+ )
+
+def makepart(rng, k):
+ '''Construct a part of a pathname, without slashes.'''
+
+ p = pickfrom(rng, firsttable)(rng)
+ l = len(p)
+ ps = [p]
+ while l <= k:
+ p = pickfrom(rng, resttable)(rng)
+ l += len(p)
+ ps.append(p)
+ ps.append(pickfrom(rng, lasttable)(rng))
+ return ''.join(ps)
+
+def makepath(rng, j, k):
+ '''Construct a complete pathname.'''
+
+ return ('data/' + '/'.join(makepart(rng, k) for _ in xrange(j)) +
+ rng.choice(['.d', '.i']))
+
+def genpath(rng, count):
+ '''Generate random pathnames with gradually increasing lengths.'''
+
+ mink, maxk = 1, 4096
+ def steps():
+ x, k = 0, mink
+ for i in xrange(count):
+ yield mink + int(round(math.sqrt((maxk - mink) * float(i) / count)))
+ for k in steps():
+ x = rng.randint(1, k)
+ y = rng.randint(1, k)
+ yield makepath(rng, x, y)
+
+def runtests(rng, seed, count):
+ nerrs = 0
+ for p in genpath(rng, count):
+ hybridencode(p)
+ return nerrs
+
+def main():
+ import getopt
+
+ # Empirically observed to take about a second to run
+ count = 100
+ seed = None
+ opts, args = getopt.getopt(sys.argv[1:], 'c:s:',
+ ['build', 'count=', 'seed='])
+ for o, a in opts:
+ if o in ('-c', '--count'):
+ count = int(a)
+ elif o in ('-s', '--seed'):
+ seed = long(a)
+ elif o == '--build':
+ buildprobtable(sys.stdout,
+ 'find .hg/store/data -type f && '
+ 'cat .hg/store/fncache 2>/dev/null')
+ sys.exit(0)
+
+ if seed is None:
+ try:
+ seed = long(binascii.hexlify(os.urandom(16)), 16)
+ except AttributeError:
+ seed = long(time.time() * 1000)
+
+ rng = random.Random(seed)
+ if runtests(rng, seed, count):
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
--- a/tests/test-status-color.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-status-color.t Fri Nov 16 10:20:32 2012 -0600
@@ -15,100 +15,100 @@
hg status in repo root:
$ hg status --color=always
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
hg status . in repo root:
$ hg status --color=always .
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd a
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd a .
- \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc)
$ hg status --color=always --cwd a ..
- \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? ../b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? ../b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? ../b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? ../in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc)
$ hg status --color=always --cwd b
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd b .
- \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc)
$ hg status --color=always --cwd b ..
- \x1b[0;35;1;4m? ../a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? ../a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? ../in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc)
$ hg status --color=always --cwd a/1
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd a/1 .
- \x1b[0;35;1;4m? in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc)
$ hg status --color=always --cwd a/1 ..
- \x1b[0;35;1;4m? in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? ../in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_a\x1b[0m (esc)
$ hg status --color=always --cwd b/1
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd b/1 .
- \x1b[0;35;1;4m? in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc)
$ hg status --color=always --cwd b/1 ..
- \x1b[0;35;1;4m? in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? ../2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? ../in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc)
$ hg status --color=always --cwd b/2
- \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc)
- \x1b[0;35;1;4m? a/in_a\x1b[0m (esc)
- \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? b/in_b\x1b[0m (esc)
- \x1b[0;35;1;4m? in_root\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc)
$ hg status --color=always --cwd b/2 .
- \x1b[0;35;1;4m? in_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc)
$ hg status --color=always --cwd b/2 ..
- \x1b[0;35;1;4m? ../1/in_b_1\x1b[0m (esc)
- \x1b[0;35;1;4m? in_b_2\x1b[0m (esc)
- \x1b[0;35;1;4m? ../in_b\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../1/in_b_1\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc)
$ cd ..
$ hg init repo2
@@ -128,59 +128,59 @@
hg status:
$ hg status --color=always
- \x1b[0;32;1mA added\x1b[0m (esc)
- \x1b[0;31;1mR removed\x1b[0m (esc)
- \x1b[0;36;1;4m! deleted\x1b[0m (esc)
- \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
+ \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
+ \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
hg status modified added removed deleted unknown never-existed ignored:
$ hg status --color=always modified added removed deleted unknown never-existed ignored
never-existed: * (glob)
- \x1b[0;32;1mA added\x1b[0m (esc)
- \x1b[0;31;1mR removed\x1b[0m (esc)
- \x1b[0;36;1;4m! deleted\x1b[0m (esc)
- \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
+ \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
+ \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
$ hg copy modified copied
hg status -C:
$ hg status --color=always -C
- \x1b[0;32;1mA added\x1b[0m (esc)
- \x1b[0;32;1mA copied\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
\x1b[0;0m modified\x1b[0m (esc)
- \x1b[0;31;1mR removed\x1b[0m (esc)
- \x1b[0;36;1;4m! deleted\x1b[0m (esc)
- \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+ \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
+ \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
hg status -A:
$ hg status --color=always -A
- \x1b[0;32;1mA added\x1b[0m (esc)
- \x1b[0;32;1mA copied\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
\x1b[0;0m modified\x1b[0m (esc)
- \x1b[0;31;1mR removed\x1b[0m (esc)
- \x1b[0;36;1;4m! deleted\x1b[0m (esc)
- \x1b[0;35;1;4m? unknown\x1b[0m (esc)
- \x1b[0;30;1mI ignored\x1b[0m (esc)
- \x1b[0;0mC .hgignore\x1b[0m (esc)
- \x1b[0;0mC modified\x1b[0m (esc)
+ \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
+ \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
+ \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignored\x1b[0m (esc)
+ \x1b[0;0mC \x1b[0m\x1b[0;0m.hgignore\x1b[0m (esc)
+ \x1b[0;0mC \x1b[0m\x1b[0;0mmodified\x1b[0m (esc)
hg status -A (with terminfo color):
$ mkdir "$TESTTMP/terminfo"
$ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm.ti"
$ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status --config color.mode=terminfo --color=always -A
- \x1b[30m\x1b[32m\x1b[1mA added\x1b[30m (esc)
- \x1b[30m\x1b[32m\x1b[1mA copied\x1b[30m (esc)
+ \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1madded\x1b[30m (esc)
+ \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1mcopied\x1b[30m (esc)
\x1b[30m\x1b[30m modified\x1b[30m (esc)
- \x1b[30m\x1b[31m\x1b[1mR removed\x1b[30m (esc)
- \x1b[30m\x1b[36m\x1b[1m\x1b[4m! deleted\x1b[30m (esc)
- \x1b[30m\x1b[35m\x1b[1m\x1b[4m? unknown\x1b[30m (esc)
- \x1b[30m\x1b[30m\x1b[1mI ignored\x1b[30m (esc)
- \x1b[30m\x1b[30mC .hgignore\x1b[30m (esc)
- \x1b[30m\x1b[30mC modified\x1b[30m (esc)
+ \x1b[30m\x1b[31m\x1b[1mR \x1b[30m\x1b[30m\x1b[31m\x1b[1mremoved\x1b[30m (esc)
+ \x1b[30m\x1b[36m\x1b[1m\x1b[4m! \x1b[30m\x1b[30m\x1b[36m\x1b[1m\x1b[4mdeleted\x1b[30m (esc)
+ \x1b[30m\x1b[35m\x1b[1m\x1b[4m? \x1b[30m\x1b[30m\x1b[35m\x1b[1m\x1b[4munknown\x1b[30m (esc)
+ \x1b[30m\x1b[30m\x1b[1mI \x1b[30m\x1b[30m\x1b[30m\x1b[1mignored\x1b[30m (esc)
+ \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30m.hgignore\x1b[30m (esc)
+ \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30mmodified\x1b[30m (esc)
$ echo "^ignoreddir$" > .hgignore
@@ -194,7 +194,7 @@
hg status -i ignoreddir/file:
$ hg status --color=always -i ignoreddir/file
- \x1b[0;30;1mI ignoreddir/file\x1b[0m (esc)
+ \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignoreddir/file\x1b[0m (esc)
$ cd ..
check 'status -q' and some combinations
@@ -220,11 +220,11 @@
$ hg --config color.status.modified=periwinkle status --color=always
ignoring unknown color/effect 'periwinkle' (configured in color.status.modified)
M modified
- \x1b[0;32;1mA added\x1b[0m (esc)
- \x1b[0;32;1mA copied\x1b[0m (esc)
- \x1b[0;31;1mR removed\x1b[0m (esc)
- \x1b[0;36;1;4m! deleted\x1b[0m (esc)
- \x1b[0;35;1;4m? unknown\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc)
+ \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc)
+ \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc)
+ \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc)
+ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc)
Run status with 2 different flags.
Check if result is the same or different.
--- a/tests/test-subrepo.t Thu Nov 15 11:27:30 2012 -0600
+++ b/tests/test-subrepo.t Fri Nov 16 10:20:32 2012 -0600
@@ -718,6 +718,14 @@
committing subrepository subrepo-2
$ hg st subrepo-2/file
+Check that share works with subrepo
+ $ hg --config extensions.share= share . ../shared
+ updating working directory
+ cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ test -f ../shared/subrepo-1/.hg/sharedpath
+ [1]
+
Check hg update --clean
$ cd $TESTTMP/t
$ rm -r t/t.orig