mercurial/util.py
changeset 896 01215ad04283
parent 839 9c918287d10b
parent 895 77b52b864249
child 897 fe30f5434b51
equal deleted inserted replaced
867:0cd2ee61b10a 896:01215ad04283
    14     for f in g:
    14     for f in g:
    15         if f not in seen:
    15         if f not in seen:
    16             seen[f] = 1
    16             seen[f] = 1
    17             yield f
    17             yield f
    18 
    18 
    19 class CommandError(Exception): pass
    19 class Abort(Exception):
       
    20     """Raised if a command needs to print an error and exit."""
    20 
    21 
    21 def always(fn): return True
    22 def always(fn): return True
    22 def never(fn): return False
    23 def never(fn): return False
    23 
    24 
    24 def globre(pat, head = '^', tail = '$'):
    25 def globre(pat, head = '^', tail = '$'):
    66             res += re.escape(c)
    67             res += re.escape(c)
    67     return head + res + tail
    68     return head + res + tail
    68 
    69 
    69 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
    70 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
    70 
    71 
    71 def matcher(cwd, names, inc, exc, head = ''):
    72 def pathto(n1, n2):
       
    73     '''return the relative path from one place to another.
       
    74     this returns a path in the form used by the local filesystem, not hg.'''
       
    75     if not n1: return localpath(n2)
       
    76     a, b = n1.split('/'), n2.split('/')
       
    77     a.reverse(), b.reverse()
       
    78     while a and b and a[-1] == b[-1]:
       
    79         a.pop(), b.pop()
       
    80     b.reverse()
       
    81     return os.sep.join((['..'] * len(a)) + b)
       
    82 
       
    83 def canonpath(repo, cwd, myname):
       
    84     rootsep = repo.root + os.sep
       
    85     name = myname
       
    86     if not name.startswith(os.sep):
       
    87         name = os.path.join(repo.root, cwd, name)
       
    88     name = os.path.normpath(name)
       
    89     if name.startswith(rootsep):
       
    90         return pconvert(name[len(rootsep):])
       
    91     elif name == repo.root:
       
    92         return ''
       
    93     else:
       
    94         raise Abort('%s not under repository root' % myname)
       
    95     
       
    96 def matcher(repo, cwd, names, inc, exc, head = ''):
    72     def patkind(name):
    97     def patkind(name):
    73         for prefix in 're:', 'glob:', 'path:':
    98         for prefix in 're:', 'glob:', 'path:', 'relpath:':
    74             if name.startswith(prefix): return name.split(':', 1)
    99             if name.startswith(prefix): return name.split(':', 1)
    75         for c in name:
   100         for c in name:
    76             if c in _globchars: return 'glob', name
   101             if c in _globchars: return 'glob', name
    77         return 'relpath', name
   102         return 'relpath', name
    78 
   103 
    79     cwdsep = cwd + os.sep
   104     def regex(kind, name, tail):
    80 
       
    81     def regex(name, tail):
       
    82         '''convert a pattern into a regular expression'''
   105         '''convert a pattern into a regular expression'''
    83         kind, name = patkind(name)
       
    84         if kind == 're':
   106         if kind == 're':
    85             return name
   107             return name
    86         elif kind == 'path':
   108         elif kind == 'path':
    87             return '^' + re.escape(name) + '$'
   109             return '^' + re.escape(name) + '(?:/|$)'
    88         if cwd: name = os.path.join(cwdsep, name)
   110         elif kind == 'relpath':
    89         name = os.path.normpath(name)
   111             return head + re.escape(name) + tail
    90         if name == '.': name = '**'
       
    91         return head + globre(name, '', tail)
   112         return head + globre(name, '', tail)
    92 
       
    93     def under(fn):
       
    94         """check if fn is under our cwd"""
       
    95         return not cwd or fn.startswith(cwdsep)
       
    96 
   113 
    97     def matchfn(pats, tail):
   114     def matchfn(pats, tail):
    98         """build a matching function from a set of patterns"""
   115         """build a matching function from a set of patterns"""
    99         if pats:
   116         if pats:
   100             pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats])
   117             pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
   101             return re.compile(pat).match
   118             return re.compile(pat).match
   102 
   119 
   103     def globprefix(pat):
   120     def globprefix(pat):
   104         '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
   121         '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
   105         root = []
   122         root = []
   106         for p in pat.split(os.sep):
   123         for p in pat.split(os.sep):
   107             if patkind(p)[0] == 'glob': break
   124             if patkind(p)[0] == 'glob': break
   108             root.append(p)
   125             root.append(p)
   109         return os.sep.join(root)
   126         return '/'.join(root)
   110 
   127 
   111     patkinds = map(patkind, names)
   128     pats = []
   112     pats = [name for (kind, name) in patkinds if kind != 'relpath']
   129     files = []
   113     files = [name for (kind, name) in patkinds if kind == 'relpath']
   130     roots = []
   114     roots = filter(None, map(globprefix, pats)) + files
   131     for kind, name in map(patkind, names):
   115     if cwd: roots = [cwdsep + r for r in roots]
   132         if kind in ('glob', 'relpath'):
       
   133             name = canonpath(repo, cwd, name)
       
   134             if name == '':
       
   135                 kind, name = 'glob', '**'
       
   136         if kind in ('glob', 'path', 're'):
       
   137             pats.append((kind, name))
       
   138         if kind == 'glob':
       
   139             root = globprefix(name)
       
   140             if root: roots.append(root)
       
   141         elif kind == 'relpath':
       
   142             files.append((kind, name))
       
   143             roots.append(name)
   116         
   144         
   117     patmatch = matchfn(pats, '$') or always
   145     patmatch = matchfn(pats, '$') or always
   118     filematch = matchfn(files, '(?:/|$)') or always
   146     filematch = matchfn(files, '(?:/|$)') or always
   119     incmatch = matchfn(inc, '(?:/|$)') or always
   147     incmatch = matchfn(map(patkind, inc), '(?:/|$)') or always
   120     excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False)
   148     excmatch = matchfn(map(patkind, exc), '(?:/|$)') or (lambda fn: False)
   121 
   149 
   122     return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
   150     return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
   123                               (fn.endswith('/') or
   151                               (fn.endswith('/') or
   124                                (not pats and not files) or
   152                                (not pats and not files) or
   125                                (pats and patmatch(fn)) or
   153                                (pats and patmatch(fn)) or
   131     if rc:
   159     if rc:
   132         errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
   160         errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
   133                             explain_exit(rc)[0])
   161                             explain_exit(rc)[0])
   134         if errprefix:
   162         if errprefix:
   135             errmsg = "%s: %s" % (errprefix, errmsg)
   163             errmsg = "%s: %s" % (errprefix, errmsg)
   136         raise CommandError(errmsg)
   164         raise Abort(errmsg)
   137 
   165 
   138 def rename(src, dst):
   166 def rename(src, dst):
   139     try:
   167     try:
   140         os.rename(src, dst)
   168         os.rename(src, dst)
   141     except:
   169     except:
   175     def set_exec(f, mode):
   203     def set_exec(f, mode):
   176         pass
   204         pass
   177 
   205 
   178     def pconvert(path):
   206     def pconvert(path):
   179         return path.replace("\\", "/")
   207         return path.replace("\\", "/")
       
   208 
       
   209     def localpath(path):
       
   210         return path.replace('/', '\\')
       
   211 
       
   212     def normpath(path):
       
   213         return pconvert(os.path.normpath(path))
   180 
   214 
   181     makelock = _makelock_file
   215     makelock = _makelock_file
   182     readlock = _readlock_file
   216     readlock = _readlock_file
   183 
   217 
   184     def explain_exit(code):
   218     def explain_exit(code):
   204             os.chmod(f, s & 0666)
   238             os.chmod(f, s & 0666)
   205 
   239 
   206     def pconvert(path):
   240     def pconvert(path):
   207         return path
   241         return path
   208 
   242 
       
   243     def localpath(path):
       
   244         return path
       
   245 
       
   246     normpath = os.path.normpath
       
   247 
   209     def makelock(info, pathname):
   248     def makelock(info, pathname):
   210         try:
   249         try:
   211             os.symlink(info, pathname)
   250             os.symlink(info, pathname)
   212         except OSError, why:
   251         except OSError, why:
   213             if why.errno == errno.EEXIST:
   252             if why.errno == errno.EEXIST: