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
.active
and i
.state
is not remote_dispatcher
.STATE_TERMINATED
:
63 return instances_found
65 max_display_name_length
= 0
66 def update_max_display_name_length(change
):
67 """The max_display_name_length serves to compute the length of the
68 whitespace used to align the output of the remote shells. A positive change
69 argument indicates that a remote shells with such a name length was enabled
70 while a negative change argument indicates a disabled remote shell"""
71 global max_display_name_length
74 if -change
< max_display_name_length
:
75 # The disabled shell didn't have the longest name
78 for i
in all_instances():
80 l
= len(i
.display_name
)
82 # The disabled shell was not alone with the longest name
84 new_max
= max(l
, new_max
)
86 new_max
= max(change
, max_display_name_length
)
88 if new_max
!= max_display_name_length
:
89 max_display_name_length
= new_max
90 update_terminal_size()
92 def update_terminal_size():
93 """Propagate the terminal size to the remote shells accounting for the
94 place taken by the longest name"""
95 w
, h
= terminal_size()
96 w
= max(w
- max_display_name_length
- 2, min(w
, 10))
97 # python bug http://python.org/sf/1112949 on amd64
99 bug
= struct
.unpack('i', struct
.pack('I', termios
.TIOCSWINSZ
))[0]
100 packed_size
= struct
.pack('HHHH', h
, w
, 0, 0)
102 for i
in all_instances():
103 if i
.enabled
and i
.term_size
!= term_size
:
104 i
.term_size
= term_size
105 fcntl
.ioctl(i
.fd
, bug
, packed_size
)
107 def format_info(info_list
):
108 """Turn a 2-dimension list of strings into a 1-dimension list of strings
109 with correct spacing"""
110 info_list
.sort(key
=lambda i
:int(i
[1][3:]))
113 nr_columns
= len(info_list
[0])
116 for i
in xrange(nr_columns
):
117 max_lengths
.append(max([len(str(info
[i
])) for info
in info_list
]))
118 for info_id
in xrange(len(info_list
)):
119 info
= info_list
[info_id
]
120 for str_id
in xrange(len(info
)):
121 orig_str
= str(info
[str_id
])
122 indent
= max_lengths
[str_id
] - len(orig_str
)
123 info
[str_id
] = orig_str
+ indent
* ' '
124 info_list
[info_id
] = ' '.join(info
)