--- a/contrib/bash_completion Mon Mar 11 12:07:33 2013 -0700
+++ b/contrib/bash_completion Sun Mar 17 23:27:14 2013 -0500
@@ -1,4 +1,4 @@
-# bash completion for the Mercurial distributed SCM
+# bash completion for the Mercurial distributed SCM -*- sh -*-
# Docs:
#
@@ -82,7 +82,7 @@
_hg_status()
{
- local files="$(_hg_cmd status -n$1 .)"
+ local files="$(_hg_cmd status -n$1 "glob:$cur**")"
local IFS=$'\n'
compopt -o filenames 2>/dev/null
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
@@ -255,7 +255,7 @@
_hg_status "mar"
;;
remove)
- _hg_status "d"
+ _hg_status "mcd"
;;
forget)
_hg_status "a"
--- a/mercurial/commands.py Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/commands.py Sun Mar 17 23:27:14 2013 -0500
@@ -808,8 +808,15 @@
scmutil.checknewlabel(repo, mark, 'bookmark')
return mark
- def checkconflict(repo, mark, force=False):
+ def checkconflict(repo, mark, force=False, target=None):
if mark in marks and not force:
+ if target:
+ anc = repo.changelog.ancestors([repo[target].rev()])
+ bmctx = repo[marks[mark]]
+ if bmctx.rev() in anc:
+ ui.status(_("moving bookmark '%s' forward from %s\n") %
+ (mark, short(bmctx.node())))
+ return
raise util.Abort(_("bookmark '%s' already exists "
"(use -f to force)") % mark)
if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
@@ -852,11 +859,11 @@
if inactive and mark == repo._bookmarkcurrent:
bookmarks.setcurrent(repo, None)
return
- checkconflict(repo, mark, force)
+ tgt = cur
if rev:
- marks[mark] = scmutil.revsingle(repo, rev).node()
- else:
- marks[mark] = cur
+ tgt = scmutil.revsingle(repo, rev).node()
+ checkconflict(repo, mark, force, tgt)
+ marks[mark] = tgt
if not inactive and cur == marks[mark]:
bookmarks.setcurrent(repo, mark)
marks.write()
--- a/mercurial/hgweb/webcommands.py Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/hgweb/webcommands.py Sun Mar 17 23:27:14 2013 -0500
@@ -816,6 +816,19 @@
if cnode == key or key == 'tip':
arch_version = short(cnode)
name = "%s-%s" % (reponame, arch_version)
+
+ ctx = webutil.changectx(web.repo, req)
+ pats = []
+ file = req.form.get('file', None)
+ if file:
+ file = file[0]
+ patandfile = file.split(':')
+ if len(patandfile) > 1 and patandfile[0].lower() in ('glob', 'relglob',
+ 'path', 'relpath', 're', 'relre', 'set'):
+ msg = 'Archive pattern not allowed: %s' % file
+ raise ErrorResponse(HTTP_FORBIDDEN, msg)
+ pats = ['path:' + file]
+
mimetype, artype, extension, encoding = web.archive_specs[type_]
headers = [
('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
@@ -825,9 +838,9 @@
req.headers.extend(headers)
req.respond(HTTP_OK, mimetype)
- ctx = webutil.changectx(web.repo, req)
+ matchfn = scmutil.match(ctx, pats, default='path')
archival.archive(web.repo, req, cnode, artype, prefix=name,
- matchfn=scmutil.match(ctx, []),
+ matchfn=matchfn,
subrepos=web.configbool("web", "archivesubrepos"))
return []
--- a/mercurial/templates/coal/map Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/templates/coal/map Sun Mar 17 23:27:14 2013 -0500
@@ -224,7 +224,7 @@
index = ../paper/index.tmpl
archiveentry = '
<li>
- <a href="{url|urlescape}archive/{node|short}{extension|urlescape}">{type|escape}</a>
+ <a href="{url|urlescape}archive/{node|short}{extension|urlescape}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a>
</li>'
notfound = ../paper/notfound.tmpl
error = ../paper/error.tmpl
--- a/mercurial/templates/gitweb/map Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/templates/gitweb/map Sun Mar 17 23:27:14 2013 -0500
@@ -289,7 +289,7 @@
<td class="link">
<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> | <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> | <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> {rename%filelogrename}</td>
</tr>'
-archiveentry = ' | <a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a> '
+archiveentry = ' | <a href="{url|urlescape}archive/{node|short}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a> '
indexentry = '
<tr class="parity{parity}">
<td>
--- a/mercurial/templates/monoblue/map Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/templates/monoblue/map Sun Mar 17 23:27:14 2013 -0500
@@ -245,7 +245,7 @@
{rename%filelogrename}
</td>
</tr>'
-archiveentry = '<li><a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a></li>'
+archiveentry = '<li><a href="{url|urlescape}archive/{node|short}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a></li>'
indexentry = '
<tr class="parity{parity}">
<td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
--- a/mercurial/templates/paper/map Mon Mar 11 12:07:33 2013 -0700
+++ b/mercurial/templates/paper/map Sun Mar 17 23:27:14 2013 -0500
@@ -232,7 +232,7 @@
index = index.tmpl
archiveentry = '
<li>
- <a href="{url|urlescape}archive/{node|short}{extension|urlescape}">{type|escape}</a>
+ <a href="{url|urlescape}archive/{node|short}{extension|urlescape}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a>
</li>'
notfound = notfound.tmpl
error = error.tmpl
--- a/tests/test-archive.t Mon Mar 11 12:07:33 2013 -0700
+++ b/tests/test-archive.t Sun Mar 17 23:27:14 2013 -0500
@@ -69,10 +69,18 @@
> msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
> except ImportError:
> pass
- > node, archive = sys.argv[1:]
- > f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
- > % (os.environ['HGPORT'], node, archive))
- > sys.stdout.write(f.read())
+ > if len(sys.argv) <= 3:
+ > node, archive = sys.argv[1:]
+ > requeststr = 'cmd=archive;node=%s;type=%s' % (node, archive)
+ > else:
+ > node, archive, file = sys.argv[1:]
+ > requeststr = 'cmd=archive;node=%s;type=%s;file=%s' % (node, archive, file)
+ > try:
+ > f = urllib2.urlopen('http://127.0.0.1:%s/?%s'
+ > % (os.environ['HGPORT'], requeststr))
+ > sys.stdout.write(f.read())
+ > except urllib2.HTTPError, e:
+ > sys.stderr.write(str(e) + '\n')
> EOF
$ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
test-archive-2c0277f05ed4/.hg_archival.txt
@@ -93,6 +101,18 @@
testing: test-archive-2c0277f05ed4/foo OK
No errors detected in compressed data of archive.zip.
+test that we can download single directories and files
+
+ $ python getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null
+ test-archive-2c0277f05ed4/baz/bletch
+ $ python getarchive.py "$TIP" gz foo | gunzip | tar tf - 2>/dev/null
+ test-archive-2c0277f05ed4/foo
+
+test that we reject unsafe patterns
+
+ $ python getarchive.py "$TIP" gz relre:baz
+ HTTP Error 403: Archive pattern not allowed: relre:baz
+
$ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
$ hg archive -t tar test.tar
--- a/tests/test-bookmarks.t Mon Mar 11 12:07:33 2013 -0700
+++ b/tests/test-bookmarks.t Sun Mar 17 23:27:14 2013 -0500
@@ -239,8 +239,8 @@
bookmark with existing name
- $ hg bookmark Z
- abort: bookmark 'Z' already exists (use -f to force)
+ $ hg bookmark X2
+ abort: bookmark 'X2' already exists (use -f to force)
[255]
$ hg bookmark -m Y Z
@@ -279,7 +279,13 @@
force bookmark with existing name
- $ hg bookmark -f Z
+ $ hg bookmark -f X2
+ $ hg bookmark -fr1 X2
+
+forward bookmark to descendant without --force
+
+ $ hg bookmark Z
+ moving bookmark 'Z' forward from f7b1eb17ad24
list bookmarks