Пример #1
0
def upload(local_path):
    peers = [i for i in dispatchers.all_instances() if i.enabled]
    if not peers:
        console_output('No other remote shell to replicate files to\n')
        return

    if len(peers) == 1:
        # We wouldn't be able to show the progress indicator with only one
        # destination. We need one remote connection in blocking mode to send
        # the base64 data to. We also need one remote connection in non blocking
        # mode for polysh to display the progress indicator via the main select
        # loop.
        console_output('Uploading to only one remote shell is not supported, '
                       'use scp instead\n')
        return

    def should_print_bw(node, already_chosen=[False]):
        if not node.children and not already_chosen[0]:
            already_chosen[0] = True
            return True
        return False

    tree = file_transfer_tree_node(None,
                                   peers[0],
                                   peers[1:],
                                   0,
                                   should_print_bw,
                                   path=local_path,
                                   is_upload=True)
Пример #2
0
 def dispatch_write(self, buf):
     """Augment the buffer with stuff to write when possible"""
     self.write_buffer += buf
     if len(self.write_buffer) > self.MAX_BUFFER_SIZE:
         console_output('Buffer too big ({:d}) for {}\n'.format(
             len(self.write_buffer), str(self)).encode())
         raise asyncore.ExitNow(1)
     return True
Пример #3
0
 def dispatch_write(self, buf):
     """Augment the buffer with stuff to write when possible"""
     assert self.allow_write
     self.write_buffer += buf
     if len(self.write_buffer) > buffered_dispatcher.MAX_BUFFER_SIZE:
         console_output('Buffer too big (%d) for %s\n' %
                                         (len(self.write_buffer), str(self)))
         raise asyncore.ExitNow(1)
Пример #4
0
 def dispatch_write(self, buf):
     """Augment the buffer with stuff to write when possible"""
     assert self.allow_write
     self.write_buffer += buf
     if len(self.write_buffer) > buffered_dispatcher.MAX_BUFFER_SIZE:
         console_output('Buffer too big (%d) for %s\n' %
                        (len(self.write_buffer), str(self)))
         raise asyncore.ExitNow(1)
Пример #5
0
 def handle_expt(self):
     pid, status = os.waitpid(self.pid, 0)
     exit_code = os.WEXITSTATUS(status)
     options.exit_code = max(options.exit_code, exit_code)
     if exit_code and options.interactive:
         console_output('Error talking to %s\n' % self.display_name)
     self.disconnect()
     if self.temporary:
         self.close()
Пример #6
0
def do_chdir(command):
    """
    Usage: :chdir LOCAL_PATH
    Change the current directory of polysh (not the remote shells).
    """
    try:
        os.chdir(expand_local_path(command.strip()))
    except OSError, e:
        console_output('%s\n' % str(e))
Пример #7
0
 def handle_expt(self):
     pid, status = os.waitpid(self.pid, 0)
     exit_code = os.WEXITSTATUS(status)
     options.exit_code = max(options.exit_code, exit_code)
     if exit_code and options.interactive:
         console_output('Error talking to %s\n' % self.display_name)
     self.disconnect()
     if self.temporary:
         self.close()
Пример #8
0
def do_upload(command):
    """
    Usage: :upload LOCAL_PATH
    Upload the specified local path to enabled remote shells.
    """
    if command:
        file_transfer.upload(command.strip())
    else:
        console_output('No local path given\n')
Пример #9
0
def do_chdir(command):
    """
    Usage: :chdir LOCAL_PATH
    Change the current directory of polysh (not the remote shells).
    """
    try:
        os.chdir(expand_local_path(command.strip()))
    except OSError, e:
        console_output('%s\n' % str(e))
Пример #10
0
def do_upload(command):
    """
    Usage: :upload LOCAL_PATH
    Upload the specified local path to enabled remote shells.
    """
    if command:
        file_transfer.upload(command.strip())
    else:
        console_output('No local path given\n')
Пример #11
0
def do_list(command):
    """
    Usage: :list [SHELLS...]
    List remote shells and their states.
    The output consists of: <hostname> <enabled?> <state>: <last printed line>.
    The special characters * ? and [] work as expected.
    """
    instances = [i.get_info() for i in selected_shells(command)]
    dispatchers.format_info(instances)
    console_output(''.join(instances))
Пример #12
0
def do_list(command):
    """
    Usage: :list [SHELLS...]
    List remote shells and their states.
    The output consists of: <hostname> <enabled?> <state>: <last printed line>.
    The special characters * ? and [] work as expected.
    """
    instances = [i.get_info() for i in selected_shells(command)]
    dispatchers.format_info(instances)
    console_output(''.join(instances))
Пример #13
0
def handle_control_command(line):
    if not line:
        return
    cmd_name = line.split()[0]
    try:
        cmd_func = get_control_command(cmd_name)
    except AttributeError:
        console_output('Unknown control command: %s\n' % cmd_name)
    else:
        parameters = line[len(cmd_name) + 1:]
        cmd_func(parameters)
Пример #14
0
def do_set_log(command: str) -> None:
    command = command.strip()
    if command:
        try:
            remote_dispatcher.options.log_file = open(command, 'a')
        except IOError as e:
            console_output('{}\n'.format(str(e)).encode())
            command = None
    if not command:
        remote_dispatcher.options.log_file = None
        console_output(b'Logging disabled\n')
Пример #15
0
def handle_control_command(line):
    if not line:
        return
    cmd_name = line.split()[0]
    try:
        cmd_func = get_control_command(cmd_name)
    except AttributeError:
        console_output(
            'Unknown control command: {}\n'.format(cmd_name).encode())
    else:
        parameters = line[len(cmd_name) + 1:]
        cmd_func(parameters)
Пример #16
0
def do_set_log(command):
    """
    Usage: :set_log [LOCAL_PATH]
    Duplicate every console I/O into the given local file.
    If LOCAL_PATH is not given, restore the default behaviour of not logging.
    """
    command = command.strip()
    if command:
        try:
            remote_dispatcher.options.log_file = file(command, 'a')
        except IOError, e:
            console_output('%s\n' % str(e))
            command = None
Пример #17
0
def do_set_log(command):
    """
    Usage: :set_log [LOCAL_PATH]
    Duplicate every console I/O into the given local file.
    If LOCAL_PATH is not given, restore the default behaviour of not logging.
    """
    command = command.strip()
    if command:
        try:
            remote_dispatcher.options.log_file = file(command, 'a')
        except IOError, e:
            console_output('%s\n' % str(e))
            command = None
Пример #18
0
def do_set_debug(command: str) -> None:
    split = command.split()
    if not split:
        console_output(b'Expected at least a letter\n')
        return
    letter = split[0].lower()
    if letter not in ('y', 'n'):
        console_output("Expected 'y' or 'n', got: {}\n".format(
            split[0]).encode())
        return
    debug = letter == 'y'
    for i in selected_shells(' '.join(split[1:])):
        i.debug = debug
Пример #19
0
def do_help(command):
    """
    Usage: :help [COMMAND]
    List control commands or show their documentations.
    """
    command = command.strip()
    if command:
        texts = []
        for name in command.split():
            try:
                cmd = get_control_command(name.lstrip(':'))
            except AttributeError:
                console_output('Unknown control command: %s\n' % name)
            else:
                doc = [d.strip() for d in cmd.__doc__.split('\n') if d.strip()]
                texts.append('\n'.join(doc))
        if texts:
            console_output('\n\n'.join(texts))
            console_output('\n')
    else:
        names = list_control_commands()
        max_name_len = max(map(len, names))
        for i in xrange(len(names)):
            name = names[i]
            txt = ':' + name + (max_name_len - len(name) + 2) * ' '
            doc = get_control_command(name).__doc__
            txt += doc.split('\n')[2].strip() + '\n'
            console_output(txt)
Пример #20
0
def do_help(command):
    """
    Usage: :help [COMMAND]
    List control commands or show their documentations.
    """
    command = command.strip()
    if command:
        texts = []
        for name in command.split():
            try:
                cmd = get_control_command(name.lstrip(':'))
            except AttributeError:
                console_output('Unknown control command: %s\n' % name)
            else:
                doc = [d.strip() for d in cmd.__doc__.split('\n') if d.strip()]
                texts.append('\n'.join(doc))
        if texts:
            console_output('\n\n'.join(texts))
            console_output('\n')
    else:
        names = list_control_commands()
        max_name_len = max(map(len, names))
        for i in xrange(len(names)):
            name = names[i]
            txt = ':' + name + (max_name_len - len(name) + 2) * ' '
            doc = get_control_command(name).__doc__
            txt += doc.split('\n')[2].strip() + '\n'
            console_output(txt)
Пример #21
0
def do_hide_password(command: str) -> None:
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output(b'Debugging disabled to avoid displaying '
                               b'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output(b'Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Пример #22
0
def do_send_ctrl(command: str) -> None:
    split = command.split()
    if not split:
        console_output(b'Expected at least a letter\n')
        return
    letter = split[0]
    if len(letter) != 1:
        console_output(
            'Expected a single letter, got: {}\n'.format(letter).encode())
        return
    control_letter = chr(ord(letter.lower()) - ord('a') + 1)
    for i in selected_shells(' '.join(split[1:])):
        if i.enabled:
            i.dispatch_write(control_letter.encode())
Пример #23
0
    def handle_close(self):
        if self.state is STATE_DEAD:
            # This connection has already been killed. Asyncore has probably
            # called handle_close() or handle_expt() on this connection twice.
            return

        pid, status = os.waitpid(self.pid, 0)
        exit_code = os.WEXITSTATUS(status)
        options.exit_code = max(options.exit_code, exit_code)
        if exit_code and options.interactive:
            console_output('Error talking to {}\n'.format(
                self.display_name).encode())
        self.disconnect()
        if self.temporary:
            self.close()
Пример #24
0
def process_input_buffer() -> None:
    """Send the content of the input buffer to all remote processes, this must
    be called in the main thread"""
    from polysh.control_commands_helpers import handle_control_command
    data = the_stdin_thread.input_buffer.get()
    remote_dispatcher.log(b'> ' + data)

    if data.startswith(b':'):
        try:
            handle_control_command(data[1:-1].decode())
        except UnicodeDecodeError as e:
            console_output(b'Could not decode command.')
        return

    if data.startswith(b'!'):
        try:
            retcode = subprocess.call(data[1:], shell=True)
        except OSError as e:
            if e.errno == errno.EINTR:
                console_output(b'Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned {:d}\n'.format(retcode).encode())
        elif retcode < 0:
            console_output('Child was terminated by signal {:d}\n'.format(
                -retcode).encode())
        return

    for r in dispatchers.all_instances():
        try:
            r.dispatch_command(data)
        except asyncore.ExitNow as e:
            raise e
        except Exception as msg:
            raise msg
            console_output('{} for {}, disconnecting\n'.format(
                str(msg), r.display_name).encode())
            r.disconnect()
        else:
            if r.enabled and r.state is remote_dispatcher.STATE_IDLE:
                r.change_state(remote_dispatcher.STATE_RUNNING)
Пример #25
0
def do_set_debug(command):
    """
    Usage: :set_debug y|n [SHELLS...]
    Enable or disable debugging output for remote shells.
    The first argument is 'y' to enable the debugging output, 'n' to
    disable it.
    The remaining optional arguments are the selected shells.
    The special characters * ? and [] work as expected.
    """
    split = command.split()
    if not split:
        console_output('Expected at least a letter\n')
        return
    letter = split[0].lower()
    if letter not in ('y', 'n'):
        console_output("Expected 'y' or 'n', got: %s\n" % split[0])
        return
    debug = letter == 'y'
    for i in selected_shells(' '.join(split[1:])):
        i.debug = debug
Пример #26
0
def do_set_debug(command):
    """
    Usage: :set_debug y|n [SHELLS...]
    Enable or disable debugging output for remote shells.
    The first argument is 'y' to enable the debugging output, 'n' to
    disable it.
    The remaining optional arguments are the selected shells.
    The special characters * ? and [] work as expected.
    """
    split = command.split()
    if not split:
        console_output('Expected at least a letter\n')
        return
    letter = split[0].lower()
    if letter not in ('y', 'n'):
        console_output("Expected 'y' or 'n', got: %s\n" % split[0])
        return
    debug = letter == 'y'
    for i in selected_shells(' '.join(split[1:])):
        i.debug = debug
Пример #27
0
def replicate(shell, path):
    peers = [i for i in dispatchers.all_instances() if i.enabled]
    if len(peers) <= 1:
        console_output('No other remote shell to replicate files to\n')
        return

    def should_print_bw(node, already_chosen=[False]):
        if not node.children and not already_chosen[0] and not node.is_upload:
            already_chosen[0] = True
            return True
        return False

    sender_index = peers.index(shell)
    destinations = peers[:sender_index] + peers[sender_index+1:]
    tree = file_transfer_tree_node(None,
                                   shell,
                                   destinations,
                                   0,
                                   should_print_bw,
                                   path=path)
Пример #28
0
def do_hide_password(command):
    """
    Usage: :hide_password
    Do not echo the next typed line.
    This is useful when entering password. If debugging or logging is enabled,
    it will be disabled to avoid displaying a password. Therefore, you will have
    to reenable logging or debugging afterwards if need be.
    """
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output('Debugging disabled to avoid displaying '
                               'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output('Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Пример #29
0
def selected_shells(command):
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if fnmatch(i.display_name, expanded_pattern):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('%s not found\n' % pattern)
Пример #30
0
def do_hide_password(command):
    """
    Usage: :hide_password
    Do not echo the next typed line.
    This is useful when entering password. If debugging or logging is enabled,
    it will be disabled to avoid displaying a password. Therefore, you will have
    to reenable logging or debugging afterwards if need be.
    """
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output('Debugging disabled to avoid displaying '
                               'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output('Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Пример #31
0
def selected_shells(command):
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if fnmatch(i.display_name, expanded_pattern):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('{} not found\n'.format(pattern).encode())
Пример #32
0
def process_input_buffer():
    """Send the content of the input buffer to all remote processes, this must
    be called in the main thread"""
    from polysh.control_commands_helpers import handle_control_command
    data = the_stdin_thread.input_buffer.get()
    remote_dispatcher.log('> ' + data)

    if data.startswith(':'):
        handle_control_command(data[1:-1])
        return

    if data.startswith('!'):
        try:
            retcode = subprocess.call(data[1:], shell=True)
        except OSError, e:
            if e.errno == errno.EINTR:
                console_output('Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned %d\n' % retcode)
        elif retcode < 0:
            console_output('Child was terminated by signal %d\n' % -retcode)
        return
Пример #33
0
def process_input_buffer():
    """Send the content of the input buffer to all remote processes, this must
    be called in the main thread"""
    from polysh.control_commands_helpers import handle_control_command
    data = the_stdin_thread.input_buffer.get()
    remote_dispatcher.log('> ' + data)

    if data.startswith(':'):
        handle_control_command(data[1:-1])
        return

    if data.startswith('!'):
        try:
            retcode = subprocess.call(data[1:], shell=True)
        except OSError, e:
            if e.errno == errno.EINTR:
                console_output('Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned %d\n' % retcode)
        elif retcode < 0:
            console_output('Child was terminated by signal %d\n' % -retcode)
        return
Пример #34
0
 def print_lines(self, lines):
     from polysh.display_names import max_display_name_length
     lines = lines.strip('\n')
     while True:
         no_empty_lines = lines.replace('\n\n', '\n')
         if len(no_empty_lines) == len(lines):
             break
         lines = no_empty_lines
     if not lines:
         return
     indent = max_display_name_length - len(self.display_name)
     log_prefix = self.display_name + indent * ' ' + ' : '
     if self.color_code is None:
         console_prefix = log_prefix
     else:
         console_prefix = '\033[1;%dm%s\033[1;m' % (self.color_code,
                                                    log_prefix)
     console_data = (console_prefix +
                     lines.replace('\n', '\n' + console_prefix) + '\n')
     log_data = log_prefix + lines.replace('\n', '\n' + log_prefix) + '\n'
     console_output(console_data, logging_msg=log_data)
     self.last_printed_line = lines[lines.rfind('\n') + 1:]
Пример #35
0
def do_send_ctrl(command):
    """
    Usage: :send_ctrl LETTER [SHELLS...]
    Send a control character to remote shells.
    The first argument is the control character to send like c, d or z.
    Note that these three control characters can be sent simply by typing them
    into polysh.
    The remaining optional arguments are the destination shells.
    The special characters * ? and [] work as expected.
    """
    split = command.split()
    if not split:
        console_output('Expected at least a letter\n')
        return
    letter = split[0]
    if len(letter) != 1:
        console_output('Expected a single letter, got: %s\n' % letter)
        return
    control_letter = chr(ord(letter.lower()) - ord('a') + 1)
    for i in selected_shells(' '.join(split[1:])):
        if i.enabled:
            i.dispatch_write(control_letter)
Пример #36
0
def do_send_ctrl(command):
    """
    Usage: :send_ctrl LETTER [SHELLS...]
    Send a control character to remote shells.
    The first argument is the control character to send like c, d or z.
    Note that these three control characters can be sent simply by typing them
    into polysh.
    The remaining optional arguments are the destination shells.
    The special characters * ? and [] work as expected.
    """
    split = command.split()
    if not split:
        console_output('Expected at least a letter\n')
        return
    letter = split[0]
    if len(letter) != 1:
        console_output('Expected a single letter, got: %s\n' % letter)
        return
    control_letter = chr(ord(letter.lower()) - ord('a') + 1)
    for i in selected_shells(' '.join(split[1:])):
        if i.enabled:
            i.dispatch_write(control_letter)
Пример #37
0
 def print_lines(self, lines):
     from polysh.display_names import max_display_name_length
     lines = lines.strip('\n')
     while True:
         no_empty_lines = lines.replace('\n\n', '\n')
         if len(no_empty_lines) == len(lines):
             break
         lines = no_empty_lines
     if not lines:
         return
     indent = max_display_name_length - len(self.display_name)
     log_prefix = self.display_name + indent * ' ' + ' : '
     if self.color_code is None:
         console_prefix = log_prefix
     else:
         console_prefix = '\033[1;%dm%s\033[1;m' % (self.color_code,
                                                    log_prefix)
     console_data = (console_prefix +
                     lines.replace('\n', '\n' + console_prefix) + '\n')
     log_data = log_prefix + lines.replace('\n', '\n' + log_prefix) + '\n'
     console_output(console_data, logging_msg=log_data)
     self.last_printed_line = lines[lines.rfind('\n') + 1:]
Пример #38
0
def selected_shells(
        command: str) -> Iterator[remote_dispatcher.RemoteDispatcher]:
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()  # type: Set[remote_dispatcher.RemoteDispatcher]
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if (fnmatch(i.display_name, expanded_pattern) or fnmatch(
                        str(i.last_printed_line), expanded_pattern)):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('{} not found\n'.format(pattern).encode())
Пример #39
0
 def print_lines(self, lines: bytes) -> None:
     from polysh.display_names import max_display_name_length
     lines = lines.strip(b'\n')
     while True:
         no_empty_lines = lines.replace(b'\n\n', b'\n')
         if len(no_empty_lines) == len(lines):
             break
         lines = no_empty_lines
     if not lines:
         return
     indent = max_display_name_length - len(self.display_name)
     log_prefix = self.display_name.encode() + indent * b' ' + b' : '
     if self.color_code is None:
         console_prefix = log_prefix
     else:
         console_prefix = (b'\033[1;' + str(self.color_code).encode() +
                           b'm' + log_prefix + b'\033[1;m')
     console_data = (console_prefix +
                     lines.replace(b'\n', b'\n' + console_prefix) + b'\n')
     log_data = (log_prefix + lines.replace(b'\n', b'\n' + log_prefix) +
                 b'\n')
     console_output(console_data, logging_msg=log_data)
     self.last_printed_line = lines[lines.rfind(b'\n') + 1:]
Пример #40
0
def loop(interactive):
    histfile = os.path.expanduser("~/.polysh_history")
    init_history(histfile)
    next_signal = None
    last_status = None
    while True:
        try:
            if next_signal:
                current_signal = next_signal
                next_signal = None
                sig2chr = {signal.SIGINT: 'C', signal.SIGTSTP: 'Z'}
                ctrl = sig2chr[current_signal]
                remote_dispatcher.log('> ^{}\n'.format(ctrl).encode())
                control_commands.do_send_ctrl(ctrl)
                console_output(b'')
                stdin.the_stdin_thread.prepend_text = None
            while dispatchers.count_awaited_processes()[0] and \
                    remote_dispatcher.main_loop_iteration(timeout=0.2):
                pass
            # Now it's quiet
            for r in dispatchers.all_instances():
                r.print_unfinished_line()
            current_status = dispatchers.count_awaited_processes()
            if current_status != last_status:
                console_output(b'')
            if remote_dispatcher.options.interactive:
                stdin.the_stdin_thread.want_raw_input()
            last_status = current_status
            if dispatchers.all_terminated():
                # Clear the prompt
                console_output(b'')
                raise asyncore.ExitNow(remote_dispatcher.options.exit_code)
            if not next_signal:
                # possible race here with the signal handler
                remote_dispatcher.main_loop_iteration()
        except KeyboardInterrupt:
            if interactive:
                next_signal = signal.SIGINT
            else:
                kill_all()
                os.kill(0, signal.SIGINT)
        except asyncore.ExitNow as e:
            console_output(b'')
            save_history(histfile)
            sys.exit(e.args[0])
Пример #41
0
def do_replicate(command):
    """
    Usage: :replicate SHELL:REMOTE_PATH
    Copy a path from one remote shell to all others
    """
    if ':' not in command:
        console_output('Usage: :replicate SHELL:REMOTE_PATH\n')
        return
    shell_name, path = command.strip().split(':', 1)
    if not path:
        console_output('No remote path given\n')
        return
    for shell in dispatchers.all_instances():
        if shell.display_name == shell_name:
            if not shell.enabled:
                console_output('%s is not enabled\n' % shell_name)
                return
            break
    else:
        console_output('%s not found\n' % shell_name)
        return
    file_transfer.replicate(shell, path)
Пример #42
0
def do_replicate(command):
    """
    Usage: :replicate SHELL:REMOTE_PATH
    Copy a path from one remote shell to all others
    """
    if ':' not in command:
        console_output('Usage: :replicate SHELL:REMOTE_PATH\n')
        return
    shell_name, path = command.strip().split(':', 1)
    if not path:
        console_output('No remote path given\n')
        return
    for shell in dispatchers.all_instances():
        if shell.display_name == shell_name:
            if not shell.enabled:
                console_output('%s is not enabled\n' % shell_name)
                return
            break
    else:
        console_output('%s not found\n' % shell_name)
        return
    file_transfer.replicate(shell, path)
Пример #43
0
def main_loop():
    global next_signal
    last_status = None
    while True:
        try:
            if next_signal:
                current_signal = next_signal
                next_signal = None
                sig2chr = {signal.SIGINT: 'c', signal.SIGTSTP: 'z'}
                ctrl = sig2chr[current_signal]
                remote_dispatcher.log('> ^%c\n' % ctrl.upper())
                control_commands.do_send_ctrl(ctrl)
                console_output('')
                the_stdin_thread.prepend_text = None
            while dispatchers.count_awaited_processes()[0] and \
                  remote_dispatcher.main_loop_iteration(timeout=0.2):
                pass
            # Now it's quiet
            for r in dispatchers.all_instances():
                r.print_unfinished_line()
            current_status = dispatchers.count_awaited_processes()
            if current_status != last_status:
                console_output('')
            if remote_dispatcher.options.interactive:
                the_stdin_thread.want_raw_input()
            last_status = current_status
            if dispatchers.all_terminated():
                # Clear the prompt
                console_output('')
                raise asyncore.ExitNow(remote_dispatcher.options.exit_code)
            if not next_signal:
                # possible race here with the signal handler
                remote_dispatcher.main_loop_iteration()
        except asyncore.ExitNow, e:
            console_output('')
            sys.exit(e.args[0])
Пример #44
0
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned %d\n' % retcode)
        elif retcode < 0:
            console_output('Child was terminated by signal %d\n' % -retcode)
        return

    for r in dispatchers.all_instances():
        try:
            r.dispatch_command(data)
        except asyncore.ExitNow, e:
            raise e
        except Exception, msg:
            console_output('%s for %s, disconnecting\n' % (msg, r.display_name))
            r.disconnect()
        else:
            if r.enabled and r.state is remote_dispatcher.STATE_IDLE:
                r.change_state(remote_dispatcher.STATE_RUNNING)

# The stdin thread uses a synchronous (with ACK) socket to communicate with the
# main thread, which is most of the time waiting in the poll() loop.
# Socket character protocol:
# d: there is new data to send
# A: ACK, same reply for every message, communications are synchronous, so the
# stdin thread sends a character to the socket, the main thread processes it,
# sends the ACK, and the stdin thread can go on.

class socket_notification_reader(asyncore.dispatcher):
    """The socket reader in the main thread"""
Пример #45
0
def do_chdir(command: str) -> None:
    try:
        os.chdir(expand_local_path(command.strip()))
    except OSError as e:
        console_output('{}\n'.format(str(e)).encode())
Пример #46
0
def do_list(command: str) -> None:
    instances = [i.get_info() for i in selected_shells(command)]
    flat_instances = dispatchers.format_info(instances)
    console_output(b''.join(flat_instances))
Пример #47
0
def do_set_log(command):
    """
    Usage: :set_log [LOCAL_PATH]
    Duplicate every console I/O into the given local file.
    If LOCAL_PATH is not given, restore the default behaviour of not logging.
    """
    command = command.strip()
    if command:
        try:
            remote_dispatcher.options.log_file = file(command, 'a')
        except IOError, e:
            console_output('%s\n' % str(e))
            command = None
    if not command:
        remote_dispatcher.options.log_file = None
        console_output('Logging disabled\n')

def complete_show_read_buffer(line, text):
    return complete_shells(line, text, lambda i: i.read_buffer or
                                                 i.read_in_state_not_started)

def do_show_read_buffer(command):
    """
    Usage: :show_read_buffer [SHELLS...]
    Print the data read by remote shells.
    The special characters * ? and [] work as expected.
    """
    for i in selected_shells(command):
        if i.read_in_state_not_started:
            i.print_lines(i.read_in_state_not_started)
            i.read_in_state_not_started = ''
Пример #48
0
 def print_debug(self, msg):
     """Log some debugging information to the console"""
     state = STATE_NAMES[self.state]
     msg = msg.encode('string_escape')
     console_output('[dbg] %s[%s]: %s\n' % (self.display_name, state, msg))