diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 9acb091..43470d5 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -12,14 +12,15 @@ Layout directory for buildozer: __version__ = '0.3-dev' -import shelve -import zipfile -import sys import fcntl import os import re +import shelve +import socket +import sys +import zipfile from select import select -from sys import stdout, stderr, exit +from sys import stdout, stderr, stdin, exit from urllib import urlretrieve from re import search from ConfigParser import SafeConfigParser @@ -29,6 +30,14 @@ from os import environ, unlink, rename, walk, sep, listdir, makedirs from copy import copy 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" COLOR_SEQ = "\033[1;{0}m" BOLD_SEQ = "\033[1m" @@ -196,8 +205,16 @@ class Buildozer(object): show_output = kwargs.pop('show_output') get_stdout = kwargs.pop('get_stdout', False) get_stderr = kwargs.pop('get_stderr', False) + break_on_error = kwargs.pop('break_on_error', True) + sensible = kwargs.pop('sensible', False) - self.debug('Run {0!r}'.format(command)) + if not sensible: + 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'))) # open the process @@ -238,14 +255,14 @@ class Buildozer(object): stderr.flush() process.communicate() - if process.returncode != 0: + if process.returncode != 0 and break_on_error: self.error('Command failed: {0}'.format(command)) raise BuildozerCommandException() if ret_stdout: ret_stdout = ''.join(ret_stdout) if ret_stderr: ret_stderr = ''.join(ret_stderr) - return (ret_stdout, ret_stderr) + return (ret_stdout, ret_stderr, process.returncode) def check_configuration_tokens(self): '''Ensure the spec file is 'correct'. @@ -493,6 +510,8 @@ class Buildozer(object): exclude_exts = self.config.getlist('app', 'source.exclude_exts', '') app_dir = self.app_dir + self.debug('Copy application source from {}'.format(source_dir)) + rmtree(self.app_dir) for root, dirs, files in walk(source_dir): @@ -896,21 +915,84 @@ class BuildozerRemote(Buildozer): def _ssh_command(self, command): self.debug('Execute remote command {}'.format(command)) - rstdin, rstdout, rstderr = self._ssh_client.exec_command(command) - - # prepare fds - while True: - chunk = rstdout.read(1) - if chunk == '': - break - stdout.write(chunk) - stdout.flush() - + #shell = self._ssh_client.invoke_shell() + #shell.sendall(command) + #shell.sendall('\nexit\n') + transport = self._ssh_client.get_transport() + channel = transport.open_session() + try: + channel.exec_command(command) + self._interactive_shell(channel) + finally: + channel.close() def usage(self): 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(): try: Buildozer().run_command(sys.argv[1:])