Commit c0fffa96 by Sébastien Eustace Committed by GitHub

Merge pull request #4084 from python-poetry/improve-self-update

Improve the `self update` command to account for the new installer
parents 9591e884 c02703ee
......@@ -72,7 +72,7 @@ You can specify a package in the following forms:
plugins = self.argument("plugins")
# Plugins should be installed in the system env to be globally available
system_env = EnvManager.get_system_env()
system_env = EnvManager.get_system_env(naive=True)
env_dir = Path(
os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path
......
......@@ -43,7 +43,7 @@ class PluginRemoveCommand(Command):
plugins = self.argument("plugins")
system_env = EnvManager.get_system_env()
system_env = EnvManager.get_system_env(naive=True)
env_dir = Path(
os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path
)
......
......@@ -38,7 +38,7 @@ class PluginShowCommand(Command):
+ PluginManager("plugin").get_plugin_entry_points()
)
system_env = EnvManager.get_system_env()
system_env = EnvManager.get_system_env(naive=True)
installed_repository = InstalledRepository.load(
system_env, with_dependencies=True
)
......
import os
from pathlib import Path
from .utils.appdirs import user_cache_dir
......@@ -10,3 +12,10 @@ DATA_DIR = user_data_dir("pypoetry")
CONFIG_DIR = user_config_dir("pypoetry")
REPOSITORY_CACHE_DIR = Path(CACHE_DIR) / "cache" / "repositories"
def data_dir() -> Path:
if os.getenv("POETRY_HOME"):
return Path(os.getenv("POETRY_HOME")).expanduser()
return Path(user_data_dir("pypoetry", roaming=True))
......@@ -595,3 +595,8 @@ class Locker:
data["develop"] = package.develop
return data
class NullLocker(Locker):
def set_lock_data(self, root: Package, packages: List[Package]) -> bool:
pass
......@@ -996,8 +996,31 @@ class EnvManager:
shutil.rmtree(str(file_path))
@classmethod
def get_system_env(cls) -> "SystemEnv":
return SystemEnv(Path(sys.prefix), cls.get_base_prefix())
def get_system_env(cls, naive: bool = False) -> "SystemEnv":
"""
Retrieve the current Python environment.
This can be the base Python environment or an activated virtual environment.
This method also workaround the issue that the virtual environment
used by Poetry internally (when installed via the custom installer)
is incorrectly detected as the system environment. Note that this workaround
happens only when `naive` is False since there are times where we actually
want to retrieve Poetry's custom virtual environment
(e.g. plugin installation or self update).
"""
prefix, base_prefix = Path(sys.prefix), cls.get_base_prefix()
if naive is False:
from poetry.locations import data_dir
try:
prefix.relative_to(data_dir())
except ValueError:
pass
else:
prefix = base_prefix
return SystemEnv(prefix, base_prefix)
@classmethod
def get_base_prefix(cls) -> Path:
......
import os
from pathlib import Path
import pytest
from poetry.__version__ import __version__
from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.core.packages.package import Package
from poetry.core.semver.version import Version
from poetry.utils._compat import WINDOWS
from poetry.factory import Factory
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.pool import Pool
from poetry.repositories.repository import Repository
from poetry.utils.env import EnvManager
FIXTURES = Path(__file__).parent.joinpath("fixtures")
......@@ -18,75 +21,85 @@ def tester(command_tester_factory):
return command_tester_factory("self update")
def test_self_update_should_install_all_necessary_elements(
tester, http, mocker, environ, tmp_dir
def test_self_update_can_update_from_recommended_installation(
tester, http, mocker, environ, tmp_venv
):
os.environ["POETRY_HOME"] = tmp_dir
mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)
command = tester.command
command._data_dir = tmp_venv.path.parent
new_version = Version.parse(__version__).next_minor().text
old_poetry = Package("poetry", __version__)
old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))
new_poetry = Package("poetry", new_version)
new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))
installed_repository = Repository()
installed_repository.add_package(old_poetry)
installed_repository.add_package(Package("cleo", "0.8.2"))
repository = Repository()
repository.add_package(new_poetry)
repository.add_package(Package("cleo", "1.0.0"))
pool = Pool()
pool.add_repository(repository)
version = Version.parse(__version__).next_minor().text
mocker.patch(
"poetry.repositories.pypi_repository.PyPiRepository.find_packages",
return_value=[Package("poetry", version)],
)
mocker.patch.object(command, "_check_recommended_installation", return_value=None)
mocker.patch.object(
command, "_get_release_name", return_value="poetry-{}-darwin".format(version)
)
mocker.patch("subprocess.check_output", return_value=b"Python 3.8.2")
http.register_uri(
"GET",
command.BASE_URL + "/{}/poetry-{}-darwin.sha256sum".format(version, version),
body=FIXTURES.joinpath("poetry-1.0.5-darwin.sha256sum").read_bytes(),
)
http.register_uri(
"GET",
command.BASE_URL + "/{}/poetry-{}-darwin.tar.gz".format(version, version),
body=FIXTURES.joinpath("poetry-1.0.5-darwin.tar.gz").read_bytes(),
)
command._pool = pool
mocker.patch.object(InstalledRepository, "load", return_value=installed_repository)
tester.execute()
bin_ = Path(tmp_dir).joinpath("bin")
lib = Path(tmp_dir).joinpath("lib")
assert bin_.exists()
script = bin_.joinpath("poetry")
assert script.exists()
expected_script = """\
# -*- coding: utf-8 -*-
import glob
import sys
import os
lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "../..", "lib"))
vendors = os.path.join(lib, "poetry", "_vendor")
current_vendors = os.path.join(
vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2]))
)
sys.path.insert(0, lib)
sys.path.insert(0, current_vendors)
if __name__ == "__main__":
from poetry.console import main
main()
expected_output = """\
Updating Poetry to 1.2.0
Updating dependencies
Resolving dependencies...
Package operations: 0 installs, 2 updates, 0 removals
- Updating cleo (0.8.2 -> 1.0.0)
- Updating poetry (1.2.0a0 -> 1.2.0)
Updating the poetry script
Poetry (1.2.0) is installed now. Great!
"""
if not WINDOWS:
expected_script = "#!/usr/bin/env python\n" + expected_script
assert expected_script == script.read_text()
if WINDOWS:
bat = bin_.joinpath("poetry.bat")
expected_bat = '@echo off\r\npython "{}" %*\r\n'.format(
str(script).replace(os.environ.get("USERPROFILE", ""), "%USERPROFILE%")
)
assert bat.exists()
with bat.open(newline="") as f:
assert expected_bat == f.read()
assert lib.exists()
assert lib.joinpath("poetry").exists()
assert tester.io.fetch_output() == expected_output
def test_self_update_does_not_update_non_recommended_installation(
tester, http, mocker, environ, tmp_venv
):
mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)
command = tester.command
new_version = Version.parse(__version__).next_minor().text
old_poetry = Package("poetry", __version__)
old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))
new_poetry = Package("poetry", new_version)
new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))
installed_repository = Repository()
installed_repository.add_package(old_poetry)
installed_repository.add_package(Package("cleo", "0.8.2"))
repository = Repository()
repository.add_package(new_poetry)
repository.add_package(Package("cleo", "1.0.0"))
pool = Pool()
pool.add_repository(repository)
command._pool = pool
with pytest.raises(PoetrySimpleConsoleException):
tester.execute()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment