1
0
mirror of https://github.com/httpie/cli.git synced 2025-08-10 22:42:05 +02:00

httpie cli check-updates

This commit is contained in:
Batuhan Taskaya
2022-04-29 14:35:12 +03:00
parent c56692c9af
commit 366b0c3fcd
6 changed files with 95 additions and 20 deletions

View File

@@ -2402,6 +2402,14 @@ This command is currently in beta.
"Program: http, Version: 0.0.1a0" "Program: http, Version: 0.0.1a0"
``` ```
#### `httpie cli plugins`
`plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins.
In the past `pip` was used to install/uninstall plugins, but on some environments (e.g., brew installed
packages) it wasn’t working properly. The new interface is a very simple overlay on top of `pip` to allow
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.

View File

@@ -2,7 +2,7 @@ import json
from contextlib import nullcontext, suppress from contextlib import nullcontext, suppress
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Any, Callable from typing import Any, Optional, Callable
import requests import requests
@@ -23,6 +23,10 @@ A new HTTPie release ({last_released_version}) is available.
To see how you can update, please visit https://httpie.io/docs/cli/{installation_method} To see how you can update, please visit https://httpie.io/docs/cli/{installation_method}
""" """
ALREADY_UP_TO_DATE_MESSAGE = """\
You are already up-to-date.
"""
def _read_data_error_free(file: Path) -> Any: def _read_data_error_free(file: Path) -> Any:
# If the file is broken / non-existent, ignore it. # If the file is broken / non-existent, ignore it.
@@ -48,8 +52,11 @@ def _fetch_updates(env: Environment) -> str:
json.dump(data, stream) json.dump(data, stream)
def fetch_updates(): def fetch_updates(env: Environment, lazy: bool = True):
spawn_daemon('fetch_updates') if lazy:
spawn_daemon('fetch_updates')
else:
_fetch_updates(env)
def maybe_fetch_updates(env: Environment) -> None: def maybe_fetch_updates(env: Environment) -> None:
@@ -65,7 +72,7 @@ def maybe_fetch_updates(env: Environment) -> None:
if current_date < earliest_fetch_date: if current_date < earliest_fetch_date:
return None return None
fetch_updates() fetch_updates(env)
def _get_suppress_context(env: Environment) -> Any: def _get_suppress_context(env: Environment) -> Any:
@@ -97,13 +104,48 @@ def _update_checker(
return wrapper return wrapper
def _get_update_status(env: Environment) -> Optional[str]:
"""If there is a new update available, return the warning text.
Otherwise just return None."""
file = env.config.version_info_file
if not file.exists():
return None
with _get_suppress_context(env):
# If the user quickly spawns multiple httpie processes
# we don't want to end in a race.
with open_with_lockfile(file) as stream:
version_info = json.load(stream)
available_channels = version_info['last_released_versions']
if BUILD_CHANNEL not in available_channels:
return None
current_version = httpie.__version__
last_released_version = available_channels[BUILD_CHANNEL]
if not is_version_greater(last_released_version, current_version):
return None
text = UPDATE_MESSAGE_FORMAT.format(
last_released_version=last_released_version,
installation_method=BUILD_CHANNEL,
)
return text
def get_update_status(env: Environment) -> str:
return _get_update_status(env) or ALREADY_UP_TO_DATE_MESSAGE
@_update_checker @_update_checker
def check_updates(env: Environment) -> None: def check_updates(env: Environment) -> None:
if env.config.get('disable_update_warnings'): if env.config.get('disable_update_warnings'):
return None return None
file = env.config.version_info_file file = env.config.version_info_file
if not file.exists(): update_status = _get_update_status(env)
if not update_status:
return None return None
# If the user quickly spawns multiple httpie processes # If the user quickly spawns multiple httpie processes
@@ -111,10 +153,6 @@ def check_updates(env: Environment) -> None:
with open_with_lockfile(file) as stream: with open_with_lockfile(file) as stream:
version_info = json.load(stream) version_info = json.load(stream)
available_channels = version_info['last_released_versions']
if BUILD_CHANNEL not in available_channels:
return None
# We don't want to spam the user with too many warnings, # We don't want to spam the user with too many warnings,
# so we'll only warn every once a while (WARN_INTERNAL). # so we'll only warn every once a while (WARN_INTERNAL).
current_date = datetime.now() current_date = datetime.now()
@@ -126,16 +164,7 @@ def check_updates(env: Environment) -> None:
if current_date < earliest_warn_date: if current_date < earliest_warn_date:
return None return None
current_version = httpie.__version__ env.log_error(update_status, level=Levels.WARNING)
last_released_version = available_channels[BUILD_CHANNEL]
if not is_version_greater(last_released_version, current_version):
return None
text = UPDATE_MESSAGE_FORMAT.format(
last_released_version=last_released_version,
installation_method=BUILD_CHANNEL,
)
env.log_error(text, level=Levels.WARNING)
version_info['last_warned_date'] = current_date.isoformat() version_info['last_warned_date'] = current_date.isoformat()
with open_with_lockfile(file, 'w') as stream: with open_with_lockfile(file, 'w') as stream:

View File

@@ -23,6 +23,9 @@ COMMANDS = {
'default': 'json' 'default': 'json'
} }
], ],
'check-updates': [
'Check for updates'
],
'sessions': { 'sessions': {
'help': 'Manage HTTPie sessions', 'help': 'Manage HTTPie sessions',
'upgrade': [ 'upgrade': [

View File

@@ -1,9 +1,11 @@
from httpie.manager.tasks.sessions import cli_sessions from httpie.manager.tasks.sessions import cli_sessions
from httpie.manager.tasks.export_args import cli_export_args from httpie.manager.tasks.export_args import cli_export_args
from httpie.manager.tasks.plugins import cli_plugins from httpie.manager.tasks.plugins import cli_plugins
from httpie.manager.tasks.check_updates import cli_check_updates
CLI_TASKS = { CLI_TASKS = {
'sessions': cli_sessions, 'sessions': cli_sessions,
'export-args': cli_export_args, 'export-args': cli_export_args,
'plugins': cli_plugins, 'plugins': cli_plugins,
'check-updates': cli_check_updates
} }

View File

@@ -0,0 +1,10 @@
import argparse
from httpie.context import Environment
from httpie.status import ExitStatus
from httpie.internal.update_warnings import fetch_updates, get_update_status
def cli_check_updates(env: Environment, args: argparse.Namespace) -> ExitStatus:
fetch_updates(env, lazy=False)
env.stdout.write(get_update_status(env))
return ExitStatus.SUCCESS

View File

@@ -9,8 +9,9 @@ import pytest
from httpie.internal.daemon_runner import STATUS_FILE from httpie.internal.daemon_runner import STATUS_FILE
from httpie.internal.daemons import spawn_daemon from httpie.internal.daemons import spawn_daemon
from httpie.status import ExitStatus
from .utils import PersistentMockEnvironment, http from .utils import PersistentMockEnvironment, http, httpie
BUILD_CHANNEL = 'test' BUILD_CHANNEL = 'test'
BUILD_CHANNEL_2 = 'test2' BUILD_CHANNEL_2 = 'test2'
@@ -166,6 +167,28 @@ def test_check_updates_first_time_after_data_fetch_unknown_build_channel(
assert not check_update_warnings(r.stderr) assert not check_update_warnings(r.stderr)
def test_cli_check_updates(
static_fetch_data, higher_build_channel
):
r = httpie('cli', 'check-updates')
assert r.exit_status == ExitStatus.SUCCESS
assert check_update_warnings(r)
@pytest.mark.parametrize(
"build_channel", [
pytest.lazy_fixture("lower_build_channel"),
pytest.lazy_fixture("unknown_build_channel")
]
)
def test_cli_check_updates_not_shown(
static_fetch_data, build_channel
):
r = httpie('cli', 'check-updates')
assert r.exit_status == ExitStatus.SUCCESS
assert not check_update_warnings(r)
@pytest.fixture @pytest.fixture
def with_warnings(tmp_path): def with_warnings(tmp_path):
env = PersistentMockEnvironment() env = PersistentMockEnvironment()