Test local directory completion
[polysh.git] / gsh / file_transfer.py
blob8f640601d6441d5e97956f840ede729c0c68500b
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) 2007, 2008 Guillaume Chazarain <guichaz@gmail.com>
19 import base64
20 import os
21 import random
23 from gsh import callbacks
24 from gsh import pity
25 from gsh.console import console_output
26 from gsh import remote_dispatcher
27 from gsh import dispatchers
29 CMD_PREFIX = 'python -c "`echo "%s"|tr , \\\\\\n|openssl base64 -d`" '
31 CMD_SEND = CMD_PREFIX + 'send "%s" "%s" "%s"\n'
32 CMD_FORWARD = CMD_PREFIX + 'forward "%s" "%s"\n'
33 CMD_RECEIVE = CMD_PREFIX + 'receive "%s" "%s"\n'
35 def find_pity_dot_py():
36 path = pity.__file__
37 if not path.endswith('.py'):
38 # Read from the .py source file
39 dot_py_start = path.find('.py')
40 if dot_py_start >= 0:
41 path = path[:dot_py_start+3]
43 if not os.path.isabs(path):
44 path = os.getcwd() + '/' + path
46 return path
48 # Save the full path, in case we change directory
49 PITY_PATH = find_pity_dot_py()
51 def base64version():
52 python_lines = []
53 for line in file(PITY_PATH):
54 hash_pos = line.find(chr(35))
55 if hash_pos < 0:
56 line = line[:hash_pos]
57 line = line.rstrip()
58 if line:
59 python_lines.append(line)
60 python_source = '\n'.join(python_lines)
61 encoded = base64.encodestring(python_source).rstrip('\n').replace('\n', ',')
62 return encoded
64 def file_transfer_cb(dispatcher, host_port):
65 previous_shell = get_previous_shell(dispatcher)
66 previous_shell.dispatch_write(pity.STDIN_PREFIX + host_port + '\n')
68 def get_infos():
69 """Returns (first, last)"""
70 first = None
71 last = None
72 for i in dispatchers.all_instances():
73 if i.enabled:
74 if not first:
75 first = i
76 last = i
77 return first, last
79 def get_previous_shell(shell):
80 shells = [i for i in dispatchers.all_instances() if i.enabled]
81 current_pos = shells.index(shell)
82 while True:
83 current_pos = (current_pos - 1) % len(shells)
84 prev_shell = shells[current_pos]
85 if prev_shell.enabled:
86 return prev_shell
88 def replicate(shell, path):
89 nr_peers = len([i for i in dispatchers.all_instances() if i.enabled])
90 if nr_peers <= 1:
91 console_output('No other remote shell to replicate files to\n')
92 return
93 receiver = get_previous_shell(shell)
94 pity_py = base64version()
95 for i in dispatchers.all_instances():
96 if not i.enabled:
97 continue
98 cb = lambda host_port, i=i: file_transfer_cb(i, host_port)
99 transfer1, transfer2 = callbacks.add('file transfer', cb, False)
100 if i == shell:
101 i.dispatch_command(CMD_SEND % (pity_py, path, transfer1, transfer2))
102 elif i != receiver:
103 i.dispatch_command(CMD_FORWARD % (pity_py, transfer1, transfer2))
104 else:
105 i.dispatch_command(CMD_RECEIVE % (pity_py, transfer1, transfer2))
106 i.change_state(remote_dispatcher.STATE_RUNNING)
108 class local_uploader(remote_dispatcher.remote_dispatcher):
109 def __init__(self, path_to_upload):
110 remote_dispatcher.remote_dispatcher.__init__(self, '.')
111 self.path_to_upload = path_to_upload
112 self.upload_started = False
114 def launch_ssh(self, name):
115 os.execl('/bin/sh', 'sh')
117 def change_state(self, state):
118 remote_dispatcher.remote_dispatcher.change_state(self, state)
119 if state != remote_dispatcher.STATE_IDLE:
120 return
122 if not self.upload_started:
123 replicate(self, self.path_to_upload)
124 self.upload_started = True
125 else:
126 self.disconnect()
127 self.close()
129 def upload(local_path):
130 local_shell = local_uploader(local_path)