napi-rs/src/build.ts

153 lines
3.8 KiB
TypeScript
Raw Normal View History

2020-07-27 00:53:09 +09:00
import os from 'os'
2020-09-04 17:22:15 +09:00
import { join, parse, sep } from 'path'
2020-07-27 00:53:09 +09:00
2020-09-04 17:22:15 +09:00
import chalk from 'chalk'
2020-07-27 00:53:09 +09:00
import { Command } from 'clipanion'
import toml from 'toml'
2020-09-04 17:22:15 +09:00
import { getNapiConfig } from './consts'
import { debugFactory } from './debug'
import { existsAsync, readFileAsync, writeFileAsync } from './utils'
const debug = debugFactory('build')
2020-07-27 00:53:09 +09:00
export class BuildCommand extends Command {
static usage = Command.Usage({
description: 'Copy native module into specified dir',
})
2020-08-21 22:51:14 +09:00
@Command.Boolean(`--platform`)
appendPlatformToFilename!: boolean
2020-07-27 00:53:09 +09:00
@Command.Boolean(`--release`)
isRelease = false
@Command.Boolean('--musl')
isMusl = false
2020-09-04 17:22:15 +09:00
@Command.String('--config,-c')
configFileName?: string
@Command.String('--cargo-name')
cargoName?: string
2020-09-04 17:22:15 +09:00
@Command.String({
required: false,
})
target = '.'
2020-07-27 00:53:09 +09:00
@Command.Path('build')
async execute() {
2020-09-04 17:22:15 +09:00
const { binaryName } = getNapiConfig(this.configFileName)
let dylibName = this.cargoName
if (!dylibName) {
let tomlContentString: string
let tomlContent: any
try {
debug('Start read toml')
tomlContentString = await readFileAsync(
join(process.cwd(), 'Cargo.toml'),
'utf-8',
)
} catch {
throw new TypeError(`Could not find Cargo.toml in ${process.cwd()}`)
}
2020-07-27 00:53:09 +09:00
try {
debug('Start parse toml')
tomlContent = toml.parse(tomlContentString)
} catch {
throw new TypeError('Could not parse the Cargo.toml')
}
2020-09-04 17:22:15 +09:00
if (tomlContent.package?.name) {
dylibName = tomlContent.package.name.replace(/-/g, '_')
} else {
throw new TypeError('No package.name field in Cargo.toml')
}
2020-07-27 00:53:09 +09:00
}
2020-09-04 17:22:15 +09:00
debug(`Dylib name: ${chalk.greenBright(dylibName)}`)
2020-07-27 00:53:09 +09:00
const platform = os.platform()
let libExt
2020-09-04 17:22:15 +09:00
debug(`Platform: ${chalk.greenBright(platform)}`)
2020-07-27 00:53:09 +09:00
// Platform based massaging for build commands
switch (platform) {
case 'darwin':
libExt = '.dylib'
2020-09-04 17:22:15 +09:00
dylibName = `lib${dylibName}`
2020-07-27 00:53:09 +09:00
break
case 'win32':
libExt = '.dll'
break
case 'linux':
case 'freebsd':
2020-09-04 17:22:15 +09:00
dylibName = `lib${dylibName}`
2020-07-27 00:53:09 +09:00
libExt = '.so'
break
default:
2020-09-04 17:22:15 +09:00
throw new TypeError(
2020-07-27 00:53:09 +09:00
'Operating system not currently supported or recognized by the build script',
)
}
const targetDir = this.isRelease ? 'release' : 'debug'
2020-08-21 22:51:14 +09:00
if (this.isMusl && !this.appendPlatformToFilename) {
throw new TypeError(`Musl flag must be used with platform flag`)
}
const platformName = this.appendPlatformToFilename
? !this.isMusl
? `.${platform}`
: `.${platform}-musl`
2020-07-27 00:53:09 +09:00
: ''
2020-09-04 17:22:15 +09:00
debug(
`Platform name: ${
platformName || chalk.green('[Empty]')
}, musl: ${chalk.greenBright(this.isMusl)}`,
)
2020-07-27 00:53:09 +09:00
2020-09-04 17:22:15 +09:00
let distModulePath = this.target
? join(this.target, `${binaryName}${platformName}.node`)
: join('target', targetDir, `${binaryName}${platformName}.node`)
const parsedDist = parse(distModulePath)
2020-07-27 00:53:09 +09:00
if (!parsedDist.ext) {
distModulePath = `${distModulePath}${platformName}.node`
}
2020-09-04 17:22:15 +09:00
const dir = await findUp()
2020-07-27 00:53:09 +09:00
2020-09-04 17:22:15 +09:00
if (!dir) {
throw new TypeError('No target dir found')
}
const sourcePath = join(dir, 'target', targetDir, `${dylibName}${libExt}`)
debug(`Read [${chalk.yellowBright(sourcePath)}] content`)
const dylibContent = await readFileAsync(sourcePath)
debug(`Write binary content to [${chalk.yellowBright(distModulePath)}]`)
2020-07-27 00:53:09 +09:00
await writeFileAsync(distModulePath, dylibContent)
}
}
2020-09-04 17:22:15 +09:00
async function findUp(dir = process.cwd()): Promise<string | null> {
const dist = join(dir, 'target')
if (await existsAsync(dist)) {
return dir
}
const dirs = dir.split(sep)
if (dirs.length < 2) {
return null
}
dirs.pop()
return findUp(dirs.join(sep))
}