Skip to content

Commit e085726

Browse files
committed
fix: et al
1 parent cb0dc0e commit e085726

3 files changed

Lines changed: 136 additions & 3 deletions

File tree

packages/cli/installIPFS.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env node
2+
import ora from "ora";
3+
import { execSync } from "node:child_process";
4+
import { createWriteStream, existsSync, mkdirSync, chmodSync, unlinkSync } from "node:fs";
5+
import { join, dirname } from "node:path";
6+
import { pipeline } from "node:stream/promises";
7+
import { fileURLToPath } from "node:url";
8+
const __dirname = dirname(fileURLToPath(import.meta.url));
9+
const BIN_DIR = join(__dirname, "..", "bin");
10+
const KUBO_VERSION = "v0.39.0";
11+
function getPlatformInfo() {
12+
const platform = process.platform;
13+
const arch = process.arch;
14+
const platformMap = {
15+
darwin: "darwin",
16+
linux: "linux",
17+
win32: "windows",
18+
};
19+
const archMap = {
20+
x64: "amd64",
21+
arm64: "arm64",
22+
arm: "arm",
23+
};
24+
const os = platformMap[platform];
25+
const cpu = archMap[arch];
26+
if (!os || !cpu) {
27+
throw new Error(`Unsupported platform: ${platform}-${arch}`);
28+
}
29+
const ext = platform === "win32" ? ".zip" : ".tar.gz";
30+
const binName = platform === "win32" ? "ipfs.exe" : "ipfs";
31+
return { os, cpu, ext, binName };
32+
}
33+
function runCommand(command) {
34+
return execSync(command, { encoding: "utf-8", stdio: "pipe" }).trim();
35+
}
36+
async function downloadFile(url, dest) {
37+
const response = await fetch(url);
38+
if (!response.ok) {
39+
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
40+
}
41+
if (!response.body) {
42+
throw new Error("Download failed: empty response body");
43+
}
44+
const fileStream = createWriteStream(dest);
45+
await pipeline(response.body, fileStream);
46+
}
47+
function extractTarGz(archivePath, destDir) {
48+
runCommand(`tar -xzf "${archivePath}" -C "${destDir}" --strip-components=1 kubo/ipfs`);
49+
}
50+
function extractZip(archivePath, destDir) {
51+
const ps = [
52+
"powershell",
53+
"-NoProfile",
54+
"-NonInteractive",
55+
"-Command",
56+
`"Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force; ` +
57+
`Move-Item -Path '${destDir}\\kubo\\ipfs.exe' -Destination '${destDir}\\ipfs.exe' -Force"`,
58+
].join(" ");
59+
runCommand(ps);
60+
}
61+
function ensureDir(dir) {
62+
if (!existsSync(dir)) {
63+
mkdirSync(dir, { recursive: true });
64+
}
65+
}
66+
function makeExecutableIfNeeded(filePath) {
67+
if (process.platform !== "win32") {
68+
chmodSync(filePath, 0o755);
69+
}
70+
}
71+
function tryGetVersion(binaryPath) {
72+
try {
73+
const v = runCommand(`"${binaryPath}" --version`);
74+
return v || null;
75+
} catch {
76+
return null;
77+
}
78+
}
79+
function failSpinner(spinner, message, error) {
80+
const errMsg = error instanceof Error ? error.message : String(error);
81+
spinner.fail(message);
82+
throw new Error(errMsg);
83+
}
84+
async function main() {
85+
const spinner = ora("Preparing IPFS (kubo) installation").start();
86+
try {
87+
const { os, cpu, ext, binName } = getPlatformInfo();
88+
const binaryPath = join(BIN_DIR, binName);
89+
ensureDir(BIN_DIR);
90+
if (existsSync(binaryPath)) {
91+
const version = tryGetVersion(binaryPath);
92+
spinner.succeed(version ? `IPFS already installed (${version})` : "IPFS already installed");
93+
return;
94+
}
95+
const filename = `kubo_${KUBO_VERSION}_${os}-${cpu}${ext}`;
96+
const url = `https://dist.ipfs.tech/kubo/${KUBO_VERSION}/${filename}`;
97+
const archivePath = join(BIN_DIR, filename);
98+
spinner.text = `Downloading ${filename}`;
99+
await downloadFile(url, archivePath);
100+
spinner.text = "Extracting binary";
101+
if (ext === ".tar.gz") {
102+
extractTarGz(archivePath, BIN_DIR);
103+
} else {
104+
extractZip(archivePath, BIN_DIR);
105+
}
106+
spinner.text = "Finalizing installation";
107+
makeExecutableIfNeeded(binaryPath);
108+
if (existsSync(archivePath)) {
109+
unlinkSync(archivePath);
110+
}
111+
const version = tryGetVersion(binaryPath);
112+
spinner.succeed(version ? `IPFS installed (${version})` : "IPFS installed");
113+
} catch (error) {
114+
failSpinner(ora().start(), "Failed to install IPFS", error);
115+
}
116+
}
117+
main().catch((e) => {
118+
const msg = e instanceof Error ? e.message : String(e);
119+
process.stderr.write(`${msg}\n`);
120+
process.exit(1);
121+
});

packages/cli/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212
"format": "bunx prettier --check .",
1313
"format:fix": "bunx prettier --write \"**/*.{js,ts,json,md}\" \"!abis/**\"",
1414
"typecheck": "bunx tsc --noEmit",
15-
"build": "bunx tsc && chmod +x dist/cli/index.js",
15+
"build": "bunx tsc -p tsconfig.build.json && chmod +x dist/src/cli/index.js",
1616
"prepublishOnly": "bun run build",
1717
"postinstall": "bun run ./installIPFS.ts || true"
1818
},
1919
"engines": {
2020
"bun": ">=1.2.6"
2121
},
2222
"bin": {
23-
"dotns": "./dist/cli/index.js"
23+
"dotns": "./dist/src/cli/index.js"
2424
},
2525
"exports": {
26-
".": "./dist/cli/index.js"
26+
".": "./dist/src/cli/index.js"
2727
},
2828
"devDependencies": {
2929
"@types/bun": "^1.2.6",

packages/cli/tsconfig.build.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"noEmit": false,
5+
6+
"outDir": "dist",
7+
"rootDir": ".",
8+
9+
"allowImportingTsExtensions": false
10+
},
11+
"include": ["src/**/*.ts", "installIPFS.ts"]
12+
}

0 commit comments

Comments
 (0)