@camera.ui/common 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.d.ts +12 -0
  2. package/dist/index.js +13 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/logger/index.d.ts +26 -0
  5. package/dist/logger/index.js +92 -0
  6. package/dist/logger/index.js.map +1 -0
  7. package/dist/messaging/index.d.ts +48 -0
  8. package/dist/messaging/index.js +141 -0
  9. package/dist/messaging/index.js.map +1 -0
  10. package/dist/nats/index.d.ts +30 -0
  11. package/dist/nats/index.js +85 -0
  12. package/dist/nats/index.js.map +1 -0
  13. package/dist/network/index.d.ts +12 -0
  14. package/dist/network/index.js +92 -0
  15. package/dist/network/index.js.map +1 -0
  16. package/dist/npm/index.d.ts +4 -0
  17. package/dist/npm/index.js +128 -0
  18. package/dist/npm/index.js.map +1 -0
  19. package/dist/packer/index.d.ts +2 -0
  20. package/dist/packer/index.js +17 -0
  21. package/dist/packer/index.js.map +1 -0
  22. package/dist/python/index.d.ts +48 -0
  23. package/dist/python/index.js +478 -0
  24. package/dist/python/index.js.map +1 -0
  25. package/dist/utils/env.d.ts +5 -0
  26. package/dist/utils/env.js +6 -0
  27. package/dist/utils/env.js.map +1 -0
  28. package/dist/utils/ffmpeg.d.ts +14 -0
  29. package/dist/utils/ffmpeg.js +61 -0
  30. package/dist/utils/ffmpeg.js.map +1 -0
  31. package/dist/utils/index.d.ts +5 -0
  32. package/dist/utils/index.js +6 -0
  33. package/dist/utils/index.js.map +1 -0
  34. package/dist/utils/reader.d.ts +5 -0
  35. package/dist/utils/reader.js +41 -0
  36. package/dist/utils/reader.js.map +1 -0
  37. package/dist/utils/subscribed.d.ts +9 -0
  38. package/dist/utils/subscribed.js +17 -0
  39. package/dist/utils/subscribed.js.map +1 -0
  40. package/dist/utils/utils.js.map +1 -0
  41. package/package.json +60 -10
  42. package/dist/packages/common/src/index.d.ts +0 -1
  43. package/dist/packages/common/src/index.js +0 -2
  44. package/dist/packages/common/src/index.js.map +0 -1
  45. package/dist/server/src/utils/utils.js.map +0 -1
  46. /package/dist/{server/src/utils → utils}/utils.d.ts +0 -0
  47. /package/dist/{server/src/utils → utils}/utils.js +0 -0
@@ -0,0 +1,128 @@
1
+ import fixPath from '@seydx/fix-path';
2
+ import { execSync } from 'node:child_process';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { homedir, platform } from 'node:os';
5
+ import { basename, dirname, join, sep } from 'node:path';
6
+ function isModuleRootDirectory(dir) {
7
+ const packageJsonPath = join(dir, 'package.json');
8
+ if (!existsSync(packageJsonPath)) {
9
+ return false;
10
+ }
11
+ try {
12
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
13
+ return isExpectedPackage(packageJson, dir);
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ function isExpectedPackage(packageJson, dir) {
20
+ const dirName = basename(dir);
21
+ const parentDirName = basename(dirname(dir));
22
+ if (parentDirName.startsWith('@')) {
23
+ return packageJson.name === `${parentDirName}/${dirName}`;
24
+ }
25
+ else {
26
+ return packageJson.name === dirName;
27
+ }
28
+ }
29
+ export function getNpmPath() {
30
+ fixPath();
31
+ if (platform() === 'win32') {
32
+ // if running on windows find the full path to npm
33
+ const windowsNpmPath = [
34
+ join(process.env.APPDATA, 'npm/npm.cmd'),
35
+ join(process.env.ProgramFiles, 'nodejs/npm.cmd'),
36
+ join(process.env.NVM_SYMLINK || process.env.ProgramFiles + '/nodejs', 'npm.cmd'),
37
+ ].filter(existsSync);
38
+ if (windowsNpmPath.length) {
39
+ return [windowsNpmPath[0]];
40
+ }
41
+ }
42
+ else {
43
+ try {
44
+ const npmPath = execSync('which npm').toString().trim();
45
+ return [npmPath];
46
+ }
47
+ catch {
48
+ //
49
+ }
50
+ if (existsSync('/opt/homebridge/bin/npm')) {
51
+ return ['/opt/homebridge/bin/npm'];
52
+ }
53
+ }
54
+ return ['npm'];
55
+ }
56
+ export function getNpmGlobalModulesDirectory() {
57
+ try {
58
+ const npmPath = getNpmPath().join(' ');
59
+ const npmPrefix = execSync(`${npmPath} -g prefix`, {
60
+ env: Object.assign({
61
+ npm_config_loglevel: 'silent',
62
+ npm_update_notifier: 'false',
63
+ }, process.env),
64
+ })
65
+ .toString('utf8')
66
+ .trim();
67
+ return platform() === 'win32' ? join(npmPrefix, 'node_modules') : join(npmPrefix, 'lib', 'node_modules');
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ export function getInstallDir(currentDir, moduleName) {
74
+ const rootDir = dirname(currentDir) === currentDir ? currentDir : sep;
75
+ while (currentDir !== rootDir) {
76
+ if (isModuleRootDirectory(currentDir)) {
77
+ return currentDir;
78
+ }
79
+ currentDir = dirname(currentDir);
80
+ }
81
+ const npmPath = getNpmPath().join(' ');
82
+ const isWindows = platform() === 'win32';
83
+ const isSudo = !isWindows && process.getuid?.() === 0;
84
+ const npmEnv = Object.assign({
85
+ npm_config_loglevel: 'silent',
86
+ npm_update_notifier: 'false',
87
+ }, process.env);
88
+ if (isWindows) {
89
+ const npmPrefix = execSync(`"${npmPath}" -g prefix`, {
90
+ encoding: 'utf8',
91
+ env: npmEnv,
92
+ }).trim();
93
+ return join(npmPrefix, 'node_modules', moduleName);
94
+ }
95
+ else {
96
+ return (execSync(`${isSudo ? 'sudo ' : ''}${npmPath} -g prefix`, {
97
+ encoding: 'utf8',
98
+ env: npmEnv,
99
+ }).trim() + `/lib/node_modules/${moduleName}`);
100
+ }
101
+ }
102
+ export function getUserHomeDir(asUser) {
103
+ const isWindows = platform() === 'win32';
104
+ const user = asUser || process.env.SUDO_USER || process.env.USER;
105
+ if (isWindows) {
106
+ return process.env.USERPROFILE || homedir();
107
+ }
108
+ try {
109
+ if (process.getuid?.() === 0) {
110
+ if (user) {
111
+ const homeDir = execSync(`eval echo ~${user}`, { encoding: 'utf8' }).trim();
112
+ if (homeDir.charAt(0) === '~') {
113
+ throw new Error('Could not resolve user home directory');
114
+ }
115
+ return homeDir;
116
+ }
117
+ }
118
+ else {
119
+ return process.env.HOME || homedir();
120
+ }
121
+ }
122
+ catch {
123
+ // Fallback
124
+ }
125
+ // Fallback
126
+ return homedir();
127
+ }
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/npm/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const pack: (message: any) => Buffer;
2
+ export declare const unpack: <T = any>(message: Buffer | Uint8Array) => T;
@@ -0,0 +1,17 @@
1
+ import { Packr, Unpackr } from 'msgpackr';
2
+ const packr = new Packr({
3
+ useRecords: false,
4
+ encodeUndefinedAsNil: true,
5
+ int64AsType: 'number',
6
+ });
7
+ const unpackr = new Unpackr({
8
+ useRecords: false,
9
+ int64AsType: 'number',
10
+ });
11
+ export const pack = (message) => {
12
+ return packr.pack(message);
13
+ };
14
+ export const unpack = (message) => {
15
+ return unpackr.unpack(message);
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/packer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;IACtB,UAAU,EAAE,KAAK;IACjB,oBAAoB,EAAE,IAAI;IAC1B,WAAW,EAAE,QAAQ;CACtB,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;IAC1B,UAAU,EAAE,KAAK;IACjB,WAAW,EAAE,QAAQ;CACtB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAY,EAAU,EAAE;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAU,OAA4B,EAAK,EAAE;IACjE,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { PortablePython } from '@bjia56/portable-python';
2
+ import { Logger } from '../logger/index.js';
3
+ import type { LoggerOptions } from '../logger/index.js';
4
+ export declare const DEFAULT_PY_VERSION = "3.11";
5
+ export declare class PythonInstaller {
6
+ static readonly versions: string[];
7
+ logger: Logger;
8
+ readonly python: PortablePython;
9
+ readonly venvPath?: string;
10
+ readonly installPath: string;
11
+ private identifier;
12
+ private needsUpdate;
13
+ get isInstalled(): boolean;
14
+ get pluginPythonPath(): string;
15
+ get serverPythonPath(): string;
16
+ get pluginPackagesPath(): string;
17
+ get serverPackagesPath(): string;
18
+ get version(): string;
19
+ private get logPrefix();
20
+ constructor(homePath: string, identifier: string, venvDir?: string, version?: string, loggerOptions?: LoggerOptions);
21
+ install(type: 'plugin' | 'server', requirementsPath?: string): Promise<void>;
22
+ installPluginPython(): Promise<void>;
23
+ uninstall(): Promise<void>;
24
+ updatePluginDependencies(requirementsPath: string): Promise<void>;
25
+ updateServerDependencies(requirementsPath: string): Promise<void>;
26
+ installPluginPackages(pkgs: string[]): Promise<string>;
27
+ installServerPackages(pkgs: string[]): Promise<string>;
28
+ reinstallPluginPackes(pkgs: string[]): Promise<string>;
29
+ reinstallServerPackages(pkgs: string[]): Promise<string>;
30
+ uninstallPluginPackages(pkgs: string[]): Promise<string>;
31
+ uninstallServerPackages(pkgs: string[]): Promise<string>;
32
+ private installPluginRequirements;
33
+ private installServerRequirements;
34
+ private updateRequirements;
35
+ private analyzeDependencies;
36
+ private updateDependencies;
37
+ private installRequirements;
38
+ private installPackages;
39
+ private uninstallPackages;
40
+ private reinstallPackages;
41
+ private ensureVenv;
42
+ private createVenv;
43
+ private removeVenv;
44
+ private removeOldVersions;
45
+ private getMajorMinorVersion;
46
+ private cleanPackageName;
47
+ private difference;
48
+ }
@@ -0,0 +1,478 @@
1
+ import { PortablePython } from '@bjia56/portable-python';
2
+ import { compareVersions } from 'compare-versions';
3
+ import { copy, ensureDir, remove } from 'fs-extra/esm';
4
+ import { exec } from 'node:child_process';
5
+ import { existsSync } from 'node:fs';
6
+ import { readdir, readFile, rm, writeFile } from 'node:fs/promises';
7
+ import { platform } from 'node:os';
8
+ import { dirname, join, resolve } from 'node:path';
9
+ import { createInterface } from 'readline';
10
+ import { Logger } from '../logger/index.js';
11
+ import { IS_ELECTRON } from '../utils/env.js';
12
+ export const DEFAULT_PY_VERSION = '3.11';
13
+ export class PythonInstaller {
14
+ static versions = ['3.12', '3.11', '3.10', '3.9'];
15
+ logger;
16
+ python;
17
+ venvPath;
18
+ installPath;
19
+ identifier;
20
+ needsUpdate = false;
21
+ get isInstalled() {
22
+ return this.python.isInstalled();
23
+ }
24
+ get pluginPythonPath() {
25
+ if (!this.venvPath) {
26
+ throw new Error('Venv path is not defined');
27
+ }
28
+ const binPath = platform() === 'win32' ? 'Scripts' : 'bin';
29
+ return join(this.venvPath, binPath, 'python');
30
+ }
31
+ get serverPythonPath() {
32
+ return this.python.executablePath;
33
+ }
34
+ get pluginPackagesPath() {
35
+ if (!this.venvPath) {
36
+ throw new Error('Venv path is not defined');
37
+ }
38
+ if (platform() === 'win32') {
39
+ return join(this.venvPath, 'Lib', 'site-packages');
40
+ }
41
+ else {
42
+ return join(this.venvPath, 'lib', `python${this.getMajorMinorVersion(this.version)}`, 'site-packages');
43
+ }
44
+ }
45
+ get serverPackagesPath() {
46
+ if (platform() === 'win32') {
47
+ return join(this.python.extractPath, 'Lib', 'site-packages');
48
+ }
49
+ else {
50
+ return join(this.python.extractPath, 'lib', `python${this.getMajorMinorVersion(this.version)}`, 'site-packages');
51
+ }
52
+ }
53
+ get version() {
54
+ return this.python.version;
55
+ }
56
+ get logPrefix() {
57
+ return `${this.identifier}:`;
58
+ }
59
+ constructor(homePath, identifier, venvDir, version = DEFAULT_PY_VERSION, loggerOptions = {}) {
60
+ this.logger = new Logger({ ...loggerOptions, prefix: 'camera.ui', suffix: 'Python Installer' });
61
+ this.identifier = identifier;
62
+ if (!PythonInstaller.versions.includes(version)) {
63
+ version = DEFAULT_PY_VERSION;
64
+ }
65
+ const pythonDir = IS_ELECTRON ? 'python-electron' : 'python';
66
+ this.installPath = `${homePath}/${pythonDir}`;
67
+ this.python = new PortablePython(version, this.installPath);
68
+ if (venvDir) {
69
+ this.venvPath = join(venvDir, `${pythonDir}-${this.getMajorMinorVersion(this.version)}`);
70
+ }
71
+ }
72
+ async install(type, requirementsPath) {
73
+ if (!this.isInstalled) {
74
+ this.logger.trace(this.logPrefix, `Installing Python v${this.version} to ${this.installPath}...`);
75
+ await ensureDir(this.installPath);
76
+ await this.removeOldVersions();
77
+ await this.python.install();
78
+ }
79
+ if (type === 'server') {
80
+ if (!requirementsPath) {
81
+ throw new Error('Requirements path is not defined');
82
+ }
83
+ await this.updateServerDependencies(requirementsPath);
84
+ if (platform() === 'win32') {
85
+ const binPath = dirname(this.serverPythonPath);
86
+ const pythonwPath = join(binPath, 'pythonw.exe');
87
+ if (!existsSync(pythonwPath)) {
88
+ await copy(this.serverPythonPath, pythonwPath);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ async installPluginPython() {
94
+ await this.install('plugin');
95
+ await this.createVenv();
96
+ }
97
+ async uninstall() {
98
+ if (this.isInstalled) {
99
+ await this.python.uninstall();
100
+ }
101
+ await this.removeVenv();
102
+ }
103
+ async updatePluginDependencies(requirementsPath) {
104
+ try {
105
+ await this.ensureVenv();
106
+ const { needsUpdate, requirementsLockPath, requirementsContent, lockContent, updatedLockContent } = await this.updateRequirements(requirementsPath);
107
+ const { reInstall, uninstall } = await this.analyzeDependencies(requirementsContent, lockContent, needsUpdate);
108
+ await this.updateDependencies('plugin', requirementsPath, requirementsContent, reInstall, uninstall);
109
+ if (updatedLockContent) {
110
+ await writeFile(requirementsLockPath, updatedLockContent);
111
+ }
112
+ }
113
+ catch (error) {
114
+ this.logger.error(this.logPrefix, `Failed to update plugin dependencies: ${error.message}`);
115
+ }
116
+ }
117
+ async updateServerDependencies(requirementsPath) {
118
+ try {
119
+ const requirementsLockPath = resolve(join(this.installPath, `requirements-lock-${this.version}.txt`));
120
+ const { needsUpdate, requirementsContent, lockContent, updatedLockContent } = await this.updateRequirements(requirementsPath, requirementsLockPath);
121
+ const { reInstall, uninstall } = await this.analyzeDependencies(requirementsContent, lockContent, needsUpdate);
122
+ await this.updateDependencies('server', requirementsPath, requirementsContent, reInstall, uninstall);
123
+ if (updatedLockContent) {
124
+ await writeFile(requirementsLockPath, updatedLockContent);
125
+ }
126
+ }
127
+ catch (error) {
128
+ this.logger.error(this.logPrefix, `Failed to update server dependencies: ${error.message}`);
129
+ }
130
+ }
131
+ async installPluginPackages(pkgs) {
132
+ await this.ensureVenv();
133
+ return this.installPackages(this.pluginPythonPath, pkgs);
134
+ }
135
+ async installServerPackages(pkgs) {
136
+ return this.installPackages(this.serverPythonPath, pkgs);
137
+ }
138
+ async reinstallPluginPackes(pkgs) {
139
+ await this.ensureVenv();
140
+ return this.reinstallPackages(this.pluginPythonPath, pkgs);
141
+ }
142
+ async reinstallServerPackages(pkgs) {
143
+ return this.reinstallPackages(this.serverPythonPath, pkgs);
144
+ }
145
+ async uninstallPluginPackages(pkgs) {
146
+ await this.ensureVenv();
147
+ return this.uninstallPackages(this.pluginPythonPath, pkgs);
148
+ }
149
+ async uninstallServerPackages(pkgs) {
150
+ return this.uninstallPackages(this.serverPythonPath, pkgs);
151
+ }
152
+ async installPluginRequirements(requirementsPath) {
153
+ return this.installRequirements(this.pluginPythonPath, requirementsPath);
154
+ }
155
+ async installServerRequirements(requirementsPath) {
156
+ return this.installRequirements(this.serverPythonPath, requirementsPath);
157
+ }
158
+ async updateRequirements(requirementsPath, requirementsLockPath) {
159
+ requirementsLockPath = requirementsLockPath || join(dirname(requirementsPath), 'requirements-lock.txt');
160
+ const requirementsContent = await readFile(requirementsPath, 'utf8');
161
+ let lockContent;
162
+ let updatedLockContent;
163
+ let requirementsLockContent = '';
164
+ let lockPythonVersion = '';
165
+ try {
166
+ lockContent = await readFile(requirementsLockPath, 'utf8');
167
+ const lockLines = lockContent.split('\n');
168
+ lockPythonVersion = lockLines[0].replace('# Python version: ', '').trim();
169
+ requirementsLockContent = lockLines.slice(1).join('\n');
170
+ }
171
+ catch {
172
+ //
173
+ }
174
+ const currentPythonVersion = this.version;
175
+ const needsUpdate = requirementsContent !== requirementsLockContent || currentPythonVersion !== lockPythonVersion;
176
+ if (needsUpdate) {
177
+ updatedLockContent = `# Python version: ${currentPythonVersion}\n${requirementsContent}`;
178
+ }
179
+ return { needsUpdate, requirementsLockPath, requirementsContent, lockContent, updatedLockContent };
180
+ }
181
+ async analyzeDependencies(reqContent, reqLockContent, needsUpdate) {
182
+ const requiredPackages = new Set(reqContent
183
+ .split('\n')
184
+ .filter((line) => /^[a-zA-Z]/.test(line))
185
+ .map((line) => this.cleanPackageName(line))
186
+ .filter((line) => line !== ''));
187
+ let oldPackeges = new Set();
188
+ if (reqLockContent) {
189
+ oldPackeges = new Set(reqLockContent
190
+ .split('\n')
191
+ .filter((line) => /^[a-zA-Z]/.test(line))
192
+ .map((line) => this.cleanPackageName(line))
193
+ .filter((line) => line !== ''));
194
+ }
195
+ const toReinstall = [];
196
+ const toUninstall = [...this.difference(oldPackeges, requiredPackages)];
197
+ if (needsUpdate || this.needsUpdate) {
198
+ toReinstall.push(...requiredPackages);
199
+ }
200
+ else {
201
+ toReinstall.push(...this.difference(requiredPackages, oldPackeges));
202
+ }
203
+ return { reInstall: toReinstall, uninstall: toUninstall };
204
+ }
205
+ async updateDependencies(type, requirementsPath, requirementsContent, reInstall = [], uninstall = []) {
206
+ if (uninstall.length > 0) {
207
+ this.logger.trace(this.logPrefix, `Uninstalling ${type} packages: ${uninstall.join(', ')}`);
208
+ if (type === 'plugin') {
209
+ await this.uninstallPluginPackages(uninstall);
210
+ }
211
+ else {
212
+ await this.uninstallServerPackages(uninstall);
213
+ }
214
+ }
215
+ if (reInstall.length > 0) {
216
+ this.logger.trace(this.logPrefix, `Installing ${type} requirements...`);
217
+ if (type === 'plugin') {
218
+ await this.installPluginRequirements(requirementsPath);
219
+ }
220
+ else {
221
+ await this.installServerRequirements(requirementsPath);
222
+ }
223
+ }
224
+ else {
225
+ this.logger.trace(this.logPrefix, `Dependencies for ${type} are up to date`);
226
+ }
227
+ }
228
+ async installRequirements(pythonPath, requirementsPath) {
229
+ const args = [pythonPath, '-m', 'pip', 'install'];
230
+ args.push('--upgrade pip');
231
+ args.push('-r', `"${requirementsPath}"`);
232
+ if ((process.env.SUDO_UID && process.env.SUDO_GID) || process.getuid?.() === 0) {
233
+ args.unshift('sudo', '-H');
234
+ args.push('--root-user-action=ignore');
235
+ }
236
+ args.push('--use-pep517', '--no-warn-script-location');
237
+ const child = exec(args.join(' '), { env: { ...process.env, PIP_DISABLE_PIP_VERSION_CHECK: '1' } });
238
+ const stdoutLine = createInterface({
239
+ input: child.stdout,
240
+ terminal: false,
241
+ });
242
+ const stderrLine = createInterface({
243
+ input: child.stderr,
244
+ terminal: false,
245
+ });
246
+ stdoutLine.on('line', (line) => {
247
+ this.logger.trace(this.logPrefix, line);
248
+ });
249
+ stderrLine.on('line', (line) => {
250
+ this.logger.error(this.logPrefix, line);
251
+ });
252
+ return new Promise((_resolve, _reject) => {
253
+ child.on('close', (code) => {
254
+ stdoutLine.close();
255
+ stderrLine.close();
256
+ if (code === 0) {
257
+ _resolve('Requirements installed');
258
+ }
259
+ else {
260
+ _reject(new Error(`Installation process exited with code ${code}`));
261
+ }
262
+ });
263
+ });
264
+ }
265
+ async installPackages(pythonPath, pkgs) {
266
+ if (pkgs.length === 0)
267
+ return Promise.resolve('');
268
+ const args = [pythonPath, '-m', 'pip', 'install'];
269
+ args.push('--upgrade pip');
270
+ args.push(...pkgs);
271
+ if ((process.env.SUDO_UID && process.env.SUDO_GID) || process.getuid?.() === 0) {
272
+ args.unshift('sudo', '-H');
273
+ args.push('--root-user-action=ignore');
274
+ }
275
+ args.push('--use-pep517', '--no-warn-script-location');
276
+ this.logger.trace(this.logPrefix, `Installing packages command: ${args.join(' ')}`);
277
+ const child = exec(args.join(' '), { env: { ...process.env, PIP_DISABLE_PIP_VERSION_CHECK: '1' } });
278
+ const stdoutLine = createInterface({
279
+ input: child.stdout,
280
+ terminal: false,
281
+ });
282
+ const stderrLine = createInterface({
283
+ input: child.stderr,
284
+ terminal: false,
285
+ });
286
+ stdoutLine.on('line', (line) => {
287
+ this.logger.trace(this.logPrefix, line);
288
+ });
289
+ stderrLine.on('line', (line) => {
290
+ this.logger.error(this.logPrefix, line);
291
+ });
292
+ return new Promise((_resolve, _reject) => {
293
+ child.on('close', (code) => {
294
+ stdoutLine.close();
295
+ stderrLine.close();
296
+ if (code === 0) {
297
+ _resolve('Packages installed');
298
+ }
299
+ else {
300
+ _reject(new Error(`Installation process exited with code ${code}`));
301
+ }
302
+ });
303
+ });
304
+ }
305
+ async uninstallPackages(pythonPath, pkgs) {
306
+ if (pkgs.length === 0)
307
+ return Promise.resolve('');
308
+ const args = [pythonPath, '-m', 'pip', 'uninstall', '-y'];
309
+ args.push(...pkgs);
310
+ if ((process.env.SUDO_UID && process.env.SUDO_GID) || process.getuid?.() === 0) {
311
+ args.unshift('sudo', '-H');
312
+ args.push('--root-user-action=ignore');
313
+ }
314
+ args.push('--no-warn-script-location');
315
+ this.logger.trace(this.logPrefix, `Uninstalling packages command: ${args.join(' ')}`);
316
+ const child = exec(args.join(' '), { env: { ...process.env, PIP_DISABLE_PIP_VERSION_CHECK: '1' } });
317
+ const stdoutLine = createInterface({
318
+ input: child.stdout,
319
+ terminal: false,
320
+ });
321
+ const stderrLine = createInterface({
322
+ input: child.stderr,
323
+ terminal: false,
324
+ });
325
+ stdoutLine.on('line', (line) => {
326
+ this.logger.trace(this.logPrefix, line);
327
+ });
328
+ stderrLine.on('line', (line) => {
329
+ this.logger.error(this.logPrefix, line);
330
+ });
331
+ return new Promise((_resolve, _reject) => {
332
+ child.on('close', (code) => {
333
+ stdoutLine.close();
334
+ stderrLine.close();
335
+ if (code === 0) {
336
+ _resolve('Packages uninstalled');
337
+ }
338
+ else {
339
+ _reject(new Error(`Installation process exited with code ${code}`));
340
+ }
341
+ });
342
+ });
343
+ }
344
+ async reinstallPackages(pythonPath, pkgs) {
345
+ if (pkgs.length === 0)
346
+ return Promise.resolve('');
347
+ const args = [pythonPath, '-m', 'pip', 'install'];
348
+ args.push('--force-reinstall');
349
+ args.push(...pkgs);
350
+ if ((process.env.SUDO_UID && process.env.SUDO_GID) || process.getuid?.() === 0) {
351
+ args.unshift('sudo', '-H');
352
+ args.push('--root-user-action=ignore');
353
+ }
354
+ args.push('--use-pep517', '--no-warn-script-location');
355
+ this.logger.trace(this.logPrefix, `Installing packages command: ${args.join(' ')}`);
356
+ const child = exec(args.join(' '), { env: { ...process.env, PIP_DISABLE_PIP_VERSION_CHECK: '1' } });
357
+ const stdoutLine = createInterface({
358
+ input: child.stdout,
359
+ terminal: false,
360
+ });
361
+ const stderrLine = createInterface({
362
+ input: child.stderr,
363
+ terminal: false,
364
+ });
365
+ stdoutLine.on('line', (line) => {
366
+ this.logger.trace(this.logPrefix, line);
367
+ });
368
+ stderrLine.on('line', (line) => {
369
+ this.logger.error(this.logPrefix, line);
370
+ });
371
+ return new Promise((_resolve, _reject) => {
372
+ child.on('close', (code) => {
373
+ stdoutLine.close();
374
+ stderrLine.close();
375
+ if (code === 0) {
376
+ _resolve('Packages reinstalled');
377
+ }
378
+ else {
379
+ _reject(new Error(`Installation process exited with code ${code}`));
380
+ }
381
+ });
382
+ });
383
+ }
384
+ async ensureVenv() {
385
+ if (!this.venvPath) {
386
+ throw new Error('Venv path is not defined');
387
+ }
388
+ if (!existsSync(this.venvPath)) {
389
+ await this.createVenv();
390
+ }
391
+ }
392
+ async createVenv() {
393
+ if (!this.venvPath) {
394
+ throw new Error('Venv path is not defined');
395
+ }
396
+ if (existsSync(this.venvPath)) {
397
+ return;
398
+ }
399
+ this.needsUpdate = true;
400
+ const args = [this.serverPythonPath, '-m', 'virtualenv', this.venvPath];
401
+ this.logger.trace(this.logPrefix, `Creating venv using virtualenv: ${args.join(' ')}`);
402
+ const child = exec(args.join(' '), { env: { ...process.env, VIRTUALENV_PYTHON: this.serverPythonPath } });
403
+ const stdoutLine = createInterface({
404
+ input: child.stdout,
405
+ terminal: false,
406
+ });
407
+ const stderrLine = createInterface({
408
+ input: child.stderr,
409
+ terminal: false,
410
+ });
411
+ stdoutLine.on('line', (line) => {
412
+ this.logger.trace(this.logPrefix, line);
413
+ });
414
+ stderrLine.on('line', (line) => {
415
+ this.logger.error(this.logPrefix, line);
416
+ });
417
+ return new Promise((_resolve, _reject) => {
418
+ child.on('close', (code) => {
419
+ stdoutLine.close();
420
+ stderrLine.close();
421
+ if (code === 0) {
422
+ _resolve();
423
+ }
424
+ else {
425
+ _reject(new Error(`Virtualenv creation process exited with code ${code}`));
426
+ }
427
+ });
428
+ });
429
+ }
430
+ async removeVenv() {
431
+ if (!this.venvPath) {
432
+ throw new Error('Venv path is not defined');
433
+ }
434
+ await rm(this.venvPath, { recursive: true, force: true });
435
+ const parentDirectory = dirname(this.venvPath);
436
+ const directories = await readdir(parentDirectory, { withFileTypes: true });
437
+ const pythonDirs = directories.filter((dirent) => dirent.isDirectory() && dirent.name.startsWith('python-')).map((dirent) => join(parentDirectory, dirent.name));
438
+ for (const dir of pythonDirs) {
439
+ await rm(dir, { recursive: true, force: true });
440
+ }
441
+ }
442
+ async removeOldVersions() {
443
+ const currentVersion = this.version;
444
+ const pythonDirs = await readdir(this.installPath);
445
+ for (const dir of pythonDirs) {
446
+ const match = dir.match(/^python-(\d+\.\d+(?:\.\d+)?)(.*)$/);
447
+ if (match) {
448
+ const version = match[1];
449
+ const platformSuffix = match[2];
450
+ if (compareVersions(version, currentVersion) === -1) {
451
+ const fullPath = join(this.installPath, `python-${version}${platformSuffix}`);
452
+ const requirementsLockPath = join(this.installPath, `requirements-lock-${version}.txt`);
453
+ this.logger.trace(this.logPrefix, `Removing old Python version: ${version}`);
454
+ await remove(fullPath);
455
+ await remove(requirementsLockPath);
456
+ }
457
+ }
458
+ }
459
+ }
460
+ getMajorMinorVersion(version) {
461
+ const match = version.match(/^(\d+)(?:\.(\d+))?/);
462
+ if (match) {
463
+ const major = match[1];
464
+ const minor = match[2] || '';
465
+ return minor ? `${major}.${minor}` : major;
466
+ }
467
+ return '';
468
+ }
469
+ cleanPackageName(line) {
470
+ const regex = /^([a-zA-Z0-9_-]+)/;
471
+ const match = line.match(regex);
472
+ return match ? match[1] : '';
473
+ }
474
+ difference(setA, setB) {
475
+ return new Set([...setA].filter((x) => !setB.has(x)));
476
+ }
477
+ }
478
+ //# sourceMappingURL=index.js.map