Pre-populate the history completion with gsh's own variables.
[gsh.git] / gsh / dispatchers.py
blobf1cfd575a603fc63001eb0bb7130be6ca6eacc47
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # See the COPYING file for license information.
17 # Copyright (c) 2006, 2007, 2008 Guillaume Chazarain <guichaz@gmail.com>
19 import asyncore
20 import fcntl
21 import struct
22 import sys
23 import termios
25 from gsh import remote_dispatcher
26 from gsh import display_names
27 from gsh.terminal_size import terminal_size
29 def all_instances():
30 """Iterator over all the remote_dispatcher instances"""
31 return sorted([i for i in asyncore.socket_map.itervalues() if
32 isinstance(i, remote_dispatcher.remote_dispatcher)],
33 key=lambda i: i.display_name)
35 def count_awaited_processes():
36 """Return a tuple with the number of awaited processes and the total
37 number"""
38 awaited = 0
39 total = 0
40 for i in all_instances():
41 if i.enabled:
42 total += 1
43 if i.state is not remote_dispatcher.STATE_IDLE:
44 awaited += 1
45 return awaited, total
47 def all_terminated():
48 """For each remote shell determine if its terminated"""
49 instances_found = False
50 for i in all_instances():
51 instances_found = True
52 if i.state not in (remote_dispatcher.STATE_TERMINATED,
53 remote_dispatcher.STATE_DEAD):
54 return False
55 return instances_found
57 def update_terminal_size():
58 """Propagate the terminal size to the remote shells accounting for the
59 place taken by the longest name"""
60 w, h = terminal_size()
61 w = max(w - display_names.max_display_name_length - 2, min(w, 10))
62 # python bug http://python.org/sf/1112949 on amd64
63 # from ajaxterm.py
64 bug = struct.unpack('i', struct.pack('I', termios.TIOCSWINSZ))[0]
65 packed_size = struct.pack('HHHH', h, w, 0, 0)
66 term_size = w, h
67 for i in all_instances():
68 if i.enabled and i.term_size != term_size:
69 i.term_size = term_size
70 fcntl.ioctl(i.fd, bug, packed_size)
72 def format_info(info_list):
73 """Turn a 2-dimension list of strings into a 1-dimension list of strings
74 with correct spacing"""
75 max_lengths = []
76 if info_list:
77 nr_columns = len(info_list[0])
78 else:
79 nr_columns = 0
80 for i in xrange(nr_columns):
81 max_lengths.append(max([len(str(info[i])) for info in info_list]))
82 for info_id in xrange(len(info_list)):
83 info = info_list[info_id]
84 for str_id in xrange(len(info) - 1):
85 # Don't justify the last column (i.e. the last printed line)
86 # as it can get much longer in some shells than in others
87 orig_str = str(info[str_id])
88 indent = max_lengths[str_id] - len(orig_str)
89 info[str_id] = orig_str + indent * ' '
90 info_list[info_id] = ' '.join(info) + '\n'
92 def create_remote_dispatchers(hosts):
93 last_message = ''
94 for i, host in enumerate(hosts):
95 if remote_dispatcher.options.interactive:
96 last_message = 'Started %d/%d remote processes\r' % (i, len(hosts))
97 sys.stdout.write(last_message)
98 sys.stdout.flush()
99 try:
100 remote_dispatcher.remote_dispatcher(host)
101 except OSError:
102 print
103 raise
105 if last_message:
106 sys.stdout.write(' ' * len(last_message) + '\r')
107 sys.stdout.flush()