mirror of
https://github.com/httpie/cli.git
synced 2024-11-28 08:38:44 +02:00
Add httpie cli plugins
in favor of the new cli namespace. (#1320)
* Add `httpie cli plugins` in favor of the new cli namespace. * Separate each task to individual modules. * Move httpie.manager.plugins to httpie.manager.tasks.plugins Co-authored-by: Jakub Roztocil <jakub@roztocil.co>
This commit is contained in:
parent
33ea977b64
commit
c157948531
@ -5,8 +5,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
## [3.1.1.dev0](https://github.com/httpie/httpie/compare/3.1.0...HEAD) (Unreleased)
|
## [3.1.1.dev0](https://github.com/httpie/httpie/compare/3.1.0...HEAD) (Unreleased)
|
||||||
|
|
||||||
|
- Changed `httpie plugins` to the new `httpie cli` namespace as `httpie cli plugins` (`httpie plugins` continues to work as a hidden alias). ([#1320](https://github.com/httpie/httpie/issues/1320))
|
||||||
- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/httpie/issues/1310))
|
- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/httpie/issues/1310))
|
||||||
|
|
||||||
|
|
||||||
## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08)
|
## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08)
|
||||||
|
|
||||||
- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312))
|
- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312))
|
||||||
|
@ -2347,7 +2347,7 @@ However, it is not recommended modifying the default behavior in a way that woul
|
|||||||
#### `plugins_dir`
|
#### `plugins_dir`
|
||||||
|
|
||||||
The directory where the plugins will be installed. HTTPie needs to have read/write access on that directory, since
|
The directory where the plugins will be installed. HTTPie needs to have read/write access on that directory, since
|
||||||
`httpie plugins install` will download new plugins to there. See [plugin manager](#plugin-manager) for more information.
|
`httpie cli plugins install` will download new plugins to there. See [plugin manager](#plugin-manager) for more information.
|
||||||
|
|
||||||
### Un-setting previously specified options
|
### Un-setting previously specified options
|
||||||
|
|
||||||
@ -2425,7 +2425,7 @@ $ httpie cli export-args | jq '"Program: " + .spec.name + ", Version: " + .vers
|
|||||||
"Program: http, Version: 0.0.1a0"
|
"Program: http, Version: 0.0.1a0"
|
||||||
```
|
```
|
||||||
|
|
||||||
### `httpie plugins`
|
#### `httpie cli plugins`
|
||||||
|
|
||||||
`plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins.
|
`plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins.
|
||||||
|
|
||||||
@ -2436,13 +2436,13 @@ plugin installations on every installation method.
|
|||||||
By default, the plugins (and their missing dependencies) will be stored under the configuration directory,
|
By default, the plugins (and their missing dependencies) will be stored under the configuration directory,
|
||||||
but this can be modified through `plugins_dir` variable on the config.
|
but this can be modified through `plugins_dir` variable on the config.
|
||||||
|
|
||||||
#### `httpie plugins install`
|
##### `httpie cli plugins install`
|
||||||
|
|
||||||
For installing plugins from [PyPI](https://pypi.org/) or from local paths, `httpie plugins install`
|
For installing plugins from [PyPI](https://pypi.org/) or from local paths, `httpie cli plugins install`
|
||||||
can be used.
|
can be used.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ httpie plugins install httpie-plugin
|
$ httpie cli plugins install httpie-plugin
|
||||||
Installing httpie-plugin...
|
Installing httpie-plugin...
|
||||||
Successfully installed httpie-plugin-1.0.2
|
Successfully installed httpie-plugin-1.0.2
|
||||||
```
|
```
|
||||||
@ -2450,12 +2450,12 @@ Successfully installed httpie-plugin-1.0.2
|
|||||||
> Tip: Generally HTTPie plugins start with `httpie-` prefix. Try searching for it on [PyPI](https://pypi.org/search/?q=httpie-)
|
> Tip: Generally HTTPie plugins start with `httpie-` prefix. Try searching for it on [PyPI](https://pypi.org/search/?q=httpie-)
|
||||||
> to find out all plugins from the community.
|
> to find out all plugins from the community.
|
||||||
|
|
||||||
#### `httpie plugins list`
|
##### `httpie cli plugins list`
|
||||||
|
|
||||||
List all installed plugins.
|
List all installed plugins.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ httpie plugins list
|
$ httpie cli plugins list
|
||||||
httpie_plugin (1.0.2)
|
httpie_plugin (1.0.2)
|
||||||
httpie_plugin (httpie.plugins.auth.v1)
|
httpie_plugin (httpie.plugins.auth.v1)
|
||||||
httpie_plugin_2 (1.0.6)
|
httpie_plugin_2 (1.0.6)
|
||||||
@ -2465,21 +2465,21 @@ httpie_converter (1.0.0)
|
|||||||
httpie_konsole_konverter (httpie.plugins.converter.v1)
|
httpie_konsole_konverter (httpie.plugins.converter.v1)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `httpie plugins upgrade`
|
##### `httpie cli plugins upgrade`
|
||||||
|
|
||||||
For upgrading already installed plugins, use `httpie plugins upgrade`.
|
For upgrading already installed plugins, use `httpie plugins upgrade`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ httpie plugins upgrade httpie-plugin
|
$ httpie cli plugins upgrade httpie-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `httpie plugins uninstall`
|
##### `httpie cli plugins uninstall`
|
||||||
|
|
||||||
Uninstall plugins from the isolated plugins directory. If the plugin is not installed
|
Uninstall plugins from the isolated plugins directory. If the plugin is not installed
|
||||||
through `httpie plugins install`, it won’t uninstall it.
|
through `httpie cli plugins install`, it won’t uninstall it.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ httpie plugins uninstall httpie-plugin
|
$ httpie cli plugins uninstall httpie-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
## Meta
|
## Meta
|
||||||
|
@ -12,37 +12,6 @@ CLI_SESSION_UPGRADE_FLAGS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
COMMANDS = {
|
COMMANDS = {
|
||||||
'plugins': {
|
|
||||||
'help': 'Manage HTTPie plugins.',
|
|
||||||
'install': [
|
|
||||||
'Install the given targets from PyPI '
|
|
||||||
'or from a local paths.',
|
|
||||||
{
|
|
||||||
'dest': 'targets',
|
|
||||||
'nargs': '+',
|
|
||||||
'help': 'targets to install'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'upgrade': [
|
|
||||||
'Upgrade the given plugins',
|
|
||||||
{
|
|
||||||
'dest': 'targets',
|
|
||||||
'nargs': '+',
|
|
||||||
'help': 'targets to upgrade'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'uninstall': [
|
|
||||||
'Uninstall the given HTTPie plugins.',
|
|
||||||
{
|
|
||||||
'dest': 'targets',
|
|
||||||
'nargs': '+',
|
|
||||||
'help': 'targets to install'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'list': [
|
|
||||||
'List all installed HTTPie plugins.'
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'cli': {
|
'cli': {
|
||||||
'help': 'Manage HTTPie for Terminal',
|
'help': 'Manage HTTPie for Terminal',
|
||||||
'export-args': [
|
'export-args': [
|
||||||
@ -82,6 +51,39 @@ COMMANDS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COMMANDS['plugins'] = COMMANDS['cli']['plugins'] = {
|
||||||
|
'help': 'Manage HTTPie plugins.',
|
||||||
|
'install': [
|
||||||
|
'Install the given targets from PyPI '
|
||||||
|
'or from a local paths.',
|
||||||
|
{
|
||||||
|
'dest': 'targets',
|
||||||
|
'nargs': '+',
|
||||||
|
'help': 'targets to install'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'upgrade': [
|
||||||
|
'Upgrade the given plugins',
|
||||||
|
{
|
||||||
|
'dest': 'targets',
|
||||||
|
'nargs': '+',
|
||||||
|
'help': 'targets to upgrade'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'uninstall': [
|
||||||
|
'Uninstall the given HTTPie plugins.',
|
||||||
|
{
|
||||||
|
'dest': 'targets',
|
||||||
|
'nargs': '+',
|
||||||
|
'help': 'targets to install'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'list': [
|
||||||
|
'List all installed HTTPie plugins.'
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def missing_subcommand(*args) -> str:
|
def missing_subcommand(*args) -> str:
|
||||||
base = COMMANDS
|
base = COMMANDS
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
@ -2,7 +2,6 @@ import argparse
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from httpie.context import Environment
|
from httpie.context import Environment
|
||||||
from httpie.manager.plugins import PluginInstaller
|
|
||||||
from httpie.status import ExitStatus
|
from httpie.status import ExitStatus
|
||||||
from httpie.manager.cli import missing_subcommand, parser
|
from httpie.manager.cli import missing_subcommand, parser
|
||||||
from httpie.manager.tasks import CLI_TASKS
|
from httpie.manager.tasks import CLI_TASKS
|
||||||
@ -36,8 +35,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus:
|
|||||||
parser.error(MSG_NAKED_INVOCATION)
|
parser.error(MSG_NAKED_INVOCATION)
|
||||||
|
|
||||||
if args.action == 'plugins':
|
if args.action == 'plugins':
|
||||||
plugins = PluginInstaller(env, debug=args.debug)
|
return dispatch_cli_task(env, args.action, args)
|
||||||
return plugins.run(args.plugins_action, args)
|
|
||||||
elif args.action == 'cli':
|
elif args.action == 'cli':
|
||||||
return dispatch_cli_task(env, args.cli_action, args)
|
return dispatch_cli_task(env, args.cli_action, args)
|
||||||
|
|
||||||
|
9
httpie/manager/tasks/__init__.py
Normal file
9
httpie/manager/tasks/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from httpie.manager.tasks.sessions import cli_sessions
|
||||||
|
from httpie.manager.tasks.export_args import cli_export_args
|
||||||
|
from httpie.manager.tasks.plugins import cli_plugins
|
||||||
|
|
||||||
|
CLI_TASKS = {
|
||||||
|
'sessions': cli_sessions,
|
||||||
|
'export-args': cli_export_args,
|
||||||
|
'plugins': cli_plugins,
|
||||||
|
}
|
27
httpie/manager/tasks/export_args.py
Normal file
27
httpie/manager/tasks/export_args.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
|
from httpie.cli.definition import options
|
||||||
|
from httpie.cli.options import to_data
|
||||||
|
from httpie.output.writer import write_raw_data
|
||||||
|
from httpie.status import ExitStatus
|
||||||
|
from httpie.context import Environment
|
||||||
|
|
||||||
|
|
||||||
|
FORMAT_TO_CONTENT_TYPE = {
|
||||||
|
'json': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def cli_export_args(env: Environment, args: argparse.Namespace) -> ExitStatus:
|
||||||
|
if args.format == 'json':
|
||||||
|
data = json.dumps(to_data(options))
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f'Unexpected format value: {args.format}')
|
||||||
|
|
||||||
|
write_raw_data(
|
||||||
|
env,
|
||||||
|
data,
|
||||||
|
stream_kwargs={'mime_overwrite': FORMAT_TO_CONTENT_TYPE[args.format]},
|
||||||
|
)
|
||||||
|
return ExitStatus.SUCCESS
|
@ -1,18 +1,18 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple, Optional, List
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
from httpie.manager.cli import parser, missing_subcommand
|
from httpie.compat import get_dist_name, importlib_metadata
|
||||||
from httpie.compat import importlib_metadata, get_dist_name
|
|
||||||
from httpie.context import Environment
|
from httpie.context import Environment
|
||||||
|
from httpie.manager.cli import missing_subcommand, parser
|
||||||
from httpie.status import ExitStatus
|
from httpie.status import ExitStatus
|
||||||
from httpie.utils import as_site
|
from httpie.utils import as_site
|
||||||
|
|
||||||
@ -248,3 +248,14 @@ class PluginInstaller:
|
|||||||
status = self.list()
|
status = self.list()
|
||||||
|
|
||||||
return status or ExitStatus.SUCCESS
|
return status or ExitStatus.SUCCESS
|
||||||
|
|
||||||
|
|
||||||
|
def cli_plugins(env: Environment, args: argparse.Namespace) -> ExitStatus:
|
||||||
|
plugins = PluginInstaller(env, debug=args.debug)
|
||||||
|
|
||||||
|
try:
|
||||||
|
action = args.cli_plugins_action
|
||||||
|
except AttributeError:
|
||||||
|
action = args.plugins_action
|
||||||
|
|
||||||
|
return plugins.run(action, args)
|
@ -1,5 +1,5 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from typing import TypeVar, Callable, Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from httpie.sessions import SESSIONS_DIR_NAME, get_httpie_session
|
from httpie.sessions import SESSIONS_DIR_NAME, get_httpie_session
|
||||||
from httpie.status import ExitStatus
|
from httpie.status import ExitStatus
|
||||||
@ -7,19 +7,7 @@ from httpie.context import Environment
|
|||||||
from httpie.legacy import cookie_format as legacy_cookies
|
from httpie.legacy import cookie_format as legacy_cookies
|
||||||
from httpie.manager.cli import missing_subcommand, parser
|
from httpie.manager.cli import missing_subcommand, parser
|
||||||
|
|
||||||
T = TypeVar('T')
|
|
||||||
|
|
||||||
CLI_TASKS = {}
|
|
||||||
|
|
||||||
|
|
||||||
def task(name: str) -> Callable[[T], T]:
|
|
||||||
def wrapper(func: T) -> T:
|
|
||||||
CLI_TASKS[name] = func
|
|
||||||
return func
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
@task('sessions')
|
|
||||||
def cli_sessions(env: Environment, args: argparse.Namespace) -> ExitStatus:
|
def cli_sessions(env: Environment, args: argparse.Namespace) -> ExitStatus:
|
||||||
action = args.cli_sessions_action
|
action = args.cli_sessions_action
|
||||||
if action is None:
|
if action is None:
|
||||||
@ -114,28 +102,3 @@ def cli_upgrade_all_sessions(env: Environment, args: argparse.Namespace) -> Exit
|
|||||||
session_name=session_name
|
session_name=session_name
|
||||||
)
|
)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
FORMAT_TO_CONTENT_TYPE = {
|
|
||||||
'json': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@task('export-args')
|
|
||||||
def cli_export(env: Environment, args: argparse.Namespace) -> ExitStatus:
|
|
||||||
import json
|
|
||||||
from httpie.cli.definition import options
|
|
||||||
from httpie.cli.options import to_data
|
|
||||||
from httpie.output.writer import write_raw_data
|
|
||||||
|
|
||||||
if args.format == 'json':
|
|
||||||
data = json.dumps(to_data(options))
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(f'Unexpected format value: {args.format}')
|
|
||||||
|
|
||||||
write_raw_data(
|
|
||||||
env,
|
|
||||||
data,
|
|
||||||
stream_kwargs={'mime_overwrite': FORMAT_TO_CONTENT_TYPE[args.format]},
|
|
||||||
)
|
|
||||||
return ExitStatus.SUCCESS
|
|
@ -5,8 +5,9 @@ from tests.utils.plugins_cli import parse_listing
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.requires_installation
|
@pytest.mark.requires_installation
|
||||||
def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin):
|
@pytest.mark.parametrize('cli_mode', [True, False])
|
||||||
lines = httpie_plugins_success('install', dummy_plugin.path)
|
def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin, cli_mode):
|
||||||
|
lines = httpie_plugins_success('install', dummy_plugin.path, cli_mode=cli_mode)
|
||||||
assert lines[0].startswith(
|
assert lines[0].startswith(
|
||||||
f'Installing {dummy_plugin.path}'
|
f'Installing {dummy_plugin.path}'
|
||||||
)
|
)
|
||||||
@ -28,8 +29,9 @@ def test_plugin_installation_with_custom_config(httpie_plugins_success, interfac
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.requires_installation
|
@pytest.mark.requires_installation
|
||||||
def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin):
|
@pytest.mark.parametrize('cli_mode', [True, False])
|
||||||
httpie_plugins_success('install', dummy_plugin.path)
|
def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin, cli_mode):
|
||||||
|
httpie_plugins_success('install', dummy_plugin.path, cli_mode=cli_mode)
|
||||||
data = parse_listing(httpie_plugins_success('list'))
|
data = parse_listing(httpie_plugins_success('list'))
|
||||||
|
|
||||||
assert data == {
|
assert data == {
|
||||||
@ -50,9 +52,10 @@ def test_plugins_listing_multiple(interface, httpie_plugins_success, dummy_plugi
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.requires_installation
|
@pytest.mark.requires_installation
|
||||||
def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin):
|
@pytest.mark.parametrize('cli_mode', [True, False])
|
||||||
httpie_plugins_success('install', dummy_plugin.path)
|
def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin, cli_mode):
|
||||||
httpie_plugins_success('uninstall', dummy_plugin.name)
|
httpie_plugins_success('install', dummy_plugin.path, cli_mode=cli_mode)
|
||||||
|
httpie_plugins_success('uninstall', dummy_plugin.name, cli_mode=cli_mode)
|
||||||
assert not interface.is_installed(dummy_plugin.name)
|
assert not interface.is_installed(dummy_plugin.name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,12 +208,17 @@ def httpie_plugins(interface):
|
|||||||
from tests.utils import httpie
|
from tests.utils import httpie
|
||||||
from httpie.plugins.registry import plugin_manager
|
from httpie.plugins.registry import plugin_manager
|
||||||
|
|
||||||
def runner(*args):
|
def runner(*args, cli_mode: bool = True):
|
||||||
|
args = list(args)
|
||||||
|
if cli_mode:
|
||||||
|
args.insert(0, 'cli')
|
||||||
|
args.insert(cli_mode, 'plugins')
|
||||||
|
|
||||||
# Prevent installed plugins from showing up.
|
# Prevent installed plugins from showing up.
|
||||||
original_plugins = plugin_manager.copy()
|
original_plugins = plugin_manager.copy()
|
||||||
clean_sys_path = set(sys.path).difference(site.getsitepackages())
|
clean_sys_path = set(sys.path).difference(site.getsitepackages())
|
||||||
with patch('sys.path', list(clean_sys_path)):
|
with patch('sys.path', list(clean_sys_path)):
|
||||||
response = httpie('plugins', *args, env=interface.environment)
|
response = httpie(*args, env=interface.environment)
|
||||||
plugin_manager.clear()
|
plugin_manager.clear()
|
||||||
plugin_manager.extend(original_plugins)
|
plugin_manager.extend(original_plugins)
|
||||||
return response
|
return response
|
||||||
@ -223,8 +228,8 @@ def httpie_plugins(interface):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def httpie_plugins_success(httpie_plugins):
|
def httpie_plugins_success(httpie_plugins):
|
||||||
def runner(*args):
|
def runner(*args, cli_mode: bool = True):
|
||||||
response = httpie_plugins(*args)
|
response = httpie_plugins(*args, cli_mode=True)
|
||||||
assert response.exit_status == ExitStatus.SUCCESS
|
assert response.exit_status == ExitStatus.SUCCESS
|
||||||
return response.splitlines()
|
return response.splitlines()
|
||||||
return runner
|
return runner
|
||||||
|
Loading…
Reference in New Issue
Block a user