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: ...@@ -72,7 +72,7 @@ You can specify a package in the following forms:
plugins = self.argument("plugins") plugins = self.argument("plugins")
# Plugins should be installed in the system env to be globally available # 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( env_dir = Path(
os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path
......
...@@ -43,7 +43,7 @@ class PluginRemoveCommand(Command): ...@@ -43,7 +43,7 @@ class PluginRemoveCommand(Command):
plugins = self.argument("plugins") plugins = self.argument("plugins")
system_env = EnvManager.get_system_env() system_env = EnvManager.get_system_env(naive=True)
env_dir = Path( env_dir = Path(
os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path
) )
......
...@@ -38,7 +38,7 @@ class PluginShowCommand(Command): ...@@ -38,7 +38,7 @@ class PluginShowCommand(Command):
+ PluginManager("plugin").get_plugin_entry_points() + PluginManager("plugin").get_plugin_entry_points()
) )
system_env = EnvManager.get_system_env() system_env = EnvManager.get_system_env(naive=True)
installed_repository = InstalledRepository.load( installed_repository = InstalledRepository.load(
system_env, with_dependencies=True system_env, with_dependencies=True
) )
......
import os
from pathlib import Path from pathlib import Path
from .utils.appdirs import user_cache_dir from .utils.appdirs import user_cache_dir
...@@ -10,3 +12,10 @@ DATA_DIR = user_data_dir("pypoetry") ...@@ -10,3 +12,10 @@ DATA_DIR = user_data_dir("pypoetry")
CONFIG_DIR = user_config_dir("pypoetry") CONFIG_DIR = user_config_dir("pypoetry")
REPOSITORY_CACHE_DIR = Path(CACHE_DIR) / "cache" / "repositories" 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: ...@@ -595,3 +595,8 @@ class Locker:
data["develop"] = package.develop data["develop"] = package.develop
return data return data
class NullLocker(Locker):
def set_lock_data(self, root: Package, packages: List[Package]) -> bool:
pass
...@@ -996,8 +996,31 @@ class EnvManager: ...@@ -996,8 +996,31 @@ class EnvManager:
shutil.rmtree(str(file_path)) shutil.rmtree(str(file_path))
@classmethod @classmethod
def get_system_env(cls) -> "SystemEnv": def get_system_env(cls, naive: bool = False) -> "SystemEnv":
return SystemEnv(Path(sys.prefix), cls.get_base_prefix()) """
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 @classmethod
def get_base_prefix(cls) -> Path: def get_base_prefix(cls) -> Path:
......
import os
from pathlib import Path from pathlib import Path
import pytest import pytest
from poetry.__version__ import __version__ from poetry.__version__ import __version__
from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.core.packages.package import Package from poetry.core.packages.package import Package
from poetry.core.semver.version import Version 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") FIXTURES = Path(__file__).parent.joinpath("fixtures")
...@@ -18,75 +21,85 @@ def tester(command_tester_factory): ...@@ -18,75 +21,85 @@ def tester(command_tester_factory):
return command_tester_factory("self update") return command_tester_factory("self update")
def test_self_update_should_install_all_necessary_elements( def test_self_update_can_update_from_recommended_installation(
tester, http, mocker, environ, tmp_dir 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 = 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 command._pool = pool
mocker.patch(
"poetry.repositories.pypi_repository.PyPiRepository.find_packages", mocker.patch.object(InstalledRepository, "load", return_value=installed_repository)
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(),
)
tester.execute() tester.execute()
bin_ = Path(tmp_dir).joinpath("bin") expected_output = """\
lib = Path(tmp_dir).joinpath("lib") Updating Poetry to 1.2.0
assert bin_.exists()
Updating dependencies
script = bin_.joinpath("poetry") Resolving dependencies...
assert script.exists()
Package operations: 0 installs, 2 updates, 0 removals
expected_script = """\
# -*- coding: utf-8 -*- - Updating cleo (0.8.2 -> 1.0.0)
import glob - Updating poetry (1.2.0a0 -> 1.2.0)
import sys
import os Updating the poetry script
lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "../..", "lib")) Poetry (1.2.0) is installed now. Great!
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()
""" """
if not WINDOWS:
expected_script = "#!/usr/bin/env python\n" + expected_script assert tester.io.fetch_output() == expected_output
assert expected_script == script.read_text()
def test_self_update_does_not_update_non_recommended_installation(
if WINDOWS: tester, http, mocker, environ, tmp_venv
bat = bin_.joinpath("poetry.bat") ):
expected_bat = '@echo off\r\npython "{}" %*\r\n'.format( mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)
str(script).replace(os.environ.get("USERPROFILE", ""), "%USERPROFILE%")
) command = tester.command
assert bat.exists()
with bat.open(newline="") as f: new_version = Version.parse(__version__).next_minor().text
assert expected_bat == f.read()
old_poetry = Package("poetry", __version__)
assert lib.exists() old_poetry.add_dependency(Factory.create_dependency("cleo", "^0.8.2"))
assert lib.joinpath("poetry").exists()
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