4
4
import os
5
5
import re
6
6
import shutil
7
+ import site
7
8
import stat
8
9
import subprocess
9
10
import sys
16
17
from cleo import option
17
18
18
19
from poetry .core .packages import Dependency
20
+ from poetry .utils ._compat import Path
19
21
20
22
from ..command import Command
21
23
@@ -60,6 +62,10 @@ class SelfUpdateCommand(Command):
60
62
REPOSITORY_URL = "https://github.com/python-poetry/poetry"
61
63
BASE_URL = REPOSITORY_URL + "/releases/download"
62
64
65
+ _data_dir = None
66
+ _bin_dir = None
67
+ _pool = None
68
+
63
69
@property
64
70
def home (self ):
65
71
from poetry .utils ._compat import Path
@@ -78,18 +84,75 @@ def lib(self):
78
84
def lib_backup (self ):
79
85
return self .home / "lib-backup"
80
86
87
+ @property
88
+ def data_dir (self ): # type: () -> Path
89
+ if self ._data_dir is not None :
90
+ return self ._data_dir
91
+
92
+ from poetry .locations import data_dir
93
+
94
+ self ._data_dir = data_dir ()
95
+
96
+ return self ._data_dir
97
+
98
+ @property
99
+ def bin_dir (self ): # type: () -> Path
100
+ if self ._data_dir is not None :
101
+ return self ._data_dir
102
+
103
+ from poetry .utils ._compat import WINDOWS
104
+
105
+ if os .getenv ("POETRY_HOME" ):
106
+ return Path (os .getenv ("POETRY_HOME" ), "bin" ).expanduser ()
107
+
108
+ user_base = site .getuserbase ()
109
+
110
+ if WINDOWS :
111
+ bin_dir = os .path .join (user_base , "Scripts" )
112
+ else :
113
+ bin_dir = os .path .join (user_base , "bin" )
114
+
115
+ self ._bin_dir = Path (bin_dir )
116
+
117
+ return self ._bin_dir
118
+
119
+ @property
120
+ def pool (self ):
121
+ if self ._pool is not None :
122
+ return self ._pool
123
+
124
+ from poetry .repositories .pool import Pool
125
+ from poetry .repositories .pypi_repository import PyPiRepository
126
+
127
+ pool = Pool ()
128
+ pool .add_repository (PyPiRepository (fallback = False ))
129
+
130
+ self ._pool = pool
131
+
132
+ return self ._pool
133
+
81
134
def handle (self ):
82
135
from poetry .__version__ import __version__
83
136
from poetry .core .semver import Version
84
- from poetry .repositories . pypi_repository import PyPiRepository
137
+ from poetry .utils . env import EnvManager
85
138
86
- self ._check_recommended_installation ()
139
+ new_update_method = False
140
+ try :
141
+ self ._check_recommended_installation ()
142
+ except RuntimeError as e :
143
+ env = EnvManager .get_system_env (naive = True )
144
+ try :
145
+ env .path .relative_to (self .data_dir )
146
+ except ValueError :
147
+ raise e
148
+
149
+ new_update_method = True
87
150
88
151
version = self .argument ("version" )
89
152
if not version :
90
153
version = ">=" + __version__
91
154
92
- repo = PyPiRepository ( fallback = False )
155
+ repo = self . pool . repositories [ 0 ]
93
156
packages = repo .find_packages (
94
157
Dependency ("poetry" , version , allows_prereleases = self .option ("preview" ))
95
158
)
@@ -127,6 +190,9 @@ def handle(self):
127
190
self .line ("You are using the latest version" )
128
191
return
129
192
193
+ if new_update_method :
194
+ return self .update_with_new_method (release .version )
195
+
130
196
self .update (release )
131
197
132
198
def update (self , release ):
@@ -165,6 +231,18 @@ def update(self, release):
165
231
)
166
232
)
167
233
234
+ def update_with_new_method (self , version ):
235
+ self .line ("Updating <c1>Poetry</c1> to <c2>{}</c2>" .format (version ))
236
+ self .line ("" )
237
+
238
+ self ._update_with_new_method (version )
239
+ self ._make_bin ()
240
+
241
+ self .line ("" )
242
+ self .line (
243
+ "<c1>Poetry</c1> (<c2>{}</c2>) is installed now. Great!" .format (version )
244
+ )
245
+
168
246
def _update (self , version ):
169
247
from poetry .utils .helpers import temporary_directory
170
248
@@ -235,6 +313,62 @@ def _update(self, version):
235
313
finally :
236
314
gz .close ()
237
315
316
+ def _update_with_new_method (self , version ):
317
+ from poetry .config .config import Config
318
+ from poetry .core .packages .dependency import Dependency
319
+ from poetry .core .packages .project_package import ProjectPackage
320
+ from poetry .installation .installer import Installer
321
+ from poetry .packages .locker import NullLocker
322
+ from poetry .repositories .installed_repository import InstalledRepository
323
+ from poetry .utils .env import EnvManager
324
+
325
+ env = EnvManager .get_system_env ()
326
+ installed = InstalledRepository .load (env )
327
+
328
+ root = ProjectPackage ("poetry-updater" , "0.0.0" )
329
+ root .python_versions = "." .join (str (c ) for c in env .version_info [:3 ])
330
+ root .add_dependency (Dependency ("poetry" , version .text ))
331
+
332
+ installer = Installer (
333
+ self .io ,
334
+ env ,
335
+ root ,
336
+ NullLocker (self .data_dir .joinpath ("poetry.lock" ), {}),
337
+ self .pool ,
338
+ Config (),
339
+ installed = installed ,
340
+ )
341
+ installer .update (True )
342
+ installer .run ()
343
+
344
+ def _make_bin (self ):
345
+ from poetry .utils ._compat import WINDOWS
346
+
347
+ self .line ("" )
348
+ self .line ("Updating the <c1>poetry</c1> script" )
349
+
350
+ self .bin_dir .mkdir (parents = True , exist_ok = True )
351
+
352
+ script = "poetry"
353
+ target_script = "venv/bin/poetry"
354
+ if WINDOWS :
355
+ script = "poetry.exe"
356
+ target_script = "venv/Scripts/poetry.exe"
357
+
358
+ if self .bin_dir .joinpath (script ).exists ():
359
+ self .bin_dir .joinpath (script ).unlink ()
360
+
361
+ try :
362
+ self .bin_dir .joinpath (script ).symlink_to (
363
+ self .data_dir .joinpath (target_script )
364
+ )
365
+ except OSError :
366
+ # This can happen if the user
367
+ # does not have the correct permission on Windows
368
+ shutil .copy (
369
+ self .data_dir .joinpath (target_script ), self .bin_dir .joinpath (script )
370
+ )
371
+
238
372
def process (self , * args ):
239
373
return subprocess .check_output (list (args ), stderr = subprocess .STDOUT )
240
374
0 commit comments