6
6
from .sampleHelper import *
7
7
8
8
9
- class ScoopPackageManager (DynamicLoadPackageManager ):
9
+ class NPMPackageManager (DynamicLoadPackageManager ):
10
10
11
11
ansi_escape = re .compile (r'\x1B\[[0-?]*[ -/]*[@-~]' )
12
12
13
13
EXECUTABLE = "npm"
14
14
15
- NAME = "NPM "
15
+ NAME = "Npm "
16
16
CACHE_FILE = os .path .join (os .path .expanduser ("~" ), f".wingetui/cacheddata/{ NAME } CachedPackages" )
17
17
CACHE_FILE_PATH = os .path .join (os .path .expanduser ("~" ), ".wingetui/cacheddata" )
18
18
19
- BLACKLISTED_PACKAGE_NAMES = ["WARNING:" , "[notice]" , "Package" ]
20
- BLACKLISTED_PACKAGE_IDS = ["WARNING:" , "[notice]" , "Package" ]
21
- BLACKLISTED_PACKAGE_VERSIONS = ["Ignoring" , "invalie" ]
19
+ BLACKLISTED_PACKAGE_NAMES = []
20
+ BLACKLISTED_PACKAGE_IDS = []
21
+ BLACKLISTED_PACKAGE_VERSIONS = []
22
22
23
23
icon = None
24
24
@@ -35,7 +35,7 @@ def getPackagesForQuery(self, query: str) -> list[Package]:
35
35
print (f"🔵 Starting { self .NAME } search for dynamic packages" )
36
36
try :
37
37
packages : list [Package ] = []
38
- p = subprocess .Popen (f"{ self .EXECUTABLE } search { query } " , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .getcwd ( ), env = os .environ .copy (), shell = True )
38
+ p = subprocess .Popen (f"{ self .EXECUTABLE } search { query } " , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .path . expanduser ( "~" ), env = os .environ .copy (), shell = True )
39
39
DashesPassed = False
40
40
while p .poll () is None :
41
41
line : str = str (p .stdout .readline ().strip (), "utf-8" , errors = "ignore" )
@@ -46,9 +46,9 @@ def getPackagesForQuery(self, query: str) -> list[Package]:
46
46
else :
47
47
package = list (filter (None , line .split ("|" )))
48
48
if len (package ) >= 4 :
49
- name = formatPackageIdAsName (package [0 ][1 :] if package [0 ][0 ] == "@" else package [0 ])
50
- id = package [0 ]
51
- version = package [4 ]
49
+ name = formatPackageIdAsName (package [0 ][1 :] if package [0 ][0 ] == "@" else package [0 ]). strip ()
50
+ id = package [0 ]. strip ()
51
+ version = package [4 ]. strip ()
52
52
source = self .NAME
53
53
if not name in self .BLACKLISTED_PACKAGE_NAMES and not id in self .BLACKLISTED_PACKAGE_IDS and not version in self .BLACKLISTED_PACKAGE_VERSIONS :
54
54
packages .append (Package (name , id , version , source , Npm ))
@@ -65,7 +65,7 @@ def getAvailableUpdates(self) -> list[UpgradablePackage]:
65
65
print (f"🔵 Starting { self .NAME } search for updates" )
66
66
try :
67
67
packages : list [UpgradablePackage ] = []
68
- p = subprocess .Popen (f"{ self .EXECUTABLE } outdated" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .getcwd ( ), env = os .environ .copy (), shell = True )
68
+ p = subprocess .Popen (f"{ self .EXECUTABLE } outdated" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .path . expanduser ( "~" ), env = os .environ .copy (), shell = True )
69
69
DashesPassed = False
70
70
while p .poll () is None :
71
71
line : str = str (p .stdout .readline ().strip (), "utf-8" , errors = "ignore" )
@@ -76,10 +76,10 @@ def getAvailableUpdates(self) -> list[UpgradablePackage]:
76
76
else :
77
77
package = list (filter (None , line .split (" " )))
78
78
if len (package ) >= 4 :
79
- name = formatPackageIdAsName (package [0 ][1 :] if package [0 ][0 ] == "@" else package [0 ])
80
- id = package [0 ]
81
- version = package [1 ]
82
- newVersion = package [3 ]
79
+ name = formatPackageIdAsName (package [0 ][1 :] if package [0 ][0 ] == "@" else package [0 ]). strip ()
80
+ id = package [0 ]. strip ()
81
+ version = package [1 ]. strip ()
82
+ newVersion = package [3 ]. strip ()
83
83
source = self .NAME
84
84
if not name in self .BLACKLISTED_PACKAGE_NAMES and not id in self .BLACKLISTED_PACKAGE_IDS and not version in self .BLACKLISTED_PACKAGE_VERSIONS and not newVersion in self .BLACKLISTED_PACKAGE_VERSIONS :
85
85
packages .append (UpgradablePackage (name , id , version , newVersion , source , Npm ))
@@ -96,7 +96,8 @@ def getInstalledPackages(self) -> list[Package]:
96
96
print (f"🔵 Starting { self .NAME } search for installed packages" )
97
97
try :
98
98
packages : list [Package ] = []
99
- p = subprocess .Popen (f"{ self .EXECUTABLE } list" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .getcwd (), env = os .environ .copy (), shell = True )
99
+ p = subprocess .Popen (f"{ self .EXECUTABLE } list" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .path .expanduser ("~" ), env = os .environ .copy (), shell = True )
100
+ currentScope = ""
100
101
while p .poll () is None :
101
102
line : str = str (p .stdout .readline ().strip (), "utf-8" , errors = "ignore" )
102
103
if line and len (line ) > 4 :
@@ -105,14 +106,15 @@ def getInstalledPackages(self) -> list[Package]:
105
106
package = line .split ("@" )
106
107
if len (package ) >= 2 :
107
108
idString = '@' .join (package [:- 1 ]).strip ()
108
- name = formatPackageIdAsName (idString [1 :] if idString [0 ] == "@" else idString )
109
- id = idString
110
- version = package [- 1 ]
109
+ name = formatPackageIdAsName (idString [1 :] if idString [0 ] == "@" else idString ). strip ()
110
+ id = idString . strip ()
111
+ version = package [- 1 ]. strip ()
111
112
if not name in self .BLACKLISTED_PACKAGE_NAMES and not id in self .BLACKLISTED_PACKAGE_IDS and not version in self .BLACKLISTED_PACKAGE_VERSIONS :
112
- packages .append (Package (name , id , version , self .NAME , Npm ))
113
- else :
114
- print (line )
115
- p = subprocess .Popen (f"{ self .EXECUTABLE } list -g" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .getcwd (), env = os .environ .copy (), shell = True )
113
+ packages .append (Package (name , id , version , self .NAME + currentScope , Npm ))
114
+ elif "@" in line .split (" " )[0 ]:
115
+ currentScope = "@" + line .split (" " )[0 ][:- 1 ]
116
+ print ("🔵 NPM changed scope to" , currentScope )
117
+ p = subprocess .Popen (f"{ self .EXECUTABLE } list -g" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .path .expanduser ("~" ), env = os .environ .copy (), shell = True )
116
118
while p .poll () is None :
117
119
line : str = str (p .stdout .readline ().strip (), "utf-8" , errors = "ignore" )
118
120
if line and len (line ) > 4 :
@@ -125,9 +127,7 @@ def getInstalledPackages(self) -> list[Package]:
125
127
id = idString
126
128
version = package [- 1 ].strip ()
127
129
if not name in self .BLACKLISTED_PACKAGE_NAMES and not id in self .BLACKLISTED_PACKAGE_IDS and not version in self .BLACKLISTED_PACKAGE_VERSIONS :
128
- packages .append (Package (name , id , version , self .NAME , Npm ))
129
- else :
130
- print (line )
130
+ packages .append (Package (name , id , version , self .NAME + "@global" , Npm ))
131
131
print (f"🟢 { self .NAME } search for installed packages finished with { len (packages )} result(s)" )
132
132
return packages
133
133
except Exception as e :
@@ -141,37 +141,42 @@ def getPackageDetails(self, package: Package) -> PackageDetails:
141
141
print (f"🔵 Starting get info for { package .Name } on { self .NAME } " )
142
142
details = PackageDetails (package )
143
143
try :
144
- details .ManifestUrl = f"https://pypi.org/project/{ package .Id } /"
145
- details .ReleaseNotesUrl = f"https://pypi.org/project/{ package .Id } /#history"
146
- details .InstallerURL = f"https://pypi.org/project/{ package .Id } /#files"
147
- details .Scopes = [_ ("User" )]
148
- details .InstallerType = "NPM"
149
-
150
- p = subprocess .Popen (f"{ self .EXECUTABLE } show { package .Id } -v" , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .getcwd (), env = os .environ , shell = True )
144
+ details .InstallerType = "Tarball"
145
+ details .ManifestUrl = f"https://www.npmjs.com/package/{ package .Id } "
146
+ details .ReleaseNotesUrl = f"https://www.npmjs.com/package/{ package .Id } ?activeTab=versions"
147
+ details .Scopes = ["Global" ]
148
+ p = subprocess .Popen (f"{ self .EXECUTABLE } info { package .Id } " , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , cwd = os .path .expanduser ("~" ), env = os .environ , shell = True )
151
149
output : list [str ] = []
152
150
while p .poll () is None :
153
151
line = p .stdout .readline ()
154
152
if line :
155
- output .append (str (line , encoding = 'utf-8' , errors = "ignore" ))
153
+ output .append (str (line , encoding = 'utf-8' , errors = "ignore" ).strip ())
154
+ lineNo = 0
155
+ ReadingMaintainer = False
156
156
for line in output :
157
- if "Name:" in line :
158
- details .Name = formatPackageIdAsName (line .replace ("Name:" , "" ).strip ()) if "-" in line else line .replace ("Name:" , "" ).strip ()
159
- elif "Author:" in line :
160
- details .Author = line .replace ("Author:" , "" ).strip ()
161
- elif "Home-page:" in line :
162
- details .HomepageURL = line .replace ("Home-page:" , "" ).strip ()
163
- elif "License:" in line :
164
- details .License = line .replace ("License:" , "" ).strip ()
165
- elif "License ::" in line :
166
- details .License = line .split ("::" )[- 1 ].strip ()
167
- elif "Summary:" in line :
168
- details .Description = line .replace ("Summary:" , "" ).strip ()
169
- elif "Release Notes" in line :
170
- details .ReleaseNotesUrl = line .replace ("Release Notes:" , "" ).strip ()
171
- elif "Topic ::" in line :
172
- if line .split ("::" )[- 1 ].strip () not in details .Tags :
173
- details .Tags .append (line .split ("::" )[- 1 ].strip ())
174
-
157
+ lineNo += 1
158
+ if lineNo == 2 :
159
+ details .License = line .split ("|" )[1 ]
160
+ elif lineNo == 3 :
161
+ details .Description = line .strip ()
162
+ elif line == 4 :
163
+ details .HomepageURL = line .strip ()
164
+ elif line .startswith (".tarball" ):
165
+ details .InstallerURL = line .replace (".tarball: " , "" ).strip ()
166
+ try :
167
+ details .InstallerSize = int (urlopen (details .InstallerURL ).length / 1000000 )
168
+ except Exception as e :
169
+ print ("🟠 Can't get installer size:" , type (e ), str (e ))
170
+ elif line .startswith (".integrity" ):
171
+ details .InstallerHash = "<br>" + line .replace (".integrity: sha512-" , "" ).replace ("==" , "" ).strip ()
172
+ elif line .startswith ("maintainers:" ):
173
+ ReadingMaintainer = True
174
+ elif ReadingMaintainer :
175
+ ReadingMaintainer = False
176
+ details .Author = line .replace ("-" , "" ).split ("<" )[0 ].strip ()
177
+ elif line .startswith ("published" ):
178
+ details .Publisher = line .split ("by" )[- 1 ].split ("<" )[0 ].strip ()
179
+ details .UpdateDate = line .split ("by" )[0 ].replace ("published" , "" ).strip ()
175
180
print (f"🟢 Get info finished for { package .Name } on { self .NAME } " )
176
181
return details
177
182
except Exception as e :
@@ -183,7 +188,7 @@ def getIcon(self, source: str) -> QIcon:
183
188
self .icon = QIcon (getMedia ("node" ))
184
189
return self .icon
185
190
186
- def getParameters (self , options : InstallationOptions , removeprogressbar : bool = True ) -> list [str ]:
191
+ def getParameters (self , options : InstallationOptions ) -> list [str ]:
187
192
Parameters : list [str ] = []
188
193
if options .CustomParameters :
189
194
Parameters += options .CustomParameters
@@ -194,19 +199,23 @@ def getParameters(self, options: InstallationOptions, removeprogressbar: bool =
194
199
return Parameters
195
200
196
201
def startInstallation (self , package : Package , options : InstallationOptions , widget : InstallationWidgetType ) -> subprocess .Popen :
197
- Command = [self .EXECUTABLE , "install" , package .Id ] + self .getParameters (options )
202
+ if "@global" in package .Source :
203
+ options .InstallationScope = "Global"
204
+ Command = ["cmd.exe" , "/C" , self .EXECUTABLE , "install" , package .Id + "@latest" ] + self .getParameters (options )
198
205
if options .RunAsAdministrator :
199
206
Command = [GSUDO_EXECUTABLE ] + Command
200
207
print (f"🔵 Starting { package } installation with Command" , Command )
201
- p = subprocess .Popen (Command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = GSUDO_EXE_LOCATION , env = os .environ )
208
+ p = subprocess .Popen (Command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = os . path . expanduser ( "~" ) , env = os .environ )
202
209
Thread (target = self .installationThread , args = (p , options , widget ,), name = f"{ self .NAME } installation thread: installing { package .Name } " ).start ()
203
210
204
- def startUpdate (self , package : Package , options : InstallationOptions , widget : InstallationWidgetType ) -> subprocess .Popen :
205
- Command = [self .EXECUTABLE , "update" , package .Id ] + self .getParameters (options )
211
+ def startUpdate (self , package : UpgradablePackage , options : InstallationOptions , widget : InstallationWidgetType ) -> subprocess .Popen :
212
+ if "@global" in package .Source :
213
+ options .InstallationScope = "Global"
214
+ Command = ["cmd.exe" , "/C" , self .EXECUTABLE , "install" , package .Id + "@" + package .NewVersion ] + self .getParameters (options )
206
215
if options .RunAsAdministrator :
207
216
Command = [GSUDO_EXECUTABLE ] + Command
208
217
print (f"🔵 Starting { package } update with Command" , Command )
209
- p = subprocess .Popen (Command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = GSUDO_EXE_LOCATION , env = os .environ )
218
+ p = subprocess .Popen (Command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = os . path . expanduser ( "~" ) , env = os .environ )
210
219
Thread (target = self .installationThread , args = (p , options , widget ,), name = f"{ self .NAME } installation thread: update { package .Name } " ).start ()
211
220
212
221
def installationThread (self , p : subprocess .Popen , options : InstallationOptions , widget : InstallationWidgetType ):
@@ -227,11 +236,13 @@ def installationThread(self, p: subprocess.Popen, options: InstallationOptions,
227
236
widget .finishInstallation .emit (outputCode , output )
228
237
229
238
def startUninstallation (self , package : Package , options : InstallationOptions , widget : InstallationWidgetType ) -> subprocess .Popen :
230
- Command = [self .EXECUTABLE , "uninstall" , package .Id , "-y" ] + self .getParameters (options , removeprogressbar = False )
239
+ if "@global" in package .Source :
240
+ options .InstallationScope = "Global"
241
+ Command = [self .EXECUTABLE , "uninstall" , ] + self .getParameters (options )
231
242
if options .RunAsAdministrator :
232
243
Command = [GSUDO_EXECUTABLE ] + Command
233
244
print (f"🔵 Starting { package } uninstall with Command" , Command )
234
- p = subprocess .Popen (Command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = GSUDO_EXE_LOCATION , env = os .environ )
245
+ p = subprocess .Popen (" " . join ( Command ) , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , stdin = subprocess .PIPE , shell = True , cwd = os . path . expanduser ( "~" ) , env = os .environ )
235
246
Thread (target = self .uninstallationThread , args = (p , options , widget ,), name = f"{ self .NAME } installation thread: uninstall { package .Name } " ).start ()
236
247
237
248
def uninstallationThread (self , p : subprocess .Popen , options : InstallationOptions , widget : InstallationWidgetType ):
@@ -263,4 +274,4 @@ def updateSources(self, signal: Signal = None) -> None:
263
274
if signal :
264
275
signal .emit ()
265
276
266
- Npm = ScoopPackageManager ()
277
+ Npm = NPMPackageManager ()
0 commit comments