From f773b57bea3582b9fd2a8f9815857538d72126ba Mon Sep 17 00:00:00 2001 From: nvbn Date: Tue, 28 Jun 2016 03:00:00 +0300 Subject: [PATCH] #511: Add `ln_s_order` rule --- README.md | 1 + tests/rules/test_ln_no_hard_link.py | 2 +- tests/rules/test_ln_s_order.py | 41 +++++++++++++++++++++++++++++ thefuck/rules/ln_no_hard_link.py | 2 +- thefuck/rules/ln_s_order.py | 26 ++++++++++++++++++ 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/rules/test_ln_s_order.py create mode 100644 thefuck/rules/ln_s_order.py diff --git a/README.md b/README.md index 55828052..395253f4 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `javac` – appends missing `.java` when compiling Java files; * `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`; * `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link; +* `ln_s_order` – fixes `ln -s` arguments order; * `ls_lah` – adds `-lah` to `ls`; * `man` – changes manual section; * `man_no_space` – fixes man commands without spaces, for example `mandiff`; diff --git a/tests/rules/test_ln_no_hard_link.py b/tests/rules/test_ln_no_hard_link.py index 9ada4d51..7d3d2743 100644 --- a/tests/rules/test_ln_no_hard_link.py +++ b/tests/rules/test_ln_no_hard_link.py @@ -20,7 +20,7 @@ def test_match(script, stderr): ("ln a b", "... hard link"), ("sudo ln a b", "... hard link"), ("a b", error)]) -def test_assert_not_match(script, stderr): +def test_not_match(script, stderr): command = Command(script, stderr=stderr) assert not match(command) diff --git a/tests/rules/test_ln_s_order.py b/tests/rules/test_ln_s_order.py new file mode 100644 index 00000000..d4119f40 --- /dev/null +++ b/tests/rules/test_ln_s_order.py @@ -0,0 +1,41 @@ +import pytest +from thefuck.rules.ln_s_order import match, get_new_command +from tests.utils import Command + + +@pytest.fixture +def file_exists(mocker): + return mocker.patch('os.path.exists', return_value=True) + + +get_stderr = "ln: failed to create symbolic link '{}': File exists".format + + +@pytest.mark.usefixtures('file_exists') +@pytest.mark.parametrize('script', [ + 'ln -s dest source', + 'ln dest -s source', + 'ln dest source -s']) +def test_match(script): + stderr = get_stderr('source') + assert match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, stderr, exists', [ + ('ln dest source', get_stderr('source'), True), + ('ls -s dest source', get_stderr('source'), True), + ('ln -s dest source', '', True), + ('ln -s dest source', get_stderr('source'), False)]) +def test_not_match(file_exists, script, stderr, exists): + file_exists.return_value = exists + assert not match(Command(script, stderr=stderr)) + + +@pytest.mark.usefixtures('file_exists') +@pytest.mark.parametrize('script, result', [ + ('ln -s dest source', 'ln -s source dest'), + ('ln dest -s source', 'ln -s source dest'), + ('ln dest source -s', 'ln source -s dest')]) +def test_match(script, result): + stderr = get_stderr('source') + assert get_new_command(Command(script, stderr=stderr)) == result diff --git a/thefuck/rules/ln_no_hard_link.py b/thefuck/rules/ln_no_hard_link.py index 3aca042b..4ee1d615 100644 --- a/thefuck/rules/ln_no_hard_link.py +++ b/thefuck/rules/ln_no_hard_link.py @@ -15,7 +15,7 @@ from thefuck.specific.sudo import sudo_support @sudo_support def match(command): return (command.stderr.endswith("hard link not allowed for directory") and - command.script.startswith("ln ")) + command.script_parts[0] == 'ln') @sudo_support diff --git a/thefuck/rules/ln_s_order.py b/thefuck/rules/ln_s_order.py new file mode 100644 index 00000000..1c07e36a --- /dev/null +++ b/thefuck/rules/ln_s_order.py @@ -0,0 +1,26 @@ +import os +from thefuck.specific.sudo import sudo_support + + +def _get_destination(script_parts): + """When arguments order is wrong first argument will be destination.""" + for part in script_parts: + if part not in {'ln', '-s', '--symbolic'} and os.path.exists(part): + return part + + +@sudo_support +def match(command): + return (command.script_parts[0] == 'ln' + and {'-s', '--symbolic'}.intersection(command.script_parts) + and 'File exists' in command.stderr + and _get_destination(command.script_parts)) + + +@sudo_support +def get_new_command(command): + destination = _get_destination(command.script_parts) + parts = command.script_parts[:] + parts.remove(destination) + parts.append(destination) + return ' '.join(parts)