"""A Spawner for JupyterHub to allow the Hub to be run as non-root.

This spawns a mediator process with sudo, which then takes actions on behalf of the user.
"""

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.


import json
from subprocess import Popen, PIPE

from tornado import gen
from tornado.concurrent import Future
from tornado.process import Subprocess

from IPython.utils.traitlets import List, Unicode, Bool

from jupyterhub.spawner import LocalProcessSpawner
from jupyterhub.utils import random_port

class SudoSpawner(LocalProcessSpawner):
    
    sudospawner_path = Unicode('sudospawner', config=True,
        help="Path to sudospawner script"
    )
    sudo_args = List(['-nH'], config=True,
        help="Extra args to pass to sudo"
    )
    debug_mediator = Bool(False, config=True,
        help="Extra log output from the mediator process for debugging",
    )
    
    def do(self, action, **kwargs):
        """Instruct the mediator process to take a given action"""
        kwargs['action'] = action
        cmd = ['sudo', '-u', self.user.name]
        cmd.extend(self.sudo_args)
        cmd.append(self.sudospawner_path)
        if self.debug_mediator:
            cmd.append('--logging=debug')
        
        p = Popen(cmd, stdin=PIPE, stdout=PIPE)
        data = json.dumps(kwargs).encode('utf8')
        stdout, _ = p.communicate(data)
        f = Future()
        f.set_result(json.loads(stdout.decode('utf8')))
        # def finish(returncode):
        #     buf = p.stdout.read().decode('utf8')
        #     f.set_result(json.loads(buf))
        #
        # p.set_exit_callback(finish)
        return f

    @gen.coroutine
    def start(self):
        self.user.server.port = random_port()
        # only args, not the base command
        reply = yield self.do(action='spawn', args=self.get_args(), env=self.env)
        self.pid = reply['pid']

    @gen.coroutine
    def _signal(self, sig):
        reply = yield self.do('kill', pid=self.pid, signal=sig)
        return reply['alive']


@@ -276,105 +276,32 @@
 son%0A
-from subprocess import Popen, PIPE%0A%0Afrom tornado import gen%0Afrom tornado.concurrent import Future
+%0Afrom tornado import gen
 %0Afro
@@ -856,24 +856,43 @@
 %0A    )%0A    %0A
+    @gen.coroutine%0A
     def do(s
@@ -1237,13 +1237,18 @@
 p = 
-Popen
+Subprocess
 (cmd
@@ -1259,42 +1259,81 @@
 din=
-PIPE, stdout=PIPE)%0A        data = 
+Subprocess.STREAM, stdout=Subprocess.STREAM)%0A        yield p.stdin.write(
 json
@@ -1353,32 +1353,33 @@
 ).encode('utf8')
+)
 %0A        stdout,
@@ -1375,310 +1375,119 @@
     
+p.
 std
-out, _ = p.communicate(data)%0A        f = Future()%0A        f.set_result(json.loads(stdout.decode('utf8')))%0A        # def finish(returncode):%0A        #     buf = p.stdout.read().decode('utf8')%0A        #     f.set_result(json.loads(buf))%0A        #%0A        # p.set_exit_callback(finish)%0A        return f
+in.close()%0A        data = yield p.stdout.read_until_close()%0A        return json.loads(data.decode('utf8'))
 %0A%0A  

make subprocess async