diff --git a/README.md b/README.md index 1b2814cb..d05ce4ca 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `cd_correction` – spellchecks and correct failed cd commands; * `cd_mkdir` – creates directories before cd'ing into them; * `cd_parent` – changes `cd..` to `cd ..`; +* `chmod_x` – add execution bit; * `composer_not_command` – fixes composer command name; * `cp_omitting_directory` – adds `-a` when you `cp` directory; * `cpp11` – adds missing `-std=c++11` to `g++` or `clang++`; diff --git a/tests/rules/test_chmod_x.py b/tests/rules/test_chmod_x.py new file mode 100644 index 00000000..bc6d411b --- /dev/null +++ b/tests/rules/test_chmod_x.py @@ -0,0 +1,39 @@ +import pytest +from tests.utils import Command +from thefuck.rules.chmod_x import match, get_new_command + + +@pytest.fixture +def file_exists(mocker): + return mocker.patch('os.path.exists', return_value=True) + + +@pytest.fixture +def file_access(mocker): + return mocker.patch('os.access', return_value=False) + + +@pytest.mark.usefixtures('file_exists', 'file_access') +@pytest.mark.parametrize('script, stderr', [ + ('./gradlew build', 'gradlew: Permission denied'), + ('./install.sh --help', 'install.sh: permission denied')]) +def test_match(script, stderr): + assert match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, stderr, exists, callable', [ + ('./gradlew build', 'gradlew: Permission denied', True, True), + ('./gradlew build', 'gradlew: Permission denied', False, False), + ('./gradlew build', 'gradlew: error', True, False), + ('gradlew build', 'gradlew: Permission denied', True, False)]) +def test_not_match(file_exists, file_access, script, stderr, exists, callable): + file_exists.return_value = exists + file_access.return_value = callable + assert not match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, result', [ + ('./gradlew build', 'chmod +x gradlew && ./gradlew build'), + ('./install.sh --help', 'chmod +x install.sh && ./install.sh --help')]) +def test_get_new_command(script, result): + assert get_new_command(Command(script)) == result diff --git a/thefuck/rules/chmod_x.py b/thefuck/rules/chmod_x.py new file mode 100644 index 00000000..d6b4e80f --- /dev/null +++ b/thefuck/rules/chmod_x.py @@ -0,0 +1,15 @@ +import os +from thefuck.shells import shell + + +def match(command): + return (command.script.startswith('./') + and 'permission denied' in command.stderr.lower() + and os.path.exists(command.script_parts[0]) + and not os.access(command.script_parts[0], os.X_OK)) + + +def get_new_command(command): + return shell.and_( + 'chmod +x {}'.format(command.script_parts[0][2:]), + command.script)