1
0
mirror of https://github.com/httpie/cli.git synced 2025-07-17 01:42:46 +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:
Batuhan Taskaya
2022-04-03 16:06:42 +03:00
committed by GitHub
parent 33ea977b64
commit c157948531
10 changed files with 120 additions and 100 deletions

View File

@ -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)
- 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))
## [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))

View File

@ -2347,7 +2347,7 @@ However, it is not recommended modifying the default behavior in a way that woul
*) echo 'Other Error!' ;;
esac
fi
```
```
### Best practices
@ -2425,7 +2425,7 @@ $ httpie cli export-args | jq '"Program: " + .spec.name + ", Version: " + .vers
##### `httpie cli plugins list`
List all installed plugins.
List all installed plugins.
```bash
$ httpie cli plugins list
@ -2436,13 +2436,13 @@ plugin installations on every installation method.
httpie_converter (1.0.0)
httpie_iterm_converter (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`.
```bash
```bash
$ httpie cli plugins upgrade httpie-plugin
```
@ -2450,12 +2450,12 @@ Successfully installed httpie-plugin-1.0.2
Uninstall plugins from the isolated plugins directory. If the plugin is not installed
through `httpie cli plugins install`, it won’t uninstall it.
```bash
$ httpie cli plugins uninstall httpie-plugin
```
## Meta
## Meta
### Interface design
@ -2465,21 +2465,21 @@ httpie_converter (1.0.0)
For example, compare this HTTP request:
```http
POST /post HTTP/1.1
POST /post HTTP/1.1
Host: pie.dev
X-API-Key: 123
User-Agent: Bacon/1.0
Content-Type: application/x-www-form-urlencoded
name=value&name2=value2
```
with the HTTPie command that sends it:
```bash
```bash
$ http -f POST pie.dev/post \
X-API-Key:123 \
User-Agent:Bacon/1.0 \
User-Agent:Bacon/1.0 \
name=value \
name2=value2
```

View File

@ -12,37 +12,6 @@ CLI_SESSION_UPGRADE_FLAGS = [
]
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': {
'help': 'Manage HTTPie for Terminal',
'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:
base = COMMANDS
for arg in args:

View File

@ -2,7 +2,6 @@ import argparse
from typing import Optional
from httpie.context import Environment
from httpie.manager.plugins import PluginInstaller
from httpie.status import ExitStatus
from httpie.manager.cli import missing_subcommand, parser
from httpie.manager.tasks import CLI_TASKS
@ -36,8 +35,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus:
parser.error(MSG_NAKED_INVOCATION)
if args.action == 'plugins':
plugins = PluginInstaller(env, debug=args.debug)
return plugins.run(args.plugins_action, args)
return dispatch_cli_task(env, args.action, args)
elif args.action == 'cli':
return dispatch_cli_task(env, args.cli_action, args)

View 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,
}

View 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

View File

@ -1,18 +1,18 @@
import argparse
import os
import re
import shutil
import subprocess
import sys
import textwrap
import re
import shutil
from collections import defaultdict
from contextlib import suppress
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 importlib_metadata, get_dist_name
from httpie.compat import get_dist_name, importlib_metadata
from httpie.context import Environment
from httpie.manager.cli import missing_subcommand, parser
from httpie.status import ExitStatus
from httpie.utils import as_site
@ -248,3 +248,14 @@ class PluginInstaller:
status = self.list()
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)

View File

@ -1,5 +1,5 @@
import argparse
from typing import TypeVar, Callable, Tuple
from typing import Tuple
from httpie.sessions import SESSIONS_DIR_NAME, get_httpie_session
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.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:
action = args.cli_sessions_action
if action is None:
@ -114,28 +102,3 @@ def cli_upgrade_all_sessions(env: Environment, args: argparse.Namespace) -> Exit
session_name=session_name
)
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

View File

@ -5,8 +5,9 @@ from tests.utils.plugins_cli import parse_listing
@pytest.mark.requires_installation
def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin):
lines = httpie_plugins_success('install', dummy_plugin.path)
@pytest.mark.parametrize('cli_mode', [True, False])
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(
f'Installing {dummy_plugin.path}'
)
@ -28,8 +29,9 @@ def test_plugin_installation_with_custom_config(httpie_plugins_success, interfac
@pytest.mark.requires_installation
def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin):
httpie_plugins_success('install', dummy_plugin.path)
@pytest.mark.parametrize('cli_mode', [True, False])
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'))
assert data == {
@ -50,9 +52,10 @@ def test_plugins_listing_multiple(interface, httpie_plugins_success, dummy_plugi
@pytest.mark.requires_installation
def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin):
httpie_plugins_success('install', dummy_plugin.path)
httpie_plugins_success('uninstall', dummy_plugin.name)
@pytest.mark.parametrize('cli_mode', [True, False])
def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin, cli_mode):
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)

View File

@ -208,12 +208,17 @@ def httpie_plugins(interface):
from tests.utils import httpie
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.
original_plugins = plugin_manager.copy()
clean_sys_path = set(sys.path).difference(site.getsitepackages())
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.extend(original_plugins)
return response
@ -223,8 +228,8 @@ def httpie_plugins(interface):
@pytest.fixture
def httpie_plugins_success(httpie_plugins):
def runner(*args):
response = httpie_plugins(*args)
def runner(*args, cli_mode: bool = True):
response = httpie_plugins(*args, cli_mode=True)
assert response.exit_status == ExitStatus.SUCCESS
return response.splitlines()
return runner