lucy-cli
Version:
Lucy Framework for WIX Studio Editor
171 lines (170 loc) โข 8.05 kB
JavaScript
import chalk from 'chalk';
import { simpleGit } from 'simple-git';
import { spawnSync } from 'child_process';
// https://www.sergevandenoever.nl/run-gulp4-tasks-programatically-from-node/
import path from 'path';
import { fileURLToPath } from 'url';
import { exec } from 'child_process';
import os from 'os';
import fs from 'fs';
import { blue, green, orange, red, yellow, magenta } from './index.js';
export async function installPackages(wixPackages, devPackages, cwd, locked) {
if (locked)
console.log("๐" + blue.underline(` => Installing & version locked packages!`));
const wixPackageNames = Object.keys(wixPackages);
const wixPackageVersions = Object.values(wixPackages);
const wixPackageNamesAndVersions = wixPackageNames.map((name, index) => `${name}@${wixPackageVersions[index]}`);
const devPackageNames = Object.keys(devPackages);
const devPackageVersions = Object.values(devPackages);
const devPackageNamesAndVersions = devPackageNames.map((name, index) => `${name}@${devPackageVersions[index]}`);
let success = true;
wixPackageNames.forEach((name, index) => {
console.log(`๐ => Installing ${orange(name)}`);
const wixInstall = locked ? `wix install ${wixPackageNamesAndVersions}` : `wix install ${name}`;
const wixres = spawnSync(wixInstall, { shell: true, stdio: 'inherit' });
if (wixres.error) {
console.log((`๐ฉ ${red.underline.bold("=> Failed to install package =>")} ${orange(wixres.error.message)}`));
success = false;
}
else {
console.log("๐" + blue.underline(` => Package installed!`));
}
});
const yarnAdd = locked ? `yarn add -D ${devPackageNamesAndVersions.join(' ')}` : `yarn add -D ${devPackageNames.join(' ')}`;
const yarnRes = spawnSync(yarnAdd, { shell: true, stdio: 'inherit' });
if (yarnRes.error) {
success = false;
console.log((`๐ฉ ${red.underline.bold("=> Failed to install dev packages =>")} ${orange(yarnRes.error.message)}`));
}
if (success) {
console.log("๐" + blue.underline(` => All Packages installed!`));
}
else {
console.log("๐" + red.underline(` => Some packages failed to install!`));
}
}
export async function gitInit(cwd, modules) {
for (const [name, repo] of Object.entries(modules)) {
console.log(chalk.green.underline.bold(`Cloning ${name}`));
const git = simpleGit({ baseDir: cwd });
try {
const repoPath = path.resolve(cwd, name);
if (!fs.existsSync(repoPath)) {
await git.submoduleAdd(repo.url, name);
}
if (fs.existsSync(repoPath)) {
console.log(`๐ ${blue.underline(' => Module already cloned!')}`);
}
const localGit = simpleGit({ baseDir: `${cwd}/${name}` });
await localGit.checkout(repo.branch);
}
catch (err) {
console.log((`๐ฉ ${red.underline.bold("=> Command failed =>")} ${orange(err)}`));
}
finally {
console.log("๐" + blue.underline(` => Cloned ${orange(name)}`));
}
}
console.log("๐ถ" + green.underline(' => All Modules cloned!'));
}
export async function runGulp(moduleSettings, projectSettings, task) {
// Get the directory name of the current module
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Resolve the path to the Gulpfile
const gulpfilePath = path.resolve(__dirname, 'Gulpfile.js');
// Dynamically import the Gulpfile
const gulpfile = await import(`file://${gulpfilePath}`);
// Check if 'dev' task exists
gulpfile.runTask(task, moduleSettings, projectSettings);
}
/**
* Clean up and run a command before exiting the process.
*/
export function cleanupWatchers() {
console.log(`๐งน ${magenta.underline('Cleaning up Watchman watchers...')}`);
const cwd = process.cwd();
const command = `watchman watch-del "${cwd}"`; // Adjust for Windows paths
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`๐ฉ ${red.underline('Failed to run cleanup:')} ${orange(error.message)}`);
return;
}
if (stderr) {
console.error(`โ ๏ธ ${yellow.underline('Watchman stderr:')} ${stderr}`);
}
console.log(`โ
${green.underline('Watchman cleanup success:')} ${stdout}`);
});
}
/**
* Kill all processes matching a specific substring in their command, with a fallback for Windows.
* @param {string} processPattern - The substring to match (e.g., "wix:dev" or "@wix/cli/bin/wix.cjs").
*/
export function killAllProcesses(processPattern) {
const isWindows = os.platform() === 'win32';
const command = isWindows
? `tasklist /FI "IMAGENAME eq node.exe" /FO CSV | findstr "${processPattern}"` // Adjust for Node.js processes
: `ps -eo pid,command | grep "${processPattern}" | grep -v grep`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`๐ฉ ${red.underline('Failed to find processes:')} ${orange(error.message)}`);
return;
}
if (stderr) {
console.error(`โ ๏ธ ${yellow.underline('Error output:')} ${stderr}`);
}
if (!stdout.trim()) {
console.log(`โน๏ธ ${blue.underline(`No processes found matching pattern:`)} ${orange(processPattern)}`);
return;
}
console.log(`๐ ${magenta.underline('Found matching processes:')}\n${stdout}`);
const lines = stdout.trim().split('\n');
const pids = isWindows
? lines.map(line => line.match(/"(\d+)"/)?.[1]) // Extract PID from Windows tasklist output
: lines.map(line => line.trim().split(/\s+/)[0]).filter(pid => !isNaN(Number(pid)));
pids.forEach(pid => {
if (!pid)
return;
try {
const killCommand = isWindows
? `taskkill /PID ${pid} /T /F` // Forcefully terminate the process on Windows
: `kill -SIGTERM ${pid}`;
exec(killCommand, (killError) => {
if (killError) {
console.error(`โ ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(killError.message)}`);
}
else {
console.log(`โ
${green.underline('Killed process with PID:')} ${orange(pid)}`);
}
});
// Schedule SIGKILL fallback for non-Windows platforms
if (!isWindows) {
setTimeout(() => {
try {
process.kill(parseInt(pid, 10), 'SIGKILL');
console.log(`๐ช ${red.underline('Sent SIGKILL to process with PID:')} ${orange(pid)} (fallback).`);
}
catch (killError) {
if (killError.code === 'ESRCH') {
console.log(`โ
${green.underline('Process with PID')} ${orange(pid)} ${green.underline('already terminated.')}`);
}
else {
console.error(`โ ๏ธ ${yellow.underline('Failed to send SIGKILL to process with PID')} ${orange(pid)}: ${red(killError.message)}`);
}
}
}, 10000);
}
}
catch (err) {
console.error(`โ ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(err.message)}`);
}
});
});
}
export async function saveConfig(config, file) {
await fs.promises.writeFile(file, JSON.stringify(config));
}
export async function readConfig(file) {
let content = await fs.promises.readFile(file, 'utf-8');
return JSON.parse(content);
}