You've already forked httpie-cli
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:
@@ -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.
|
||||||
|
|
||||||
|
@@ -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:
|
||||||
|
@@ -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': [
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
10
httpie/manager/tasks/check_updates.py
Normal file
10
httpie/manager/tasks/check_updates.py
Normal 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
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user