mirror of
https://github.com/nvbn/thefuck.git
synced 2025-02-07 13:41:21 +00:00
Update docker commands. (#940)
* Add: Tests for newer version docker support. * Add: Support for newer versions of docker (Modified rules.docker_not_command). * Fix: Updated disabling memoize. * Change: removed empty list check. * Fix: _parse_commands now uses line.strip() internally and ends_with arg now doesn't end with newline. * Change: Replaced disable_memoize in favor of no_memoize fixture. * Fix: removed unused import.
This commit is contained in:
parent
d88454a638
commit
1683f45e94
@ -4,6 +4,46 @@ from thefuck.types import Command
|
|||||||
from thefuck.rules.docker_not_command import get_new_command, match
|
from thefuck.rules.docker_not_command import get_new_command, match
|
||||||
|
|
||||||
|
|
||||||
|
_DOCKER_SWARM_OUTPUT = '''
|
||||||
|
Usage: docker swarm COMMAND
|
||||||
|
|
||||||
|
Manage Swarm
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
ca Display and rotate the root CA
|
||||||
|
init Initialize a swarm
|
||||||
|
join Join a swarm as a node and/or manager
|
||||||
|
join-token Manage join tokens
|
||||||
|
leave Leave the swarm
|
||||||
|
unlock Unlock swarm
|
||||||
|
unlock-key Manage the unlock key
|
||||||
|
update Update the swarm
|
||||||
|
|
||||||
|
Run 'docker swarm COMMAND --help' for more information on a command.
|
||||||
|
'''
|
||||||
|
_DOCKER_IMAGE_OUTPUT = '''
|
||||||
|
Usage: docker image COMMAND
|
||||||
|
|
||||||
|
Manage images
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
build Build an image from a Dockerfile
|
||||||
|
history Show the history of an image
|
||||||
|
import Import the contents from a tarball to create a filesystem image
|
||||||
|
inspect Display detailed information on one or more images
|
||||||
|
load Load an image from a tar archive or STDIN
|
||||||
|
ls List images
|
||||||
|
prune Remove unused images
|
||||||
|
pull Pull an image or a repository from a registry
|
||||||
|
push Push an image or a repository to a registry
|
||||||
|
rm Remove one or more images
|
||||||
|
save Save one or more images to a tar archive (streamed to STDOUT by default)
|
||||||
|
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
|
||||||
|
|
||||||
|
Run 'docker image COMMAND --help' for more information on a command.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def docker_help(mocker):
|
def docker_help(mocker):
|
||||||
help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
|
help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
|
||||||
@ -104,6 +144,94 @@ Run 'docker COMMAND --help' for more information on a command.
|
|||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def docker_help_new(mocker):
|
||||||
|
helptext_new = b'''
|
||||||
|
Usage: docker [OPTIONS] COMMAND
|
||||||
|
|
||||||
|
A self-sufficient runtime for containers
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--config string Location of client config files (default "/Users/ik1ne/.docker")
|
||||||
|
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var
|
||||||
|
and default context set with "docker context use")
|
||||||
|
-D, --debug Enable debug mode
|
||||||
|
-H, --host list Daemon socket(s) to connect to
|
||||||
|
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
|
||||||
|
--tls Use TLS; implied by --tlsverify
|
||||||
|
--tlscacert string Trust certs signed only by this CA (default "/Users/ik1ne/.docker/ca.pem")
|
||||||
|
--tlscert string Path to TLS certificate file (default "/Users/ik1ne/.docker/cert.pem")
|
||||||
|
--tlskey string Path to TLS key file (default "/Users/ik1ne/.docker/key.pem")
|
||||||
|
--tlsverify Use TLS and verify the remote
|
||||||
|
-v, --version Print version information and quit
|
||||||
|
|
||||||
|
Management Commands:
|
||||||
|
builder Manage builds
|
||||||
|
config Manage Docker configs
|
||||||
|
container Manage containers
|
||||||
|
context Manage contexts
|
||||||
|
image Manage images
|
||||||
|
network Manage networks
|
||||||
|
node Manage Swarm nodes
|
||||||
|
plugin Manage plugins
|
||||||
|
secret Manage Docker secrets
|
||||||
|
service Manage services
|
||||||
|
stack Manage Docker stacks
|
||||||
|
swarm Manage Swarm
|
||||||
|
system Manage Docker
|
||||||
|
trust Manage trust on Docker images
|
||||||
|
volume Manage volumes
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
attach Attach local standard input, output, and error streams to a running container
|
||||||
|
build Build an image from a Dockerfile
|
||||||
|
commit Create a new image from a container's changes
|
||||||
|
cp Copy files/folders between a container and the local filesystem
|
||||||
|
create Create a new container
|
||||||
|
diff Inspect changes to files or directories on a container's filesystem
|
||||||
|
events Get real time events from the server
|
||||||
|
exec Run a command in a running container
|
||||||
|
export Export a container's filesystem as a tar archive
|
||||||
|
history Show the history of an image
|
||||||
|
images List images
|
||||||
|
import Import the contents from a tarball to create a filesystem image
|
||||||
|
info Display system-wide information
|
||||||
|
inspect Return low-level information on Docker objects
|
||||||
|
kill Kill one or more running containers
|
||||||
|
load Load an image from a tar archive or STDIN
|
||||||
|
login Log in to a Docker registry
|
||||||
|
logout Log out from a Docker registry
|
||||||
|
logs Fetch the logs of a container
|
||||||
|
pause Pause all processes within one or more containers
|
||||||
|
port List port mappings or a specific mapping for the container
|
||||||
|
ps List containers
|
||||||
|
pull Pull an image or a repository from a registry
|
||||||
|
push Push an image or a repository to a registry
|
||||||
|
rename Rename a container
|
||||||
|
restart Restart one or more containers
|
||||||
|
rm Remove one or more containers
|
||||||
|
rmi Remove one or more images
|
||||||
|
run Run a command in a new container
|
||||||
|
save Save one or more images to a tar archive (streamed to STDOUT by default)
|
||||||
|
search Search the Docker Hub for images
|
||||||
|
start Start one or more stopped containers
|
||||||
|
stats Display a live stream of container(s) resource usage statistics
|
||||||
|
stop Stop one or more running containers
|
||||||
|
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
|
||||||
|
top Display the running processes of a container
|
||||||
|
unpause Unpause all processes within one or more containers
|
||||||
|
update Update configuration of one or more containers
|
||||||
|
version Show the Docker version information
|
||||||
|
wait Block until one or more containers stop, then print their exit codes
|
||||||
|
|
||||||
|
Run 'docker COMMAND --help' for more information on a command.
|
||||||
|
'''
|
||||||
|
mock = mocker.patch('subprocess.Popen')
|
||||||
|
mock.return_value.stdout = BytesIO(b'')
|
||||||
|
mock.return_value.stderr = BytesIO(helptext_new)
|
||||||
|
return mock
|
||||||
|
|
||||||
|
|
||||||
def output(cmd):
|
def output(cmd):
|
||||||
return "docker: '{}' is not a docker command.\n" \
|
return "docker: '{}' is not a docker command.\n" \
|
||||||
"See 'docker --help'.".format(cmd)
|
"See 'docker --help'.".format(cmd)
|
||||||
@ -113,6 +241,24 @@ def test_match():
|
|||||||
assert match(Command('docker pes', output('pes')))
|
assert match(Command('docker pes', output('pes')))
|
||||||
|
|
||||||
|
|
||||||
|
# tests docker (management command)
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('script, output', [
|
||||||
|
('docker swarn', output('swarn')),
|
||||||
|
('docker imge', output('imge'))])
|
||||||
|
def test_match_management_cmd(script, output):
|
||||||
|
assert match(Command(script, output))
|
||||||
|
|
||||||
|
|
||||||
|
# tests docker (management cmd) (management subcmd)
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
|
@pytest.mark.parametrize('script, output', [
|
||||||
|
('docker swarm int', _DOCKER_SWARM_OUTPUT),
|
||||||
|
('docker image la', _DOCKER_IMAGE_OUTPUT)])
|
||||||
|
def test_match_management_subcmd(script, output):
|
||||||
|
assert match(Command(script, output))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('script, output', [
|
@pytest.mark.parametrize('script, output', [
|
||||||
('docker ps', ''),
|
('docker ps', ''),
|
||||||
('cat pes', output('pes'))])
|
('cat pes', output('pes'))])
|
||||||
@ -120,10 +266,28 @@ def test_not_match(script, output):
|
|||||||
assert not match(Command(script, output))
|
assert not match(Command(script, output))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('docker_help')
|
@pytest.mark.usefixtures('no_memoize', 'docker_help')
|
||||||
@pytest.mark.parametrize('wrong, fixed', [
|
@pytest.mark.parametrize('wrong, fixed', [
|
||||||
('pes', ['ps', 'push', 'pause']),
|
('pes', ['ps', 'push', 'pause']),
|
||||||
('tags', ['tag', 'stats', 'images'])])
|
('tags', ['tag', 'stats', 'images'])])
|
||||||
def test_get_new_command(wrong, fixed):
|
def test_get_new_command(wrong, fixed):
|
||||||
command = Command('docker {}'.format(wrong), output(wrong))
|
command = Command('docker {}'.format(wrong), output(wrong))
|
||||||
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
|
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
|
||||||
|
@pytest.mark.parametrize('wrong, fixed', [
|
||||||
|
('swarn', ['swarm', 'start', 'search']),
|
||||||
|
('inage', ['image', 'images', 'rename'])])
|
||||||
|
def test_get_new_management_command(wrong, fixed):
|
||||||
|
command = Command('docker {}'.format(wrong), output(wrong))
|
||||||
|
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
|
||||||
|
@pytest.mark.parametrize('wrong, fixed, output', [
|
||||||
|
('swarm int', ['swarm init', 'swarm join', 'swarm join-token'], _DOCKER_SWARM_OUTPUT),
|
||||||
|
('image la', ['image load', 'image ls', 'image tag'], _DOCKER_IMAGE_OUTPUT)])
|
||||||
|
def test_get_new_management_command_subcommand(wrong, fixed, output):
|
||||||
|
command = Command('docker {}'.format(wrong), output)
|
||||||
|
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
|
||||||
|
@ -8,16 +8,30 @@ from thefuck.specific.sudo import sudo_support
|
|||||||
@sudo_support
|
@sudo_support
|
||||||
@for_app('docker')
|
@for_app('docker')
|
||||||
def match(command):
|
def match(command):
|
||||||
return 'is not a docker command' in command.output
|
return 'is not a docker command' in command.output or 'Usage: docker' in command.output
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_commands(lines, starts_with):
|
||||||
|
lines = dropwhile(lambda line: not line.startswith(starts_with), lines)
|
||||||
|
lines = islice(lines, 1, None)
|
||||||
|
lines = list(takewhile(lambda line: line.strip(), lines))
|
||||||
|
return [line.strip().split(' ')[0] for line in lines]
|
||||||
|
|
||||||
|
|
||||||
def get_docker_commands():
|
def get_docker_commands():
|
||||||
proc = subprocess.Popen('docker', stdout=subprocess.PIPE)
|
proc = subprocess.Popen('docker', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
lines = [line.decode('utf-8') for line in proc.stdout.readlines()]
|
|
||||||
lines = dropwhile(lambda line: not line.startswith('Commands:'), lines)
|
# Old version docker returns its output to stdout, while newer version returns to stderr.
|
||||||
lines = islice(lines, 1, None)
|
lines = proc.stdout.readlines() or proc.stderr.readlines()
|
||||||
lines = list(takewhile(lambda line: line != '\n', lines))
|
lines = [line.decode('utf-8') for line in lines]
|
||||||
return [line.strip().split(' ')[0] 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'):
|
if which('docker'):
|
||||||
@ -26,6 +40,10 @@ if which('docker'):
|
|||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
def get_new_command(command):
|
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(
|
wrong_command = re.findall(
|
||||||
r"docker: '(\w+)' is not a docker command.", command.output)[0]
|
r"docker: '(\w+)' is not a docker command.", command.output)[0]
|
||||||
return replace_command(command, wrong_command, get_docker_commands())
|
return replace_command(command, wrong_command, get_docker_commands())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user