mercurial/localrepo.py
changeset 1615 83238c1db6de
parent 1597 96b47ef8f740
child 1616 f0f9e84849e7
equal deleted inserted replaced
1614:0952d164030e 1615:83238c1db6de
    17         if not path:
    17         if not path:
    18             p = os.getcwd()
    18             p = os.getcwd()
    19             while not os.path.isdir(os.path.join(p, ".hg")):
    19             while not os.path.isdir(os.path.join(p, ".hg")):
    20                 oldp = p
    20                 oldp = p
    21                 p = os.path.dirname(p)
    21                 p = os.path.dirname(p)
    22                 if p == oldp: raise repo.RepoError(_("no repo found"))
    22                 if p == oldp:
       
    23                     raise repo.RepoError(_("no repo found"))
    23             path = p
    24             path = p
    24         self.path = os.path.join(path, ".hg")
    25         self.path = os.path.join(path, ".hg")
    25 
    26 
    26         if not create and not os.path.isdir(self.path):
    27         if not create and not os.path.isdir(self.path):
    27             raise repo.RepoError(_("repository %s not found") % path)
    28             raise repo.RepoError(_("repository %s not found") % path)
    42             os.mkdir(self.join("data"))
    43             os.mkdir(self.join("data"))
    43 
    44 
    44         self.dirstate = dirstate.dirstate(self.opener, ui, self.root)
    45         self.dirstate = dirstate.dirstate(self.opener, ui, self.root)
    45         try:
    46         try:
    46             self.ui.readconfig(self.join("hgrc"))
    47             self.ui.readconfig(self.join("hgrc"))
    47         except IOError: pass
    48         except IOError:
       
    49             pass
    48 
    50 
    49     def hook(self, name, **args):
    51     def hook(self, name, **args):
    50         def runhook(name, cmd):
    52         def runhook(name, cmd):
    51             self.ui.note(_("running hook %s: %s\n") % (name, cmd))
    53             self.ui.note(_("running hook %s: %s\n") % (name, cmd))
    52             old = {}
    54             old = {}
   124         for t, n in self.tags().items():
   126         for t, n in self.tags().items():
   125             try:
   127             try:
   126                 r = self.changelog.rev(n)
   128                 r = self.changelog.rev(n)
   127             except:
   129             except:
   128                 r = -2 # sort to the beginning of the list if unknown
   130                 r = -2 # sort to the beginning of the list if unknown
   129             l.append((r,t,n))
   131             l.append((r, t, n))
   130         l.sort()
   132         l.sort()
   131         return [(t,n) for r,t,n in l]
   133         return [(t, n) for r, t, n in l]
   132 
   134 
   133     def nodetags(self, node):
   135     def nodetags(self, node):
   134         '''return the tags associated with a node'''
   136         '''return the tags associated with a node'''
   135         if not self.nodetagscache:
   137         if not self.nodetagscache:
   136             self.nodetagscache = {}
   138             self.nodetagscache = {}
   137             for t,n in self.tags().items():
   139             for t, n in self.tags().items():
   138                 self.nodetagscache.setdefault(n,[]).append(t)
   140                 self.nodetagscache.setdefault(n, []).append(t)
   139         return self.nodetagscache.get(node, [])
   141         return self.nodetagscache.get(node, [])
   140 
   142 
   141     def lookup(self, key):
   143     def lookup(self, key):
   142         try:
   144         try:
   143             return self.tags()[key]
   145             return self.tags()[key]
   158 
   160 
   159     def wjoin(self, f):
   161     def wjoin(self, f):
   160         return os.path.join(self.root, f)
   162         return os.path.join(self.root, f)
   161 
   163 
   162     def file(self, f):
   164     def file(self, f):
   163         if f[0] == '/': f = f[1:]
   165         if f[0] == '/':
       
   166             f = f[1:]
   164         return filelog.filelog(self.opener, f)
   167         return filelog.filelog(self.opener, f)
   165 
   168 
   166     def getcwd(self):
   169     def getcwd(self):
   167         return self.dirstate.getcwd()
   170         return self.dirstate.getcwd()
   168 
   171 
   334         n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
   337         n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
   335         tr.close()
   338         tr.close()
   336         if update_dirstate:
   339         if update_dirstate:
   337             self.dirstate.setparents(n, nullid)
   340             self.dirstate.setparents(n, nullid)
   338 
   341 
   339     def commit(self, files = None, text = "", user = None, date = None,
   342     def commit(self, files=None, text="", user=None, date=None,
   340                match = util.always, force=False):
   343                match=util.always, force=False):
   341         commit = []
   344         commit = []
   342         remove = []
   345         remove = []
   343         changed = []
   346         changed = []
   344 
   347 
   345         if files:
   348         if files:
   470                     util.pathto(self.getcwd(), fn), short(node)))
   473                     util.pathto(self.getcwd(), fn), short(node)))
   471         else:
   474         else:
   472             for src, fn in self.dirstate.walk(files, match):
   475             for src, fn in self.dirstate.walk(files, match):
   473                 yield src, fn
   476                 yield src, fn
   474 
   477 
   475     def changes(self, node1 = None, node2 = None, files = [],
   478     def changes(self, node1=None, node2=None, files=[], match=util.always):
   476                 match = util.always):
       
   477         mf2, u = None, []
   479         mf2, u = None, []
   478 
   480 
   479         def fcmp(fn, mf):
   481         def fcmp(fn, mf):
   480             t1 = self.wread(fn)
   482             t1 = self.wread(fn)
   481             t2 = self.file(fn).read(mf.get(fn, nullid))
   483             t2 = self.file(fn).read(mf.get(fn, nullid))
   520                 change = self.changelog.read(self.dirstate.parents()[0])
   522                 change = self.changelog.read(self.dirstate.parents()[0])
   521                 mf2 = mfmatches(change[0])
   523                 mf2 = mfmatches(change[0])
   522             for f in a + c + l:
   524             for f in a + c + l:
   523                 mf2[f] = ""
   525                 mf2[f] = ""
   524             for f in d:
   526             for f in d:
   525                 if f in mf2: del mf2[f]
   527                 if f in mf2:
       
   528                     del mf2[f]
   526         else:
   529         else:
   527             change = self.changelog.read(node2)
   530             change = self.changelog.read(node2)
   528             mf2 = mfmatches(change[0])
   531             mf2 = mfmatches(change[0])
   529 
   532 
   530         # flush lists from dirstate before comparing manifests
   533         # flush lists from dirstate before comparing manifests
   554         for f in list:
   557         for f in list:
   555             p = self.wjoin(f)
   558             p = self.wjoin(f)
   556             if not os.path.exists(p):
   559             if not os.path.exists(p):
   557                 self.ui.warn(_("%s does not exist!\n") % f)
   560                 self.ui.warn(_("%s does not exist!\n") % f)
   558             elif not os.path.isfile(p):
   561             elif not os.path.isfile(p):
   559                 self.ui.warn(_("%s not added: only files supported currently\n") % f)
   562                 self.ui.warn(_("%s not added: only files supported currently\n")
       
   563                              % f)
   560             elif self.dirstate.state(f) in 'an':
   564             elif self.dirstate.state(f) in 'an':
   561                 self.ui.warn(_("%s already tracked!\n") % f)
   565                 self.ui.warn(_("%s already tracked!\n") % f)
   562             else:
   566             else:
   563                 self.dirstate.update([f], "a")
   567                 self.dirstate.update([f], "a")
   564 
   568 
   574         if unlink:
   578         if unlink:
   575             for f in list:
   579             for f in list:
   576                 try:
   580                 try:
   577                     util.unlink(self.wjoin(f))
   581                     util.unlink(self.wjoin(f))
   578                 except OSError, inst:
   582                 except OSError, inst:
   579                     if inst.errno != errno.ENOENT: raise
   583                     if inst.errno != errno.ENOENT:
       
   584                         raise
   580         wlock = self.wlock()
   585         wlock = self.wlock()
   581         for f in list:
   586         for f in list:
   582             p = self.wjoin(f)
   587             p = self.wjoin(f)
   583             if os.path.exists(p):
   588             if os.path.exists(p):
   584                 self.ui.warn(_("%s still exists!\n") % f)
   589                 self.ui.warn(_("%s still exists!\n") % f)
   729                     l = out.setdefault(h, [])
   734                     l = out.setdefault(h, [])
   730                     l[len(l):] = self.nodetags(b)
   735                     l[len(l):] = self.nodetags(b)
   731         return out
   736         return out
   732 
   737 
   733     def branches(self, nodes):
   738     def branches(self, nodes):
   734         if not nodes: nodes = [self.changelog.tip()]
   739         if not nodes:
       
   740             nodes = [self.changelog.tip()]
   735         b = []
   741         b = []
   736         for n in nodes:
   742         for n in nodes:
   737             t = n
   743             t = n
   738             while n:
   744             while n:
   739                 p = self.changelog.parents(n)
   745                 p = self.changelog.parents(n)
   801             while unknown:
   807             while unknown:
   802                 n = unknown.pop(0)
   808                 n = unknown.pop(0)
   803                 if n[0] in seen:
   809                 if n[0] in seen:
   804                     continue
   810                     continue
   805 
   811 
   806                 self.ui.debug(_("examining %s:%s\n") % (short(n[0]), short(n[1])))
   812                 self.ui.debug(_("examining %s:%s\n")
       
   813                               % (short(n[0]), short(n[1])))
   807                 if n[0] == nullid:
   814                 if n[0] == nullid:
   808                     break
   815                     break
   809                 if n in seenbranch:
   816                 if n in seenbranch:
   810                     self.ui.debug(_("branch already found\n"))
   817                     self.ui.debug(_("branch already found\n"))
   811                     continue
   818                     continue
   837                 for p in range(0, len(r), 10):
   844                 for p in range(0, len(r), 10):
   838                     for b in remote.branches(r[p:p+10]):
   845                     for b in remote.branches(r[p:p+10]):
   839                         self.ui.debug(_("received %s:%s\n") %
   846                         self.ui.debug(_("received %s:%s\n") %
   840                                       (short(b[0]), short(b[1])))
   847                                       (short(b[0]), short(b[1])))
   841                         if b[0] in m:
   848                         if b[0] in m:
   842                             self.ui.debug(_("found base node %s\n") % short(b[0]))
   849                             self.ui.debug(_("found base node %s\n")
       
   850                                           % short(b[0]))
   843                             base[b[0]] = 1
   851                             base[b[0]] = 1
   844                         elif b[0] not in seen:
   852                         elif b[0] not in seen:
   845                             unknown.append(b)
   853                             unknown.append(b)
   846 
   854 
   847         # do binary search on the branches we found
   855         # do binary search on the branches we found
   910                 subset.append(n)
   918                 subset.append(n)
   911 
   919 
   912         # this is the set of all roots we have to push
   920         # this is the set of all roots we have to push
   913         return subset
   921         return subset
   914 
   922 
   915     def pull(self, remote, heads = None):
   923     def pull(self, remote, heads=None):
   916         lock = self.lock()
   924         lock = self.lock()
   917 
   925 
   918         # if we have an empty repo, fetch everything
   926         # if we have an empty repo, fetch everything
   919         if self.changelog.tip() == nullid:
   927         if self.changelog.tip() == nullid:
   920             self.ui.status(_("requesting all changes\n"))
   928             self.ui.status(_("requesting all changes\n"))
  1281 
  1289 
  1282     def addchangegroup(self, source):
  1290     def addchangegroup(self, source):
  1283 
  1291 
  1284         def getchunk():
  1292         def getchunk():
  1285             d = source.read(4)
  1293             d = source.read(4)
  1286             if not d: return ""
  1294             if not d:
       
  1295                 return ""
  1287             l = struct.unpack(">l", d)[0]
  1296             l = struct.unpack(">l", d)[0]
  1288             if l <= 4: return ""
  1297             if l <= 4:
       
  1298                 return ""
  1289             d = source.read(l - 4)
  1299             d = source.read(l - 4)
  1290             if len(d) < l - 4:
  1300             if len(d) < l - 4:
  1291                 raise repo.RepoError(_("premature EOF reading chunk"
  1301                 raise repo.RepoError(_("premature EOF reading chunk"
  1292                                        " (got %d bytes, expected %d)")
  1302                                        " (got %d bytes, expected %d)")
  1293                                      % (len(d), l - 4))
  1303                                      % (len(d), l - 4))
  1294             return d
  1304             return d
  1295 
  1305 
  1296         def getgroup():
  1306         def getgroup():
  1297             while 1:
  1307             while 1:
  1298                 c = getchunk()
  1308                 c = getchunk()
  1299                 if not c: break
  1309                 if not c:
       
  1310                     break
  1300                 yield c
  1311                 yield c
  1301 
  1312 
  1302         def csmap(x):
  1313         def csmap(x):
  1303             self.ui.debug(_("add changeset %s\n") % short(x))
  1314             self.ui.debug(_("add changeset %s\n") % short(x))
  1304             return self.changelog.count()
  1315             return self.changelog.count()
  1305 
  1316 
  1306         def revmap(x):
  1317         def revmap(x):
  1307             return self.changelog.rev(x)
  1318             return self.changelog.rev(x)
  1308 
  1319 
  1309         if not source: return
  1320         if not source:
       
  1321             return
  1310         changesets = files = revisions = 0
  1322         changesets = files = revisions = 0
  1311 
  1323 
  1312         tr = self.transaction()
  1324         tr = self.transaction()
  1313 
  1325 
  1314         oldheads = len(self.changelog.heads())
  1326         oldheads = len(self.changelog.heads())
  1329 
  1341 
  1330         # process the files
  1342         # process the files
  1331         self.ui.status(_("adding file changes\n"))
  1343         self.ui.status(_("adding file changes\n"))
  1332         while 1:
  1344         while 1:
  1333             f = getchunk()
  1345             f = getchunk()
  1334             if not f: break
  1346             if not f:
       
  1347                 break
  1335             self.ui.debug(_("adding %s revisions\n") % f)
  1348             self.ui.debug(_("adding %s revisions\n") % f)
  1336             fl = self.file(f)
  1349             fl = self.file(f)
  1337             o = fl.count()
  1350             o = fl.count()
  1338             n = fl.addgroup(getgroup(), revmap, tr)
  1351             n = fl.addgroup(getgroup(), revmap, tr)
  1339             revisions += fl.count() - o
  1352             revisions += fl.count() - o
  1350 
  1363 
  1351         tr.close()
  1364         tr.close()
  1352 
  1365 
  1353         if changesets > 0:
  1366         if changesets > 0:
  1354             if not self.hook("changegroup",
  1367             if not self.hook("changegroup",
  1355                               node=hex(self.changelog.node(cor+1))):
  1368                              node=hex(self.changelog.node(cor+1))):
  1356                 self.ui.warn(_("abort: changegroup hook returned failure!\n"))
  1369                 self.ui.warn(_("abort: changegroup hook returned failure!\n"))
  1357                 return 1
  1370                 return 1
  1358 
  1371 
  1359             for i in range(cor + 1, cnr + 1):
  1372             for i in range(cor + 1, cnr + 1):
  1360                 self.hook("commit", node=hex(self.changelog.node(i)))
  1373                 self.hook("commit", node=hex(self.changelog.node(i)))
  1386             if c or a or d:
  1399             if c or a or d:
  1387                 raise util.Abort(_("outstanding uncommited changes"))
  1400                 raise util.Abort(_("outstanding uncommited changes"))
  1388         if not forcemerge and not force:
  1401         if not forcemerge and not force:
  1389             for f in u:
  1402             for f in u:
  1390                 if f in m2:
  1403                 if f in m2:
  1391                      t1 = self.wread(f)
  1404                     t1 = self.wread(f)
  1392                      t2 = self.file(f).read(m2[f])
  1405                     t2 = self.file(f).read(m2[f])
  1393                      if cmp(t1, t2) != 0:
  1406                     if cmp(t1, t2) != 0:
  1394                         raise util.Abort(_("'%s' already exists in the working"
  1407                         raise util.Abort(_("'%s' already exists in the working"
  1395                                            " dir and differs from remote") % f)
  1408                                            " dir and differs from remote") % f)
  1396 
  1409 
  1397         # is this a jump, or a merge?  i.e. is there a linear path
  1410         # is this a jump, or a merge?  i.e. is there a linear path
  1398         # from p1 to p2?
  1411         # from p1 to p2?
  1421 
  1434 
  1422         if moddirstate:
  1435         if moddirstate:
  1423             wlock = self.wlock()
  1436             wlock = self.wlock()
  1424 
  1437 
  1425         for f in d:
  1438         for f in d:
  1426             if f in mw: del mw[f]
  1439             if f in mw:
       
  1440                 del mw[f]
  1427 
  1441 
  1428             # If we're jumping between revisions (as opposed to merging),
  1442             # If we're jumping between revisions (as opposed to merging),
  1429             # and if neither the working directory nor the target rev has
  1443             # and if neither the working directory nor the target rev has
  1430             # the file, then we need to remove it from the dirstate, to
  1444             # the file, then we need to remove it from the dirstate, to
  1431             # prevent the dirstate from listing the file when it is no
  1445             # prevent the dirstate from listing the file when it is no
  1433             if moddirstate and linear_path and f not in m2:
  1447             if moddirstate and linear_path and f not in m2:
  1434                 self.dirstate.forget((f,))
  1448                 self.dirstate.forget((f,))
  1435 
  1449 
  1436         # Compare manifests
  1450         # Compare manifests
  1437         for f, n in mw.iteritems():
  1451         for f, n in mw.iteritems():
  1438             if choose and not choose(f): continue
  1452             if choose and not choose(f):
       
  1453                 continue
  1439             if f in m2:
  1454             if f in m2:
  1440                 s = 0
  1455                 s = 0
  1441 
  1456 
  1442                 # is the wfile new since m1, and match m2?
  1457                 # is the wfile new since m1, and match m2?
  1443                 if f not in m1:
  1458                 if f not in m1:
  1476                         util.set_exec(self.wjoin(f), mf2[f])
  1491                         util.set_exec(self.wjoin(f), mf2[f])
  1477                     else:
  1492                     else:
  1478                         a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
  1493                         a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
  1479                         mode = ((a^b) | (a^c)) ^ a
  1494                         mode = ((a^b) | (a^c)) ^ a
  1480                         if mode != b:
  1495                         if mode != b:
  1481                             self.ui.debug(_(" updating permissions for %s\n") % f)
  1496                             self.ui.debug(_(" updating permissions for %s\n")
       
  1497                                           % f)
  1482                             util.set_exec(self.wjoin(f), mode)
  1498                             util.set_exec(self.wjoin(f), mode)
  1483                 del m2[f]
  1499                 del m2[f]
  1484             elif f in ma:
  1500             elif f in ma:
  1485                 if n != ma[f]:
  1501                 if n != ma[f]:
  1486                     r = _("d")
  1502                     r = _("d")
  1506                         self.ui.debug(_("local modified %s, keeping\n") % f)
  1522                         self.ui.debug(_("local modified %s, keeping\n") % f)
  1507                 else:
  1523                 else:
  1508                     self.ui.debug(_("working dir created %s, keeping\n") % f)
  1524                     self.ui.debug(_("working dir created %s, keeping\n") % f)
  1509 
  1525 
  1510         for f, n in m2.iteritems():
  1526         for f, n in m2.iteritems():
  1511             if choose and not choose(f): continue
  1527             if choose and not choose(f):
  1512             if f[0] == "/": continue
  1528                 continue
       
  1529             if f[0] == "/":
       
  1530                 continue
  1513             if f in ma and n != ma[f]:
  1531             if f in ma and n != ma[f]:
  1514                 r = _("k")
  1532                 r = _("k")
  1515                 if not force and (linear_path or allow):
  1533                 if not force and (linear_path or allow):
  1516                     r = self.ui.prompt(
  1534                     r = self.ui.prompt(
  1517                         (_("remote changed %s which local deleted\n") % f) +
  1535                         (_("remote changed %s which local deleted\n") % f) +
  1518                          _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
  1536                          _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
  1519                 if r == _("k"): get[f] = n
  1537                 if r == _("k"):
       
  1538                     get[f] = n
  1520             elif f not in ma:
  1539             elif f not in ma:
  1521                 self.ui.debug(_("remote created %s\n") % f)
  1540                 self.ui.debug(_("remote created %s\n") % f)
  1522                 get[f] = n
  1541                 get[f] = n
  1523             else:
  1542             else:
  1524                 if force or p2 == pa: # going backwards?
  1543                 if force or p2 == pa: # going backwards?
  1544                                  " affecting the following files:\n"))
  1563                                  " affecting the following files:\n"))
  1545                 fl = merge.keys() + get.keys()
  1564                 fl = merge.keys() + get.keys()
  1546                 fl.sort()
  1565                 fl.sort()
  1547                 for f in fl:
  1566                 for f in fl:
  1548                     cf = ""
  1567                     cf = ""
  1549                     if f in merge: cf = _(" (resolve)")
  1568                     if f in merge:
       
  1569                         cf = _(" (resolve)")
  1550                     self.ui.status(" %s%s\n" % (f, cf))
  1570                     self.ui.status(" %s%s\n" % (f, cf))
  1551                 self.ui.warn(_("aborting update spanning branches!\n"))
  1571                 self.ui.warn(_("aborting update spanning branches!\n"))
  1552                 self.ui.status(_("(use update -m to merge across branches"
  1572                 self.ui.status(_("(use update -m to merge across branches"
  1553                                  " or -C to lose changes)\n"))
  1573                                  " or -C to lose changes)\n"))
  1554                 return 1
  1574                 return 1
  1556 
  1576 
  1557         # get the files we don't need to change
  1577         # get the files we don't need to change
  1558         files = get.keys()
  1578         files = get.keys()
  1559         files.sort()
  1579         files.sort()
  1560         for f in files:
  1580         for f in files:
  1561             if f[0] == "/": continue
  1581             if f[0] == "/":
       
  1582                 continue
  1562             self.ui.note(_("getting %s\n") % f)
  1583             self.ui.note(_("getting %s\n") % f)
  1563             t = self.file(f).read(get[f])
  1584             t = self.file(f).read(get[f])
  1564             self.wwrite(f, t)
  1585             self.wwrite(f, t)
  1565             util.set_exec(self.wjoin(f), mf2[f])
  1586             util.set_exec(self.wjoin(f), mf2[f])
  1566             if moddirstate:
  1587             if moddirstate:
  1719             for f, fn in ff:
  1740             for f, fn in ff:
  1720                 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
  1741                 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
  1721 
  1742 
  1722         self.ui.status(_("crosschecking files in changesets and manifests\n"))
  1743         self.ui.status(_("crosschecking files in changesets and manifests\n"))
  1723 
  1744 
  1724         for m,c in neededmanifests.items():
  1745         for m, c in neededmanifests.items():
  1725             err(_("Changeset %s refers to unknown manifest %s") %
  1746             err(_("Changeset %s refers to unknown manifest %s") %
  1726                 (short(m), short(c)))
  1747                 (short(m), short(c)))
  1727         del neededmanifests
  1748         del neededmanifests
  1728 
  1749 
  1729         for f in filenodes:
  1750         for f in filenodes:
  1736 
  1757 
  1737         self.ui.status(_("checking files\n"))
  1758         self.ui.status(_("checking files\n"))
  1738         ff = filenodes.keys()
  1759         ff = filenodes.keys()
  1739         ff.sort()
  1760         ff.sort()
  1740         for f in ff:
  1761         for f in ff:
  1741             if f == "/dev/null": continue
  1762             if f == "/dev/null":
       
  1763                 continue
  1742             files += 1
  1764             files += 1
  1743             fl = self.file(f)
  1765             fl = self.file(f)
  1744             d = fl.checksize()
  1766             d = fl.checksize()
  1745             if d:
  1767             if d:
  1746                 err(_("%s file data short %d bytes") % (f, d))
  1768                 err(_("%s file data short %d bytes") % (f, d))
  1747 
  1769 
  1748             nodes = { nullid: 1 }
  1770             nodes = {nullid: 1}
  1749             seen = {}
  1771             seen = {}
  1750             for i in range(fl.count()):
  1772             for i in range(fl.count()):
  1751                 revisions += 1
  1773                 revisions += 1
  1752                 n = fl.node(i)
  1774                 n = fl.node(i)
  1753 
  1775