Skip to content

Commit ac72230

Browse files
authored
Merge pull request #1037 from marticliment/add-npm
Add npm
2 parents ef5a407 + b8d8ded commit ac72230

File tree

5 files changed

+99
-78
lines changed

5 files changed

+99
-78
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,6 @@ share-component-source/packages/*
9191
wui-1.7.0-console.zip
9292
wui1.7.0-debug2.zip
9393
env/
94-
.vs/*
94+
.vs/*
95+
wingetui/components/package-lock.json
96+
wingetui/components/package.json

wingetui/PackageManagers/npm.py

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66
from .sampleHelper import *
77

88

9-
class ScoopPackageManager(DynamicLoadPackageManager):
9+
class NPMPackageManager(DynamicLoadPackageManager):
1010

1111
ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
1212

1313
EXECUTABLE = "npm"
1414

15-
NAME = "NPM"
15+
NAME = "Npm"
1616
CACHE_FILE = os.path.join(os.path.expanduser("~"), f".wingetui/cacheddata/{NAME}CachedPackages")
1717
CACHE_FILE_PATH = os.path.join(os.path.expanduser("~"), ".wingetui/cacheddata")
1818

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 = []
2222

2323
icon = None
2424

@@ -35,7 +35,7 @@ def getPackagesForQuery(self, query: str) -> list[Package]:
3535
print(f"🔵 Starting {self.NAME} search for dynamic packages")
3636
try:
3737
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)
3939
DashesPassed = False
4040
while p.poll() is None:
4141
line: str = str(p.stdout.readline().strip(), "utf-8", errors="ignore")
@@ -46,9 +46,9 @@ def getPackagesForQuery(self, query: str) -> list[Package]:
4646
else:
4747
package = list(filter(None, line.split("|")))
4848
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()
5252
source = self.NAME
5353
if not name in self.BLACKLISTED_PACKAGE_NAMES and not id in self.BLACKLISTED_PACKAGE_IDS and not version in self.BLACKLISTED_PACKAGE_VERSIONS:
5454
packages.append(Package(name, id, version, source, Npm))
@@ -65,7 +65,7 @@ def getAvailableUpdates(self) -> list[UpgradablePackage]:
6565
print(f"🔵 Starting {self.NAME} search for updates")
6666
try:
6767
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)
6969
DashesPassed = False
7070
while p.poll() is None:
7171
line: str = str(p.stdout.readline().strip(), "utf-8", errors="ignore")
@@ -76,10 +76,10 @@ def getAvailableUpdates(self) -> list[UpgradablePackage]:
7676
else:
7777
package = list(filter(None, line.split(" ")))
7878
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()
8383
source = self.NAME
8484
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:
8585
packages.append(UpgradablePackage(name, id, version, newVersion, source, Npm))
@@ -96,7 +96,8 @@ def getInstalledPackages(self) -> list[Package]:
9696
print(f"🔵 Starting {self.NAME} search for installed packages")
9797
try:
9898
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 = ""
100101
while p.poll() is None:
101102
line: str = str(p.stdout.readline().strip(), "utf-8", errors="ignore")
102103
if line and len(line) > 4:
@@ -105,14 +106,15 @@ def getInstalledPackages(self) -> list[Package]:
105106
package = line.split("@")
106107
if len(package) >= 2:
107108
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()
111112
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)
116118
while p.poll() is None:
117119
line: str = str(p.stdout.readline().strip(), "utf-8", errors="ignore")
118120
if line and len(line) > 4:
@@ -125,9 +127,7 @@ def getInstalledPackages(self) -> list[Package]:
125127
id = idString
126128
version = package[-1].strip()
127129
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))
131131
print(f"🟢 {self.NAME} search for installed packages finished with {len(packages)} result(s)")
132132
return packages
133133
except Exception as e:
@@ -141,37 +141,42 @@ def getPackageDetails(self, package: Package) -> PackageDetails:
141141
print(f"🔵 Starting get info for {package.Name} on {self.NAME}")
142142
details = PackageDetails(package)
143143
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)
151149
output: list[str] = []
152150
while p.poll() is None:
153151
line = p.stdout.readline()
154152
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
156156
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()
175180
print(f"🟢 Get info finished for {package.Name} on {self.NAME}")
176181
return details
177182
except Exception as e:
@@ -183,7 +188,7 @@ def getIcon(self, source: str) -> QIcon:
183188
self.icon = QIcon(getMedia("node"))
184189
return self.icon
185190

186-
def getParameters(self, options: InstallationOptions, removeprogressbar: bool = True) -> list[str]:
191+
def getParameters(self, options: InstallationOptions) -> list[str]:
187192
Parameters: list[str] = []
188193
if options.CustomParameters:
189194
Parameters += options.CustomParameters
@@ -194,19 +199,23 @@ def getParameters(self, options: InstallationOptions, removeprogressbar: bool =
194199
return Parameters
195200

196201
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)
198205
if options.RunAsAdministrator:
199206
Command = [GSUDO_EXECUTABLE] + Command
200207
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)
202209
Thread(target=self.installationThread, args=(p, options, widget,), name=f"{self.NAME} installation thread: installing {package.Name}").start()
203210

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)
206215
if options.RunAsAdministrator:
207216
Command = [GSUDO_EXECUTABLE] + Command
208217
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)
210219
Thread(target=self.installationThread, args=(p, options, widget,), name=f"{self.NAME} installation thread: update {package.Name}").start()
211220

212221
def installationThread(self, p: subprocess.Popen, options: InstallationOptions, widget: InstallationWidgetType):
@@ -227,11 +236,13 @@ def installationThread(self, p: subprocess.Popen, options: InstallationOptions,
227236
widget.finishInstallation.emit(outputCode, output)
228237

229238
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)
231242
if options.RunAsAdministrator:
232243
Command = [GSUDO_EXECUTABLE] + Command
233244
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)
235246
Thread(target=self.uninstallationThread, args=(p, options, widget,), name=f"{self.NAME} installation thread: uninstall {package.Name}").start()
236247

237248
def uninstallationThread(self, p: subprocess.Popen, options: InstallationOptions, widget: InstallationWidgetType):
@@ -263,4 +274,4 @@ def updateSources(self, signal: Signal = None) -> None:
263274
if signal:
264275
signal.emit()
265276

266-
Npm = ScoopPackageManager()
277+
Npm = NPMPackageManager()

wingetui/PackageManagers/pip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .sampleHelper import *
77

88

9-
class ScoopPackageManager(DynamicLoadPackageManager):
9+
class PipPackageManager(DynamicLoadPackageManager):
1010

1111
ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
1212

@@ -254,4 +254,4 @@ def updateSources(self, signal: Signal = None) -> None:
254254
if signal:
255255
signal.emit()
256256

257-
Pip = ScoopPackageManager()
257+
Pip = PipPackageManager()

wingetui/PackageManagers/sampleHelper.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def updateSources(self, signal: Signal = None) -> None:
265265
subprocess.run(f"{self.EXECUTABLE} update self", shell=True, stdout=subprocess.PIPE)
266266
if signal:
267267
signal.emit()
268-
268+
269269
class DynamicLoadPackageManager(SamplePackageManager):
270270

271271
def getAvailablePackages(self, second_attempt: bool = False) -> list[Package]:
@@ -281,6 +281,5 @@ def getPackagesForQuery(self, query: str) -> list[Package]:
281281
"""
282282
raise NotImplementedError("This method must be reimplemented")
283283

284-
285284
if(__name__=="__main__"):
286285
import __init__

0 commit comments

Comments
 (0)