Show More
@@ -7,7 +7,7 b'' | |||
|
7 | 7 | |
|
8 | 8 | from i18n import _ |
|
9 | 9 | import struct |
|
10 | import sys, os | |
|
10 | import sys, os, errno, traceback, SocketServer | |
|
11 | 11 | import dispatch, encoding, util |
|
12 | 12 | |
|
13 | 13 | logfile = None |
@@ -256,8 +256,59 b' class pipeservice(object):' | |||
|
256 | 256 | def run(self): |
|
257 | 257 | return self.server.serve() |
|
258 | 258 | |
|
259 | class _requesthandler(SocketServer.StreamRequestHandler): | |
|
260 | def handle(self): | |
|
261 | ui = self.server.ui | |
|
262 | repo = self.server.repo | |
|
263 | sv = server(ui, repo, self.rfile, self.wfile) | |
|
264 | try: | |
|
265 | try: | |
|
266 | sv.serve() | |
|
267 | # handle exceptions that may be raised by command server. most of | |
|
268 | # known exceptions are caught by dispatch. | |
|
269 | except util.Abort, inst: | |
|
270 | ui.warn(_('abort: %s\n') % inst) | |
|
271 | except IOError, inst: | |
|
272 | if inst.errno != errno.EPIPE: | |
|
273 | raise | |
|
274 | except KeyboardInterrupt: | |
|
275 | pass | |
|
276 | except: # re-raises | |
|
277 | # also write traceback to error channel. otherwise client cannot | |
|
278 | # see it because it is written to server's stderr by default. | |
|
279 | traceback.print_exc(file=sv.cerr) | |
|
280 | raise | |
|
281 | ||
|
282 | class unixservice(object): | |
|
283 | """ | |
|
284 | Listens on unix domain socket and forks server per connection | |
|
285 | """ | |
|
286 | def __init__(self, ui, repo, opts): | |
|
287 | self.ui = ui | |
|
288 | self.repo = repo | |
|
289 | self.address = opts['address'] | |
|
290 | if not util.safehasattr(SocketServer, 'UnixStreamServer'): | |
|
291 | raise util.Abort(_('unsupported platform')) | |
|
292 | if not self.address: | |
|
293 | raise util.Abort(_('no socket path specified with --address')) | |
|
294 | ||
|
295 | def init(self): | |
|
296 | class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer): | |
|
297 | ui = self.ui | |
|
298 | repo = self.repo | |
|
299 | self.server = cls(self.address, _requesthandler) | |
|
300 | self.ui.status(_('listening at %s\n') % self.address) | |
|
301 | self.ui.flush() # avoid buffering of status message | |
|
302 | ||
|
303 | def run(self): | |
|
304 | try: | |
|
305 | self.server.serve_forever() | |
|
306 | finally: | |
|
307 | os.unlink(self.address) | |
|
308 | ||
|
259 | 309 | _servicemap = { |
|
260 | 310 | 'pipe': pipeservice, |
|
311 | 'unix': unixservice, | |
|
261 | 312 | } |
|
262 | 313 | |
|
263 | 314 | def createservice(ui, repo, opts): |
@@ -1,5 +1,6 b'' | |||
|
1 | 1 | import os, stat |
|
2 | 2 | import re |
|
3 | import socket | |
|
3 | 4 | import sys |
|
4 | 5 | import tempfile |
|
5 | 6 | |
@@ -258,6 +259,10 b' def has_unix_permissions():' | |||
|
258 | 259 | finally: |
|
259 | 260 | os.rmdir(d) |
|
260 | 261 | |
|
262 | @check("unix-socket", "AF_UNIX socket family") | |
|
263 | def has_unix_socket(): | |
|
264 | return getattr(socket, 'AF_UNIX', None) is not None | |
|
265 | ||
|
261 | 266 | @check("root", "root permissions") |
|
262 | 267 | def has_root(): |
|
263 | 268 | return getattr(os, 'geteuid', None) and os.geteuid() == 0 |
@@ -545,3 +545,63 b' start without repository:' | |||
|
545 | 545 | *** runcommand init repo2 |
|
546 | 546 | *** runcommand id -R repo2 |
|
547 | 547 | 000000000000 tip |
|
548 | ||
|
549 | ||
|
550 | unix domain socket: | |
|
551 | ||
|
552 | $ cd repo | |
|
553 | $ hg update -q | |
|
554 | ||
|
555 | #if unix-socket | |
|
556 | ||
|
557 | >>> import cStringIO | |
|
558 | >>> from hgclient import unixserver, readchannel, runcommand, check | |
|
559 | >>> server = unixserver('.hg/server.sock', '.hg/server.log') | |
|
560 | >>> def hellomessage(conn): | |
|
561 | ... ch, data = readchannel(conn) | |
|
562 | ... print '%c, %r' % (ch, data) | |
|
563 | ... runcommand(conn, ['id']) | |
|
564 | >>> check(hellomessage, server.connect) | |
|
565 | o, 'capabilities: getencoding runcommand\nencoding: *' (glob) | |
|
566 | *** runcommand id | |
|
567 | eff892de26ec tip bm1/bm2/bm3 | |
|
568 | >>> def unknowncommand(conn): | |
|
569 | ... readchannel(conn) | |
|
570 | ... conn.stdin.write('unknowncommand\n') | |
|
571 | >>> check(unknowncommand, server.connect) # error sent to server.log | |
|
572 | >>> def serverinput(conn): | |
|
573 | ... readchannel(conn) | |
|
574 | ... patch = """ | |
|
575 | ... # HG changeset patch | |
|
576 | ... # User test | |
|
577 | ... # Date 0 0 | |
|
578 | ... 2 | |
|
579 | ... | |
|
580 | ... diff -r eff892de26ec -r 1ed24be7e7a0 a | |
|
581 | ... --- a/a | |
|
582 | ... +++ b/a | |
|
583 | ... @@ -1,1 +1,2 @@ | |
|
584 | ... 1 | |
|
585 | ... +2 | |
|
586 | ... """ | |
|
587 | ... runcommand(conn, ['import', '-'], input=cStringIO.StringIO(patch)) | |
|
588 | ... runcommand(conn, ['log', '-rtip', '-q']) | |
|
589 | >>> check(serverinput, server.connect) | |
|
590 | *** runcommand import - | |
|
591 | applying patch from stdin | |
|
592 | *** runcommand log -rtip -q | |
|
593 | 2:1ed24be7e7a0 | |
|
594 | >>> server.shutdown() | |
|
595 | ||
|
596 | $ cat .hg/server.log | |
|
597 | listening at .hg/server.sock | |
|
598 | abort: unknown command unknowncommand | |
|
599 | killed! | |
|
600 | ||
|
601 | #else | |
|
602 | ||
|
603 | $ hg serve --cmdserver unix -a .hg/server.sock | |
|
604 | abort: unsupported platform | |
|
605 | [255] | |
|
606 | ||
|
607 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now