mercurial/dirstate.py
changeset 4616 9b00b73a5286
parent 4615 a8be3c875988
child 4617 70352337934e
equal deleted inserted replaced
4615:a8be3c875988 4616:9b00b73a5286
    23         self._dirty = 0
    23         self._dirty = 0
    24         self._ui = ui
    24         self._ui = ui
    25 
    25 
    26     def __getattr__(self, name):
    26     def __getattr__(self, name):
    27         if name == '_map':
    27         if name == '_map':
    28             self.read()
    28             self._read()
    29             return self._map
    29             return self._map
    30         elif name == '_copymap':
    30         elif name == '_copymap':
    31             self.read()
    31             self._read()
    32             return self._copymap
    32             return self._copymap
    33         elif name == '_branch':
    33         elif name == '_branch':
    34             try:
    34             try:
    35                 self._branch = self._opener("branch").read().strip()\
    35                 self._branch = self._opener("branch").read().strip()\
    36                                or "default"
    36                                or "default"
    44                 if len(st) == 40:
    44                 if len(st) == 40:
    45                     self._pl = st[:20], st[20:40]
    45                     self._pl = st[:20], st[20:40]
    46             except IOError, err:
    46             except IOError, err:
    47                 if err.errno != errno.ENOENT: raise
    47                 if err.errno != errno.ENOENT: raise
    48             return self._pl
    48             return self._pl
    49         elif name == 'dirs':
    49         elif name == '_dirs':
    50             self.dirs = {}
    50             self._dirs = {}
    51             for f in self._map:
    51             for f in self._map:
    52                 self.updatedirs(f, 1)
    52                 self._incpath(f)
    53             return self.dirs
    53             return self._dirs
    54         elif name == '_ignore':
    54         elif name == '_ignore':
    55             files = [self.wjoin('.hgignore')] + self._ui.hgignorefiles()
    55             files = [self.wjoin('.hgignore')] + self._ui.hgignorefiles()
    56             self._ignore = ignore.ignore(self._root, files, self._ui.warn)
    56             self._ignore = ignore.ignore(self._root, files, self._ui.warn)
    57             return self._ignore
    57             return self._ignore
    58         elif name == '_slash':
    58         elif name == '_slash':
   118         self._opener("branch", "w").write(branch + '\n')
   118         self._opener("branch", "w").write(branch + '\n')
   119 
   119 
   120     def state(self, key):
   120     def state(self, key):
   121         return self._map.get(key, ("?",))[0]
   121         return self._map.get(key, ("?",))[0]
   122 
   122 
   123     def read(self):
   123     def _read(self):
   124         self._map = {}
   124         self._map = {}
   125         self._copymap = {}
   125         self._copymap = {}
   126         self._pl = [nullid, nullid]
   126         self._pl = [nullid, nullid]
   127         try:
   127         try:
   128             st = self._opener("dirstate").read()
   128             st = self._opener("dirstate").read()
   154                 copymap[f] = c
   154                 copymap[f] = c
   155             dmap[f] = e[:4]
   155             dmap[f] = e[:4]
   156             pos = newpos
   156             pos = newpos
   157 
   157 
   158     def invalidate(self):
   158     def invalidate(self):
   159         for a in "_map _copymap _branch pl dirs _ignore".split():
   159         for a in "_map _copymap _branch pl _dirs _ignore".split():
   160             if hasattr(self, a):
   160             if hasattr(self, a):
   161                 self.__delattr__(a)
   161                 self.__delattr__(a)
   162 
   162 
   163     def copy(self, source, dest):
   163     def copy(self, source, dest):
   164         self.markdirty()
   164         self.markdirty()
   168         return self._copymap.get(file, None)
   168         return self._copymap.get(file, None)
   169 
   169 
   170     def copies(self):
   170     def copies(self):
   171         return self._copymap
   171         return self._copymap
   172 
   172 
   173     def updatedirs(self, path, delta):
   173     def _incpath(self, path):
   174         for c in strutil.findall(path, '/'):
   174         for c in strutil.findall(path, '/'):
   175             pc = path[:c]
   175             pc = path[:c]
   176             self.dirs.setdefault(pc, 0)
   176             self._dirs.setdefault(pc, 0)
   177             self.dirs[pc] += delta
   177             self._dirs[pc] += 1
       
   178 
       
   179     def _decpath(self, path):
       
   180         for c in strutil.findall(path, '/'):
       
   181             pc = path[:c]
       
   182             self._dirs.setdefault(pc, 0)
       
   183             self._dirs[pc] -= 1
   178 
   184 
   179     def checkinterfering(self, files):
   185     def checkinterfering(self, files):
   180         def prefixes(f):
   186         def prefixes(f):
   181             for c in strutil.rfindall(f, '/'):
   187             for c in strutil.rfindall(f, '/'):
   182                 yield f[:c]
   188                 yield f[:c]
   183         seendirs = {}
   189         seendirs = {}
   184         for f in files:
   190         for f in files:
   185             # shadows
   191             # shadows
   186             if self.dirs.get(f):
   192             if self._dirs.get(f):
   187                 raise util.Abort(_('directory named %r already in dirstate') %
   193                 raise util.Abort(_('directory named %r already in dirstate') %
   188                                  f)
   194                                  f)
   189             for d in prefixes(f):
   195             for d in prefixes(f):
   190                 if d in seendirs:
   196                 if d in seendirs:
   191                     break
   197                     break
   209         if state == "a":
   215         if state == "a":
   210             self.checkinterfering(files)
   216             self.checkinterfering(files)
   211         for f in files:
   217         for f in files:
   212             if state == "r":
   218             if state == "r":
   213                 self._map[f] = ('r', 0, 0, 0)
   219                 self._map[f] = ('r', 0, 0, 0)
   214                 self.updatedirs(f, -1)
   220                 self._decpath(f)
   215             else:
   221             else:
   216                 if state == "a":
   222                 if state == "a":
   217                     self.updatedirs(f, 1)
   223                     self._incpath(f)
   218                 s = os.lstat(self.wjoin(f))
   224                 s = os.lstat(self.wjoin(f))
   219                 st_size = kw.get('st_size', s.st_size)
   225                 st_size = kw.get('st_size', s.st_size)
   220                 st_mtime = kw.get('st_mtime', s.st_mtime)
   226                 st_mtime = kw.get('st_mtime', s.st_mtime)
   221                 self._map[f] = (state, s.st_mode, st_size, st_mtime)
   227                 self._map[f] = (state, s.st_mode, st_size, st_mtime)
   222             if self._copymap.has_key(f):
   228             if self._copymap.has_key(f):
   226         if not files: return
   232         if not files: return
   227         self.markdirty()
   233         self.markdirty()
   228         for f in files:
   234         for f in files:
   229             try:
   235             try:
   230                 del self._map[f]
   236                 del self._map[f]
   231                 self.updatedirs(f, -1)
   237                 self._decpath(f)
   232             except KeyError:
   238             except KeyError:
   233                 self._ui.warn(_("not in dirstate: %s!\n") % f)
   239                 self._ui.warn(_("not in dirstate: %s!\n") % f)
   234                 pass
   240                 pass
   235 
   241 
   236     def rebuild(self, parent, files):
   242     def rebuild(self, parent, files):
   288                 else:
   294                 else:
   289                     break
   295                     break
   290                 bs += 1
   296                 bs += 1
   291         return ret
   297         return ret
   292 
   298 
   293     def supported_type(self, f, st, verbose=False):
   299     def _supported(self, f, st, verbose=False):
   294         if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
   300         if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
   295             return True
   301             return True
   296         if verbose:
   302         if verbose:
   297             kind = 'unknown'
   303             kind = 'unknown'
   298             if stat.S_ISCHR(st.st_mode): kind = _('character device')
   304             if stat.S_ISCHR(st.st_mode): kind = _('character device')
   381                             if directories:
   387                             if directories:
   382                                 yield 'd', np, st
   388                                 yield 'd', np, st
   383                         if imatch(np) and np in dc:
   389                         if imatch(np) and np in dc:
   384                             yield 'm', np, st
   390                             yield 'm', np, st
   385                     elif imatch(np):
   391                     elif imatch(np):
   386                         if self.supported_type(np, st):
   392                         if self._supported(np, st):
   387                             yield 'f', np, st
   393                             yield 'f', np, st
   388                         elif np in dc:
   394                         elif np in dc:
   389                             yield 'm', np, st
   395                             yield 'm', np, st
   390 
   396 
   391         known = {'.hg': 1}
   397         known = {'.hg': 1}
   419                 sorted_.sort(cmp1)
   425                 sorted_.sort(cmp1)
   420                 for e in sorted_:
   426                 for e in sorted_:
   421                     yield e
   427                     yield e
   422             else:
   428             else:
   423                 if not seen(nf) and match(nf):
   429                 if not seen(nf) and match(nf):
   424                     if self.supported_type(ff, st, verbose=True):
   430                     if self._supported(ff, st, verbose=True):
   425                         yield 'f', nf, st
   431                         yield 'f', nf, st
   426                     elif ff in dc:
   432                     elif ff in dc:
   427                         yield 'm', nf, st
   433                         yield 'm', nf, st
   428 
   434 
   429         # step two run through anything left in the dc hash and yield
   435         # step two run through anything left in the dc hash and yield
   456                     except OSError, inst:
   462                     except OSError, inst:
   457                         if inst.errno != errno.ENOENT:
   463                         if inst.errno != errno.ENOENT:
   458                             raise
   464                             raise
   459                         st = None
   465                         st = None
   460                     # We need to re-check that it is a valid file
   466                     # We need to re-check that it is a valid file
   461                     if st and self.supported_type(fn, st):
   467                     if st and self._supported(fn, st):
   462                         nonexistent = False
   468                         nonexistent = False
   463                 # XXX: what to do with file no longer present in the fs
   469                 # XXX: what to do with file no longer present in the fs
   464                 # who are not removed in the dirstate ?
   470                 # who are not removed in the dirstate ?
   465                 if nonexistent and type_ in "nm":
   471                 if nonexistent and type_ in "nm":
   466                     deleted.append(fn)
   472                     deleted.append(fn)