mercurial/hg.py
changeset 740 d2422f10c136
parent 721 fed842bb84b2
parent 737 8db4d406b3d3
child 741 156dc2f3be7f
equal deleted inserted replaced
722:e5b39ce2c3c9 740:d2422f10c136
   275         self.dirty = 0
   275         self.dirty = 0
   276         self.ui = ui
   276         self.ui = ui
   277         self.map = None
   277         self.map = None
   278         self.pl = None
   278         self.pl = None
   279         self.copies = {}
   279         self.copies = {}
       
   280         self.ignorefunc = None
       
   281 
       
   282     def wjoin(self, f):
       
   283         return os.path.join(self.root, f)
       
   284 
       
   285     def ignore(self, f):
       
   286         if not self.ignorefunc:
       
   287             bigpat = []
       
   288             try:
       
   289                 l = file(self.wjoin(".hgignore"))
       
   290                 for pat in l:
       
   291                     if pat != "\n":
       
   292                         p = util.pconvert(pat[:-1])
       
   293                         try:
       
   294                             r = re.compile(p)
       
   295                         except:
       
   296                             self.ui.warn("ignoring invalid ignore"
       
   297                                          + " regular expression '%s'\n" % p)
       
   298                         else:
       
   299                             bigpat.append(util.pconvert(pat[:-1]))
       
   300             except IOError: pass
       
   301 
       
   302             if bigpat:
       
   303                 s = "(?:%s)" % (")|(?:".join(bigpat))
       
   304                 r = re.compile(s)
       
   305                 self.ignorefunc = r.search
       
   306             else:
       
   307                 self.ignorefunc = util.never
       
   308 
       
   309         return self.ignorefunc(f)
   280 
   310 
   281     def __del__(self):
   311     def __del__(self):
   282         if self.dirty:
   312         if self.dirty:
   283             self.write()
   313             self.write()
   284 
   314 
   296     def parents(self):
   326     def parents(self):
   297         if not self.pl:
   327         if not self.pl:
   298             self.read()
   328             self.read()
   299         return self.pl
   329         return self.pl
   300 
   330 
       
   331     def markdirty(self):
       
   332         if not self.dirty:
       
   333             self.dirty = 1
       
   334 
   301     def setparents(self, p1, p2 = nullid):
   335     def setparents(self, p1, p2 = nullid):
   302         self.dirty = 1
   336         self.markdirty()
   303         self.pl = p1, p2
   337         self.pl = p1, p2
   304 
   338 
   305     def state(self, key):
   339     def state(self, key):
   306         try:
   340         try:
   307             return self[key][0]
   341             return self[key][0]
   332             self.map[f] = e[:4]
   366             self.map[f] = e[:4]
   333             pos += l
   367             pos += l
   334 
   368 
   335     def copy(self, source, dest):
   369     def copy(self, source, dest):
   336         self.read()
   370         self.read()
   337         self.dirty = 1
   371         self.markdirty()
   338         self.copies[dest] = source
   372         self.copies[dest] = source
   339 
   373 
   340     def copied(self, file):
   374     def copied(self, file):
   341         return self.copies.get(file, None)
   375         return self.copies.get(file, None)
   342 
   376 
   347         r  marked for removal
   381         r  marked for removal
   348         a  marked for addition'''
   382         a  marked for addition'''
   349 
   383 
   350         if not files: return
   384         if not files: return
   351         self.read()
   385         self.read()
   352         self.dirty = 1
   386         self.markdirty()
   353         for f in files:
   387         for f in files:
   354             if state == "r":
   388             if state == "r":
   355                 self.map[f] = ('r', 0, 0, 0)
   389                 self.map[f] = ('r', 0, 0, 0)
   356             else:
   390             else:
   357                 s = os.stat(os.path.join(self.root, f))
   391                 s = os.stat(os.path.join(self.root, f))
   358                 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
   392                 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
   359 
   393 
   360     def forget(self, files):
   394     def forget(self, files):
   361         if not files: return
   395         if not files: return
   362         self.read()
   396         self.read()
   363         self.dirty = 1
   397         self.markdirty()
   364         for f in files:
   398         for f in files:
   365             try:
   399             try:
   366                 del self.map[f]
   400                 del self.map[f]
   367             except KeyError:
   401             except KeyError:
   368                 self.ui.warn("not in dirstate: %s!\n" % f)
   402                 self.ui.warn("not in dirstate: %s!\n" % f)
   369                 pass
   403                 pass
   370 
   404 
   371     def clear(self):
   405     def clear(self):
   372         self.map = {}
   406         self.map = {}
   373         self.dirty = 1
   407         self.markdirty()
   374 
   408 
   375     def write(self):
   409     def write(self):
   376         st = self.opener("dirstate", "w")
   410         st = self.opener("dirstate", "w")
   377         st.write("".join(self.pl))
   411         st.write("".join(self.pl))
   378         for f, e in self.map.items():
   412         for f, e in self.map.items():
   381                 f = f + "\0" + c
   415                 f = f + "\0" + c
   382             e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
   416             e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
   383             st.write(e + f)
   417             st.write(e + f)
   384         self.dirty = 0
   418         self.dirty = 0
   385 
   419 
   386     def changes(self, files, ignore):
   420     def walk(self, files = None, match = util.always):
   387         self.read()
   421         self.read()
   388         dc = self.map.copy()
   422         dc = self.map.copy()
   389         lookup, changed, added, unknown = [], [], [], []
   423         # walk all files by default
   390 
       
   391         # compare all files by default
       
   392         if not files: files = [self.root]
   424         if not files: files = [self.root]
   393 
   425         def traverse():
   394         # recursive generator of all files listed
       
   395         def walk(files):
       
   396             for f in util.unique(files):
   426             for f in util.unique(files):
   397                 f = os.path.join(self.root, f)
   427                 f = os.path.join(self.root, f)
   398                 if os.path.isdir(f):
   428                 if os.path.isdir(f):
   399                     for dir, subdirs, fl in os.walk(f):
   429                     for dir, subdirs, fl in os.walk(f):
   400                         d = dir[len(self.root) + 1:]
   430                         d = dir[len(self.root) + 1:]
       
   431                         if d == '.hg':
       
   432                             subdirs[:] = []
       
   433                             continue
   401                         for sd in subdirs:
   434                         for sd in subdirs:
   402                             if ignore(os.path.join(d, sd +'/')):
   435                             ds = os.path.join(d, sd +'/')
       
   436                             if self.ignore(ds) or not match(ds):
   403                                 subdirs.remove(sd)
   437                                 subdirs.remove(sd)
   404                         for fn in fl:
   438                         for fn in fl:
   405                             fn = util.pconvert(os.path.join(d, fn))
   439                             fn = util.pconvert(os.path.join(d, fn))
   406                             yield fn
   440                             yield 'f', fn
   407                 else:
   441                 else:
   408                     yield f[len(self.root) + 1:]
   442                     yield 'f', f[len(self.root) + 1:]
   409 
   443 
   410             for k in dc.keys():
   444             for k in dc.keys():
   411                 yield k
   445                 yield 'm', k
   412 
   446 
   413         for fn in util.unique(walk(files)):
   447         # yield only files that match: all in dirstate, others only if
       
   448         # not in .hgignore
       
   449 
       
   450         for src, fn in util.unique(traverse()):
       
   451             if fn in dc:
       
   452                 del dc[fn]
       
   453             elif self.ignore(fn):
       
   454                 continue
       
   455             if match(fn):
       
   456                 yield src, fn
       
   457 
       
   458     def changes(self, files = None, match = util.always):
       
   459         self.read()
       
   460         dc = self.map.copy()
       
   461         lookup, changed, added, unknown = [], [], [], []
       
   462 
       
   463         for src, fn in self.walk(files, match):
   414             try: s = os.stat(os.path.join(self.root, fn))
   464             try: s = os.stat(os.path.join(self.root, fn))
   415             except: continue
   465             except: continue
   416 
   466 
   417             if fn in dc:
   467             if fn in dc:
   418                 c = dc[fn]
   468                 c = dc[fn]
   427                 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
   477                 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
   428                     changed.append(fn)
   478                     changed.append(fn)
   429                 elif c[1] != s.st_mode or c[3] != s.st_mtime:
   479                 elif c[1] != s.st_mode or c[3] != s.st_mtime:
   430                     lookup.append(fn)
   480                     lookup.append(fn)
   431             else:
   481             else:
   432                 if not ignore(fn): unknown.append(fn)
   482                 if match(fn): unknown.append(fn)
   433 
   483 
   434         return (lookup, changed, added, dc.keys(), unknown)
   484         return (lookup, changed, added, filter(match, dc.keys()), unknown)
   435 
   485 
   436 # used to avoid circular references so destructors work
   486 # used to avoid circular references so destructors work
   437 def opener(base):
   487 def opener(base):
   438     p = base
   488     p = base
   439     def o(path, mode="r"):
   489     def o(path, mode="r"):
   491 
   541 
   492         self.opener = opener(self.path)
   542         self.opener = opener(self.path)
   493         self.wopener = opener(self.root)
   543         self.wopener = opener(self.root)
   494         self.manifest = manifest(self.opener)
   544         self.manifest = manifest(self.opener)
   495         self.changelog = changelog(self.opener)
   545         self.changelog = changelog(self.opener)
   496         self.ignorefunc = None
       
   497         self.tagscache = None
   546         self.tagscache = None
   498         self.nodetagscache = None
   547         self.nodetagscache = None
   499 
   548 
   500         if not self.remote:
   549         if not self.remote:
   501             self.dirstate = dirstate(self.opener, ui, self.root)
   550             self.dirstate = dirstate(self.opener, ui, self.root)
   502             try:
   551             try:
   503                 self.ui.readconfig(self.opener("hgrc"))
   552                 self.ui.readconfig(self.opener("hgrc"))
   504             except IOError: pass
   553             except IOError: pass
   505 
       
   506     def ignore(self, f):
       
   507         if not self.ignorefunc:
       
   508             bigpat = ["^.hg/$"]
       
   509             try:
       
   510                 l = file(self.wjoin(".hgignore"))
       
   511                 for pat in l:
       
   512                     if pat != "\n":
       
   513                         p = util.pconvert(pat[:-1])
       
   514                         try:
       
   515                             r = re.compile(p)
       
   516                         except:
       
   517                             self.ui.warn("ignoring invalid ignore"
       
   518                                          + " regular expression '%s'\n" % p)
       
   519                         else:
       
   520                             bigpat.append(util.pconvert(pat[:-1]))
       
   521             except IOError: pass
       
   522 
       
   523             s = "(?:%s)" % (")|(?:".join(bigpat))
       
   524             r = re.compile(s)
       
   525             self.ignorefunc = r.search
       
   526 
       
   527         return self.ignorefunc(f)
       
   528 
   554 
   529     def hook(self, name, **args):
   555     def hook(self, name, **args):
   530         s = self.ui.config("hooks", name)
   556         s = self.ui.config("hooks", name)
   531         if s:
   557         if s:
   532             self.ui.note("running hook %s: %s\n" % (name, s))
   558             self.ui.note("running hook %s: %s\n" % (name, s))
   736                 elif s == 'r':
   762                 elif s == 'r':
   737                     remove.append(f)
   763                     remove.append(f)
   738                 else:
   764                 else:
   739                     self.ui.warn("%s not tracked!\n" % f)
   765                     self.ui.warn("%s not tracked!\n" % f)
   740         else:
   766         else:
   741             (c, a, d, u) = self.changes(None, None)
   767             (c, a, d, u) = self.changes()
   742             commit = c + a
   768             commit = c + a
   743             remove = d
   769             remove = d
   744 
   770 
   745         if not commit and not remove:
   771         if not commit and not remove:
   746             self.ui.status("nothing changed\n")
   772             self.ui.status("nothing changed\n")
   813         self.dirstate.forget(remove)
   839         self.dirstate.forget(remove)
   814 
   840 
   815         if not self.hook("commit", node=hex(n)):
   841         if not self.hook("commit", node=hex(n)):
   816             return 1
   842             return 1
   817 
   843 
   818     def changes(self, node1, node2, files=None):
   844     def walk(self, node = None, files = [], match = util.always):
       
   845         if node:
       
   846             for fn in self.manifest.read(self.changelog.read(node)[0]):
       
   847                 yield 'm', fn
       
   848         else:
       
   849             for src, fn in self.dirstate.walk(files, match):
       
   850                 yield src, fn
       
   851 
       
   852     def changes(self, node1 = None, node2 = None, files = [],
       
   853                 match = util.always):
   819         mf2, u = None, []
   854         mf2, u = None, []
   820 
   855 
   821         def fcmp(fn, mf):
   856         def fcmp(fn, mf):
   822             t1 = self.wfile(fn).read()
   857             t1 = self.wfile(fn).read()
   823             t2 = self.file(fn).revision(mf[fn])
   858             t2 = self.file(fn).revision(mf[fn])
   824             return cmp(t1, t2)
   859             return cmp(t1, t2)
   825 
   860 
       
   861         def mfmatches(node):
       
   862             mf = dict(self.manifest.read(node))
       
   863             for fn in mf.keys():
       
   864                 if not match(fn):
       
   865                     del mf[fn]
       
   866             return mf
       
   867             
   826         # are we comparing the working directory?
   868         # are we comparing the working directory?
   827         if not node2:
   869         if not node2:
   828             l, c, a, d, u = self.dirstate.changes(files, self.ignore)
   870             l, c, a, d, u = self.dirstate.changes(files, match)
   829 
   871 
   830             # are we comparing working dir against its parent?
   872             # are we comparing working dir against its parent?
   831             if not node1:
   873             if not node1:
   832                 if l:
   874                 if l:
   833                     # do a full compare of any files that might have changed
   875                     # do a full compare of any files that might have changed
   834                     change = self.changelog.read(self.dirstate.parents()[0])
   876                     change = self.changelog.read(self.dirstate.parents()[0])
   835                     mf2 = self.manifest.read(change[0])
   877                     mf2 = mfmatches(change[0])
   836                     for f in l:
   878                     for f in l:
   837                         if fcmp(f, mf2):
   879                         if fcmp(f, mf2):
   838                             c.append(f)
   880                             c.append(f)
   839 
   881 
   840                 for l in c, a, d, u:
   882                 for l in c, a, d, u:
   845         # are we comparing working dir against non-tip?
   887         # are we comparing working dir against non-tip?
   846         # generate a pseudo-manifest for the working dir
   888         # generate a pseudo-manifest for the working dir
   847         if not node2:
   889         if not node2:
   848             if not mf2:
   890             if not mf2:
   849                 change = self.changelog.read(self.dirstate.parents()[0])
   891                 change = self.changelog.read(self.dirstate.parents()[0])
   850                 mf2 = self.manifest.read(change[0]).copy()
   892                 mf2 = mfmatches(change[0])
   851             for f in a + c + l:
   893             for f in a + c + l:
   852                 mf2[f] = ""
   894                 mf2[f] = ""
   853             for f in d:
   895             for f in d:
   854                 if f in mf2: del mf2[f]
   896                 if f in mf2: del mf2[f]
   855         else:
   897         else:
   856             change = self.changelog.read(node2)
   898             change = self.changelog.read(node2)
   857             mf2 = self.manifest.read(change[0])
   899             mf2 = mfmatches(change[0])
   858 
   900 
   859         # flush lists from dirstate before comparing manifests
   901         # flush lists from dirstate before comparing manifests
   860         c, a = [], []
   902         c, a = [], []
   861 
   903 
   862         change = self.changelog.read(node1)
   904         change = self.changelog.read(node1)
   863         mf1 = self.manifest.read(change[0]).copy()
   905         mf1 = mfmatches(change[0])
   864 
   906 
   865         for fn in mf2:
   907         for fn in mf2:
   866             if mf1.has_key(fn):
   908             if mf1.has_key(fn):
   867                 if mf1[fn] != mf2[fn]:
   909                 if mf1[fn] != mf2[fn]:
   868                     if mf2[fn] != "" or fcmp(fn, mf1):
   910                     if mf2[fn] != "" or fcmp(fn, mf1):
   883             p = self.wjoin(f)
   925             p = self.wjoin(f)
   884             if not os.path.exists(p):
   926             if not os.path.exists(p):
   885                 self.ui.warn("%s does not exist!\n" % f)
   927                 self.ui.warn("%s does not exist!\n" % f)
   886             elif not os.path.isfile(p):
   928             elif not os.path.isfile(p):
   887                 self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
   929                 self.ui.warn("%s not added: mercurial only supports files currently\n" % f)
   888             elif self.dirstate.state(f) == 'n':
   930             elif self.dirstate.state(f) in 'an':
   889                 self.ui.warn("%s already tracked!\n" % f)
   931                 self.ui.warn("%s already tracked!\n" % f)
   890             else:
   932             else:
   891                 self.dirstate.update([f], "a")
   933                 self.dirstate.update([f], "a")
   892 
   934 
   893     def forget(self, list):
   935     def forget(self, list):
  1266         m2 = self.manifest.read(m2n)
  1308         m2 = self.manifest.read(m2n)
  1267         mf2 = self.manifest.readflags(m2n)
  1309         mf2 = self.manifest.readflags(m2n)
  1268         ma = self.manifest.read(man)
  1310         ma = self.manifest.read(man)
  1269         mfa = self.manifest.readflags(man)
  1311         mfa = self.manifest.readflags(man)
  1270 
  1312 
  1271         (c, a, d, u) = self.changes(None, None)
  1313         (c, a, d, u) = self.changes()
  1272 
  1314 
  1273         # is this a jump, or a merge?  i.e. is there a linear path
  1315         # is this a jump, or a merge?  i.e. is there a linear path
  1274         # from p1 to p2?
  1316         # from p1 to p2?
  1275         linear_path = (pa == p1 or pa == p2)
  1317         linear_path = (pa == p1 or pa == p2)
  1276 
  1318