feat(ide): new IDE support
This commit is contained in:
+150
-100
@@ -11,40 +11,49 @@ var { cloneWithFallback, cleanupTemp } = require('../utils/git');
|
|||||||
var SSH_URL = 'ssh://git@git.davinti.com.br:2222/davinTI/ide-config.git';
|
var SSH_URL = 'ssh://git@git.davinti.com.br:2222/davinTI/ide-config.git';
|
||||||
var HTTPS_URL = 'https://git.davinti.com.br/davinTI/ide-config.git';
|
var HTTPS_URL = 'https://git.davinti.com.br/davinTI/ide-config.git';
|
||||||
|
|
||||||
var SUPPORTED_IDES = ['vscode'];
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the VSCode User snippets directory for the current OS.
|
* Resolves the snippets directory for a vscode-fork IDE entry.
|
||||||
* Linux/macOS: ~/.config/Code/User/snippets/
|
* Linux base: ~/. Windows base: %APPDATA%\
|
||||||
* Windows: %APPDATA%\Code\User\snippets\
|
|
||||||
*/
|
*/
|
||||||
function getSnippetsDir() {
|
function resolveSnippetsDir(ideEntry) {
|
||||||
if (process.platform === 'win32') {
|
var platform = process.platform === 'win32' ? 'win32' : 'linux';
|
||||||
|
var rel = ideEntry.snippetsDir[platform];
|
||||||
|
if (!rel) throw new Error('snippetsDir not defined for platform ' + platform);
|
||||||
|
if (platform === 'win32') {
|
||||||
var appData = process.env.APPDATA;
|
var appData = process.env.APPDATA;
|
||||||
if (!appData) {
|
if (!appData) throw new Error('APPDATA environment variable is not set.');
|
||||||
throw new Error('APPDATA environment variable is not set.');
|
return path.join(appData, rel);
|
||||||
}
|
}
|
||||||
return path.join(appData, 'Code', 'User', 'snippets');
|
return path.join(os.homedir(), rel);
|
||||||
}
|
|
||||||
return path.join(os.homedir(), '.config', 'Code', 'User', 'snippets');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the `code` CLI binary name for the current OS.
|
* Returns all existing JetBrains config directories.
|
||||||
* Windows ships it as `code.cmd` on PATH.
|
* Linux: ~/.config/JetBrains/<product><version>/
|
||||||
|
* Windows: %APPDATA%\JetBrains\<product><version>\
|
||||||
*/
|
*/
|
||||||
function getCodeBin() {
|
function findJetBrainsDirs() {
|
||||||
return process.platform === 'win32' ? 'code.cmd' : 'code';
|
var base;
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
base = path.join(process.env.APPDATA || '', 'JetBrains');
|
||||||
|
} else {
|
||||||
|
base = path.join(os.homedir(), '.config', 'JetBrains');
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(base)) return [];
|
||||||
|
return fs.readdirSync(base)
|
||||||
|
.map(function (name) { return path.join(base, name); })
|
||||||
|
.filter(function (p) { return fs.statSync(p).isDirectory(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a VSCode extension is currently installed.
|
* Checks whether a VSCode-fork extension is currently installed by listing
|
||||||
* Returns true/false. Fails silently (returns false) if `code` is unavailable.
|
* extensions via the IDE's own CLI. Returns true/false; fails silently.
|
||||||
*/
|
*/
|
||||||
function isExtensionInstalled(extensionId) {
|
function isExtensionInstalled(bin, extensionId) {
|
||||||
try {
|
try {
|
||||||
var codeBin = getCodeBin();
|
var output = execSync(bin + ' --list-extensions', { stdio: 'pipe' }).toString();
|
||||||
var output = execSync(codeBin + ' --list-extensions', { stdio: 'pipe' }).toString();
|
|
||||||
return output.split('\n').some(function (line) {
|
return output.split('\n').some(function (line) {
|
||||||
return line.trim().toLowerCase() === extensionId.toLowerCase();
|
return line.trim().toLowerCase() === extensionId.toLowerCase();
|
||||||
});
|
});
|
||||||
@@ -54,54 +63,126 @@ function isExtensionInstalled(extensionId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a .vsix file using the `code` CLI.
|
* Prompts the user to select an IDE from the manifest.
|
||||||
* Always passes --force so it also updates an already-installed extension.
|
* Returns the selected IDE key string.
|
||||||
*/
|
*/
|
||||||
function installVsix(vsixPath) {
|
function promptIde(ideKeys, manifest) {
|
||||||
var codeBin = getCodeBin();
|
|
||||||
execSync(codeBin + ' --install-extension "' + vsixPath + '" --force', { stdio: 'inherit' });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to pick an IDE from a numbered list.
|
|
||||||
* Resolves with the chosen IDE string.
|
|
||||||
*/
|
|
||||||
function promptIde() {
|
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('IDEs disponíveis:');
|
console.log('IDEs disponíveis:');
|
||||||
SUPPORTED_IDES.forEach(function (ide, i) {
|
ideKeys.forEach(function (key, i) {
|
||||||
console.log(' ' + (i + 1) + '. ' + ide);
|
console.log(' ' + (i + 1) + '. ' + manifest[key].label + ' (' + key + ')');
|
||||||
});
|
});
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
rl.question('Escolha a IDE [1]: ', function (answer) {
|
rl.question('Escolha a IDE [1]: ', function (answer) {
|
||||||
rl.close();
|
rl.close();
|
||||||
var trimmed = answer.trim();
|
var trimmed = answer.trim();
|
||||||
var index;
|
var index = (trimmed === '' || trimmed === '1') ? 0 : parseInt(trimmed, 10) - 1;
|
||||||
if (trimmed === '' || trimmed === '1') {
|
if (isNaN(index) || index < 0 || index >= ideKeys.length) {
|
||||||
index = 0;
|
|
||||||
} else {
|
|
||||||
index = parseInt(trimmed, 10) - 1;
|
|
||||||
}
|
|
||||||
if (isNaN(index) || index < 0 || index >= SUPPORTED_IDES.length) {
|
|
||||||
console.error('Opção inválida: ' + trimmed);
|
console.error('Opção inválida: ' + trimmed);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
resolve(SUPPORTED_IDES[index]);
|
resolve(ideKeys[index]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Installers ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function installVscodeFork(ideEntry, repoRoot) {
|
||||||
|
var platform = process.platform === 'win32' ? 'win32' : 'linux';
|
||||||
|
var bin = ideEntry.bin[platform];
|
||||||
|
|
||||||
|
// Extension
|
||||||
|
if (ideEntry.extension) {
|
||||||
|
var vsixPath = path.join(repoRoot, ideEntry.extension);
|
||||||
|
if (!fs.existsSync(vsixPath)) {
|
||||||
|
console.log('Aviso: arquivo de extensão não encontrado em ' + vsixPath + '. Pulando extensão.');
|
||||||
|
} else {
|
||||||
|
var extId = path.basename(vsixPath, '.vsix');
|
||||||
|
var alreadyInstalled = isExtensionInstalled(bin, extId);
|
||||||
|
console.log((alreadyInstalled ? 'Atualizando' : 'Instalando') + ' extensão ' + extId + '...');
|
||||||
|
try {
|
||||||
|
execSync(bin + ' --install-extension "' + vsixPath + '" --force', { stdio: 'inherit' });
|
||||||
|
console.log('Extensão instalada com sucesso.');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Erro ao instalar a extensão: ' + e.message);
|
||||||
|
console.error('Certifique-se de que o comando "' + bin + '" está disponível no PATH.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snippets
|
||||||
|
if (ideEntry.snippets) {
|
||||||
|
var snippetsSrc = path.join(repoRoot, ideEntry.snippets);
|
||||||
|
if (!fs.existsSync(snippetsSrc)) {
|
||||||
|
console.log('Aviso: arquivo de snippets não encontrado em ' + snippetsSrc + '. Pulando snippets.');
|
||||||
|
} else {
|
||||||
|
var snippetsDir;
|
||||||
|
try {
|
||||||
|
snippetsDir = resolveSnippetsDir(ideEntry);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Erro ao determinar diretório de snippets: ' + e.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
fse.ensureDirSync(snippetsDir);
|
||||||
|
var snippetFile = path.basename(snippetsSrc);
|
||||||
|
var snippetDest = path.join(snippetsDir, snippetFile);
|
||||||
|
var action = fs.existsSync(snippetDest) ? 'atualizado' : 'instalado';
|
||||||
|
fse.copySync(snippetsSrc, snippetDest);
|
||||||
|
console.log('Snippet ' + snippetFile + ' ' + action + ' em ' + snippetDest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function installJetBrains(ideEntry, repoRoot) {
|
||||||
|
if (!ideEntry.templates) {
|
||||||
|
console.log('Aviso: nenhum arquivo de templates definido para JetBrains. Pulando.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var templatesSrc = path.join(repoRoot, ideEntry.templates);
|
||||||
|
if (!fs.existsSync(templatesSrc)) {
|
||||||
|
console.log('Aviso: arquivo de templates não encontrado em ' + templatesSrc + '. Pulando.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jbDirs = findJetBrainsDirs();
|
||||||
|
if (jbDirs.length === 0) {
|
||||||
|
console.log('Nenhuma instalação do JetBrains encontrada no sistema.');
|
||||||
|
console.log('Copie manualmente o arquivo abaixo para o diretório "templates" da sua IDE:');
|
||||||
|
console.log(' ' + templatesSrc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var templateFile = path.basename(templatesSrc);
|
||||||
|
var installed = 0;
|
||||||
|
jbDirs.forEach(function (jbDir) {
|
||||||
|
var templatesDir = path.join(jbDir, 'templates');
|
||||||
|
fse.ensureDirSync(templatesDir);
|
||||||
|
var dest = path.join(templatesDir, templateFile);
|
||||||
|
var action = fs.existsSync(dest) ? 'atualizado' : 'instalado';
|
||||||
|
fse.copySync(templatesSrc, dest);
|
||||||
|
console.log(' ' + path.basename(jbDir) + ' — templates ' + action);
|
||||||
|
installed++;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(installed + ' instalação(ões) JetBrains atualizada(s).');
|
||||||
|
console.log('Reinicie sua IDE para carregar os novos templates.');
|
||||||
|
console.log('');
|
||||||
|
console.log('Nota: a instalação do plugin Vitruvio para JetBrains deve ser feita manualmente.');
|
||||||
|
console.log('Acesse Settings → Plugins → Install Plugin from Disk e selecione o arquivo .jar.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Command ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function register(program) {
|
function register(program) {
|
||||||
program
|
program
|
||||||
.command('update-ide')
|
.command('update-ide')
|
||||||
.description('Instala ou atualiza a extensão Vitruvio e os snippets na IDE escolhida')
|
.description('Instala ou atualiza a extensão Vitruvio e os snippets na IDE escolhida')
|
||||||
.action(function () {
|
.action(function () {
|
||||||
promptIde().then(function (ide) {
|
|
||||||
console.log('IDE selecionada: ' + ide);
|
|
||||||
console.log('Buscando repositório ide-config...');
|
console.log('Buscando repositório ide-config...');
|
||||||
|
|
||||||
var tmpDir = null;
|
var tmpDir = null;
|
||||||
@@ -113,72 +194,41 @@ function register(program) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var manifest;
|
||||||
try {
|
try {
|
||||||
var ideDir = path.join(tmpDir, ide); // e.g. <tmp>/vscode
|
var manifestPath = path.join(tmpDir, 'ide-manifest.json');
|
||||||
|
if (!fs.existsSync(manifestPath)) {
|
||||||
if (!fs.existsSync(ideDir)) {
|
throw new Error('ide-manifest.json não encontrado no repositório ide-config.');
|
||||||
console.error('Erro: diretório "' + ide + '" não encontrado no repositório ide-config.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
||||||
// ── Extension ─────────────────────────────────────────────────────
|
|
||||||
var vsixFiles = fs.readdirSync(ideDir).filter(function (f) {
|
|
||||||
return f.endsWith('.vsix');
|
|
||||||
});
|
|
||||||
|
|
||||||
if (vsixFiles.length === 0) {
|
|
||||||
console.log('Aviso: nenhum arquivo .vsix encontrado em ' + ideDir + '. Pulando extensão.');
|
|
||||||
} else {
|
|
||||||
var vsixFile = vsixFiles[0];
|
|
||||||
var vsixPath = path.join(ideDir, vsixFile);
|
|
||||||
|
|
||||||
// Derive extension ID from the vsix filename (publisher.name.vsix → publisher.name)
|
|
||||||
var extId = vsixFile.replace(/\.vsix$/i, '');
|
|
||||||
var alreadyInstalled = isExtensionInstalled(extId);
|
|
||||||
|
|
||||||
if (alreadyInstalled) {
|
|
||||||
console.log('Extensão já instalada, atualizando ' + extId + '...');
|
|
||||||
} else {
|
|
||||||
console.log('Instalando extensão ' + extId + '...');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
installVsix(vsixPath);
|
|
||||||
console.log('Extensão instalada com sucesso.');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Erro ao instalar a extensão: ' + e.message);
|
cleanupTemp(tmpDir);
|
||||||
console.error('Certifique-se de que o comando "code" está disponível no PATH.');
|
console.error('Erro ao ler o manifesto de IDEs: ' + e.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ideKeys = Object.keys(manifest);
|
||||||
|
if (ideKeys.length === 0) {
|
||||||
|
cleanupTemp(tmpDir);
|
||||||
|
console.error('Nenhuma IDE encontrada no manifesto.');
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Snippets ───────────────────────────────────────────────────────
|
promptIde(ideKeys, manifest).then(function (ideKey) {
|
||||||
var snippetFiles = fs.readdirSync(ideDir).filter(function (f) {
|
var ideEntry = manifest[ideKey];
|
||||||
return f.endsWith('.code-snippets');
|
console.log('IDE selecionada: ' + ideEntry.label);
|
||||||
});
|
console.log('');
|
||||||
|
|
||||||
if (snippetFiles.length === 0) {
|
|
||||||
console.log('Aviso: nenhum arquivo .code-snippets encontrado em ' + ideDir + '. Pulando snippets.');
|
|
||||||
} else {
|
|
||||||
var snippetsDir;
|
|
||||||
try {
|
try {
|
||||||
snippetsDir = getSnippetsDir();
|
if (ideEntry.type === 'vscode-fork') {
|
||||||
} catch (e) {
|
installVscodeFork(ideEntry, tmpDir);
|
||||||
console.error('Erro ao determinar diretório de snippets: ' + e.message);
|
} else if (ideEntry.type === 'jetbrains') {
|
||||||
|
installJetBrains(ideEntry, tmpDir);
|
||||||
|
} else {
|
||||||
|
console.error('Tipo de IDE desconhecido: ' + ideEntry.type);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fse.ensureDirSync(snippetsDir);
|
|
||||||
|
|
||||||
snippetFiles.forEach(function (snippetFile) {
|
|
||||||
var src = path.join(ideDir, snippetFile);
|
|
||||||
var dest = path.join(snippetsDir, snippetFile);
|
|
||||||
var action = fs.existsSync(dest) ? 'atualizado' : 'instalado';
|
|
||||||
fse.copySync(src, dest);
|
|
||||||
console.log('Snippet ' + snippetFile + ' ' + action + ' em ' + dest);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Configuração da IDE concluída.');
|
console.log('Configuração da IDE concluída.');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user