--- a/mercurial/commands.py Mon Nov 07 19:00:51 2005 +0100
+++ b/mercurial/commands.py Wed Nov 09 12:52:05 2005 -0800
@@ -788,14 +788,10 @@
raise util.Abort(str(inst))
def docopy(ui, repo, pats, opts):
- if not pats:
- raise util.Abort(_('no source or destination specified'))
- elif len(pats) == 1:
- raise util.Abort(_('no destination specified'))
- pats = list(pats)
- dest = pats.pop()
- sources = []
- dir2dir = len(pats) == 1 and os.path.isdir(pats[0])
+ cwd = repo.getcwd()
+ errors = 0
+ copied = []
+ targets = {}
def okaytocopy(abs, rel, exact):
reasons = {'?': _('is not managed'),
@@ -806,74 +802,77 @@
else:
return True
- for src, abs, rel, exact in walk(repo, pats, opts):
- if okaytocopy(abs, rel, exact):
- sources.append((abs, rel, exact))
- if not sources:
- raise util.Abort(_('no files to copy'))
-
- cwd = repo.getcwd()
- absdest = util.canonpath(repo.root, cwd, dest)
- reldest = util.pathto(cwd, absdest)
- if os.path.exists(reldest):
- destisfile = not os.path.isdir(reldest)
- else:
- destisfile = not dir2dir and (len(sources) == 1
- or repo.dirstate.state(absdest) != '?')
-
- if destisfile and len(sources) > 1:
- raise util.Abort(_('with multiple sources, destination must be a '
- 'directory'))
-
- srcpfxlen = 0
- if dir2dir:
- srcpfx = util.pathto(cwd, util.canonpath(repo.root, cwd, pats[0]))
- if os.path.exists(reldest):
- srcpfx = os.path.split(srcpfx)[0]
- if srcpfx:
- srcpfx += os.sep
- srcpfxlen = len(srcpfx)
-
- errs, copied = 0, []
- for abs, rel, exact in sources:
- if destisfile:
- mydest = reldest
- elif dir2dir:
- mydest = os.path.join(dest, rel[srcpfxlen:])
- else:
- mydest = os.path.join(dest, os.path.basename(rel))
- myabsdest = util.canonpath(repo.root, cwd, mydest)
- myreldest = util.pathto(cwd, myabsdest)
- if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
- ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
- continue
- mydestdir = os.path.dirname(myreldest) or '.'
+ def copy(abssrc, relsrc, target, exact):
+ abstarget = util.canonpath(repo.root, cwd, target)
+ reltarget = util.pathto(cwd, abstarget)
+ prevsrc = targets.get(abstarget)
+ if prevsrc is not None:
+ ui.warn(_('%s: not overwriting - %s collides with %s\n') %
+ (reltarget, abssrc, prevsrc))
+ return
+ elif os.path.exists(reltarget):
+ if opts['force']:
+ os.unlink(reltarget)
+ else:
+ ui.warn(_('%s: not overwriting - file exists\n') %
+ reltarget)
+ return
+ if ui.verbose or not exact:
+ ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
if not opts['after']:
+ targetdir = os.path.dirname(reltarget) or '.'
+ if not os.path.isdir(targetdir):
+ os.makedirs(targetdir)
try:
- if dir2dir: os.makedirs(mydestdir)
- elif not destisfile: os.mkdir(mydestdir)
- except OSError, inst:
- if inst.errno != errno.EEXIST: raise
- if ui.verbose or not exact:
- ui.status(_('copying %s to %s\n') % (rel, myreldest))
- if not opts['after']:
- try:
- shutil.copyfile(rel, myreldest)
- shutil.copymode(rel, myreldest)
+ shutil.copyfile(relsrc, reltarget)
+ shutil.copymode(relsrc, reltarget)
except shutil.Error, inst:
raise util.Abort(str(inst))
except IOError, inst:
if inst.errno == errno.ENOENT:
- ui.warn(_('%s: deleted in working copy\n') % rel)
+ ui.warn(_('%s: deleted in working copy\n') % relsrc)
else:
- ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror))
- errs += 1
- continue
- repo.copy(abs, myabsdest)
- copied.append((abs, rel, exact))
- if errs:
+ ui.warn(_('%s: cannot copy - %s\n') %
+ (relsrc, inst.strerror))
+ errors += 1
+ return
+ targets[abstarget] = abssrc
+ repo.copy(abssrc, abstarget)
+ copied.append((abssrc, relsrc, exact))
+
+ pats = list(pats)
+ if not pats:
+ raise util.Abort(_('no source or destination specified'))
+ if len(pats) == 1:
+ raise util.Abort(_('no destination specified'))
+ dest = pats.pop()
+ destdirexists = os.path.isdir(dest)
+ if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists:
+ raise util.Abort(_('with multiple sources, destination must be an '
+ 'existing directory'))
+
+ for pat in pats:
+ if os.path.isdir(pat):
+ if destdirexists:
+ striplen = len(os.path.split(pat)[0])
+ else:
+ striplen = len(pat)
+ if striplen:
+ striplen += len(os.sep)
+ targetpath = lambda p: os.path.join(dest, p[striplen:])
+ elif destdirexists:
+ targetpath = lambda p: os.path.join(dest, os.path.basename(p))
+ else:
+ targetpath = lambda p: dest
+ for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
+ if okaytocopy(abssrc, relsrc, exact):
+ copy(abssrc, relsrc, targetpath(abssrc), exact)
+
+ if errors:
ui.warn(_('(consider using --after)\n'))
- return errs, copied
+ if len(copied) == 0:
+ raise util.Abort(_('no files to copy'))
+ return errors, copied
def copy(ui, repo, *pats, **opts):
"""mark files as copied for the next commit
@@ -1734,7 +1733,9 @@
This command tries to fix the repository status after an interrupted
operation. It should only be necessary when Mercurial suggests it.
"""
- repo.recover()
+ if repo.recover():
+ return repo.verify()
+ return False
def remove(ui, repo, pat, *pats, **opts):
"""remove the specified files on the next commit
--- a/mercurial/dirstate.py Mon Nov 07 19:00:51 2005 +0100
+++ b/mercurial/dirstate.py Wed Nov 09 12:52:05 2005 -0800
@@ -175,7 +175,7 @@
if state == "r":
self.map[f] = ('r', 0, 0, 0)
else:
- s = os.lstat(os.path.join(self.root, f))
+ s = os.lstat(self.wjoin(f))
st_size = kw.get('st_size', s.st_size)
st_mtime = kw.get('st_mtime', s.st_mtime)
self.map[f] = (state, s.st_mode, st_size, st_mtime)
@@ -332,7 +332,7 @@
# step one, find all files that match our criteria
files.sort()
for ff in util.unique(files):
- f = os.path.join(self.root, ff)
+ f = self.wjoin(ff)
try:
st = os.lstat(f)
except OSError, inst:
@@ -380,7 +380,7 @@
nonexistent = True
if not st:
try:
- f = os.path.join(self.root, fn)
+ f = self.wjoin(fn)
st = os.lstat(f)
except OSError, inst:
if inst.errno != errno.ENOENT:
--- a/mercurial/hgweb.py Mon Nov 07 19:00:51 2005 +0100
+++ b/mercurial/hgweb.py Wed Nov 09 12:52:05 2005 -0800
@@ -165,7 +165,6 @@
common_filters = {
"escape": cgi.escape,
"strip": lambda x: x.strip(),
- "rstrip": lambda x: x.rstrip(),
"age": age,
"date": lambda x: util.datestr(x),
"addbreaks": nl2br,
--- a/mercurial/localrepo.py Mon Nov 07 19:00:51 2005 +0100
+++ b/mercurial/localrepo.py Wed Nov 09 12:52:05 2005 -0800
@@ -43,7 +43,7 @@
self.dirstate = dirstate.dirstate(self.opener, ui, self.root)
try:
- self.ui.readconfig(os.path.join(self.path, "hgrc"))
+ self.ui.readconfig(self.join("hgrc"))
except IOError: pass
def hook(self, name, **args):
@@ -225,9 +225,11 @@
lock = self.lock()
if os.path.exists(self.join("journal")):
self.ui.status(_("rolling back interrupted transaction\n"))
- return transaction.rollback(self.opener, self.join("journal"))
+ transaction.rollback(self.opener, self.join("journal"))
+ return True
else:
self.ui.warn(_("no interrupted transaction available\n"))
+ return False
def undo(self):
lock = self.lock()
--- a/mercurial/revlog.py Mon Nov 07 19:00:51 2005 +0100
+++ b/mercurial/revlog.py Wed Nov 09 12:52:05 2005 -0800
@@ -784,6 +784,10 @@
continue
delta = chunk[80:]
+ for p in (p1, p2):
+ if not p in self.nodemap:
+ raise RevlogError(_("unknown parent %s") % short(p1))
+
if not chain:
# retrieve the parent revision of the delta chain
chain = p1
--- a/templates/changelogentry-rss.tmpl Mon Nov 07 19:00:51 2005 +0100
+++ b/templates/changelogentry-rss.tmpl Wed Nov 09 12:52:05 2005 -0800
@@ -1,5 +1,5 @@
<item>
- <title>#desc|strip|firstline|rstrip|escape#</title>
+ <title>#desc|strip|firstline|strip|escape#</title>
<link>#url#?cs=#node|short#</link>
<description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
<author>#author|obfuscate#</author>
--- a/templates/filelogentry-rss.tmpl Mon Nov 07 19:00:51 2005 +0100
+++ b/templates/filelogentry-rss.tmpl Wed Nov 09 12:52:05 2005 -0800
@@ -1,5 +1,5 @@
<item>
- <title>#desc|strip|firstline|rstrip|escape#</title>
+ <title>#desc|strip|firstline|strip|escape#</title>
<link>#url#?f=#filenode|short#;file=#file#</link>
<description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
<author>#author|obfuscate#</author>
--- a/tests/test-help.out Mon Nov 07 19:00:51 2005 +0100
+++ b/tests/test-help.out Wed Nov 09 12:52:05 2005 -0800
@@ -191,6 +191,8 @@
R = removed
? = not tracked
+aliases: st
+
options:
-m --modified show only modified files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename Wed Nov 09 12:52:05 2005 -0800
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+hg init
+mkdir d1 d1/d11 d2
+echo d1/a > d1/a
+echo d1/ba > d1/ba
+echo d1/a1 > d1/d11/a1
+echo d1/b > d1/b
+echo d2/b > d2/b
+hg add d1/a d1/b d1/ba d1/d11/a1 d2/b
+hg commit -m "1" -d "0 0"
+
+echo "# rename a single file"
+hg rename d1/d11/a1 d2/c
+hg status
+hg update -C
+
+echo "# move a single file to an existing directory"
+hg rename d1/d11/a1 d2
+hg status
+hg update -C
+
+echo "# rename directory d1 as d3"
+hg rename d1 d3
+hg status
+hg update -C
+
+echo "# move directory d1/d11 to an existing directory d2 (removes empty d1)"
+hg rename d1/d11 d2
+hg status
+hg update -C
+
+echo "# move directories d1 and d2 to a new directory d3"
+mkdir d3
+hg rename d1 d2 d3
+hg status
+hg update -C
+
+echo "# move everything under directory d1 to existing directory d2, do not"
+echo "# overwrite existing files (d2/b)"
+hg rename d1/* d2
+hg status
+diff d1/b d2/b
+hg update -C
+
+echo "# attempt to move potentially more than one file into a non-existent"
+echo "# directory"
+hg rename 'glob:d1/**' dx
+
+echo "# move every file under d1 to d2/d21 (glob)"
+mkdir d2/d21
+hg rename 'glob:d1/**' d2/d21
+hg status
+hg update -C
+
+echo "# move every file under d1 starting with an 'a' to d2/d21 (regexp)"
+mkdir d2/d21
+hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21
+hg status
+hg update -C
+
+echo "# attempt to overwrite an existing file"
+echo "ca" > d1/ca
+hg rename d1/ba d1/ca
+hg status
+hg update -C
+
+echo "# forced overwrite of an existing file"
+echo "ca" > d1/ca
+hg rename --force d1/ba d1/ca
+hg status
+hg update -C
+
+echo "# replace a symlink with a file"
+ln -s ba d1/ca
+hg rename --force d1/ba d1/ca
+hg status
+hg update -C
+
+echo "# do not copy more than one source file to the same destination file"
+mkdir d3
+hg rename d1/* d2/* d3
+hg status
+hg update -C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename.out Wed Nov 09 12:52:05 2005 -0800
@@ -0,0 +1,115 @@
+# rename a single file
+A d2/c
+R d1/d11/a1
+# move a single file to an existing directory
+A d2/a1
+R d1/d11/a1
+# rename directory d1 as d3
+copying d1/a to d3/a
+copying d1/b to d3/b
+copying d1/ba to d3/ba
+copying d1/d11/a1 to d3/d11/a1
+removing d1/a
+removing d1/b
+removing d1/ba
+removing d1/d11/a1
+A d3/a
+A d3/b
+A d3/ba
+A d3/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+# move directory d1/d11 to an existing directory d2 (removes empty d1)
+copying d1/d11/a1 to d2/d11/a1
+removing d1/d11/a1
+A d2/d11/a1
+R d1/d11/a1
+# move directories d1 and d2 to a new directory d3
+copying d1/a to d3/d1/a
+copying d1/b to d3/d1/b
+copying d1/ba to d3/d1/ba
+copying d1/d11/a1 to d3/d1/d11/a1
+copying d2/b to d3/d2/b
+removing d1/a
+removing d1/b
+removing d1/ba
+removing d1/d11/a1
+removing d2/b
+A d3/d1/a
+A d3/d1/b
+A d3/d1/ba
+A d3/d1/d11/a1
+A d3/d2/b
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+R d2/b
+# move everything under directory d1 to existing directory d2, do not
+# overwrite existing files (d2/b)
+d2/b: not overwriting - file exists
+copying d1/d11/a1 to d2/d11/a1
+removing d1/d11/a1
+A d2/a
+A d2/ba
+A d2/d11/a1
+R d1/a
+R d1/ba
+R d1/d11/a1
+1c1
+< d1/b
+---
+> d2/b
+# attempt to move potentially more than one file into a non-existent
+# directory
+abort: with multiple sources, destination must be an existing directory
+# move every file under d1 to d2/d21 (glob)
+copying d1/a to d2/d21/a
+copying d1/b to d2/d21/b
+copying d1/ba to d2/d21/ba
+copying d1/d11/a1 to d2/d21/a1
+removing d1/a
+removing d1/b
+removing d1/ba
+removing d1/d11/a1
+A d2/d21/a
+A d2/d21/a1
+A d2/d21/b
+A d2/d21/ba
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+# move every file under d1 starting with an 'a' to d2/d21 (regexp)
+copying d1/a to d2/d21/a
+copying d1/d11/a1 to d2/d21/a1
+removing d1/a
+removing d1/d11/a1
+A d2/d21/a
+A d2/d21/a1
+R d1/a
+R d1/d11/a1
+# attempt to overwrite an existing file
+d1/ca: not overwriting - file exists
+abort: no files to copy
+? d1/ca
+# forced overwrite of an existing file
+A d1/ca
+R d1/ba
+# replace a symlink with a file
+A d1/ca
+R d1/ba
+# do not copy more than one source file to the same destination file
+copying d1/d11/a1 to d3/d11/a1
+d3/b: not overwriting - d2/b collides with d1/b
+removing d1/d11/a1
+A d3/a
+A d3/b
+A d3/ba
+A d3/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1