diff --git a/CHANGELOG.md b/CHANGELOG.md index c8a9de4..b844b1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to the "pixi-code" extension will be documented in this file The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.1] + +- Fix environment discovery failure when project contains unsupported environments +- Support relative paths and `${workspaceFolder}` in `pixi-code.pixiExecutable` setting +- Add error handling to package manager refresh + ## [0.2.0] - Use published @vscode/python-environments API package diff --git a/README.md b/README.md index f5ba625..f5492e5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The extension will automatically discover Pixi environments and register them wi ## Extension Settings -- `pixi-code.pixiExecutable`: Path to the Pixi executable. Leave empty to use auto-discovery (default). +- `pixi-code.pixiExecutable`: Path to the Pixi executable (supports `${workspaceFolder}` and relative paths). Leave empty to use auto-discovery (default). ## Limitations diff --git a/package-lock.json b/package-lock.json index da1720b..a3b60bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pixi-code", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pixi-code", - "version": "0.2.0", + "version": "0.2.1", "license": "MIT", "dependencies": { "@types/semver": "^7.7.1", @@ -925,9 +925,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.24", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.24.tgz", - "integrity": "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA==", + "version": "2.11.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", + "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -938,16 +938,16 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/braces": { @@ -963,9 +963,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", "dev": true, "funding": [ { @@ -983,11 +983,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" @@ -1004,9 +1004,9 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001791", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", - "integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "dev": true, "funding": [ { @@ -1157,9 +1157,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.345", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.345.tgz", - "integrity": "sha512-F9JXQGiMrz6yVNPI2qOVPvB9HzjH5cGzhs8oJ6A28V5L/YnzN/0KsuiibqF+F1Fd9qxFzD1BUnYSd8JfULxTwg==", + "version": "1.5.433", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.433.tgz", + "integrity": "sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==", "dev": true, "license": "ISC" }, @@ -1504,9 +1504,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -2018,11 +2018,14 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.38", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", - "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", + "version": "2.0.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.56.tgz", + "integrity": "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/optionator": { "version": "0.9.4", @@ -2723,9 +2726,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 0c59232..620d486 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Pixi support for the Python Environments extension", "icon": "assets/icon.png", "license": "MIT", - "version": "0.2.0", + "version": "0.2.1", "homepage": "https://github.com/renan-r-santos/pixi-code", "repository": { "type": "git", diff --git a/src/pixi/projectManager.ts b/src/pixi/projectManager.ts index b76b4a1..96dae29 100644 --- a/src/pixi/projectManager.ts +++ b/src/pixi/projectManager.ts @@ -72,13 +72,16 @@ export class PixiPackageManager implements PackageManager, Disposable { } const projectPath = path.dirname(environment.pixiInfo.project_info.manifest_path); - const pixiPackages = await listPixiPackages(environment.name, projectPath); - - const before = environment.packages; - const after = pixiPkgsToPackages(pixiPackages, environment.envId.id); - - environment.packages = after; - this.triggerOnDidChangePackages(environment, before, after); + try { + const pixiPackages = await listPixiPackages(environment.name, projectPath); + const before = environment.packages; + const after = pixiPkgsToPackages(pixiPackages, environment.envId.id); + + environment.packages = after; + this.triggerOnDidChangePackages(environment, before, after); + } catch (error) { + traceVerbose(`Failed to refresh packages for environment '${environment.name}': ${error}`); + } }, ); } diff --git a/src/pixi/utils.ts b/src/pixi/utils.ts index f49d12e..e5881e3 100644 --- a/src/pixi/utils.ts +++ b/src/pixi/utils.ts @@ -1,5 +1,7 @@ import { Package } from '@vscode/python-environments'; import * as ch from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; import { CancellationError, CancellationToken, ThemeIcon, Uri, window, workspace } from 'vscode'; import which from 'which'; @@ -27,7 +29,21 @@ export async function getPixi(): Promise { const value = config.get('pixiExecutable'); if (value) { - return untildify(value); + let resolved = untildify(value); + if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { + const firstFolder = workspace.workspaceFolders[0].uri.fsPath; + resolved = resolved.replace(/\$\{workspaceFolder\}/g, firstFolder); + if (!path.isAbsolute(resolved)) { + for (const folder of workspace.workspaceFolders) { + const candidate = path.resolve(folder.uri.fsPath, resolved); + if (fs.existsSync(candidate)) { + resolved = candidate; + break; + } + } + } + } + return resolved; } const pixiPath = await findPixi(); @@ -87,7 +103,12 @@ async function _runPixi( export async function runPixi(args: string[], options?: ch.SpawnOptions, token?: CancellationToken): Promise { const pixi = await getPixi(); - return _runPixi(pixi, args, options, token); + const defaultCwd = workspace.workspaceFolders?.[0]?.uri.fsPath; + const spawnOptions: ch.SpawnOptions = { + ...(defaultCwd ? { cwd: defaultCwd } : {}), + ...options, + }; + return _runPixi(pixi, args, spawnOptions, token); } export async function listPixiPackages(envName: string, projectPath: string): Promise { @@ -113,7 +134,14 @@ export async function refreshPixi(projectPath: string): Promise { - const pixiPackages = await listPixiPackages(pixiEnv.name, projectPath); + let pixiPackages: PixiPackage[]; + try { + pixiPackages = await listPixiPackages(pixiEnv.name, projectPath); + } catch (error) { + traceInfo(`Skipping Pixi environment '${pixiEnv.name}': ${error}`); + return null; + } + const pythonPackage = pixiPackages.find((pkg) => pkg.name === 'python'); if (!pythonPackage) {