mirror of
https://github.com/nvbn/thefuck.git
synced 2025-01-31 02:01:13 +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
|
||||
|
||||
|
||||
_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
|
||||
def docker_help(mocker):
|
||||
help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
|
||||
@ -104,6 +144,94 @@ Run 'docker COMMAND --help' for more information on a command.
|
||||
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):
|
||||
return "docker: '{}' is not a docker command.\n" \
|
||||
"See 'docker --help'.".format(cmd)
|
||||
@ -113,6 +241,24 @@ def test_match():
|
||||
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', [
|
||||
('docker ps', ''),
|
||||
('cat pes', output('pes'))])
|
||||
@ -120,10 +266,28 @@ def test_not_match(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', [
|
||||
('pes', ['ps', 'push', 'pause']),
|
||||
('tags', ['tag', 'stats', 'images'])])
|
||||
def test_get_new_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', [
|
||||
('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
|
||||
@for_app('docker')
|
||||
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():
|
||||
proc = subprocess.Popen('docker', stdout=subprocess.PIPE)
|
||||
lines = [line.decode('utf-8') for line in proc.stdout.readlines()]
|
||||
lines = dropwhile(lambda line: not line.startswith('Commands:'), lines)
|
||||
lines = islice(lines, 1, None)
|
||||
lines = list(takewhile(lambda line: line != '\n', lines))
|
||||
return [line.strip().split(' ')[0] for line in lines]
|
||||
proc = subprocess.Popen('docker', stdout=subprocess.PIPE, 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'):
|
||||
@ -26,6 +40,10 @@ if which('docker'):
|
||||
|
||||
@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())
|
||||
|
Loading…
x
Reference in New Issue
Block a user