From 7b10a86267dfa6e2c0fa0bebe4d4229f5e1dfd38 Mon Sep 17 00:00:00 2001 From: David Hart Date: Fri, 5 Jan 2018 21:20:03 +0000 Subject: [PATCH] Add rule for ADB unknown commands (#765) --- README.md | 1 + tests/rules/test_adb_unknown_command.py | 41 +++++++++++++++++++ thefuck/rules/adb_unknown_command.py | 54 +++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/rules/test_adb_unknown_command.py create mode 100644 thefuck/rules/adb_unknown_command.py diff --git a/README.md b/README.md index c07f40f4..184e20a3 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ pip3 install thefuck --upgrade The Fuck tries to match a rule for the previous command, creates a new command using the matched rule and runs it. Rules enabled by default are as follows: +* `adb_unknown_command` – fixes misspelled commands like `adb logcta`; * `ag_literal` – adds `-Q` to `ag` when suggested; * `aws_cli` – fixes misspelled commands like `aws dynamdb scan`; * `cargo` – runs `cargo build` instead of `cargo`; diff --git a/tests/rules/test_adb_unknown_command.py b/tests/rules/test_adb_unknown_command.py new file mode 100644 index 00000000..f2c32562 --- /dev/null +++ b/tests/rules/test_adb_unknown_command.py @@ -0,0 +1,41 @@ +import pytest +from thefuck.rules.adb_unknown_command import match, get_new_command +from thefuck.types import Command + + +@pytest.fixture +def output(): + return '''Android Debug Bridge version 1.0.31 + + -d - directs command to the only connected USB device + returns an error if more than one USB device is present. + -e - directs command to the only running emulator. + returns an error if more than one emulator is running. + -s - directs command to the device or emulator with the given + serial number or qualifier. Overrides ANDROID_SERIAL + environment variable. +''' + + +@pytest.mark.parametrize('script', [ + ('adb lgcat'), + ('adb puhs')]) +def test_match(output, script): + assert match(Command(script, output)) + + +@pytest.mark.parametrize('script', [ + 'git branch foo', + 'abd push']) +def test_not_match(script): + assert not match(Command(script, '')) + + +@pytest.mark.parametrize('script, new_command', [ + ('adb puhs test.bin /sdcard/test.bin', 'adb push test.bin /sdcard/test.bin'), + ('adb -s 1111 logcta', 'adb -s 1111 logcat'), + ('adb -P 666 pulll /sdcard/test.bin', 'adb -P 666 pull /sdcard/test.bin'), + ('adb -d logcatt', 'adb -d logcat'), + ('adb -e reboott', 'adb -e reboot')]) +def test_get_new_command(script, output, new_command): + assert get_new_command(Command(script, output)) == new_command diff --git a/thefuck/rules/adb_unknown_command.py b/thefuck/rules/adb_unknown_command.py new file mode 100644 index 00000000..bd33ca17 --- /dev/null +++ b/thefuck/rules/adb_unknown_command.py @@ -0,0 +1,54 @@ +from thefuck.utils import is_app, get_closest, replace_argument + + +_ADB_COMMANDS = ( + 'backup', + 'bugreport', + 'connect', + 'devices', + 'disable-verity', + 'disconnect', + 'enable-verity', + 'emu', + 'forward', + 'get-devpath', + 'get-serialno', + 'get-state', + 'install', + 'install-multiple', + 'jdwp', + 'keygen', + 'kill-server', + 'logcat', + 'pull', + 'push', + 'reboot', + 'reconnect', + 'restore', + 'reverse', + 'root', + 'run-as', + 'shell', + 'sideload', + 'start-server', + 'sync', + 'tcpip', + 'uninstall', + 'unroot', + 'usb', + 'wait-for', +) + + +def match(command): + return (is_app(command, 'adb') + and command.output.startswith('Android Debug Bridge version')) + + +def get_new_command(command): + for idx, arg in enumerate(command.script_parts[1:]): + # allowed params to ADB are a/d/e/s/H/P/L where s, H, P and L take additional args + # for example 'adb -s 111 logcat' or 'adb -e logcat' + if not arg[0] == '-' and not command.script_parts[idx] in ('-s', '-H', '-P', '-L'): + adb_cmd = get_closest(arg, _ADB_COMMANDS) + return replace_argument(command.script, arg, adb_cmd)