Skip to content

Commit

Permalink
Complete refactoring for v1.0 and add a copy of the workflow itself t…
Browse files Browse the repository at this point in the history
…o the repository.

New feature: display the origin/source of suggested completions.
  • Loading branch information
isometry committed Mar 16, 2013
1 parent 1ead3d9 commit 89d0ca1
Showing 1 changed file with 46 additions and 27 deletions.
73 changes: 46 additions & 27 deletions alfredssh.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Open SSH.alfredworkflow, v0.10
# Open SSH.alfredworkflow, v1.0
# Robin Breathe, 2013

import alfred
Expand All @@ -7,19 +7,43 @@
import json
import re

class SSHItem(alfred.Item):
def __init__(self, user, host):
_arg = user and '@'.join([user,host]) or host
class Hosts(object):
def __init__(self, original, user=None):
self.original = original
self.hosts = {original: ['input']}
self.user = user

def add(self, host, source):
if host in self.hosts:
self.hosts[host].append(source)
else:
self.hosts[host] = [source]

def update(self, _list):
(hosts, source) = _list
for host in hosts:
self.add(host, source)

def item(self, host, source):
_arg = self.user and '@'.join([self.user,host]) or host
_uri = 'ssh://%s' % _arg
return super(SSHItem, self).__init__(attributes={'uid':_uri, 'arg':_arg},
title=_uri, subtitle='SSH to %s' % host, icon='icon.png')
_sub = 'Connect to %s (source: %s)' % (_uri, ', '.join(source))
return alfred.Item(attributes={'uid':_uri, 'arg':_arg, 'autocomplete':_arg},
title=_uri, subtitle=_sub, icon='icon.png')

def xml(self, _filter=(lambda x:True)):
items = [self.item(host=self.original, source=self.hosts[self.original])]
for (host, source) in ((x,y) for (x,y) in self.hosts.iteritems() if x<>self.original and _filter(x)):
items.append(self.item(host, source))
return alfred.xml(items)


def fetch_ssh_config(_path):
def fetch_ssh_config(_path, alias='~/.ssh/ssh_config'):
master = path.expanduser(_path)
if path.isfile(master):
cache = path.join(alfred.work(volatile=True), 'ssh_config.1.json')
if path.isfile(cache) and path.getmtime(cache) > path.getmtime(master):
return json.load(open(cache, 'r'))
return (json.load(open(cache, 'r')), alias)
else:
results = set([])
try:
Expand All @@ -29,14 +53,14 @@ def fetch_ssh_config(_path):
except IOError:
pass
json.dump(list(results), open(cache, 'w'))
return results
return (results, alias)

def fetch_known_hosts(_path):
def fetch_known_hosts(_path, alias='~/.ssh/known_hosts'):
master = path.expanduser(_path)
if path.isfile(master):
cache = path.join(alfred.work(volatile=True), 'known_hosts.1.json')
if path.isfile(cache) and path.getmtime(cache) > path.getmtime(master):
return json.load(open(cache, 'r'))
return (json.load(open(cache, 'r')), alias)
else:
results = set([])
try:
Expand All @@ -46,14 +70,14 @@ def fetch_known_hosts(_path):
except IOError:
pass
json.dump(list(results), open(cache, 'w'))
return results
return (results, alias)

def fetch_hosts(_path):
def fetch_hosts(_path, alias='/etc/hosts'):
master = path.expanduser(_path)
if path.isfile(master):
cache = path.join(alfred.work(volatile=True), 'hosts.1.json')
if path.isfile(cache) and path.getmtime(cache) > path.getmtime(master):
return json.load(open(cache, 'r'))
return (json.load(open(cache, 'r')), alias)
else:
results = set([])
try:
Expand All @@ -64,26 +88,26 @@ def fetch_hosts(_path):
except IOError:
pass
json.dump(list(results), open(cache, 'w'))
return results
return (results, alias)

def fetch_bonjour(_service):
def fetch_bonjour(_service, alias='Bonjour'):
cache = path.join(alfred.work(volatile=True), 'bonjour.1.json')
if path.isfile(cache) and (time() - path.getmtime(cache) < 10):
return json.load(open(cache, 'r'))
if path.isfile(cache) and (time() - path.getmtime(cache) < 60):
return (json.load(open(cache, 'r')), alias)
else:
results = set([])
try:
from pybonjour import DNSServiceBrowse, DNSServiceProcessResult
from select import select
bj_callback = lambda s, f, i, e, n, t, d: results.add('%s.%s' % (n, d))
bj_callback = lambda s, f, i, e, n, t, d: results.add('%s.%s' % (n.lower(), d[:-1]))
bj_browser = DNSServiceBrowse(regtype = _service, callBack = bj_callback)
select([bj_browser], [], [], 0.1)
DNSServiceProcessResult(bj_browser)
bj_browser.close()
except ImportError:
pass
json.dump(list(results), open(cache, 'w'))
return results
return (results, alias)

def complete(query):
if '@' in query:
Expand All @@ -94,15 +118,10 @@ def complete(query):
host_chars = map(lambda x: '\.' if x is '.' else x, list(host))
pattern = re.compile('.*?%s' % '.*?\b?'.join(host_chars), flags=re.IGNORECASE)

hosts = set([])
hosts = Hosts(original=host, user=user)
hosts.update(fetch_ssh_config('~/.ssh/config'))
hosts.update(fetch_known_hosts('~/.ssh/known_hosts'))
hosts.update(fetch_hosts('/etc/hosts'))
hosts.update(fetch_bonjour('_ssh._tcp'))
hosts.discard(host)

results = [SSHItem(user, host)]
for host in (x for x in hosts if pattern.match(x)):
results.append(SSHItem(user, host))

return alfred.xml(results)
return hosts.xml(pattern.match)

0 comments on commit 89d0ca1

Please sign in to comment.