Commit d829ee47 authored by Ivan Mazhukin's avatar Ivan Mazhukin

Fix VS Code extension path detection and build

parent 00cd32cb
.vscode/** .vscode/**
.gitignore .gitignore
*.vsix *.vsix
node_modules/**
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
1. Откройте эту папку в VS Code: `vscode-extension`. 1. Откройте эту папку в VS Code: `vscode-extension`.
2. Нажмите `F5`, чтобы запустить Extension Development Host. 2. Нажмите `F5`, чтобы запустить Extension Development Host.
3. В открывшемся окне откройте репозиторий с `epm-docker-test.sh`. 3. В открывшемся окне откройте репозиторий `eepm` или любой его подкаталог.
4. Используйте панель `EPM Test` на боковой панели активности или кнопку `$(beaker) EPM Test` в строке состояния. 4. Используйте панель `EPM Test` на боковой панели активности или кнопку `$(beaker) EPM Test` в строке состояния.
Расширение запускает команды в обычном терминале VS Code, поэтому вывод и интерактивные сообщения остаются видимыми. Расширение запускает команды в обычном терминале VS Code, поэтому вывод и интерактивные сообщения остаются видимыми.
...@@ -26,11 +26,12 @@ rsync -a --delete ./ ~/.vscode/extensions/eter.epm-docker-test-runner-0.1.0/ ...@@ -26,11 +26,12 @@ rsync -a --delete ./ ~/.vscode/extensions/eter.epm-docker-test-runner-0.1.0/
```bash ```bash
cd vscode-extension cd vscode-extension
npm install -g @vscode/vsce npm install
vsce package npm run build
code --install-extension epm-docker-test-runner-0.1.0.vsix npm run package:install
``` ```
Скрипт `npm run build` собирает файл `epm-docker-test-runner.vsix`.
Этот же VSIX можно установить через команду VS Code `Extensions: Install from VSIX...`. Этот же VSIX можно установить через команду VS Code `Extensions: Install from VSIX...`.
## Действия ## Действия
...@@ -78,7 +79,19 @@ code --install-extension epm-docker-test-runner-0.1.0.vsix ...@@ -78,7 +79,19 @@ code --install-extension epm-docker-test-runner-0.1.0.vsix
- `epmDockerTest.defaultMode`: `auto`, `local` или `remote`. - `epmDockerTest.defaultMode`: `auto`, `local` или `remote`.
- `epmDockerTest.latest`: передавать `--latest`. - `epmDockerTest.latest`: передавать `--latest`.
- `epmDockerTest.parallelJobs`: передавать `-j N`, если значение больше `1`. - `epmDockerTest.parallelJobs`: передавать `-j N`, если значение больше `1`.
- `epmDockerTest.localEpmRoot`: локальное дерево eepm для команд `./bin/epm play` вне контейнера. - `epmDockerTest.localEpmRoot`: локальное дерево eepm для команд `./bin/epm play` вне контейнера; если пусто, путь определяется автоматически.
- `epmDockerTest.eepmDir`, `epmDockerTest.eepmSource`, `epmDockerTest.remoteHost`, `epmDockerTest.remoteUser`, `epmDockerTest.builderUser`, `epmDockerTest.builderPath`, `epmDockerTest.logRoot`: соответствуют одноимённым опциям скрипта. - `epmDockerTest.eepmDir`, `epmDockerTest.eepmSource`, `epmDockerTest.remoteHost`, `epmDockerTest.remoteUser`, `epmDockerTest.builderUser`, `epmDockerTest.builderPath`, `epmDockerTest.logRoot`: соответствуют одноимённым опциям скрипта.
Для Docker-тестов автоопределение предпочитает ближайший родительский каталог активного файла, в котором есть и `bin/epm`, и `epm-docker-test.sh`. Этот каталог используется как рабочий каталог команды, а его `epm-docker-test.sh` используется как запускаемый скрипт. ## Автоопределение путей
Если `epmDockerTest.scriptPath` и `epmDockerTest.localEpmRoot` не заданы, расширение ищет ближайший родительский каталог с `bin/epm`:
1. Сначала от активного файла.
2. Затем от корня открытого workspace.
3. Затем от каталога самого расширения в режиме разработки.
Найденный каталог считается корнем репозитория. Из него автоматически берутся:
- `./bin/epm` для команд `Local ./bin/epm play`.
- `./epm-docker-test.sh` для Docker-тестов.
- Рабочий каталог команды, если `epmDockerTest.workingDirectory` не задан.
...@@ -279,20 +279,18 @@ async function runExec() { ...@@ -279,20 +279,18 @@ async function runExec() {
} }
async function runLocalPlay(latest) { async function runLocalPlay(latest) {
const eepmRoot = resolveWorkspacePath(getConfig().get('localEpmRoot', '/home/vano/eter/static2/eepm')); const repoRoot = resolveLocalEpmRoot();
const epm = path.join(eepmRoot, 'bin', 'epm'); if (!repoRoot) {
if (!fs.existsSync(epm)) {
vscode.window.showErrorMessage(`Could not find local epm: ${epm}`);
return; return;
} }
const inferred = inferAppFromActiveEditor(eepmRoot); const inferred = inferAppFromActiveEditor(repoRoot);
const app = await promptForApp({ const app = await promptForApp({
title: latest ? 'Local epm play --latest' : 'Local epm play', title: latest ? 'Local epm play --latest' : 'Local epm play',
prompt: 'Application name for local ./bin/epm play', prompt: 'Application name for local ./bin/epm play',
fallbackKey: 'lastLocalApp', fallbackKey: 'lastLocalApp',
inferred inferred,
repoRoot
}); });
if (!app) { if (!app) {
...@@ -307,7 +305,7 @@ async function runLocalPlay(latest) { ...@@ -307,7 +305,7 @@ async function runLocalPlay(latest) {
const command = [ const command = [
'cd', 'cd',
shellQuote(eepmRoot), shellQuote(repoRoot),
'&&', '&&',
'./bin/epm', './bin/epm',
...args.map(shellQuote) ...args.map(shellQuote)
...@@ -320,7 +318,7 @@ async function runLocalPlay(latest) { ...@@ -320,7 +318,7 @@ async function runLocalPlay(latest) {
} }
async function promptForApp(options) { async function promptForApp(options) {
const inferred = options.inferred || inferAppFromActiveEditor(resolveWorkspacePath(getConfig().get('localEpmRoot', '/home/vano/eter/static2/eepm'))); const inferred = options.inferred || inferAppFromActiveEditor(options.repoRoot || findRepositoryRoot());
const fallback = getWorkspaceState(options.fallbackKey, getWorkspaceState('lastApp', '')); const fallback = getWorkspaceState(options.fallbackKey, getWorkspaceState('lastApp', ''));
const initialValue = inferred?.app || fallback; const initialValue = inferred?.app || fallback;
...@@ -606,13 +604,14 @@ function configuredLogRoot() { ...@@ -606,13 +604,14 @@ function configuredLogRoot() {
function resolvePaths() { function resolvePaths() {
const config = getConfig(); const config = getConfig();
const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; const workspaceFolders = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath) || [];
const workspaceFolder = workspaceFolders[0];
const configuredScript = config.get('scriptPath', '').trim(); const configuredScript = config.get('scriptPath', '').trim();
const configuredCwd = config.get('workingDirectory', '').trim(); const configuredCwd = config.get('workingDirectory', '').trim();
const detectedEepmRoot = configuredCwd ? undefined : findEepmRootFromActiveEditor(); const detectedRepoRoot = configuredCwd ? findParentWithBinEpm(resolveWorkspacePath(configuredCwd)) : findRepositoryRoot();
const script = configuredScript const script = configuredScript
? resolveWorkspacePath(configuredScript) ? resolveWorkspacePath(configuredScript)
: findScript(workspaceFolder, detectedEepmRoot); : findScript(workspaceFolders, detectedRepoRoot);
if (!script || !fs.existsSync(script)) { if (!script || !fs.existsSync(script)) {
vscode.window.showErrorMessage('Could not find epm-docker-test.sh. Set epmDockerTest.scriptPath.'); vscode.window.showErrorMessage('Could not find epm-docker-test.sh. Set epmDockerTest.scriptPath.');
...@@ -621,29 +620,71 @@ function resolvePaths() { ...@@ -621,29 +620,71 @@ function resolvePaths() {
const cwd = configuredCwd const cwd = configuredCwd
? resolveWorkspacePath(configuredCwd) ? resolveWorkspacePath(configuredCwd)
: detectedEepmRoot || workspaceFolder || path.dirname(script); : detectedRepoRoot || workspaceFolder || path.dirname(script);
return { script, cwd }; return { script, cwd };
} }
function findScript(workspaceFolder, detectedEepmRoot) { function findScript(workspaceFolders, detectedRepoRoot) {
const candidates = []; const candidates = [];
if (detectedEepmRoot) { if (detectedRepoRoot) {
candidates.push(path.join(detectedEepmRoot, 'epm-docker-test.sh')); candidates.push(path.join(detectedRepoRoot, 'epm-docker-test.sh'));
} }
if (workspaceFolder) { for (const workspaceFolder of workspaceFolders) {
candidates.push( candidates.push(
path.join(workspaceFolder, 'epm-docker-test.sh'), path.join(workspaceFolder, 'epm-docker-test.sh'),
path.join(workspaceFolder, 'epm-docker-test', 'epm-docker-test.sh') path.join(workspaceFolder, 'epm-docker-test', 'epm-docker-test.sh')
); );
} }
candidates.push(path.resolve(__dirname, '..', 'epm-docker-test.sh')); const extensionRepoRoot = findParentWithBinEpm(__dirname);
if (extensionRepoRoot) {
candidates.push(path.join(extensionRepoRoot, 'epm-docker-test.sh'));
} else {
candidates.push(path.resolve(__dirname, '..', 'epm-docker-test.sh'));
}
return candidates.find((candidate) => fs.existsSync(candidate)); return candidates.find((candidate) => fs.existsSync(candidate));
} }
function findEepmRootFromActiveEditor() { function resolveLocalEpmRoot() {
const editor = vscode.window.activeTextEditor; const configuredRoot = getConfig().get('localEpmRoot', '').trim();
const filePath = editor?.document?.uri?.scheme === 'file' ? editor.document.uri.fsPath : undefined; if (configuredRoot) {
const resolvedRoot = resolveWorkspacePath(configuredRoot);
const epm = path.join(resolvedRoot, 'bin', 'epm');
if (fs.existsSync(epm)) {
return resolvedRoot;
}
vscode.window.showErrorMessage(`Could not find local epm: ${epm}`);
return undefined;
}
const detectedRoot = findRepositoryRoot();
if (detectedRoot) {
return detectedRoot;
}
vscode.window.showErrorMessage('Could not find a repository root with bin/epm. Open the eepm repository or set epmDockerTest.localEpmRoot.');
return undefined;
}
function findRepositoryRoot() {
const candidates = [
getActiveEditorFilePath(),
...(vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath) || []),
__dirname
];
for (const candidate of candidates) {
const root = findParentWithBinEpm(candidate);
if (root) {
return root;
}
}
return undefined;
}
function findParentWithBinEpm(filePath) {
if (!filePath) { if (!filePath) {
return undefined; return undefined;
} }
...@@ -654,11 +695,9 @@ function findEepmRootFromActiveEditor() { ...@@ -654,11 +695,9 @@ function findEepmRootFromActiveEditor() {
} catch { } catch {
return undefined; return undefined;
} }
while (current && current !== path.dirname(current)) { while (current && current !== path.dirname(current)) {
if ( if (fs.existsSync(path.join(current, 'bin', 'epm'))) {
fs.existsSync(path.join(current, 'bin', 'epm')) &&
fs.existsSync(path.join(current, 'epm-docker-test.sh'))
) {
return current; return current;
} }
current = path.dirname(current); current = path.dirname(current);
...@@ -668,8 +707,7 @@ function findEepmRootFromActiveEditor() { ...@@ -668,8 +707,7 @@ function findEepmRootFromActiveEditor() {
} }
function inferAppFromActiveEditor(eepmRoot) { function inferAppFromActiveEditor(eepmRoot) {
const editor = vscode.window.activeTextEditor; const filePath = getActiveEditorFilePath();
const filePath = editor?.document?.uri?.scheme === 'file' ? editor.document.uri.fsPath : undefined;
if (!filePath) { if (!filePath) {
return undefined; return undefined;
} }
...@@ -682,11 +720,16 @@ function inferAppFromActiveEditor(eepmRoot) { ...@@ -682,11 +720,16 @@ function inferAppFromActiveEditor(eepmRoot) {
const baseName = path.basename(filePath, path.extname(filePath)); const baseName = path.basename(filePath, path.extname(filePath));
const parsed = inferAppFromFileContent(filePath); const parsed = inferAppFromFileContent(filePath);
const app = parsed || baseName; const app = parsed || baseName;
const relative = path.relative(eepmRoot, filePath); const relative = eepmRoot ? path.relative(eepmRoot, filePath) : undefined;
const source = relative && !relative.startsWith('..') ? relative : filePath; const source = relative && !relative.startsWith('..') ? relative : filePath;
return { app, source }; return { app, source };
} }
function getActiveEditorFilePath() {
const editor = vscode.window.activeTextEditor;
return editor?.document?.uri?.scheme === 'file' ? editor.document.uri.fsPath : undefined;
}
function inferAppFromFileContent(filePath) { function inferAppFromFileContent(filePath) {
try { try {
const text = fs.readFileSync(filePath, 'utf8').slice(0, 8192); const text = fs.readFileSync(filePath, 'utf8').slice(0, 8192);
......
...@@ -4,9 +4,21 @@ ...@@ -4,9 +4,21 @@
"description": "VS Code buttons for running epm-docker-test.sh test commands.", "description": "VS Code buttons for running epm-docker-test.sh test commands.",
"version": "0.1.0", "version": "0.1.0",
"publisher": "eter", "publisher": "eter",
"repository": {
"type": "git",
"url": "https://gitlab.eterfund.ru/vanomj/epm-docker-test.git"
},
"engines": { "engines": {
"vscode": "^1.85.0" "vscode": "^1.85.0"
}, },
"scripts": {
"build": "npm run package",
"package": "vsce package --no-dependencies --out epm-docker-test-runner.vsix",
"package:install": "code --install-extension ./epm-docker-test-runner.vsix"
},
"devDependencies": {
"@vscode/vsce": "^3.6.1"
},
"categories": [ "categories": [
"Other" "Other"
], ],
...@@ -22,7 +34,7 @@ ...@@ -22,7 +34,7 @@
"onCommand:epmDockerTest.runLocalPlay", "onCommand:epmDockerTest.runLocalPlay",
"onCommand:epmDockerTest.runLocalPlayLatest" "onCommand:epmDockerTest.runLocalPlayLatest"
], ],
"main": "./extension.js", "main": "extension.js",
"contributes": { "contributes": {
"commands": [ "commands": [
{ {
...@@ -76,12 +88,12 @@ ...@@ -76,12 +88,12 @@
"epmDockerTest.scriptPath": { "epmDockerTest.scriptPath": {
"type": "string", "type": "string",
"default": "", "default": "",
"description": "Path to epm-docker-test.sh. Empty means auto-detect in the workspace." "description": "Path to epm-docker-test.sh. Empty means auto-detect it from the nearest repository root with bin/epm."
}, },
"epmDockerTest.workingDirectory": { "epmDockerTest.workingDirectory": {
"type": "string", "type": "string",
"default": "", "default": "",
"description": "Working directory for test commands. Empty means the workspace folder or script directory." "description": "Working directory for test commands. Empty means the detected repository root or the workspace folder."
}, },
"epmDockerTest.defaultSystems": { "epmDockerTest.defaultSystems": {
"type": "string", "type": "string",
...@@ -160,8 +172,8 @@ ...@@ -160,8 +172,8 @@
}, },
"epmDockerTest.localEpmRoot": { "epmDockerTest.localEpmRoot": {
"type": "string", "type": "string",
"default": "/home/vano/eter/static2/eepm", "default": "",
"description": "Path to the local eepm tree used by local ./bin/epm play commands." "description": "Path to the local eepm tree used by local ./bin/epm play commands. Empty means auto-detect the nearest repository root with bin/epm."
}, },
"epmDockerTest.additionalArgs": { "epmDockerTest.additionalArgs": {
"type": "array", "type": "array",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment