Skip to content
This repository was archived by the owner on Sep 25, 2026. It is now read-only.

Commit 49ff95e

Browse files
committed
fix: more flexible install command
1 parent 33db046 commit 49ff95e

1 file changed

Lines changed: 271 additions & 50 deletions

File tree

‎src/commands/chain/install.ts‎

Lines changed: 271 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
import {WalletPluginPrivateKey} from '@wharfkit/wallet-plugin-privatekey'
33
import {executeCommand, getDevKeys, getPlatform} from './utils'
44
import {NonInteractiveConsoleUI} from '../../utils/wharfkit-ui'
5+
import * as os from 'os'
6+
import * as path from 'path'
7+
import * as fs from 'fs'
8+
9+
const LEAP_VERSION = 'v5.0.3'
10+
const LEAP_REPO = 'https://github.com/AntelopeIO/leap'
511

612
export interface InstallationStatus {
713
installed: boolean
@@ -14,6 +20,13 @@ export interface InstallationStatus {
1420
}
1521
}
1622

23+
/**
24+
* Get the directory where LEAP will be cloned and built
25+
*/
26+
function getLeapBuildDir(): string {
27+
return path.join(os.homedir(), '.wharfkit', 'leap-build')
28+
}
29+
1730
/**
1831
* Check if LEAP is installed
1932
*/
@@ -59,10 +72,162 @@ export async function checkLeapInstallation(): Promise<InstallationStatus> {
5972
}
6073

6174
/**
62-
* Install LEAP on macOS using Homebrew
75+
* Ensure directory exists
76+
*/
77+
async function ensureBuildDir(dir: string): Promise<void> {
78+
if (!fs.existsSync(dir)) {
79+
await fs.promises.mkdir(dir, {recursive: true})
80+
}
81+
}
82+
83+
/**
84+
* Clone and checkout LEAP repository
85+
*/
86+
async function cloneLeapRepo(buildDir: string): Promise<void> {
87+
const leapDir = path.join(buildDir, 'leap')
88+
89+
// Check if already cloned
90+
if (fs.existsSync(path.join(leapDir, '.git'))) {
91+
console.log('LEAP repository already cloned, updating...')
92+
try {
93+
await executeCommand(`cd ${leapDir} && git fetch --all --tags`)
94+
await executeCommand(`cd ${leapDir} && git checkout ${LEAP_VERSION}`)
95+
await executeCommand(`cd ${leapDir} && git pull || true`)
96+
await executeCommand(`cd ${leapDir} && git submodule update --init --recursive`)
97+
} catch (error: unknown) {
98+
const message = error instanceof Error ? error.message : String(error)
99+
throw new Error(`Failed to update LEAP repository: ${message}`)
100+
}
101+
} else {
102+
console.log('Cloning LEAP repository...')
103+
try {
104+
await executeCommand(`git clone --recursive ${LEAP_REPO} ${leapDir}`)
105+
await executeCommand(`cd ${leapDir} && git fetch --all --tags`)
106+
await executeCommand(`cd ${leapDir} && git checkout ${LEAP_VERSION}`)
107+
await executeCommand(`cd ${leapDir} && git submodule update --init --recursive`)
108+
} catch (error: unknown) {
109+
const message = error instanceof Error ? error.message : String(error)
110+
throw new Error(`Failed to clone LEAP repository: ${message}`)
111+
}
112+
}
113+
}
114+
115+
/**
116+
* Build LEAP from source
117+
*/
118+
async function buildLeap(buildDir: string, numJobs?: number): Promise<void> {
119+
const leapDir = path.join(buildDir, 'leap')
120+
const leapBuildDir = path.join(leapDir, 'build')
121+
122+
// Create build directory
123+
await ensureBuildDir(leapBuildDir)
124+
125+
const jobs = numJobs || Math.max(1, Math.floor(os.cpus().length / 2))
126+
console.log(`Building LEAP with ${jobs} parallel jobs (this may take a while)...`)
127+
128+
try {
129+
const {os: platform} = getPlatform()
130+
131+
if (platform === 'darwin') {
132+
// macOS build - use llvm from Homebrew
133+
const llvmPrefix = await getLlvmPrefix()
134+
await executeCommand(
135+
`cd ${leapBuildDir} && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=${llvmPrefix} ..`
136+
)
137+
} else {
138+
// Linux build
139+
await executeCommand(
140+
`cd ${leapBuildDir} && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..`
141+
)
142+
}
143+
144+
await executeCommand(`cd ${leapBuildDir} && make -j ${jobs}`)
145+
} catch (error: unknown) {
146+
const message = error instanceof Error ? error.message : String(error)
147+
throw new Error(`Failed to build LEAP: ${message}`)
148+
}
149+
}
150+
151+
/**
152+
* Get LLVM prefix path on macOS
153+
*/
154+
async function getLlvmPrefix(): Promise<string> {
155+
try {
156+
const {stdout} = await executeCommand('brew --prefix llvm@11')
157+
return stdout.trim()
158+
} catch {
159+
// Try llvm without version
160+
try {
161+
const {stdout} = await executeCommand('brew --prefix llvm')
162+
return stdout.trim()
163+
} catch {
164+
return '/usr/local/opt/llvm'
165+
}
166+
}
167+
}
168+
169+
/**
170+
* Install built LEAP binaries
171+
*/
172+
async function installBuiltLeap(buildDir: string): Promise<void> {
173+
const leapDir = path.join(buildDir, 'leap')
174+
const leapBuildDir = path.join(leapDir, 'build')
175+
const binDir = path.join(leapBuildDir, 'bin')
176+
177+
console.log('Installing LEAP binaries...')
178+
179+
const binaries = ['nodeos', 'cleos', 'keosd', 'leap-util']
180+
const targetDir = '/usr/local/bin'
181+
182+
try {
183+
const {os: platform} = getPlatform()
184+
185+
// First, try to copy binaries directly (works if user owns /usr/local/bin)
186+
try {
187+
for (const binary of binaries) {
188+
const src = path.join(binDir, binary)
189+
const dest = path.join(targetDir, binary)
190+
if (fs.existsSync(src)) {
191+
await fs.promises.copyFile(src, dest)
192+
await fs.promises.chmod(dest, 0o755)
193+
}
194+
}
195+
console.log('Binaries copied to /usr/local/bin')
196+
return
197+
} catch {
198+
// Direct copy failed, try sudo methods
199+
console.log('Direct copy failed, trying with elevated permissions...')
200+
}
201+
202+
if (platform === 'darwin') {
203+
// On macOS, use make install with sudo
204+
await executeCommand(`cd ${leapBuildDir} && sudo make install`)
205+
} else {
206+
// On Linux, install the .deb package if available, otherwise make install
207+
try {
208+
const {stdout} = await executeCommand(
209+
`ls ${leapBuildDir}/leap*.deb 2>/dev/null | head -1`
210+
)
211+
if (stdout.trim()) {
212+
await executeCommand(`sudo apt-get install -y ${stdout.trim()}`)
213+
} else {
214+
await executeCommand(`cd ${leapBuildDir} && sudo make install`)
215+
}
216+
} catch {
217+
await executeCommand(`cd ${leapBuildDir} && sudo make install`)
218+
}
219+
}
220+
} catch (error: unknown) {
221+
const message = error instanceof Error ? error.message : String(error)
222+
throw new Error(`Failed to install LEAP: ${message}`)
223+
}
224+
}
225+
226+
/**
227+
* Install LEAP on macOS by building from source
63228
*/
64229
async function installLeapMacOS(): Promise<void> {
65-
console.log('Installing LEAP on macOS using Homebrew...')
230+
console.log('Installing LEAP on macOS by building from source...')
66231

67232
// Check if Homebrew is installed
68233
try {
@@ -73,81 +238,137 @@ async function installLeapMacOS(): Promise<void> {
73238
)
74239
}
75240

76-
// Tap AntelopeIO
77-
console.log('Adding AntelopeIO tap...')
241+
// Install build dependencies
242+
console.log('Installing build dependencies...')
78243
try {
79-
await executeCommand('brew tap antelopeio/leap')
80-
} catch (error: any) {
81-
throw new Error(`Failed to add AntelopeIO tap: ${error.message}`)
244+
await executeCommand('brew install cmake git llvm@11 gmp curl python3 numpy || true')
245+
} catch (error: unknown) {
246+
const message = error instanceof Error ? error.message : String(error)
247+
throw new Error(`Failed to install dependencies: ${message}`)
82248
}
83249

84-
// Install LEAP
85-
console.log('Installing LEAP (this may take a few minutes)...')
86-
try {
87-
await executeCommand('brew install leap')
88-
} catch (error: any) {
89-
throw new Error(`Failed to install LEAP: ${error.message}`)
90-
}
250+
const buildDir = getLeapBuildDir()
251+
await ensureBuildDir(buildDir)
252+
253+
// Clone repository
254+
await cloneLeapRepo(buildDir)
255+
256+
// Build from source
257+
await buildLeap(buildDir)
258+
259+
// Install
260+
await installBuiltLeap(buildDir)
91261

92262
console.log('LEAP installed successfully!')
93263
}
94264

95265
/**
96-
* Install LEAP on Linux using apt
266+
* Get Ubuntu version for determining LLVM version
97267
*/
98-
async function installLeapLinux(): Promise<void> {
99-
console.log('Installing LEAP on Linux using apt...')
100-
101-
// Detect distribution
102-
let distro = 'ubuntu'
103-
let version = '22.04'
104-
105-
try {
106-
const {stdout} = await executeCommand('lsb_release -is')
107-
distro = stdout.trim().toLowerCase()
108-
} catch {
109-
console.log('Could not detect distribution, assuming Ubuntu')
110-
}
111-
268+
async function getUbuntuVersion(): Promise<string> {
112269
try {
113270
const {stdout} = await executeCommand('lsb_release -rs')
114-
version = stdout.trim()
271+
return stdout.trim()
115272
} catch {
116-
console.log('Could not detect version, assuming 22.04')
273+
return '22.04'
117274
}
275+
}
118276

119-
// Add AntelopeIO repository
120-
console.log('Adding AntelopeIO repository...')
121-
try {
122-
await executeCommand(
123-
'wget -O - https://apt.antelope.io/repos/antelope.gpg.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/antelope.gpg > /dev/null'
124-
)
125-
await executeCommand(
126-
`echo "deb [arch=amd64] https://apt.antelope.io ${distro} ${version}" | sudo tee /etc/apt/sources.list.d/antelope.list`
127-
)
128-
} catch (error: any) {
129-
throw new Error(`Failed to add AntelopeIO repository: ${error.message}`)
130-
}
277+
/**
278+
* Install LEAP on Linux by building from source
279+
*/
280+
async function installLeapLinux(): Promise<void> {
281+
console.log('Installing LEAP on Linux by building from source...')
282+
283+
const ubuntuVersion = await getUbuntuVersion()
284+
const majorVersion = parseInt(ubuntuVersion.split('.')[0], 10)
131285

132286
// Update package list
133287
console.log('Updating package list...')
134288
try {
135289
await executeCommand('sudo apt-get update')
136-
} catch (error: any) {
137-
throw new Error(`Failed to update package list: ${error.message}`)
290+
} catch (error: unknown) {
291+
const message = error instanceof Error ? error.message : String(error)
292+
throw new Error(`Failed to update package list: ${message}`)
138293
}
139294

140-
// Install LEAP
141-
console.log('Installing LEAP (this may take a few minutes)...')
295+
// Install build dependencies
296+
console.log('Installing build dependencies...')
142297
try {
143-
await executeCommand('sudo apt-get install -y leap')
144-
} catch (error: any) {
145-
throw new Error(`Failed to install LEAP: ${error.message}`)
298+
await executeCommand(`sudo apt-get install -y \
299+
build-essential \
300+
cmake \
301+
git \
302+
libcurl4-openssl-dev \
303+
libgmp-dev \
304+
llvm-11-dev \
305+
python3-numpy \
306+
file \
307+
zlib1g-dev`)
308+
309+
// On Ubuntu 20.04, install gcc-10 for C++20 support
310+
if (majorVersion === 20) {
311+
await executeCommand('sudo apt-get install -y g++-10')
312+
}
313+
} catch (error: unknown) {
314+
const message = error instanceof Error ? error.message : String(error)
315+
throw new Error(`Failed to install dependencies: ${message}`)
146316
}
147317

318+
const buildDir = getLeapBuildDir()
319+
await ensureBuildDir(buildDir)
320+
321+
// Clone repository
322+
await cloneLeapRepo(buildDir)
323+
324+
// Build from source (with Ubuntu 20.04 specific compiler flags)
325+
await buildLeapLinux(buildDir, majorVersion)
326+
327+
// Install
328+
await installBuiltLeap(buildDir)
329+
148330
console.log('LEAP installed successfully!')
149331
}
150332

333+
/**
334+
* Build LEAP on Linux with version-specific settings
335+
*/
336+
async function buildLeapLinux(buildDir: string, ubuntuMajorVersion: number): Promise<void> {
337+
const leapDir = path.join(buildDir, 'leap')
338+
const leapBuildDir = path.join(leapDir, 'build')
339+
340+
// Create build directory
341+
await ensureBuildDir(leapBuildDir)
342+
343+
const jobs = Math.max(1, Math.floor(os.cpus().length / 2))
344+
console.log(`Building LEAP with ${jobs} parallel jobs (this may take a while)...`)
345+
346+
try {
347+
if (ubuntuMajorVersion === 20) {
348+
// Ubuntu 20.04 needs gcc-10 specified
349+
await executeCommand(
350+
`cd ${leapBuildDir} && cmake \
351+
-DCMAKE_C_COMPILER=gcc-10 \
352+
-DCMAKE_CXX_COMPILER=g++-10 \
353+
-DCMAKE_BUILD_TYPE=Release \
354+
-DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..`
355+
)
356+
} else {
357+
// Ubuntu 22.04+ has gcc-11 by default
358+
await executeCommand(
359+
`cd ${leapBuildDir} && cmake \
360+
-DCMAKE_BUILD_TYPE=Release \
361+
-DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..`
362+
)
363+
}
364+
365+
await executeCommand(`cd ${leapBuildDir} && make -j ${jobs}`)
366+
} catch (error: unknown) {
367+
const message = error instanceof Error ? error.message : String(error)
368+
throw new Error(`Failed to build LEAP: ${message}`)
369+
}
370+
}
371+
151372
/**
152373
* Install LEAP based on platform
153374
*/

0 commit comments

Comments
 (0)