iconmate
Version:
CLI to fetch icons and save them into your Vite, NextJS, or similar TypeScript project
152 lines (129 loc) • 4.48 kB
JavaScript
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const https = require("https");
const { pipeline } = require("stream");
const { promisify } = require("util");
// Version should match your Rust crate version
const VERSION = require("./package.json").version;
const BINARY_NAME = "iconmate";
function getPlatformInfo() {
const platform = process.platform;
const arch = process.arch;
// Map Node.js platform/arch to Rust target triples
const platformMap = {
darwin: {
x64: "x86_64-apple-darwin",
arm64: "aarch64-apple-darwin",
},
linux: {
x64: "x86_64-unknown-linux-gnu",
arm64: "aarch64-unknown-linux-gnu",
},
win32: {
x64: "x86_64-pc-windows-msvc",
},
};
if (!platformMap[platform]) {
throw new Error(`Unsupported platform: ${platform}`);
}
if (!platformMap[platform][arch]) {
throw new Error(`Unsupported architecture: ${arch} on ${platform}`);
}
const target = platformMap[platform][arch];
const extension = platform === "win32" ? ".zip" : ".tar.xz";
const binaryName = platform === "win32" ? `${BINARY_NAME}.exe` : BINARY_NAME;
return {
target,
extension,
binaryName,
filename: `${BINARY_NAME}-${target}${extension}`,
url: `https://github.com/Blankeos/iconmate/releases/download/v${VERSION}/${BINARY_NAME}-${target}${extension}`,
};
}
async function downloadFile(url, dest) {
console.log(`Downloading ${url}...`);
const file = fs.createWriteStream(dest);
const response = await new Promise((resolve, reject) => {
https
.get(url, (res) => {
if (res.statusCode === 302 || res.statusCode === 301) {
https.get(res.headers.location, resolve).on("error", reject);
} else if (res.statusCode === 200) {
resolve(res);
} else {
reject(
new Error(
`Failed to download: ${res.statusCode} ${res.statusMessage}`,
),
);
}
})
.on("error", reject);
});
response.pipe(file);
return new Promise((resolve, reject) => {
file.on("finish", () => {
file.close();
resolve();
});
file.on("error", (err) => {
fs.unlink(dest, () => {});
reject(err);
});
});
}
function extractArchive(archivePath, extractDir, platformInfo) {
console.log("Extracting binary...");
const cmd =
platformInfo.extension === ".zip"
? `unzip -o "${archivePath}" -d "${extractDir}" 2>/dev/null || powershell -command \"Expand-Archive -Path '${archivePath}' -DestinationPath '${extractDir}' -Force\"`
: `tar -xf "${archivePath}" -C "${extractDir}"`;
execSync(cmd, { stdio: "inherit" });
}
async function install() {
try {
const platformInfo = getPlatformInfo();
const binDir = path.join(__dirname, "bin");
const archivePath = path.join(__dirname, platformInfo.filename);
const binaryPath = path.join(binDir, platformInfo.binaryName);
if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true });
await downloadFile(platformInfo.url, archivePath);
extractArchive(archivePath, __dirname, platformInfo);
const extractedBinaryPath = path.join(__dirname, platformInfo.binaryName);
if (fs.existsSync(extractedBinaryPath)) {
fs.renameSync(extractedBinaryPath, binaryPath);
} else {
const subdirPath = path.join(
__dirname,
`${BINARY_NAME}-${platformInfo.target}`,
platformInfo.binaryName,
);
if (fs.existsSync(subdirPath)) {
fs.renameSync(subdirPath, binaryPath);
fs.rmSync(path.dirname(subdirPath), { recursive: true, force: true });
} else {
throw new Error("Binary not found after extraction");
}
}
if (process.platform !== "win32") {
fs.chmodSync(binaryPath, 0o755);
}
fs.unlinkSync(archivePath);
console.log(`✅ iconmate v${VERSION} installed successfully!`);
process.exit(0);
} catch (error) {
console.error("❌ Installation failed:", error.message);
console.error("\\nYou can install iconmate directly using:");
console.error(
'curl --proto \"=https\" --tlsv1.2 -LsSf https://github.com/Blankeos/iconmate/releases/latest/download/iconmate-installer.sh | sh',
);
process.exit(1);
}
}
// Only run install if this script is executed directly
if (require.main === module) {
install();
}
module.exports = { getPlatformInfo };