Merge branch 'master' into python3
authorFredrik Tolf <fredrik@dolda2000.com>
Sun, 15 Jan 2012 07:06:54 +0000 (08:06 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Sun, 15 Jan 2012 07:06:54 +0000 (08:06 +0100)
pdm/__init__.py
pdm/cli.py
pdm/sshsock.py [new file with mode: 0644]

index b3cce04..537a31e 100644 (file)
@@ -9,7 +9,7 @@ This package contains the following modules:
 
  - srv -- Server module
  - cli -- Client module
- - perf -- Library for implementing object for the PERF protocol
+ - perf -- Library for implementing objects for the PERF protocol
 
 The protocol allows multiple management subprotocols for different
 modes of operation. Currently, the following two management protocols
@@ -19,13 +19,13 @@ are supported.
    accepts arbitrary Python code, executes it in the daemon process,
    and returns its replies, all in text form. The protocol is simple,
    generic, and has few failure modes, but is hardly suitable for
-   programmatic interaction. See the documentation for pdm.srv.repl
-   and pdm.cli.replclient for further details.
+   programmatic interaction. See the documentation for L{pdm.srv.repl}
+   and L{pdm.cli.replclient} for further details.
 
  - The PERF protocol is intended for programmatic interaction with the
    daemon process. Various Python modules may expose objects that
    implement one or several of a few pre-defined interfaces that allow
    for various forms of inspection and management of the program
-   state. See the documentation for pdm.srv.perf and
-   pdm.cli.perfclient for further details.
+   state. See the documentation for L{pdm.srv.perf} and
+   L{pdm.cli.perfclient} for further details.
 """
index 0b31682..272be86 100644 (file)
@@ -19,16 +19,21 @@ def resolve(spec):
         return spec
     sk = None
     try:
-        if "/" in spec:
+        if ":" in spec:
+            p = spec.rindex(":")
+            first, second = spec[:p], spec[p + 1:]
+            if "/" in second:
+                import sshsock
+                sk = sshsock.sshsocket(first, second)
+            else:
+                sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                sk.connect((first, second))
+        elif "/" in spec:
             sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
             sk.connect(spec)
         elif spec.isdigit():
             sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             sk.connect(("localhost", int(spec)))
-        elif ":" in spec:
-            sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            p = spec.rindex(":")
-            sk.connect((spec[:p], int(spec[p + 1:])))
         else:
             raise Exception("Unknown target specification %r" % spec)
         rv = sk
diff --git a/pdm/sshsock.py b/pdm/sshsock.py
new file mode 100644 (file)
index 0000000..feb2f9f
--- /dev/null
@@ -0,0 +1,73 @@
+import sys, os
+import subprocess, socket, fcntl, select
+
+class sshsocket(object):
+    def __init__(self, host, path, user = None, port = None):
+        args = ["ssh"]
+        if user is not None:
+            args += ["-u", str(user)]
+        if port is not None:
+            args += ["-p", str(int(port))]
+        args += [host]
+        args += ["python", "-m", "pdm.sshsock", path]
+        self.proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)
+        fcntl.fcntl(self.proc.stdout, fcntl.F_SETFL, fcntl.fcntl(self.proc.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+    def close(self):
+        if self.proc is not None:
+            self.proc.stdin.close()
+            self.proc.stdout.close()
+            self.proc.wait()
+            self.proc = None
+
+    def send(self, data, flags = 0):
+        self.proc.stdin.write(data)
+        return len(data)
+
+    def recv(self, buflen, flags = 0):
+        if (flags & socket.MSG_DONTWAIT) == 0:
+            select.select([self.proc.stdout], [], [])
+        return self.proc.stdout.read(buflen)
+
+    def fileno(self):
+        return self.proc.stdout.fileno()
+
+    def __del__(self):
+        self.close()
+
+def cli():
+    fcntl.fcntl(sys.stdin, fcntl.F_SETFL, fcntl.fcntl(sys.stdin, fcntl.F_GETFL) | os.O_NONBLOCK)
+    sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    try:
+        sk.connect(sys.argv[1])
+        buf1 = ""
+        buf2 = ""
+        while True:
+            wfd = []
+            if buf1: wfd.append(sk)
+            if buf2: wfd.append(sys.stdout)
+            rfd, wfd, efd = select.select([sk, sys.stdin], wfd, [])
+            if sk in rfd:
+                ret = sk.recv(65536)
+                if ret == "":
+                    break
+                else:
+                    buf2 += ret
+            if sys.stdin in rfd:
+                ret = sys.stdin.read()
+                if ret == "":
+                    break
+                else:
+                    buf1 = ret
+            if sk in wfd:
+                ret = sk.send(buf1)
+                buf1 = buf1[ret:]
+            if sys.stdout in wfd:
+                sys.stdout.write(buf2)
+                sys.stdout.flush()
+                buf2 = ""
+    finally:
+        sk.close()
+
+if __name__ == "__main__":
+    cli()