Commit 5b1f55e1 by Sébastien Eustace

Add the self:update command

parent edc9f67b
......@@ -8,6 +8,7 @@
- Added a fallback mechanism for missing dependencies.
- Added the `search` command.
- Added support for local files as dependencies.
- Added the `self:update` command.
### Changes
......
......@@ -28,6 +28,8 @@ from .commands import VersionCommand
from .commands.debug import DebugInfoCommand
from .commands.debug import DebugResolveCommand
from .commands.self import SelfUpdateCommand
class Application(BaseApplication):
......@@ -113,4 +115,9 @@ class Application(BaseApplication):
DebugResolveCommand(),
]
# Self commands
commands += [
SelfUpdateCommand(),
]
return commands
from .update import SelfUpdateCommand
import os
import shutil
import subprocess
import sys
from email.parser import Parser
from functools import cmp_to_key
from ..command import Command
class SelfUpdateCommand(Command):
"""
Updates poetry to the latest version.
self:update
{ version? : The version to update to. }
{ --preview : Install prereleases. }
"""
def handle(self):
from poetry.repositories.pypi_repository import PyPiRepository
from poetry.semver.comparison import less_than
version = self.argument('version')
if not version:
version = '>=' + self.poetry.VERSION
repo = PyPiRepository(fallback=False)
packages = repo.find_packages('poetry', version)
if not packages:
self.line('No release found for the specified version')
return
packages.sort(
key=cmp_to_key(
lambda x, y:
0 if x.version == y.version
else -1 * int(less_than(x.version, y.version) or -1)
)
)
release = None
for package in reversed(packages):
if package.is_prerelease():
if self.option('preview'):
release = package
break
continue
release = package
break
if release is None:
self.line('No new release found')
return
if release.version == self.poetry.VERSION:
self.line('You are using the latest version')
return
try:
self.update(release)
except subprocess.CalledProcessError as e:
self.line('')
self.output.block([
'[CalledProcessError]',
'An error has occured: {}'.format(str(e)),
e.output
], style='error')
return e.returncode
def update(self, release):
from poetry.utils._compat import Path
from poetry.utils.helpers import temporary_directory
version = release.version
self.line('Updating to <info>{}</info>'.format(version))
prefix = sys.prefix
base_prefix = getattr(sys, 'base_prefix', None)
real_prefix = getattr(sys, 'real_prefix', None)
prefix_poetry = Path(prefix) / 'bin' / 'poetry'
if prefix_poetry.exists():
pip = (prefix_poetry.parent / 'pip').resolve()
elif (
base_prefix
and base_prefix != prefix
and (Path(base_prefix) / 'bin' / 'poetry').exists()
):
pip = Path(base_prefix) / 'bin' / 'pip'
elif real_prefix:
pip = Path(real_prefix) / 'bin' / 'pip'
else:
raise RuntimeError('Unable to determine poetry\'s path')
with temporary_directory(prefix='poetry-update-') as temp_dir:
temp_dir = Path(temp_dir)
dist = temp_dir / 'dist'
self.line(' - Getting dependencies')
self.process(
str(pip), 'install', '-U',
'poetry=={}'.format(release.version),
'--target', str(dist)
)
self.line(' - Vendorizing dependencies')
poetry_dir = dist / 'poetry'
vendor_dir = poetry_dir / '_vendor'
# Everything, except poetry itself, should
# be put in the _vendor directory
for file in dist.glob('*'):
if file.name.startswith('poetry'):
continue
dest = vendor_dir / file.name
if file.is_dir():
shutil.copytree(str(file), str(dest))
shutil.rmtree(str(file))
else:
shutil.copy(str(file), str(dest))
os.unlink(str(file))
wheel_data = dist / 'poetry-{}.dist-info'.format(version) / 'WHEEL'
with wheel_data.open() as f:
wheel_data = Parser().parsestr(f.read())
tag = wheel_data['Tag']
# Repack everything and install
self.line(' - Updating <info>poetry</info>')
shutil.make_archive(
str(temp_dir / 'poetry-{}-{}'.format(version, tag)),
format='zip',
root_dir=str(dist)
)
os.rename(
str(temp_dir / 'poetry-{}-{}.zip'.format(version, tag)),
str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag)),
)
self.process(
str(pip),
'install',
'--upgrade',
'--no-deps',
str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag))
)
self.line('')
self.line(
'<info>poetry</> (<comment>{}</>) '
'successfully installed!'.format(
version
)
)
def process(self, *args):
return subprocess.check_output(list(args), stderr=subprocess.STDOUT)
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