rework how buildozer-remote pipeline commands works (support stdin now.)

This commit is contained in:
Mathieu Virbel 2013-01-25 13:00:43 +01:00
parent 17cc24ea87
commit 057f3bcb59

View file

@ -12,14 +12,15 @@ Layout directory for buildozer:
__version__ = '0.3-dev' __version__ = '0.3-dev'
import shelve
import zipfile
import sys
import fcntl import fcntl
import os import os
import re import re
import shelve
import socket
import sys
import zipfile
from select import select from select import select
from sys import stdout, stderr, exit from sys import stdout, stderr, stdin, exit
from urllib import urlretrieve from urllib import urlretrieve
from re import search from re import search
from ConfigParser import SafeConfigParser from ConfigParser import SafeConfigParser
@ -29,6 +30,14 @@ from os import environ, unlink, rename, walk, sep, listdir, makedirs
from copy import copy from copy import copy
from shutil import copyfile, rmtree, copytree from shutil import copyfile, rmtree, copytree
# windows does not have termios...
try:
import termios
import tty
has_termios = True
except ImportError:
has_termios = False
RESET_SEQ = "\033[0m" RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;{0}m" COLOR_SEQ = "\033[1;{0}m"
BOLD_SEQ = "\033[1m" BOLD_SEQ = "\033[1m"
@ -196,8 +205,16 @@ class Buildozer(object):
show_output = kwargs.pop('show_output') show_output = kwargs.pop('show_output')
get_stdout = kwargs.pop('get_stdout', False) get_stdout = kwargs.pop('get_stdout', False)
get_stderr = kwargs.pop('get_stderr', False) get_stderr = kwargs.pop('get_stderr', False)
break_on_error = kwargs.pop('break_on_error', True)
sensible = kwargs.pop('sensible', False)
if not sensible:
self.debug('Run {0!r}'.format(command)) self.debug('Run {0!r}'.format(command))
else:
if type(command) in (list, tuple):
self.debug('Run {0!r} ...'.format(command[0]))
else:
self.debug('Run {0!r} ...'.format(command.split()[0]))
self.debug('Cwd {}'.format(kwargs.get('cwd'))) self.debug('Cwd {}'.format(kwargs.get('cwd')))
# open the process # open the process
@ -238,14 +255,14 @@ class Buildozer(object):
stderr.flush() stderr.flush()
process.communicate() process.communicate()
if process.returncode != 0: if process.returncode != 0 and break_on_error:
self.error('Command failed: {0}'.format(command)) self.error('Command failed: {0}'.format(command))
raise BuildozerCommandException() raise BuildozerCommandException()
if ret_stdout: if ret_stdout:
ret_stdout = ''.join(ret_stdout) ret_stdout = ''.join(ret_stdout)
if ret_stderr: if ret_stderr:
ret_stderr = ''.join(ret_stderr) ret_stderr = ''.join(ret_stderr)
return (ret_stdout, ret_stderr) return (ret_stdout, ret_stderr, process.returncode)
def check_configuration_tokens(self): def check_configuration_tokens(self):
'''Ensure the spec file is 'correct'. '''Ensure the spec file is 'correct'.
@ -493,6 +510,8 @@ class Buildozer(object):
exclude_exts = self.config.getlist('app', 'source.exclude_exts', '') exclude_exts = self.config.getlist('app', 'source.exclude_exts', '')
app_dir = self.app_dir app_dir = self.app_dir
self.debug('Copy application source from {}'.format(source_dir))
rmtree(self.app_dir) rmtree(self.app_dir)
for root, dirs, files in walk(source_dir): for root, dirs, files in walk(source_dir):
@ -896,21 +915,84 @@ class BuildozerRemote(Buildozer):
def _ssh_command(self, command): def _ssh_command(self, command):
self.debug('Execute remote command {}'.format(command)) self.debug('Execute remote command {}'.format(command))
rstdin, rstdout, rstderr = self._ssh_client.exec_command(command) #shell = self._ssh_client.invoke_shell()
#shell.sendall(command)
# prepare fds #shell.sendall('\nexit\n')
while True: transport = self._ssh_client.get_transport()
chunk = rstdout.read(1) channel = transport.open_session()
if chunk == '': try:
break channel.exec_command(command)
stdout.write(chunk) self._interactive_shell(channel)
stdout.flush() finally:
channel.close()
def usage(self): def usage(self):
print 'Usage: buildozer-remote [--verbose] [remote-name] [buildozer args]' print 'Usage: buildozer-remote [--verbose] [remote-name] [buildozer args]'
def _interactive_shell(self, chan):
if has_termios:
self._posix_shell(chan)
else:
self._windows_shell(chan)
def _posix_shell(self, chan):
oldtty = termios.tcgetattr(stdin)
try:
#tty.setraw(stdin.fileno())
#tty.setcbreak(stdin.fileno())
chan.settimeout(0.0)
while True:
r, w, e = select([chan, stdin], [], [])
if chan in r:
try:
x = chan.recv(128)
if len(x) == 0:
print '\r\n*** EOF\r\n',
break
stdout.write(x)
stdout.flush()
#print len(x), repr(x)
except socket.timeout:
pass
if stdin in r:
x = stdin.read(1)
if len(x) == 0:
break
chan.sendall(x)
finally:
termios.tcsetattr(stdin, termios.TCSADRAIN, oldtty)
# thanks to Mike Looijmans for this code
def _windows_shell(self,chan):
import threading
stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
def writeall(sock):
while True:
data = sock.recv(256)
if not data:
stdout.write('\r\n*** EOF ***\r\n\r\n')
stdout.flush()
break
stdout.write(data)
stdout.flush()
writer = threading.Thread(target=writeall, args=(chan,))
writer.start()
try:
while True:
d = stdin.read(1)
if not d:
break
chan.send(d)
except EOFError:
# user hit ^Z or F6
pass
def run(): def run():
try: try:
Buildozer().run_command(sys.argv[1:]) Buildozer().run_command(sys.argv[1:])