mercurial/hgweb.py
changeset 1063 58eefdfb8472
parent 1062 6d5a62a549fa
child 1073 7b35a980b982
equal deleted inserted replaced
1062:6d5a62a549fa 1063:58eefdfb8472
    11 from mercurial.ui import *
    11 from mercurial.ui import *
    12 
    12 
    13 def templatepath():
    13 def templatepath():
    14     for f in "templates", "../templates":
    14     for f in "templates", "../templates":
    15         p = os.path.join(os.path.dirname(__file__), f)
    15         p = os.path.join(os.path.dirname(__file__), f)
    16         if os.path.isdir(p): return p
    16         if os.path.isdir(p):
       
    17             return p
    17 
    18 
    18 def age(t):
    19 def age(t):
    19     def plural(t, c):
    20     def plural(t, c):
    20         if c == 1: return t
    21         if c == 1:
       
    22             return t
    21         return t + "s"
    23         return t + "s"
    22     def fmt(t, c):
    24     def fmt(t, c):
    23         return "%d %s" % (c, plural(t, c))
    25         return "%d %s" % (c, plural(t, c))
    24 
    26 
    25     now = time.time()
    27     now = time.time()
    35 
    37 
    36     scales.reverse()
    38     scales.reverse()
    37 
    39 
    38     for t, s in scales:
    40     for t, s in scales:
    39         n = delta / s
    41         n = delta / s
    40         if n >= 2 or s == 1: return fmt(t, n)
    42         if n >= 2 or s == 1:
       
    43             return fmt(t, n)
    41 
    44 
    42 def nl2br(text):
    45 def nl2br(text):
    43     return text.replace('\n', '<br/>\n')
    46     return text.replace('\n', '<br/>\n')
    44 
    47 
    45 def obfuscate(text):
    48 def obfuscate(text):
    46     return ''.join([ '&#%d;' % ord(c) for c in text ])
    49     return ''.join(['&#%d;' % ord(c) for c in text])
    47 
    50 
    48 def up(p):
    51 def up(p):
    49     if p[0] != "/": p = "/" + p
    52     if p[0] != "/":
    50     if p[-1] == "/": p = p[:-1]
    53         p = "/" + p
       
    54     if p[-1] == "/":
       
    55         p = p[:-1]
    51     up = os.path.dirname(p)
    56     up = os.path.dirname(p)
    52     if up == "/":
    57     if up == "/":
    53         return "/"
    58         return "/"
    54     return up + "/"
    59     return up + "/"
    55 
    60 
   171             yield self.t("filedifflink", node=hex(changeset), file=f)
   176             yield self.t("filedifflink", node=hex(changeset), file=f)
   172         if len(files) > self.maxfiles:
   177         if len(files) > self.maxfiles:
   173             yield self.t("fileellipses")
   178             yield self.t("fileellipses")
   174 
   179 
   175     def parents(self, t1, nodes=[], rev=None,**args):
   180     def parents(self, t1, nodes=[], rev=None,**args):
   176         if not rev: rev = lambda x: ""
   181         if not rev:
       
   182             rev = lambda x: ""
   177         for node in nodes:
   183         for node in nodes:
   178             if node != nullid:
   184             if node != nullid:
   179                 yield self.t(t1, node=hex(node), rev=rev(node), **args)
   185                 yield self.t(t1, node=hex(node), rev=rev(node), **args)
   180 
   186 
   181     def showtag(self, t1, node=nullid, **args):
   187     def showtag(self, t1, node=nullid, **args):
   182         for t in self.repo.nodetags(node):
   188         for t in self.repo.nodetags(node):
   183              yield self.t(t1, tag=t, **args)
   189              yield self.t(t1, tag=t, **args)
   184 
   190 
   185     def diff(self, node1, node2, files):
   191     def diff(self, node1, node2, files):
   186         def filterfiles(list, files):
   192         def filterfiles(list, files):
   187             l = [ x for x in list if x in files ]
   193             l = [x for x in list if x in files]
   188 
   194 
   189             for f in files:
   195             for f in files:
   190                 if f[-1] != os.sep: f += os.sep
   196                 if f[-1] != os.sep:
   191                 l += [ x for x in list if x.startswith(f) ]
   197                     f += os.sep
       
   198                 l += [x for x in list if x.startswith(f)]
   192             return l
   199             return l
   193 
   200 
   194         parity = [0]
   201         parity = [0]
   195         def diffblock(diff, f, fn):
   202         def diffblock(diff, f, fn):
   196             yield self.t("diffblock",
   203             yield self.t("diffblock",
   197                          lines = prettyprintlines(diff),
   204                          lines=prettyprintlines(diff),
   198                          parity = parity[0],
   205                          parity=parity[0],
   199                          file = f,
   206                          file=f,
   200                          filenode = hex(fn or nullid))
   207                          filenode=hex(fn or nullid))
   201             parity[0] = 1 - parity[0]
   208             parity[0] = 1 - parity[0]
   202 
   209 
   203         def prettyprintlines(diff):
   210         def prettyprintlines(diff):
   204             for l in diff.splitlines(1):
   211             for l in diff.splitlines(1):
   205                 if l.startswith('+'):
   212                 if l.startswith('+'):
   247                 for f in seq(factor * 10):
   254                 for f in seq(factor * 10):
   248                     yield f
   255                     yield f
   249 
   256 
   250             l = []
   257             l = []
   251             for f in seq():
   258             for f in seq():
   252                 if f < self.maxchanges / 2: continue
   259                 if f < self.maxchanges / 2:
   253                 if f > count: break
   260                     continue
       
   261                 if f > count:
       
   262                     break
   254                 r = "%d" % f
   263                 r = "%d" % f
   255                 if pos + f < count: l.append(("+" + r, pos + f))
   264                 if pos + f < count:
   256                 if pos - f >= 0: l.insert(0, ("-" + r, pos - f))
   265                     l.append(("+" + r, pos + f))
       
   266                 if pos - f >= 0:
       
   267                     l.insert(0, ("-" + r, pos - f))
   257 
   268 
   258             yield {"rev": 0, "label": "(0)"}
   269             yield {"rev": 0, "label": "(0)"}
   259 
   270 
   260             for label, rev in l:
   271             for label, rev in l:
   261                 yield {"label": label, "rev": rev}
   272                 yield {"label": label, "rev": rev}
   270                 n = cl.node(i)
   281                 n = cl.node(i)
   271                 changes = cl.read(n)
   282                 changes = cl.read(n)
   272                 hn = hex(n)
   283                 hn = hex(n)
   273                 t = float(changes[2].split(' ')[0])
   284                 t = float(changes[2].split(' ')[0])
   274 
   285 
   275                 l.insert(0, {
   286                 l.insert(0, {"parity": parity,
   276                     "parity": parity,
   287                              "author": changes[1],
   277                     "author": changes[1],
   288                              "parent": self.parents("changelogparent",
   278                     "parent": self.parents("changelogparent",
   289                                                     cl.parents(n), cl.rev),
   279                                           cl.parents(n), cl.rev),
   290                              "changelogtag": self.showtag("changelogtag",n),
   280                     "changelogtag": self.showtag("changelogtag",n),
   291                              "manifest": hex(changes[0]),
   281                     "manifest": hex(changes[0]),
   292                              "desc": changes[4],
   282                     "desc": changes[4],
   293                              "date": t,
   283                     "date": t,
   294                              "files": self.listfilediffs(changes[3], n),
   284                     "files": self.listfilediffs(changes[3], n),
   295                              "rev": i,
   285                     "rev": i,
   296                              "node": hn})
   286                     "node": hn})
       
   287                 parity = 1 - parity
   297                 parity = 1 - parity
   288 
   298 
   289             for e in l: yield e
   299             for e in l:
       
   300                 yield e
   290 
   301 
   291         cl = self.repo.changelog
   302         cl = self.repo.changelog
   292         mf = cl.read(cl.tip())[0]
   303         mf = cl.read(cl.tip())[0]
   293         count = cl.count()
   304         count = cl.count()
   294         start = max(0, pos - self.maxchanges + 1)
   305         start = max(0, pos - self.maxchanges + 1)
   324                     if not (q in changes[1].lower() or
   335                     if not (q in changes[1].lower() or
   325                             q in changes[4].lower() or
   336                             q in changes[4].lower() or
   326                             q in " ".join(changes[3][:20]).lower()):
   337                             q in " ".join(changes[3][:20]).lower()):
   327                         miss = 1
   338                         miss = 1
   328                         break
   339                         break
   329                 if miss: continue
   340                 if miss:
       
   341                     continue
   330 
   342 
   331                 count += 1
   343                 count += 1
   332                 hn = hex(n)
   344                 hn = hex(n)
   333                 t = float(changes[2].split(' ')[0])
   345                 t = float(changes[2].split(' ')[0])
   334 
   346 
   335                 yield self.t(
   347                 yield self.t('searchentry',
   336                     'searchentry',
   348                              parity=count & 1,
   337                     parity=count & 1,
   349                              author=changes[1],
   338                     author=changes[1],
   350                              parent=self.parents("changelogparent",
   339                     parent=self.parents("changelogparent",
   351                                                  cl.parents(n), cl.rev),
   340                                           cl.parents(n), cl.rev),
   352                              changelogtag=self.showtag("changelogtag",n),
   341                     changelogtag=self.showtag("changelogtag",n),
   353                              manifest=hex(changes[0]),
   342                     manifest=hex(changes[0]),
   354                              desc=changes[4],
   343                     desc=changes[4],
   355                              date=t,
   344                     date=t,
   356                              files=self.listfilediffs(changes[3], n),
   345                     files=self.listfilediffs(changes[3], n),
   357                              rev=i,
   346                     rev=i,
   358                              node=hn)
   347                     node=hn)
   359 
   348 
   360                 if count >= self.maxchanges:
   349                 if count >= self.maxchanges: break
   361                     break
   350 
   362 
   351         cl = self.repo.changelog
   363         cl = self.repo.changelog
   352         mf = cl.read(cl.tip())[0]
   364         mf = cl.read(cl.tip())[0]
   353 
   365 
   354         yield self.t('search',
   366         yield self.t('search',
   365 
   377 
   366         files = []
   378         files = []
   367         mf = self.repo.manifest.read(changes[0])
   379         mf = self.repo.manifest.read(changes[0])
   368         for f in changes[3]:
   380         for f in changes[3]:
   369             files.append(self.t("filenodelink",
   381             files.append(self.t("filenodelink",
   370                                 filenode = hex(mf.get(f, nullid)), file=f))
   382                                 filenode=hex(mf.get(f, nullid)), file=f))
   371 
   383 
   372         def diff(**map):
   384         def diff(**map):
   373             yield self.diff(p1, n, None)
   385             yield self.diff(p1, n, None)
   374 
   386 
   375         yield self.t('changeset',
   387         yield self.t('changeset',
   376                      diff=diff,
   388                      diff=diff,
   377                      rev=cl.rev(n),
   389                      rev=cl.rev(n),
   378                      node=nodeid,
   390                      node=nodeid,
   379                      parent=self.parents("changesetparent",
   391                      parent=self.parents("changesetparent",
   380                                            cl.parents(n), cl.rev),
   392                                          cl.parents(n), cl.rev),
   381                      changesettag=self.showtag("changesettag",n),
   393                      changesettag=self.showtag("changesettag",n),
   382                      manifest=hex(changes[0]),
   394                      manifest=hex(changes[0]),
   383                      author=changes[1],
   395                      author=changes[1],
   384                      desc=changes[4],
   396                      desc=changes[4],
   385                      date=t,
   397                      date=t,
   393         def entries(**map):
   405         def entries(**map):
   394             l = []
   406             l = []
   395             parity = (count - 1) & 1
   407             parity = (count - 1) & 1
   396 
   408 
   397             for i in range(count):
   409             for i in range(count):
   398 
       
   399                 n = fl.node(i)
   410                 n = fl.node(i)
   400                 lr = fl.linkrev(n)
   411                 lr = fl.linkrev(n)
   401                 cn = cl.node(lr)
   412                 cn = cl.node(lr)
   402                 cs = cl.read(cl.node(lr))
   413                 cs = cl.read(cl.node(lr))
   403                 t = float(cs[2].split(' ')[0])
   414                 t = float(cs[2].split(' ')[0])
   408                              "file": f,
   419                              "file": f,
   409                              "node": hex(cn),
   420                              "node": hex(cn),
   410                              "author": cs[1],
   421                              "author": cs[1],
   411                              "date": t,
   422                              "date": t,
   412                              "parent": self.parents("filelogparent",
   423                              "parent": self.parents("filelogparent",
   413                                        fl.parents(n), fl.rev, file=f),
   424                                                     fl.parents(n),
       
   425                                                     fl.rev, file=f),
   414                              "desc": cs[4]})
   426                              "desc": cs[4]})
   415                 parity = 1 - parity
   427                 parity = 1 - parity
   416 
   428 
   417             for e in l: yield e
   429             for e in l:
   418 
   430                 yield e
   419         yield self.t("filelog",
   431 
   420                      file=f,
   432         yield self.t("filelog", file=f, filenode=filenode, entries=entries)
   421                      filenode=filenode,
       
   422                      entries=entries)
       
   423 
   433 
   424     def filerevision(self, f, node):
   434     def filerevision(self, f, node):
   425         fl = self.repo.file(f)
   435         fl = self.repo.file(f)
   426         n = bin(node)
   436         n = bin(node)
   427         text = fl.read(n)
   437         text = fl.read(n)
   436             for l, t in enumerate(text.splitlines(1)):
   446             for l, t in enumerate(text.splitlines(1)):
   437                 yield {"line": t,
   447                 yield {"line": t,
   438                        "linenumber": "% 6d" % (l + 1),
   448                        "linenumber": "% 6d" % (l + 1),
   439                        "parity": l & 1}
   449                        "parity": l & 1}
   440 
   450 
   441         yield self.t("filerevision", file=f,
   451         yield self.t("filerevision",
       
   452                      file=f,
   442                      filenode=node,
   453                      filenode=node,
   443                      path=up(f),
   454                      path=up(f),
   444                      text=lines(),
   455                      text=lines(),
   445                      rev=changerev,
   456                      rev=changerev,
   446                      node=hex(cn),
   457                      node=hex(cn),
   447                      manifest=hex(mfn),
   458                      manifest=hex(mfn),
   448                      author=cs[1],
   459                      author=cs[1],
   449                      date=t,
   460                      date=t,
   450                      parent=self.parents("filerevparent",
   461                      parent=self.parents("filerevparent",
   451                                            fl.parents(n), fl.rev, file=f),
   462                                          fl.parents(n), fl.rev, file=f),
   452                      permissions=self.repo.manifest.readflags(mfn)[f])
   463                      permissions=self.repo.manifest.readflags(mfn)[f])
   453 
   464 
   454     def fileannotate(self, f, node):
   465     def fileannotate(self, f, node):
   455         bcache = {}
   466         bcache = {}
   456         ncache = {}
   467         ncache = {}
   496                        "author": name,
   507                        "author": name,
   497                        "file": f,
   508                        "file": f,
   498                        "line": l}
   509                        "line": l}
   499 
   510 
   500         yield self.t("fileannotate",
   511         yield self.t("fileannotate",
   501                      file = f,
   512                      file=f,
   502                      filenode = node,
   513                      filenode=node,
   503                      annotate = annotate,
   514                      annotate=annotate,
   504                      path = up(f),
   515                      path=up(f),
   505                      rev = changerev,
   516                      rev=changerev,
   506                      node = hex(cn),
   517                      node=hex(cn),
   507                      manifest = hex(mfn),
   518                      manifest=hex(mfn),
   508                      author = cs[1],
   519                      author=cs[1],
   509                      date = t,
   520                      date=t,
   510                      parent = self.parents("fileannotateparent",
   521                      parent=self.parents("fileannotateparent",
   511                                            fl.parents(n), fl.rev, file=f),
   522                                          fl.parents(n), fl.rev, file=f),
   512                      permissions = self.repo.manifest.readflags(mfn)[f])
   523                      permissions=self.repo.manifest.readflags(mfn)[f])
   513 
   524 
   514     def manifest(self, mnode, path):
   525     def manifest(self, mnode, path):
   515         mf = self.repo.manifest.read(bin(mnode))
   526         mf = self.repo.manifest.read(bin(mnode))
   516         rev = self.repo.manifest.rev(bin(mnode))
   527         rev = self.repo.manifest.rev(bin(mnode))
   517         node = self.repo.changelog.node(rev)
   528         node = self.repo.changelog.node(rev)
   607                      file=file,
   618                      file=file,
   608                      filenode=hex(mf.get(file, nullid)),
   619                      filenode=hex(mf.get(file, nullid)),
   609                      node=changeset,
   620                      node=changeset,
   610                      rev=self.repo.changelog.rev(n),
   621                      rev=self.repo.changelog.rev(n),
   611                      parent=self.parents("filediffparent",
   622                      parent=self.parents("filediffparent",
   612                               cl.parents(n), cl.rev),
   623                                          cl.parents(n), cl.rev),
   613                      diff=diff)
   624                      diff=diff)
   614 
   625 
   615     # add tags to things
   626     # add tags to things
   616     # tags -> list of changesets corresponding to tags
   627     # tags -> list of changesets corresponding to tags
   617     # find tag, changeset, file
   628     # find tag, changeset, file
   632         if args.has_key('style'):
   643         if args.has_key('style'):
   633             style = args['style'][0]
   644             style = args['style'][0]
   634         if style:
   645         if style:
   635             b = os.path.basename("map-" + style)
   646             b = os.path.basename("map-" + style)
   636             p = os.path.join(t, b)
   647             p = os.path.join(t, b)
   637             if os.path.isfile(p): m = p
   648             if os.path.isfile(p):
       
   649                 m = p
   638 
   650 
   639         port = os.environ["SERVER_PORT"]
   651         port = os.environ["SERVER_PORT"]
   640         port = port != "80" and (":" + port) or ""
   652         port = port != "80" and (":" + port) or ""
   641         uri = os.environ["REQUEST_URI"]
   653         uri = os.environ["REQUEST_URI"]
   642         if "?" in uri: uri = uri.split("?")[0]
   654         if "?" in uri:
       
   655             uri = uri.split("?")[0]
   643         url = "http://%s%s%s" % (os.environ["SERVER_NAME"], port, uri)
   656         url = "http://%s%s%s" % (os.environ["SERVER_NAME"], port, uri)
   644 
   657 
   645         self.t = templater(m, common_filters,
   658         self.t = templater(m, common_filters,
   646                            {"url": url,
   659                            {"url": url,
   647                             "repo": self.reponame,
   660                             "repo": self.reponame,
   648                             "header": header,
   661                             "header": header,
   649                             "footer": footer,
   662                             "footer": footer,
   650                             })
   663                            })
   651 
   664 
   652         if not args.has_key('cmd'):
   665         if not args.has_key('cmd'):
   653             args['cmd'] = [self.t.cache['default'],]
   666             args['cmd'] = [self.t.cache['default'],]
   654 
   667 
   655         if args['cmd'][0] == 'changelog':
   668         if args['cmd'][0] == 'changelog':
   701 
   714 
   702         elif args['cmd'][0] == 'between':
   715         elif args['cmd'][0] == 'between':
   703             httphdr("application/mercurial-0.1")
   716             httphdr("application/mercurial-0.1")
   704             nodes = []
   717             nodes = []
   705             if args.has_key('pairs'):
   718             if args.has_key('pairs'):
   706                 pairs = [ map(bin, p.split("-"))
   719                 pairs = [map(bin, p.split("-"))
   707                           for p in args['pairs'][0].split(" ") ]
   720                          for p in args['pairs'][0].split(" ")]
   708             for b in self.repo.between(pairs):
   721             for b in self.repo.between(pairs):
   709                 sys.stdout.write(" ".join(map(hex, b)) + "\n")
   722                 sys.stdout.write(" ".join(map(hex, b)) + "\n")
   710 
   723 
   711         elif args['cmd'][0] == 'changegroup':
   724         elif args['cmd'][0] == 'changegroup':
   712             httphdr("application/mercurial-0.1")
   725             httphdr("application/mercurial-0.1")
   719 
   732 
   720             z = zlib.compressobj()
   733             z = zlib.compressobj()
   721             f = self.repo.changegroup(nodes)
   734             f = self.repo.changegroup(nodes)
   722             while 1:
   735             while 1:
   723                 chunk = f.read(4096)
   736                 chunk = f.read(4096)
   724                 if not chunk: break
   737                 if not chunk:
       
   738                     break
   725                 sys.stdout.write(z.compress(chunk))
   739                 sys.stdout.write(z.compress(chunk))
   726 
   740 
   727             sys.stdout.write(z.flush())
   741             sys.stdout.write(z.flush())
   728 
   742 
   729         else:
   743         else:
   765 
   779 
   766         def do_POST(self):
   780         def do_POST(self):
   767             try:
   781             try:
   768                 self.do_hgweb()
   782                 self.do_hgweb()
   769             except socket.error, inst:
   783             except socket.error, inst:
   770                 if inst.args[0] != 32: raise
   784                 if inst.args[0] != 32:
       
   785                     raise
   771 
   786 
   772         def do_GET(self):
   787         def do_GET(self):
   773             self.do_POST()
   788             self.do_POST()
   774 
   789 
   775         def do_hgweb(self):
   790         def do_hgweb(self):