Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 209 additions & 44 deletions Mote.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import sublime, sublime_plugin

import subprocess
import os, time
import os, time, inspect, sys
import threading
import json
import posixpath
import time
import shutil
from collections import deque

# use this if you want to include modules from a subforder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"lib")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)

import paramiko

MOTES = {}

def main():
Expand Down Expand Up @@ -103,6 +110,7 @@ def run(self):
print MOTES[server]['thread'].sftp
print MOTES[server]['thread'].results


class MoteDisconnectCommand(sublime_plugin.WindowCommand):
def run(self, server=''):
MOTES[server]['thread'].add_command('exit','')
Expand All @@ -125,9 +133,25 @@ def on_post_save(self, view):
class MoteSearchThread(threading.Thread):
def __init__(self, server, search_path='', connection_string='', password=None, idle_recursive=False, private_key=None, port=None):
self.server = server
self.search_path = ''
self.search_path = search_path
self.hostname = ''
self.password = password #didn't see this in the namespace so added it
self.connection_string = connection_string

self.os_mode = os.name
self.base_dir = ''
if not port == None:
self.port = port
else:
print "Port Not Defined Defaulting to 22"
self.port = 22

#Identify if this is a username@hostname string
connection_string_parts = connection_string.split('@')
if len(connection_string_parts) > 1:
self.hostname = connection_string_parts[1]
self.username = connection_string_parts[0]
else:
self.hostname = connection_string

if ('-pw' not in connection_string) and password:
self.connection_string = [r'-pw', password, connection_string]
Expand All @@ -142,8 +166,9 @@ def __init__(self, server, search_path='', connection_string='', password=None,

self.idle_recursive = idle_recursive


self.results = {}
self.transport = None
self.sshClient = None
self.sftp = None

self.results_lock = threading.Condition()
Expand All @@ -153,11 +178,49 @@ def __init__(self, server, search_path='', connection_string='', password=None,

threading.Thread.__init__(self)

def is_os_mode(self, mode):
return self.os_mode == mode

def connect(self):
if not self.sftp:
self.sftp = psftp(self.connection_string)
self.sftp.next()
return self
if not self.is_os_mode('posix'):
if not self.sftp:
self.sftp = psftp(self.connection_string)
self.sftp.next()
return self
else:
try:
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
except IOError:
try:
# try ~/ssh/ too, because windows can't have a folder named ~/.ssh/
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
except IOError:
print '*** Unable to open host keys file'
host_keys = {}

if host_keys.has_key(self.hostname):
hostkeytype = host_keys[self.hostname].keys()[0]
hostkey = host_keys[self.hostname][hostkeytype]
print 'Using host key of type %s' % hostkeytype
try:
self.sshClient = client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(self.hostname, self.port, username=self.username, password=self.password)
#keyfile = paramiko.DSSKey.from_private_key_file(private_key)
#self.transport = t = paramiko.Transport((self.hostname, 22))
#t.connect(username=self.username, password=self.password, hostkey=hostkey)
#self.sftp = paramiko.SFTPClient.from_transport(t)
self.transport = t = client.get_transport()
self.sftp = paramiko.SFTPClient.from_transport(t)
#self.sftp = client.open_sftp()
print "SFTP INIT: "+ str(self.transport.is_active())
self.add_command('cd',self.search_path, True)
except Exception as e:
sublime.set_timeout(lambda:sublime.status_message('Server Config Error Check that you have valid credentils in servers.json'),0)
print "transport Failed ", e
return self


def disconnect(self):
self.add_command('exit','')
Expand All @@ -178,14 +241,49 @@ def get_front_command(self):
else:
return (None,None)

def send_cmd(self, command, path, show_panel):
print "Command: " + command
print "Path: " + path
if command == 'ls':
if show_panel == True:
sublime.set_timeout(lambda:sublime.status_message('Opening %s' % path),0)
self.ls(path)
if show_panel == True:
self.showfilepanel()
sublime.set_timeout(lambda:sublime.status_message('Finished opening %s' % path),0)
elif command == 'open':
sublime.set_timeout(lambda:sublime.status_message('Downloading %s' % path),0)
self.download(path)
sublime.set_timeout(lambda:sublime.status_message('Finished downloading %s' % path),0)
elif command == 'save':
sublime.set_timeout(lambda:sublime.status_message('Uploading %s' % path),0)
self.upload(path)
sublime.set_timeout(lambda:sublime.status_message('Finished uploading %s' % path),0)
elif command == 'cd':
self.cd(path, show_panel)


def cd(self, path, show_panel):
if not self.is_os_mode('posix'):
self.sftp.send('cd "%s"' % (path) )
self.add_command('ls','', show_panel)
else:
print "changing dir: " + path
print self.sftp.getcwd()
try:
self.sftp.chdir(path)
self.search_path = self.sftp.getcwd()
print self.sftp.getcwd()
self.add_command('ls',path, show_panel)
except Exception as e:
sublime.set_timeout(lambda:sublime.status_message('Generic Error processing %s' % path),10)


def run(self):
sublime.set_timeout(lambda:sublime.status_message('Connecting to %s' % self.server),0)
self.connect()
while True:



self.results_lock.acquire()
if len(self.command_deque) == 0:
self.results_lock.wait()
Expand All @@ -197,59 +295,74 @@ def run(self):

print command, path, show_panel

if command == 'ls':
if show_panel == True:
sublime.set_timeout(lambda:sublime.status_message('Opening %s' % path),0)
self.ls(path)
if show_panel == True:
self.showfilepanel()
sublime.set_timeout(lambda:sublime.status_message('Finished opening %s' % path),0)
elif command == 'open':
sublime.set_timeout(lambda:sublime.status_message('Downloading %s' % path),0)
self.download(path)
sublime.set_timeout(lambda:sublime.status_message('Finished downloading %s' % path),0)
elif command == 'save':
sublime.set_timeout(lambda:sublime.status_message('Uploading %s' % path),0)
self.upload(path)
sublime.set_timeout(lambda:sublime.status_message('Finished uploading %s' % path),0)
elif command == 'cd':
self.sftp.send('cd "%s"' % (path) )
self.add_command('ls','', show_panel)
elif command == 'exit':
self.send_cmd(command, path, show_panel)

if command == 'exit':
break
else:
pass


sublime.set_timeout(lambda:sublime.status_message('Disconnectin from %s' % self.server),0)
sublime.set_timeout(lambda:sublime.status_message('Disconnecting from %s' % self.server),0)
try:
self.sftp.send('exit')
if not self.is_os_mode('posix'):
self.sftp.send('exit')
else:
self.sftp.close()
print self.transport.is_active()
self.transport.close()
print self.transport.is_active()
print self.transport.stop_thread()
self.sftp = None
self._Thread__stop()
print threading.enumerate()
#if os.path.exists(os.path.join(sublime.packages_path(),'Mote','temp',self.server)):
#print os.path.join(sublime.packages_path(),'Mote','temp',self.server)
#self.rm_rf(str(os.path.join(sublime.packages_path(),'Mote','temp',self.server)))

except StopIteration:
pass
self.sftp = None

threading.Thread.__init__(self)

def ls(self, search_path = ''):
fullpath = cleanpath(self.search_path,search_path)

results = self.cleanls(fullpath, self.sftp.send('ls "%s"' % fullpath))
if not self.is_os_mode('posix'):
results = self.sftp.send('ls "%s"' % fullpath)
results = self.cleanls(fullpath, results)
self.results.update(results)
else:
file_list = {}
try:
file_list = dict(zip(self.sftp.listdir(self.sftp.getcwd()), self.sftp.listdir_attr(self.sftp.getcwd())))
results = self.cleanlsposix(fullpath, file_list)
self.results = results
except IOError as io:
sublime.set_timeout(lambda:sublime.status_message('IO Error %s when listing -> %s' % (io,fullpath)),10)
except Exception as e:
sublime.set_timeout(lambda:sublime.status_message('Generic Error processing %s' % fullpath),10)

if self.idle_recursive:
subfolders = dict((k,v) for k,v in results.items() if v['type'] == 'folder')
for recur_folder in subfolders:
self.add_command('ls',results[recur_folder]['path'])

#print results
self.results.update(results)

def download(self, path):
localpath = os.path.normpath(os.path.join(sublime.packages_path(),'Mote','temp',self.server,path))
if not self.is_os_mode('posix'):
localpath = os.path.normpath(os.path.join(sublime.packages_path(),'Mote','temp',self.server,path))
else:
localpath = os.path.normpath(os.path.join(sublime.packages_path(),'Mote','temp',self.server,path[1:]))

if not os.path.exists(os.path.dirname(localpath)):
os.makedirs(os.path.dirname(localpath))

self.sftp.send('get "%s" "%s"' % (path,localpath) )
if not self.is_os_mode('posix'):
self.sftp.send('get "%s" "%s"' % (path,localpath) )
else:
try:
self.sftp.get(path, localpath)
except Exception as e:
sublime.set_timeout(lambda:sublime.status_message('Generic Error processing %s' % path),10)

sublime.set_timeout(lambda:self.window.open_file(localpath), 0)

Expand All @@ -258,14 +371,55 @@ def download(self, path):

def upload(self, path):
localpath = os.path.normpath(os.path.join(sublime.packages_path(),'Mote','temp',self.server,path))
self.sftp.send('put "%s" "%s"' % (localpath,path) )
if not self.is_os_mode('posix'):
self.sftp.send('put "%s" "%s"' % (localpath,path) )
else:
try:
self.sftp.put(localpath, '/'+path)
except Exception as e:
sublime.set_timeout(lambda:sublime.status_message('Generic Error processing %s' % path),10)

def showfilepanel(self):
self.keys = sorted(self.results.keys())
def show_quick_panel():
self.window.show_quick_panel(self.keys, self.on_select)
sublime.set_timeout(show_quick_panel, 10)

def cleanlsposix(self, fullpath, file_list):
paths = {}
paths['..'] = {}
tpath = '/'.join(self.sftp.getcwd().split('/')[0:-1])
if tpath == "":
tpath = "/"
paths['..']['path'] = tpath
paths['..']['type'] = 'folder'
for path, attr in file_list.items():
dflag = oct(attr.st_mode)
named_path = cleanpath(fullpath, path)
if str(dflag[0:2]) == '04':
path_key = named_path + '/..'
elif str(dflag[0:3]) == '012':
path_key = named_path + "->" + self.sftp.readlink(path)
else:
path_key = named_path + '-'

paths[path_key] = {}
paths[path_key]['path'] = named_path
if str(dflag[0:2]) == '04':
paths[path_key]['type'] = 'folder'
elif str(dflag[0:3]) == '012':
realpath = self.sftp.readlink(path)
substat = self.sftp.lstat(realpath)
subdflag = oct(substat.st_mode)
paths[path_key]['path'] = realpath
if str(subdflag[0:2]) == '04':
paths[path_key]['type'] = 'folder'
else:
paths[path_key]['type'] = 'file'
else:
paths[path_key]['type'] = 'file'
return paths

def cleanls(self,fullpath, out):
paths = {}
for path in out.split('\n')[2:-1]:
Expand All @@ -275,6 +429,7 @@ def cleanls(self,fullpath, out):

named_path = cleanpath(fullpath,raw_path)
path_key = named_path + ('' if path[0] == '-' else '/..')
print named_path+" " +path_key + " "+path[0]

#print named_path
paths[path_key] = {}
Expand All @@ -292,10 +447,21 @@ def on_select(self, picked):
key = self.keys[picked]

if self.results[key]['type'] == 'folder':
self.add_command('ls',self.results[key]['path'], True)
if not self.is_os_mode('posix'):
self.add_command('ls',self.results[key]['path'], True)
else:
self.add_command('cd',self.results[key]['path'], True)
elif self.results[key]['type'] == 'file':
self.add_command('open',self.results[key]['path'])

def rm_rf(dir):
for path in (os.path.join(d,f) for f in os.listdir(d)):
if os.path.isdir(path):
rm_rf(path)
else:
os.unlink(path)
os.rmdir(d)


def cleanpath(*args):
return posixpath.normpath(posixpath.join(*args))
Expand All @@ -316,7 +482,6 @@ def psftp(connection_string):
untilprompt(p,'exit')
return


def untilprompt(proc, strinput = None):
if strinput:
proc.stdin.write(strinput+'\n')
Expand All @@ -331,4 +496,4 @@ def untilprompt(proc, strinput = None):
break
return buff

MOTES = main()
MOTES = main()
Loading