Visão Geral da Arquitetura: Modularidade e Eficiência
O jsvu é uma ferramenta de linha de comando projetada para gerenciar e atualizar versões de diversas engines JavaScript, como GraalJS, Hermes, JavaScriptCore, QuickJS, SpiderMonkey e V8. Sua arquitetura modular permite uma administração unificada, facilitando a obtenção de versões específicas ou as mais recentes dessas engines.
A arquitetura do jsvu é dividida em dois componentes principais: módulos de engine e módulos compartilhados. Essa separação garante manutenibilidade, escalabilidade e uma interface consistente para a gestão de versões.
Módulos de Engine: Implementações Específicas
No diretório engines/, cada engine possui um módulo dedicado, como engines/graaljs/ ou engines/v8/. Cada módulo inclui arquivos-chave para lidar com lógicas particulares:
get-latest-version.js: Recupera informações da versão mais recente da engine.predict-url.js: Gera URLs de download para os binários da engine.extract.js: Gerencia a extração dos arquivos baixados.test.js: Verifica se a engine instalada está funcionando corretamente.
Essa estrutura simplifica a adição de novas engines, bastando criar um diretório correspondente com os arquivos essenciais.
Módulos Compartilhados: Reutilização de Código
O diretório shared/ contém módulos funcionais compartilhados entre todas as engines, maximizando a reutilização de código:
engine.js: Controla o fluxo principal de atualização da engine.download.js: Lida com o download de arquivos.installer.js: Responsável pela instalação de binários e criação de symlinks.status.js: Gerencia o estado das versões instaladas.
Ao adotar essa abordagem modular, o jsvu alcança "escreva uma vez, reutilize em múltiplas engines", reduzindo redundância e custos de manutenção.
Mecanismo de Gerenciamento de Versões: Do Detecção à Instalação
O núcleo do gerenciamento de versões do jsvu reside na função updateEngine do módulo shared/engine.js. Essa função orquestra o processo completo, desde a detecção até a instalação.
1. Detecção e Comparação de Versões
Primeiramente, o jsvu invoca a função get-latest-version.js do módullo da angine para obter a versão mais recente:
const versaoRecente = await buscarUltimaVersao(status.sistemaOperacional);
Em seguida, compara essa versão com a já instalada. Se já estiver atualizado, o usuário é notificado:
if (status[id] === versaoRecente) {
log.falha(`${nome} v${versaoRecente} já está instalado.`);
return;
}
2. Previsão de URL e Download
Para engines que precisam de atualização, o jsvu gera o link de download usando predict-url.js:
const linkDownload = preverUrl(versaoRecente, status.sistemaOperacional);
Depois, utiliza o módulo shared/download.js para baixar o binário:
const caminhoArquivo = await baixar(linkDownload);
3. Extração e Instalação
Após o download, o módulo extract.js da engine processa a extração:
await extrair({
caminhoArquivo: caminhoArquivo,
binario: id,
apelido: apelido,
sistemaOperacional: status.sistemaOperacional,
});
Por fim, a classe Instalador (de shared/installer.js) conclui a instalação dos binários e a criação de symlinks.
4. Verificação e Atualização de Estado
Para garantir a funcionalidade, o jsvu executa test.js da engine:
await verificar({
binario: id,
apelido: apelido,
});
Após a verificação, o estado é atualizado no arquivo de status para evitar reinstalações desnecessárias:
status[id] = versaoRecente;
salvarStatus(status);
Mecanismo de Instalação: Gerenciamento Flexível de Arquivos
A classe Instalador em shared/installer.js oferece funcionalidades de instalação adaptáveis, atendendo a diferentes necessidades das engines.
Instalação de Binários
O método instalarBinario configura permissões apropriadas para os arquivos executáveis:
fs.chmodSync(destino, 0o555);
Gerenciamento de Symlinks
Para acesso direto via linha de comando, symlinks são criados com instalarSymlinkBinario:
fs.garantirSymlinkSync(destino, origem);
Isso economiza espaço em disco e simplifica a alternância entre versões.
Geração de Scripts Wrapper
Alguns engines requerem parâmetros de inicialização específicos; o método instalarScript gera scripts wrapper para garantir a execução correta.
Suporte Multi-Engine: Equilíbrio entre Interface Unificada e Personalização
A capacidade do jsvu de suportar múltiplas engines é sustentada por uma abstração de interface consistente e implementações personalizáveis.
Design de Interface Unificada
Todos os módulos de engine seguem um padrão de interface, fornecendo funções como get-latest-version, predict-url, extract e test. Isso permite que shared/engine.js processe todas as engines de maneira uniforme.
Implementações Personalizadas
Apesar da interface unificada, cada módulo pode conter lógicas específicas. Por exemplo, o módulo da V8 inclui um arquivo adicional predict-file-name.js para tratar seu formato de nome de arquivo exclusivo.
Essa estratégia de "interface unificada mais implementação personalizada" equilibra clareza arquitetônica com flexibilidade para requisitos únicos de cada engine.