import re from subprocess import Popen, PIPE from thefrick.utils import memoize, which from thefrick.shells import shell enabled_by_default = bool(which('lsof')) patterns = [ r"bind on address \('.*', (?P<port>\d+)\)", r'Unable to bind [^ ]*:(?P<port>\d+)', r"can't listen on port (?P<port>\d+)", r'listen EADDRINUSE [^ ]*:(?P<port>\d+)' ] @memoize def _get_pid_by_port(port): proc = Popen(['lsof', '-i', ':{}'.format(port)], stdout=PIPE) lines = proc.stdout.read().decode().split('\n') if len(lines) > 1: return lines[1].split()[1] else: return None @memoize def _get_used_port(command): for pattern in patterns: matched = re.search(pattern, command.output) if matched: return matched.group('port')
stderr=subprocess.PIPE) # Old version docker returns its output to stdout, while newer version returns to stderr. lines = proc.stdout.readlines() or proc.stderr.readlines() lines = [line.decode('utf-8') for line in lines] # Only newer versions of docker have management commands in the help text. if 'Management Commands:\n' in lines: management_commands = _parse_commands(lines, 'Management Commands:') else: management_commands = [] regular_commands = _parse_commands(lines, 'Commands:') return management_commands + regular_commands if which('docker'): get_docker_commands = cache(which('docker'))(get_docker_commands) @sudo_support def get_new_command(command): if 'Usage:' in command.output and len(command.script_parts) > 1: management_subcommands = _parse_commands(command.output.split('\n'), 'Commands:') return replace_command(command, command.script_parts[2], management_subcommands) wrong_command = re.findall(r"docker: '(\w+)' is not a docker command.", command.output)[0] return replace_command(command, wrong_command, get_docker_commands())
def match(command): return (not which(command.script_parts[0]) and ('not found' in command.output or 'is not recognized as' in command.output) and bool( get_close_matches(command.script_parts[0], get_all_executables())))
def match(command): if 'command not found' in command.output: command_name = _get_command_name(command) return which(command_name)
COMMON_TYPOS = { 'list': ['versions', 'install --list'], 'remove': ['uninstall'], } @for_app('pyenv') def match(command): return 'pyenv: no such command' in command.output def get_pyenv_commands(): proc = Popen(['pyenv', 'commands'], stdout=PIPE) return [line.decode('utf-8').strip() for line in proc.stdout.readlines()] if which('pyenv'): get_pyenv_commands = cache(which('pyenv'))(get_pyenv_commands) @for_app('pyenv') def get_new_command(command): broken = re.findall(r"pyenv: no such command `([^']*)'", command.output)[0] matched = [ replace_argument(command.script, broken, common_typo) for common_typo in COMMON_TYPOS.get(broken, []) ] matched.extend(replace_command(command, broken, get_pyenv_commands())) return matched
from thefrick.utils import which yum_available = bool(which('yum'))
def match(command): if 'not found' in command.output or 'not installed' in command.output: executable = _get_executable(command) return not which(executable) and get_package(executable) else: return False
from thefrick.utils import which nix_available = bool(which('nix'))
npm_commands = {'require': 'add'} @eager def _get_all_tasks(): proc = Popen(['yarn', '--help'], stdout=PIPE) should_yield = False for line in proc.stdout.readlines(): line = line.decode().strip() if 'Commands:' in line: should_yield = True continue if should_yield and '- ' in line: yield line.split(' ')[-1] if which('yarn'): _get_all_tasks = cache(which('yarn'))(_get_all_tasks) def get_new_command(command): misspelled_task = regex.findall(command.output)[0] if misspelled_task in npm_commands: yarn_command = npm_commands[misspelled_task] return replace_argument(command.script, misspelled_task, yarn_command) else: tasks = _get_all_tasks() return replace_command(command, misspelled_task, tasks)
from thefrick.utils import for_app, which @for_app("choco", "cinst") def match(command): return ((command.script.startswith('choco install') or 'cinst' in command.script_parts) and 'Installing the following packages' in command.output) def get_new_command(command): # Find the argument that is the package name for script_part in command.script_parts: if (script_part not in ["choco", "cinst", "install"] # Need exact match (bc chocolatey is a package) and not script_part.startswith('-') # Leading hyphens are parameters; some packages contain them though and '=' not in script_part and '/' not in script_part # These are certainly parameters ): return command.script.replace(script_part, script_part + ".install") return [] enabled_by_default = bool(which("choco")) or bool(which("cinst"))
def match(command): return (not which(command.script_parts[0]) and 'not found' in command.output and os.path.isfile('gradlew'))
@for_app('gem') def match(command): return ('ERROR: While executing gem ... (Gem::CommandLineError)' in command.output and 'Unknown command' in command.output) def _get_unknown_command(command): return re.findall(r'Unknown command (.*)$', command.output)[0] @eager def _get_all_commands(): proc = subprocess.Popen(['gem', 'help', 'commands'], stdout=subprocess.PIPE) for line in proc.stdout.readlines(): line = line.decode() if line.startswith(' '): yield line.strip().split(' ')[0] if which('gem'): _get_all_commands = cache(which('gem'))(_get_all_commands) def get_new_command(command): unknown_command = _get_unknown_command(command) all_commands = _get_all_commands() return replace_command(command, unknown_command, all_commands)
@sudo_support @for_app('yum') def match(command): return 'No such command: ' in command.output def _get_operations(): proc = subprocess.Popen('yum', stdout=subprocess.PIPE) lines = proc.stdout.readlines() lines = [line.decode('utf-8') for line in lines] lines = dropwhile(lambda line: not line.startswith("List of Commands:"), lines) lines = islice(lines, 2, None) lines = list(takewhile(lambda line: line.strip(), lines)) return [line.strip().split(' ')[0] for line in lines] if which('yum'): _get_operations = cache(which('yum'))(_get_operations) @sudo_support def get_new_command(command): invalid_operation = command.script_parts[1] if invalid_operation == 'uninstall': return [command.script.replace('uninstall', 'remove')] return replace_command(command, invalid_operation, _get_operations())
import re from subprocess import Popen, PIPE from thefrick.utils import memoize, eager, which npm_available = bool(which('npm')) @memoize @eager def get_scripts(): """Get custom npm scripts.""" proc = Popen(['npm', 'run-script'], stdout=PIPE) should_yeild = False for line in proc.stdout.readlines(): line = line.decode() if 'available via `npm run-script`:' in line: should_yeild = True continue if should_yeild and re.match(r'^ [^ ]+', line): yield line.strip().split(' ')[0]
from itertools import dropwhile, islice, takewhile import subprocess from thefrick.utils import get_closest, replace_argument, for_app, which, cache def get_golang_commands(): proc = subprocess.Popen('go', stderr=subprocess.PIPE) lines = [line.decode('utf-8').strip() for line in proc.stderr.readlines()] lines = dropwhile(lambda line: line != 'The commands are:', lines) lines = islice(lines, 2, None) lines = takewhile(lambda line: line, lines) return [line.split(' ')[0] for line in lines] if which('go'): get_docker_commands = cache(which('go'))(get_golang_commands) @for_app('go') def match(command): return 'unknown command' in command.output def get_new_command(command): closest_subcommand = get_closest(command.script_parts[1], get_golang_commands()) return replace_argument(command.script, command.script_parts[1], closest_subcommand)
from thefrick.utils import which dnf_available = bool(which('dnf'))