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>
24 from gsh
import remote_dispatcher
25 from gsh
.terminal_size
import terminal_size
28 """Iterator over all the remote_dispatcher instances"""
29 for i
in asyncore
.socket_map
.itervalues():
30 if isinstance(i
, remote_dispatcher
.remote_dispatcher
):
33 def make_unique_name(name
):
34 """Each shell must have a unique display name, so identical hostnames are
35 suffixed by #NUMBER"""
36 display_names
= set([i
.display_name
for i
in all_instances()])
39 while candidate_name
in display_names
:
41 candidate_name
= '%s#%d' % (name
, i
)
44 def count_awaited_processes():
45 """Return a tuple with the number of awaited processes and the total
49 for i
in all_instances():
52 if i
.state
is not remote_dispatcher
.STATE_IDLE
:
57 """For each remote shell determine if its terminated"""
58 instances_found
= False
59 for i
in all_instances():
60 instances_found
= True
61 if i
.state
not in (remote_dispatcher
.STATE_TERMINATED
,
62 remote_dispatcher
.STATE_DEAD
):
64 return instances_found
66 max_display_name_length
= 0
67 def update_max_display_name_length(change
):
68 """The max_display_name_length serves to compute the length of the
69 whitespace used to align the output of the remote shells. A positive change
70 argument indicates that a remote shells with such a name length was enabled
71 while a negative change argument indicates a disabled remote shell"""
72 global max_display_name_length
75 if -change
< max_display_name_length
:
76 # The disabled shell didn't have the longest name
79 for i
in all_instances():
81 l
= len(i
.display_name
)
83 # The disabled shell was not alone with the longest name
85 new_max
= max(l
, new_max
)
87 new_max
= max(change
, max_display_name_length
)
89 if new_max
!= max_display_name_length
:
90 max_display_name_length
= new_max
91 update_terminal_size()
93 def update_terminal_size():
94 """Propagate the terminal size to the remote shells accounting for the
95 place taken by the longest name"""
96 w
, h
= terminal_size()
97 w
= max(w
- max_display_name_length
- 2, min(w
, 10))
98 # python bug http://python.org/sf/1112949 on amd64
100 bug
= struct
.unpack('i', struct
.pack('I', termios
.TIOCSWINSZ
))[0]
101 packed_size
= struct
.pack('HHHH', h
, w
, 0, 0)
103 for i
in all_instances():
104 if i
.enabled
and i
.term_size
!= term_size
:
105 i
.term_size
= term_size
106 fcntl
.ioctl(i
.fd
, bug
, packed_size
)
108 def format_info(info_list
):
109 """Turn a 2-dimension list of strings into a 1-dimension list of strings
110 with correct spacing"""
111 info_list
.sort(key
=lambda i
:i
[0])
114 nr_columns
= len(info_list
[0])
117 for i
in xrange(nr_columns
):
118 max_lengths
.append(max([len(str(info
[i
])) for info
in info_list
]))
119 for info_id
in xrange(len(info_list
)):
120 info
= info_list
[info_id
]
121 for str_id
in xrange(len(info
)):
122 orig_str
= str(info
[str_id
])
123 indent
= max_lengths
[str_id
] - len(orig_str
)
124 info
[str_id
] = orig_str
+ indent
* ' '
125 info_list
[info_id
] = ' '.join(info
) + '\n'