--- a/mercurial/cmdutil.py Sun Dec 02 17:04:16 2007 -0600
+++ b/mercurial/cmdutil.py Sun Dec 02 18:11:59 2007 -0600
@@ -8,7 +8,7 @@
from node import *
from i18n import _
import os, sys, bisect, stat
-import mdiff, bdiff, util, templater, patch
+import mdiff, bdiff, util, templater, patch, errno
revrangesep = ':'
@@ -286,6 +286,204 @@
if not dry_run:
repo.copy(old, new)
+def copy(ui, repo, pats, opts):
+ # called with the repo lock held
+ #
+ # hgsep => pathname that uses "/" to separate directories
+ # ossep => pathname that uses os.sep to separate directories
+ cwd = repo.getcwd()
+ errors = 0
+ copied = []
+ targets = {}
+
+ # abs: hgsep
+ # rel: ossep
+ # return: hgsep
+ def okaytocopy(abs, rel, exact):
+ reasons = {'?': _('is not managed'),
+ 'r': _('has been marked for remove')}
+ state = repo.dirstate[abs]
+ reason = reasons.get(state)
+ if reason:
+ if exact:
+ ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
+ else:
+ if state == 'a':
+ origsrc = repo.dirstate.copied(abs)
+ if origsrc is not None:
+ return origsrc
+ return abs
+
+ # origsrc: hgsep
+ # abssrc: hgsep
+ # relsrc: ossep
+ # otarget: ossep
+ def copy(origsrc, abssrc, relsrc, otarget, exact):
+ abstarget = util.canonpath(repo.root, cwd, otarget)
+ reltarget = repo.pathto(abstarget, cwd)
+ prevsrc = targets.get(abstarget)
+ src = repo.wjoin(abssrc)
+ target = repo.wjoin(abstarget)
+ if prevsrc is not None:
+ ui.warn(_('%s: not overwriting - %s collides with %s\n') %
+ (reltarget, repo.pathto(abssrc, cwd),
+ repo.pathto(prevsrc, cwd)))
+ return
+ if (not opts['after'] and os.path.exists(target) or
+ opts['after'] and repo.dirstate[abstarget] in 'mn'):
+ if not opts['force']:
+ ui.warn(_('%s: not overwriting - file exists\n') %
+ reltarget)
+ return
+ if not opts['after'] and not opts.get('dry_run'):
+ os.unlink(target)
+ if opts['after']:
+ if not os.path.exists(target):
+ return
+ else:
+ targetdir = os.path.dirname(target) or '.'
+ if not os.path.isdir(targetdir) and not opts.get('dry_run'):
+ os.makedirs(targetdir)
+ try:
+ restore = repo.dirstate[abstarget] == 'r'
+ if restore and not opts.get('dry_run'):
+ repo.undelete([abstarget])
+ try:
+ if not opts.get('dry_run'):
+ util.copyfile(src, target)
+ restore = False
+ finally:
+ if restore:
+ repo.remove([abstarget])
+ except IOError, inst:
+ if inst.errno == errno.ENOENT:
+ ui.warn(_('%s: deleted in working copy\n') % relsrc)
+ else:
+ ui.warn(_('%s: cannot copy - %s\n') %
+ (relsrc, inst.strerror))
+ errors += 1
+ return
+ if ui.verbose or not exact:
+ ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
+ targets[abstarget] = abssrc
+ if abstarget != origsrc:
+ if repo.dirstate[origsrc] == 'a':
+ if not ui.quiet:
+ ui.warn(_("%s has not been committed yet, so no copy "
+ "data will be stored for %s.\n")
+ % (repo.pathto(origsrc, cwd), reltarget))
+ if abstarget not in repo.dirstate and not opts.get('dry_run'):
+ repo.add([abstarget])
+ elif not opts.get('dry_run'):
+ repo.copy(origsrc, abstarget)
+ copied.append((abssrc, relsrc, exact))
+
+ # pat: ossep
+ # dest ossep
+ # srcs: list of (hgsep, hgsep, ossep, bool)
+ # return: function that takes hgsep and returns ossep
+ def targetpathfn(pat, dest, srcs):
+ if os.path.isdir(pat):
+ abspfx = util.canonpath(repo.root, cwd, pat)
+ abspfx = util.localpath(abspfx)
+ if destdirexists:
+ striplen = len(os.path.split(abspfx)[0])
+ else:
+ striplen = len(abspfx)
+ if striplen:
+ striplen += len(os.sep)
+ res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
+ elif destdirexists:
+ res = lambda p: os.path.join(dest,
+ os.path.basename(util.localpath(p)))
+ else:
+ res = lambda p: dest
+ return res
+
+ # pat: ossep
+ # dest ossep
+ # srcs: list of (hgsep, hgsep, ossep, bool)
+ # return: function that takes hgsep and returns ossep
+ def targetpathafterfn(pat, dest, srcs):
+ if util.patkind(pat, None)[0]:
+ # a mercurial pattern
+ res = lambda p: os.path.join(dest,
+ os.path.basename(util.localpath(p)))
+ else:
+ abspfx = util.canonpath(repo.root, cwd, pat)
+ if len(abspfx) < len(srcs[0][0]):
+ # A directory. Either the target path contains the last
+ # component of the source path or it does not.
+ def evalpath(striplen):
+ score = 0
+ for s in srcs:
+ t = os.path.join(dest, util.localpath(s[0])[striplen:])
+ if os.path.exists(t):
+ score += 1
+ return score
+
+ abspfx = util.localpath(abspfx)
+ striplen = len(abspfx)
+ if striplen:
+ striplen += len(os.sep)
+ if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
+ score = evalpath(striplen)
+ striplen1 = len(os.path.split(abspfx)[0])
+ if striplen1:
+ striplen1 += len(os.sep)
+ if evalpath(striplen1) > score:
+ striplen = striplen1
+ res = lambda p: os.path.join(dest,
+ util.localpath(p)[striplen:])
+ else:
+ # a file
+ if destdirexists:
+ res = lambda p: os.path.join(dest,
+ os.path.basename(util.localpath(p)))
+ else:
+ res = lambda p: dest
+ return res
+
+
+ pats = util.expand_glob(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 not destdirexists:
+ if len(pats) > 1 or util.patkind(pats[0], None)[0]:
+ raise util.Abort(_('with multiple sources, destination must be an '
+ 'existing directory'))
+ if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep):
+ raise util.Abort(_('destination %s is not a directory') % dest)
+ if opts['after']:
+ tfn = targetpathafterfn
+ else:
+ tfn = targetpathfn
+ copylist = []
+ for pat in pats:
+ srcs = []
+ for tag, abssrc, relsrc, exact in walk(repo, [pat], opts,
+ globbed=True):
+ origsrc = okaytocopy(abssrc, relsrc, exact)
+ if origsrc:
+ srcs.append((origsrc, abssrc, relsrc, exact))
+ if not srcs:
+ continue
+ copylist.append((tfn(pat, dest, srcs), srcs))
+ if not copylist:
+ raise util.Abort(_('no files to copy'))
+
+ for targetpath, srcs in copylist:
+ for origsrc, abssrc, relsrc, exact in srcs:
+ copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
+
+ if errors:
+ ui.warn(_('(consider using --after)\n'))
+ return errors, copied
+
def service(opts, parentfn=None, initfn=None, runfn=None):
'''Run a command as a service.'''
--- a/mercurial/commands.py Sun Dec 02 17:04:16 2007 -0600
+++ b/mercurial/commands.py Sun Dec 02 18:11:59 2007 -0600
@@ -438,204 +438,6 @@
force_editor=opts.get('force_editor'))
cmdutil.commit(ui, repo, commitfunc, pats, opts)
-def docopy(ui, repo, pats, opts):
- # called with the repo lock held
- #
- # hgsep => pathname that uses "/" to separate directories
- # ossep => pathname that uses os.sep to separate directories
- cwd = repo.getcwd()
- errors = 0
- copied = []
- targets = {}
-
- # abs: hgsep
- # rel: ossep
- # return: hgsep
- def okaytocopy(abs, rel, exact):
- reasons = {'?': _('is not managed'),
- 'r': _('has been marked for remove')}
- state = repo.dirstate[abs]
- reason = reasons.get(state)
- if reason:
- if exact:
- ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
- else:
- if state == 'a':
- origsrc = repo.dirstate.copied(abs)
- if origsrc is not None:
- return origsrc
- return abs
-
- # origsrc: hgsep
- # abssrc: hgsep
- # relsrc: ossep
- # otarget: ossep
- def copy(origsrc, abssrc, relsrc, otarget, exact):
- abstarget = util.canonpath(repo.root, cwd, otarget)
- reltarget = repo.pathto(abstarget, cwd)
- prevsrc = targets.get(abstarget)
- src = repo.wjoin(abssrc)
- target = repo.wjoin(abstarget)
- if prevsrc is not None:
- ui.warn(_('%s: not overwriting - %s collides with %s\n') %
- (reltarget, repo.pathto(abssrc, cwd),
- repo.pathto(prevsrc, cwd)))
- return
- if (not opts['after'] and os.path.exists(target) or
- opts['after'] and repo.dirstate[abstarget] in 'mn'):
- if not opts['force']:
- ui.warn(_('%s: not overwriting - file exists\n') %
- reltarget)
- return
- if not opts['after'] and not opts.get('dry_run'):
- os.unlink(target)
- if opts['after']:
- if not os.path.exists(target):
- return
- else:
- targetdir = os.path.dirname(target) or '.'
- if not os.path.isdir(targetdir) and not opts.get('dry_run'):
- os.makedirs(targetdir)
- try:
- restore = repo.dirstate[abstarget] == 'r'
- if restore and not opts.get('dry_run'):
- repo.undelete([abstarget])
- try:
- if not opts.get('dry_run'):
- util.copyfile(src, target)
- restore = False
- finally:
- if restore:
- repo.remove([abstarget])
- except IOError, inst:
- if inst.errno == errno.ENOENT:
- ui.warn(_('%s: deleted in working copy\n') % relsrc)
- else:
- ui.warn(_('%s: cannot copy - %s\n') %
- (relsrc, inst.strerror))
- errors += 1
- return
- if ui.verbose or not exact:
- ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
- targets[abstarget] = abssrc
- if abstarget != origsrc:
- if repo.dirstate[origsrc] == 'a':
- if not ui.quiet:
- ui.warn(_("%s has not been committed yet, so no copy "
- "data will be stored for %s.\n")
- % (repo.pathto(origsrc, cwd), reltarget))
- if abstarget not in repo.dirstate and not opts.get('dry_run'):
- repo.add([abstarget])
- elif not opts.get('dry_run'):
- repo.copy(origsrc, abstarget)
- copied.append((abssrc, relsrc, exact))
-
- # pat: ossep
- # dest ossep
- # srcs: list of (hgsep, hgsep, ossep, bool)
- # return: function that takes hgsep and returns ossep
- def targetpathfn(pat, dest, srcs):
- if os.path.isdir(pat):
- abspfx = util.canonpath(repo.root, cwd, pat)
- abspfx = util.localpath(abspfx)
- if destdirexists:
- striplen = len(os.path.split(abspfx)[0])
- else:
- striplen = len(abspfx)
- if striplen:
- striplen += len(os.sep)
- res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
- elif destdirexists:
- res = lambda p: os.path.join(dest,
- os.path.basename(util.localpath(p)))
- else:
- res = lambda p: dest
- return res
-
- # pat: ossep
- # dest ossep
- # srcs: list of (hgsep, hgsep, ossep, bool)
- # return: function that takes hgsep and returns ossep
- def targetpathafterfn(pat, dest, srcs):
- if util.patkind(pat, None)[0]:
- # a mercurial pattern
- res = lambda p: os.path.join(dest,
- os.path.basename(util.localpath(p)))
- else:
- abspfx = util.canonpath(repo.root, cwd, pat)
- if len(abspfx) < len(srcs[0][0]):
- # A directory. Either the target path contains the last
- # component of the source path or it does not.
- def evalpath(striplen):
- score = 0
- for s in srcs:
- t = os.path.join(dest, util.localpath(s[0])[striplen:])
- if os.path.exists(t):
- score += 1
- return score
-
- abspfx = util.localpath(abspfx)
- striplen = len(abspfx)
- if striplen:
- striplen += len(os.sep)
- if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
- score = evalpath(striplen)
- striplen1 = len(os.path.split(abspfx)[0])
- if striplen1:
- striplen1 += len(os.sep)
- if evalpath(striplen1) > score:
- striplen = striplen1
- res = lambda p: os.path.join(dest,
- util.localpath(p)[striplen:])
- else:
- # a file
- if destdirexists:
- res = lambda p: os.path.join(dest,
- os.path.basename(util.localpath(p)))
- else:
- res = lambda p: dest
- return res
-
-
- pats = util.expand_glob(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 not destdirexists:
- if len(pats) > 1 or util.patkind(pats[0], None)[0]:
- raise util.Abort(_('with multiple sources, destination must be an '
- 'existing directory'))
- if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep):
- raise util.Abort(_('destination %s is not a directory') % dest)
- if opts['after']:
- tfn = targetpathafterfn
- else:
- tfn = targetpathfn
- copylist = []
- for pat in pats:
- srcs = []
- for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
- globbed=True):
- origsrc = okaytocopy(abssrc, relsrc, exact)
- if origsrc:
- srcs.append((origsrc, abssrc, relsrc, exact))
- if not srcs:
- continue
- copylist.append((tfn(pat, dest, srcs), srcs))
- if not copylist:
- raise util.Abort(_('no files to copy'))
-
- for targetpath, srcs in copylist:
- for origsrc, abssrc, relsrc, exact in srcs:
- copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
-
- if errors:
- ui.warn(_('(consider using --after)\n'))
- return errors, copied
-
def copy(ui, repo, *pats, **opts):
"""mark files as copied for the next commit
@@ -652,7 +454,7 @@
"""
wlock = repo.wlock(False)
try:
- errs, copied = docopy(ui, repo, pats, opts)
+ errs, copied = cmdutil.copy(ui, repo, pats, opts)
finally:
del wlock
return errs
@@ -2260,7 +2062,7 @@
"""
wlock = repo.wlock(False)
try:
- errs, copied = docopy(ui, repo, pats, opts)
+ errs, copied = cmdutil.copy(ui, repo, pats, opts)
names = []
for abs, rel, exact in copied:
if ui.verbose or not exact: