mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-10 23:10:42 +01:00
Change ui messaging for the updater (#6437)
This commit is contained in:
+2
-11
@@ -10,21 +10,12 @@ logger = logging.getLogger(__name__)
|
||||
class CmdVersion(CmdBaseNoRepo):
|
||||
def run(self):
|
||||
from dvc.info import get_dvc_info
|
||||
from dvc.repo import NotDvcRepoError, Repo
|
||||
from dvc.updater import notify_updates
|
||||
|
||||
dvc_info = get_dvc_info()
|
||||
ui.write(dvc_info, force=True)
|
||||
|
||||
try:
|
||||
with Repo() as repo:
|
||||
from dvc.updater import Updater
|
||||
|
||||
hardlink_lock = repo.config["core"].get("hardlink_lock", False)
|
||||
updater = Updater(repo.tmp_dir, hardlink_lock=hardlink_lock)
|
||||
updater.check()
|
||||
except NotDvcRepoError:
|
||||
pass
|
||||
|
||||
notify_updates()
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
+58
-43
@@ -2,17 +2,20 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
import colorama
|
||||
from packaging import version
|
||||
|
||||
from dvc import __version__
|
||||
from dvc.utils.pkg import PKG
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from rich.text import Text
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Updater: # pragma: no cover
|
||||
class Updater:
|
||||
URL = "https://updater.dvc.org"
|
||||
UPDATER_FILE = "updater"
|
||||
TIMEOUT = 24 * 60 * 60 # every day
|
||||
@@ -105,57 +108,58 @@ class Updater: # pragma: no cover
|
||||
with open(self.updater_file, "w+") as fobj:
|
||||
json.dump(info, fobj)
|
||||
|
||||
def _notify(self, latest):
|
||||
def _notify(self, latest: str, pkg: Optional[str] = PKG) -> None:
|
||||
from dvc.ui import ui
|
||||
|
||||
if not sys.stdout.isatty():
|
||||
return
|
||||
|
||||
message = (
|
||||
"Update available {red}{current}{reset} -> {green}{latest}{reset}"
|
||||
+ "\n"
|
||||
+ self._get_update_instructions()
|
||||
).format(
|
||||
red=colorama.Fore.RED,
|
||||
reset=colorama.Fore.RESET,
|
||||
green=colorama.Fore.GREEN,
|
||||
yellow=colorama.Fore.YELLOW,
|
||||
blue=colorama.Fore.BLUE,
|
||||
current=self.current,
|
||||
latest=latest,
|
||||
message = self._get_message(latest, pkg=pkg)
|
||||
return ui.error_write(message, styled=True)
|
||||
|
||||
def _get_message(
|
||||
self,
|
||||
latest: str,
|
||||
current: str = None,
|
||||
color: str = "yellow",
|
||||
pkg: Optional[str] = None,
|
||||
) -> "Text":
|
||||
from rich.text import Text
|
||||
|
||||
current = current or self.current
|
||||
update_message = Text.from_markup(
|
||||
f"You are using dvc version [bold]{current}[/]; "
|
||||
f"however, version [bold]{latest}[/] is available."
|
||||
)
|
||||
instruction = Text.from_markup(self._get_update_instructions(pkg=pkg))
|
||||
return Text.assemble(
|
||||
"\n", update_message, "\n", instruction, style=color
|
||||
)
|
||||
|
||||
from dvc.utils import boxify
|
||||
def _get_update_instructions(self, pkg: Optional[str] = None) -> str:
|
||||
if pkg in ("osxpkg", "exe", "binary"):
|
||||
return (
|
||||
"To upgrade, uninstall dvc and reinstall from "
|
||||
"[blue]https://dvc.org[/]."
|
||||
)
|
||||
|
||||
logger.info(boxify(message, border_color="yellow"))
|
||||
|
||||
def _get_update_instructions(self):
|
||||
instructions = {
|
||||
"pip": "Run `{yellow}pip{reset} install dvc "
|
||||
"{blue}--upgrade{reset}`",
|
||||
"rpm": "Run `{yellow}yum{reset} update dvc`",
|
||||
"brew": "Run `{yellow}brew{reset} upgrade dvc`",
|
||||
"deb": (
|
||||
"Run `{yellow}apt-get{reset} install"
|
||||
" {blue}--only-upgrade{reset} dvc`"
|
||||
),
|
||||
"binary": (
|
||||
"To upgrade follow these steps:\n"
|
||||
"1. Uninstall dvc binary\n"
|
||||
"2. Go to {blue}https://dvc.org{reset}\n"
|
||||
"3. Download and install new binary"
|
||||
),
|
||||
"conda": "Run `{yellow}conda{reset} update dvc`",
|
||||
"choco": "Run `{yellow}choco{reset} upgrade dvc`",
|
||||
None: (
|
||||
"Find the latest release at\n"
|
||||
"{blue}https://github.com/iterative/dvc/releases/latest{reset}"
|
||||
),
|
||||
"pip": "pip install --upgrade dvc",
|
||||
"rpm": "yum update dvc",
|
||||
"brew": "brew upgrade dvc",
|
||||
"deb": "apt-get install --only-upgrade dvc",
|
||||
"conda": "conda update dvc",
|
||||
"choco": "choco upgrade dvc",
|
||||
}
|
||||
|
||||
package_manager = PKG
|
||||
if package_manager in ("osxpkg", "exe"):
|
||||
package_manager = "binary"
|
||||
if pkg not in instructions:
|
||||
return (
|
||||
"Find the latest release at "
|
||||
"[blue]https://github.com/iterative/dvc/releases/latest[/]."
|
||||
)
|
||||
|
||||
return instructions[package_manager]
|
||||
instruction = instructions[pkg]
|
||||
return f"To upgrade, run '{instruction}'."
|
||||
|
||||
def is_enabled(self):
|
||||
from dvc.config import Config, to_bool
|
||||
@@ -167,3 +171,14 @@ class Updater: # pragma: no cover
|
||||
"Check for update is {}abled.".format("en" if enabled else "dis")
|
||||
)
|
||||
return enabled
|
||||
|
||||
|
||||
def notify_updates():
|
||||
from contextlib import suppress
|
||||
|
||||
from dvc.repo import NotDvcRepoError, Repo
|
||||
|
||||
with suppress(NotDvcRepoError), Repo() as repo:
|
||||
hardlink_lock = repo.config["core"].get("hardlink_lock", False)
|
||||
updater = Updater(repo.tmp_dir, hardlink_lock=hardlink_lock)
|
||||
updater.check()
|
||||
|
||||
@@ -8,6 +8,7 @@ import pytest
|
||||
|
||||
from dvc import __version__
|
||||
from dvc.updater import Updater
|
||||
from tests.func.parsing.test_errors import escape_ansi
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -85,19 +86,26 @@ def test_check_update_respect_config(mock_check, result, updater, mocker):
|
||||
],
|
||||
ids=["uptodate", "behind", "ahead"],
|
||||
)
|
||||
def test_check_updates(mock_tty, updater, caplog, current, latest, notify):
|
||||
def test_check_updates(mocker, capsys, updater, current, latest, notify):
|
||||
mocker.patch("sys.stdout.isatty", return_value=True)
|
||||
|
||||
updater.current = current
|
||||
with open(updater.updater_file, "w+") as f:
|
||||
json.dump({"version": latest}, f)
|
||||
|
||||
caplog.clear()
|
||||
with caplog.at_level(logging.INFO, logger="dvc.updater"):
|
||||
updater.check()
|
||||
updater.check()
|
||||
out, err = capsys.readouterr()
|
||||
expected_message = (
|
||||
(
|
||||
f"You are using dvc version {current}; "
|
||||
f"however, version {latest} is available.\n"
|
||||
)
|
||||
if notify
|
||||
else ""
|
||||
)
|
||||
|
||||
if notify:
|
||||
assert f"Update available {current} -> {latest}" in caplog.text
|
||||
else:
|
||||
assert not caplog.text
|
||||
assert expected_message in escape_ansi(err)
|
||||
assert not out
|
||||
|
||||
|
||||
def test_check_refetches_each_day(mock_tty, updater, caplog, mocker):
|
||||
@@ -138,3 +146,45 @@ def test_check(mock_check, updater):
|
||||
updater.check()
|
||||
|
||||
assert mock_check.call_count == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pkg, instruction",
|
||||
[
|
||||
("pip", "To upgrade, run 'pip install --upgrade dvc'."),
|
||||
("rpm", "To upgrade, run 'yum update dvc'."),
|
||||
("brew", "To upgrade, run 'brew upgrade dvc'."),
|
||||
("deb", "To upgrade, run 'apt-get install --only-upgrade dvc'."),
|
||||
("conda", "To upgrade, run 'conda update dvc'."),
|
||||
("choco", "To upgrade, run 'choco upgrade dvc'."),
|
||||
(
|
||||
"osxpkg",
|
||||
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
|
||||
),
|
||||
(
|
||||
"exe",
|
||||
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
|
||||
),
|
||||
(
|
||||
"binary",
|
||||
"To upgrade, uninstall dvc and reinstall from https://dvc.org.",
|
||||
),
|
||||
(
|
||||
None,
|
||||
"Find the latest release at "
|
||||
"https://github.com/iterative/dvc/releases/latest.",
|
||||
),
|
||||
(
|
||||
"unknown",
|
||||
"Find the latest release at "
|
||||
"https://github.com/iterative/dvc/releases/latest.",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_notify_message(updater, pkg, instruction):
|
||||
update_message = (
|
||||
"You are using dvc version 0.0.2; however, version 0.0.3 is available."
|
||||
)
|
||||
|
||||
message = updater._get_message("0.0.3", current="0.0.2", pkg=pkg)
|
||||
assert message.plain.splitlines() == ["", update_message, instruction]
|
||||
|
||||
Reference in New Issue
Block a user