##// END OF EJS Templates
Add an sshrepository class and hg serve --stdio
Matt Mackall -
r624:876333a2 default
parent child Browse files
Show More
@@ -9,7 +9,7 b' from demandload import *'
9 9 demandload(globals(), "os re sys signal")
10 10 demandload(globals(), "fancyopts ui hg util")
11 11 demandload(globals(), "hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version")
12 demandload(globals(), "errno socket version struct")
13 13
14 14 class UnknownCommand(Exception): pass
15 15
@@ -823,9 +823,67 b' def root(ui, repo):'
823 823
824 824 def serve(ui, repo, **opts):
825 825 """export the repository via HTTP"""
826
827 if opts["stdio"]:
828 def getarg():
829 argline = sys.stdin.readline()[:-1]
830 arg, l = argline.split()
831 val = sys.stdin.read(int(l))
832 return arg, val
833 def respond(v):
834 sys.stdout.write("%d\n" % len(v))
835 sys.stdout.write(v)
836 sys.stdout.flush()
837
838 while 1:
839 cmd = sys.stdin.readline()[:-1]
840 if cmd == '':
841 return
842 if cmd == "heads":
843 h = repo.heads()
844 respond(" ".join(map(hg.hex, h)) + "\n")
845 elif cmd == "branches":
846 arg, nodes = getarg()
847 nodes = map(hg.bin, nodes.split(" "))
848 r = []
849 for b in repo.branches(nodes):
850 r.append(" ".join(map(hg.hex, b)) + "\n")
851 respond("".join(r))
852 elif cmd == "between":
853 arg, pairs = getarg()
854 pairs = [ map(hg.bin, p.split("-")) for p in pairs.split(" ") ]
855 r = []
856 for b in repo.between(pairs):
857 r.append(" ".join(map(hg.hex, b)) + "\n")
858 respond("".join(r))
859 elif cmd == "changegroup":
860 nodes = []
861 arg, roots = getarg()
862 nodes = map(hg.bin, roots.split(" "))
863
864 b = []
865 t = 0
866 for chunk in repo.changegroup(nodes):
867 t += len(chunk)
868 b.append(chunk)
869 if t > 4096:
870 sys.stdout.write(struct.pack(">l", t))
871 for c in b:
872 sys.stdout.write(c)
873 t = 0
874 b = []
875
876 sys.stdout.write(struct.pack(">l", t))
877 for c in b:
878 sys.stdout.write(c)
879
880 sys.stdout.write(struct.pack(">l", -1))
881 sys.stdout.flush()
882
826 883 def openlog(opt, default):
827 884 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
828 885 else: return default
886
829 887 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
830 888 opts["address"], opts["port"],
831 889 openlog('accesslog', sys.stdout),
@@ -1017,6 +1075,7 b' table = {'
1017 1075 ('p', 'port', 8000, 'listen port'),
1018 1076 ('a', 'address', '', 'interface address'),
1019 1077 ('n', 'name', os.getcwd(), 'repository name'),
1078 ('', 'stdio', None, 'for remote clients'),
1020 1079 ('t', 'templates', "", 'template map')],
1021 1080 "hg serve [options]"),
1022 1081 "^status": (status, [], 'hg status'),
@@ -1592,6 +1592,88 b' class httprepository:'
1592 1592 yield zd.decompress(d)
1593 1593 self.ui.note("%d bytes of data transfered\n" % bytes)
1594 1594
1595 class sshrepository:
1596 def __init__(self, ui, path):
1597 self.url = path
1598 self.ui = ui
1599
1600 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
1601 if not m:
1602 raise RepoError("couldn't parse destination %s\n" % path)
1603
1604 self.user = m.group(2)
1605 self.host = m.group(3)
1606 self.port = m.group(5)
1607 self.path = m.group(7)
1608
1609 args = self.user and ("%s@%s" % (self.user, self.host)) or self.host
1610 args = self.port and ("%s -p %s") % (args, self.port) or args
1611 path = self.path or ""
1612
1613 cmd = "ssh %s 'hg -R %s serve --stdio'"
1614 cmd = cmd % (args, path)
1615
1616 self.pipeo, self.pipei = os.popen2(cmd)
1617
1618 def __del__(self):
1619 self.pipeo.close()
1620 self.pipei.close()
1621
1622 def do_cmd(self, cmd, **args):
1623 self.ui.debug("sending %s command\n" % cmd)
1624 self.pipeo.write("%s\n" % cmd)
1625 for k, v in args.items():
1626 self.pipeo.write("%s %d\n" % (k, len(v)))
1627 self.pipeo.write(v)
1628 self.pipeo.flush()
1629
1630 return self.pipei
1631
1632 def call(self, cmd, **args):
1633 r = self.do_cmd(cmd, **args)
1634 l = int(r.readline())
1635 return r.read(l)
1636
1637 def heads(self):
1638 d = self.call("heads")
1639 try:
1640 return map(bin, d[:-1].split(" "))
1641 except:
1642 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1643 raise
1644
1645 def branches(self, nodes):
1646 n = " ".join(map(hex, nodes))
1647 d = self.call("branches", nodes=n)
1648 try:
1649 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
1650 return br
1651 except:
1652 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1653 raise
1654
1655 def between(self, pairs):
1656 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
1657 d = self.call("between", pairs=n)
1658 try:
1659 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
1660 return p
1661 except:
1662 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
1663 raise
1664
1665 def changegroup(self, nodes):
1666 n = " ".join(map(hex, nodes))
1667 f = self.do_cmd("changegroup", roots=n)
1668 bytes = 0
1669 while 1:
1670 l = struct.unpack(">l", f.read(4))[0]
1671 if l == -1: break
1672 d = f.read(l)
1673 bytes += len(d)
1674 yield d
1675 self.ui.note("%d bytes of data transfered\n" % bytes)
1676
1595 1677 def repository(ui, path=None, create=0):
1596 1678 if path:
1597 1679 if path.startswith("http://"):
@@ -1600,5 +1682,7 b' def repository(ui, path=None, create=0):'
1600 1682 return httprepository(ui, path.replace("hg://", "http://"))
1601 1683 if path.startswith("old-http://"):
1602 1684 return localrepository(ui, path.replace("old-http://", "http://"))
1685 if path.startswith("ssh://"):
1686 return sshrepository(ui, path)
1603 1687
1604 1688 return localrepository(ui, path, create)
General Comments 0
You need to be logged in to leave comments. Login now