diff --git a/sshpyk/__init__.py b/sshpyk/__init__.py index 565e3ae..f218d6a 100644 --- a/sshpyk/__init__.py +++ b/sshpyk/__init__.py @@ -2,7 +2,7 @@ from subprocess import run, PIPE from getpass import getuser from shutil import which -from os.path import join +from os.path import join, exists from json import dump import tempfile import json @@ -10,6 +10,8 @@ import re import os +from .kernel.utils import kinfo_exe, rexists + try: from .__version__ import __version__ _VERSION = __version__ @@ -100,7 +102,7 @@ def simplify(name): return kernel_name -def get_kernel_desc( all=False ): +def get_kernel_desc( all=False, valid_only=True ): def _json( kernel_path ): with open( join( kernel_path, 'kernel.json' ) ) as f: return json.load(f) @@ -109,4 +111,11 @@ def _json( kernel_path ): km = ks.KernelSpecManager( ) kdirs = km.find_kernel_specs( ) keys = sorted( kdirs.keys( ) if all else filter( lambda k: k.startswith('ssh_'), kdirs.keys( ) ) ) - return { k: { 'ssh': k.startswith("ssh_"), 'path': kdirs[k], 'spec': _json(kdirs[k]) } for k in keys } + result = { k: { 'ssh': k.startswith("ssh_"), 'path': kdirs[k], 'spec': _json(kdirs[k]) } for k in keys } + if valid_only == False: + return result + else: + def is_valid(kinfo): + ex = kinfo_exe(kinfo[1]) + return exists(ex[0]) and (ex[1] is None or rexists(ex[2],ex[1])) + return dict( filter( is_valid, result.items( ) ) ) diff --git a/sshpyk/kernel/ls.py b/sshpyk/kernel/ls.py index 387b6aa..aef2f35 100644 --- a/sshpyk/kernel/ls.py +++ b/sshpyk/kernel/ls.py @@ -1,50 +1,12 @@ from argparse import ArgumentParser, SUPPRESS -from os.path import join, exists, basename -from subprocess import run, PIPE -from shutil import which +from os.path import exists + +from .utils import kinfo_exe as _exe +from .utils import rexists def _red( s ): return f'''\033[31m{s}\033[0m''' -def _remote_exe( argv ): - result = [None,None] - for p in zip(argv[1:][::2],argv[2:][::2]): - if p[0] == '--python' or p[0] == "-p": - result[0] = f'''{p[1]}/bin/python''' if len(p[1]) > 0 else None - if p[0] == '--host' or p[0] == "-H": - result[1] = p[1] - return result - -def _exe( desc ): - if desc['ssh']: - return ( desc['spec']['argv'][0], *_remote_exe(desc['spec']['argv']) ) if desc['spec'] else ( None, None, None ) - else: - return ( desc['spec']['argv'][0], None, None ) - -_rexists_checked_ = { } -def rexists( host, path ): - if f'''{host}:{path}''' in _rexists_checked_: - return _rexists_checked_[f'''{host}:{path}'''] - - if host is not None and path is not None: - ssh = which('ssh') - rproc = run( [ ssh, host, f'''file {path}/bin/python''' ], stdout=PIPE, stderr=PIPE ) - - output = rproc.stdout.decode('ASCII') - - if len(output) == 0: - _rexists_checked_[f'''{host}:{path}'''] = False - return False - - if '(No such file or directory)' in output: - _rexists_checked_[f'''{host}:{path}'''] = False - return False - - _rexists_checked_[f'''{host}:{path}'''] = True - return True - - return False - def _kernel_paths( kinfo ): colsize = 0 for k in kinfo.keys( ): @@ -103,7 +65,7 @@ def _remote_paths( kinfo ): args = parse.parse_args( ) - kinfo = get_kernel_desc( args.all ) + kinfo = get_kernel_desc( all=args.all, valid_only=False ) if args.local: _local_paths( kinfo ) elif args.remote: diff --git a/sshpyk/kernel/utils.py b/sshpyk/kernel/utils.py new file mode 100644 index 0000000..9903f8c --- /dev/null +++ b/sshpyk/kernel/utils.py @@ -0,0 +1,70 @@ +from subprocess import run, PIPE +from shutil import which + + +def _remote_exe( argv ): + result = [None,None] + for p in zip(argv[1:][::2],argv[2:][::2]): + if p[0] == '--python' or p[0] == "-p": + result[0] = f'''{p[1]}/bin/python''' if len(p[1]) > 0 else None + if p[0] == '--host' or p[0] == "-H": + result[1] = p[1] + return result + +def kinfo_exe( kinfo ): + '''Retrieve the python executables from a kernel info dictionary: + + Parameters + ---------- + kinfo: dict + Kernel info for one kernel specification + + Returns + ------- + tuple: ( str, str, str ) + Returns a tuple containing (1) local Python path, (2) remote Python path, (3) remote + host. If the spec is for a regular kernel, the last two elements will be None + ''' + if kinfo['ssh']: + return ( kinfo['spec']['argv'][0], *_remote_exe(kinfo['spec']['argv']) ) if kinfo['spec'] else ( None, None, None ) + else: + return ( kinfo['spec']['argv'][0], None, None ) + + +__rexists_checked = { } +def rexists( host, path ): + '''Check to see if exists on : + + Parameters + ---------- + host: str + Hostname which accessible with SSH + path: str + The path to check for existence on on + + Returns + ------- + bool + True if exists on otherwise False + ''' + if f'''{host}:{path}''' in __rexists_checked: + return __rexists_checked[f'''{host}:{path}'''] + + if host is not None and path is not None: + ssh = which('ssh') + rproc = run( [ ssh, host, f'''file {path}/bin/python''' ], stdout=PIPE, stderr=PIPE ) + + output = rproc.stdout.decode('ASCII') + + if len(output) == 0: + __rexists_checked[f'''{host}:{path}'''] = False + return False + + if '(No such file or directory)' in output: + __rexists_checked[f'''{host}:{path}'''] = False + return False + + __rexists_checked[f'''{host}:{path}'''] = True + return True + + return False