Merge pull request #240 from napi-rs/refactor-cli

Refactor cli
This commit is contained in:
LongYinan 2020-12-02 22:53:19 +08:00 committed by GitHub
commit 85ac3fe9e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 6367 additions and 440 deletions

View file

@ -3,7 +3,6 @@ name: Linux-aarch64
env:
DEBUG: 'napi:*'
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: 'aarch64-linux-gnu-gcc'
NAPI_RS_INCLUDE_PATH: '/usr/aarch64-linux-gnu/include'
on:
push:
@ -12,7 +11,7 @@ on:
jobs:
build:
name: stable - x86_64-unknown-linux-musl - node@14
name: stable - aarch64-unknown-linux-gnu - node@14
runs-on: ubuntu-latest
steps:
@ -45,19 +44,19 @@ jobs:
uses: actions/cache@v1
with:
path: ~/.cargo/registry
key: stable-linux-aarch64-node@14-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
key: stable-linux-aarch64-gnu-node@14-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v1
with:
path: ~/.cargo/git
key: stable-linux-aarch64gnu-node@14-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
key: stable-linux-aarch64-gnu-node@14-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache NPM dependencies
uses: actions/cache@v1
with:
path: node_modules
key: npm-cache-linux-aarch64-node@14-${{ hashFiles('yarn.lock') }}
key: npm-cache-linux-aarch64-gnu-node@14-${{ hashFiles('yarn.lock') }}
- name: Install cross compile toolchain
run: sudo apt-get install gcc-aarch64-linux-gnu g++-6-aarch64-linux-gnu -y

View file

@ -44,9 +44,6 @@ jobs:
- name: 'Install node dependencies'
run: docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/napi-rs -w /napi-rs builder yarn
- name: 'Install swc musl'
run: docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/napi-rs -w /napi-rs builder yarn add @swc/core-linux-musl --dev
- name: 'Build TypeScript'
run: docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/napi-rs -w /napi-rs builder yarn build

View file

@ -56,7 +56,7 @@ jobs:
key: napi3-${{ hashFiles('yarn.lock') }}
- name: 'Install dependencies'
run: yarn add ava@2 --dev --ignore-engines
run: yarn add ava@2 --dev --ignore-engines -W
- name: 'Build TypeScript'
run: yarn --ignore-engines build

View file

@ -1,2 +1,3 @@
target
node_modules
node_modules
scripts

View file

@ -111,11 +111,11 @@ Run `cargo build` to produce the `Dynamic lib` file. And install the `napi-rs` t
{
"package": "your pkg",
"devDependencies": {
"napi-rs": "latest"
"@napi-rs/cli": "latest"
},
"scripts": {
"build": "cargo build && napi build",
"build-release": "cargo build --release && napi build --release"
"build": "napi build",
"build-release": "napi build --release"
}
}
```

View file

@ -1,6 +1,6 @@
const configuration = {
extensions: ['ts', 'tsx'],
files: ['test_module/__test__/**/*.spec.ts'],
files: ['test_module/__test__/**/*.spec.ts', 'cli/__test__/**/*.spec.ts'],
require: ['ts-node/register/transpile-only'],
environmentVariables: {
TS_NODE_PROJECT: './test_module/tsconfig.json',

View file

@ -2,6 +2,6 @@
"name": "test-module",
"version": "1.0.0",
"scripts": {
"build": "cargo build --release && node ../scripts/index.js build --release"
"build": "node ../cli/scripts/index.js build --release"
}
}

View file

@ -106,6 +106,9 @@ pub fn setup() {
"cargo:rustc-link-search=native={}",
link_search_dir.display()
);
// Link `win_delay_load_hook.obj`
// Needed for electron, but okay for other environments
// https://github.com/neon-bindings/neon/pull/627
println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
}

21
cli/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 LongYinan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

79
cli/README.md Normal file
View file

@ -0,0 +1,79 @@
# `@napi-rs/cli`
> Cli tools for napi-rs
## Commands
### Debug mode
```bash
DEBUG="napi:*" napi [command]
```
### `napi build`
> Build command. Build rust codes and copy the dynamic lib binary file to the dist dir.
#### `--platform`
> default `false`
Append `platform-arch-[abi]` name to dist file. eg: `index.darwin-x64.node`.
#### `--release`
> default `false`
Is release build. This flag will be passed to `Cargo` directly.
#### `--features`
> default `''`
Cargo features, passthrough to `cargo build` command.
#### `--config,-c`
> default `package.json`
`napi-rs` config file name. `napi-rs` config example :
```js
{
"name": "@native-binding/fib",
"version": "0.1.0",
"napi": {
"name": "fib", // binary name
"triples": {
"defaults": true, // default true, if this value is true, will build `x86_64-pc-windows-msvc`, `x86_64-apple-darwin` and `x86_64-unknown-linux-gnu`
"addition": [
"x86_64-unknown-linux-musl",
"x86_64-unknown-freebsd",
"aarch64-unknown-linux-gnu"
]
}
}
}
```
#### `--cargo-name`
> default `undefined`
If not set, cli will read the `package.name` field in `Cargo.toml` under `process.cwd()`. The `-` in the name will be replaced with `_`.
#### `--target`
> default `undefined`
This value will be passed to `Cargo build` command directly. eg: `napi build --target x86_64-unknown-linux-musl`
#### `--cargo-flags`
> default `undefined`
Other flags you want pass to `Cargo build`.
### `napi artifacts`
> Copy artifact files in Github actions.

50
cli/package.json Normal file
View file

@ -0,0 +1,50 @@
{
"name": "@napi-rs/cli",
"version": "1.0.0-alpha.9",
"description": "Cli tools for napi-rs",
"keywords": ["cli", "rust", "napi", "n-api", "neon"],
"author": "LongYinan <lynweklm@gmail.com>",
"homepage": "https://github.com/napi-rs/napi-rs/tree/master/cli#readme",
"license": "MIT",
"bin": {
"napi": "./scripts/index.js"
},
"files": ["scripts"],
"engines": {
"node": ">= 10"
},
"maintainers": [
{
"name": "LongYinan",
"email": "lynweklm@gmail.com",
"homepage": "https://github.com/Brooooooklyn"
}
],
"repository": {
"type": "git",
"url": "git+https://github.com/napi-rs/napi-rs.git"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"bugs": {
"url": "https://github.com/napi-rs/napi-rs/issues"
},
"dependencies": {
"@octokit/rest": "^18.0.10",
"chalk": "^4.1.0",
"clipanion": "^2.6.2",
"debug": "^4.3.1",
"fdir": "^4.1.0",
"inquirer": "^7.3.3",
"lodash": "^4.17.20",
"putasset": "^5.0.3",
"toml": "^3.0.0",
"tslib": "^2.0.3"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
}

View file

@ -0,0 +1,119 @@
import test from 'ava'
import { parseTriple, getDefaultTargetTriple } from '../parse-triple'
const triples = [
{
name: 'x86_64-unknown-linux-musl',
expected: {
abi: 'musl',
arch: 'x64',
platform: 'linux',
platformArchABI: 'linux-x64-musl',
raw: 'x86_64-unknown-linux-musl',
} as const,
},
{
name: 'x86_64-unknown-linux-gnu',
expected: {
abi: 'gnu',
arch: 'x64',
platform: 'linux',
platformArchABI: 'linux-x64-gnu',
raw: 'x86_64-unknown-linux-gnu',
} as const,
},
{
name: 'x86_64-pc-windows-msvc',
expected: {
abi: 'msvc',
arch: 'x64',
platform: 'win32',
platformArchABI: 'win32-x64-msvc',
raw: 'x86_64-pc-windows-msvc',
} as const,
},
{
name: 'x86_64-apple-darwin',
expected: {
abi: null,
arch: 'x64',
platform: 'darwin',
platformArchABI: 'darwin-x64',
raw: 'x86_64-apple-darwin',
} as const,
},
{
name: 'i686-pc-windows-msvc',
expected: {
abi: 'msvc',
arch: 'ia32',
platform: 'win32',
platformArchABI: 'win32-ia32-msvc',
raw: 'i686-pc-windows-msvc',
} as const,
},
{
name: 'x86_64-unknown-freebsd',
expected: {
abi: null,
arch: 'x64',
platform: 'freebsd',
platformArchABI: 'freebsd-x64',
raw: 'x86_64-unknown-freebsd',
} as const,
},
{
name: 'aarch64-unknown-linux-gnu',
expected: {
abi: 'gnu',
arch: 'arm64',
platform: 'linux',
platformArchABI: 'linux-arm64-gnu',
raw: 'aarch64-unknown-linux-gnu',
} as const,
},
{
name: 'aarch64-pc-windows-msvc',
expected: {
abi: 'msvc',
arch: 'arm64',
platform: 'win32',
platformArchABI: 'win32-arm64-msvc',
raw: 'aarch64-pc-windows-msvc',
} as const,
},
{
name: 'armv7-unknown-linux-gnueabihf',
expected: {
abi: 'gnueabihf',
arch: 'arm',
platform: 'linux',
platformArchABI: 'linux-arm-gnueabihf',
raw: 'armv7-unknown-linux-gnueabihf',
} as const,
},
]
for (const triple of triples) {
test(`should parse ${triple.name}`, (t) => {
t.deepEqual(parseTriple(triple.name), triple.expected)
})
}
test('should parse default triple from rustup show active', (t) => {
t.deepEqual(
getDefaultTargetTriple(
`x86_64-unknown-linux-gnu (directory override for '/home/runner/work/fast-escape/fast-escape')`,
),
parseTriple('x86_64-unknown-linux-gnu'),
)
t.deepEqual(
getDefaultTargetTriple(`stable-x86_64-apple-darwin (default)`),
parseTriple(`x86_64-apple-darwin`),
)
t.deepEqual(
getDefaultTargetTriple(`nightly-2020-08-29-x86_64-apple-darwin (default)`),
parseTriple('x86_64-apple-darwin'),
)
})

View file

@ -4,6 +4,7 @@ import chalk from 'chalk'
import { Command } from 'clipanion'
import { fdir } from 'fdir'
import { getNapiConfig } from './consts'
import { debugFactory } from './debug'
import { readFileAsync, writeFileAsync } from './utils'
@ -13,43 +14,26 @@ export class ArtifactsCommand extends Command {
@Command.String('-d,--dir')
sourceDir = 'artifacts'
@Command.String('-t,--target')
targetDir = '.'
@Command.String('--dist')
distDir = 'npm'
@Command.String('-c,--config')
configFileName?: string
@Command.Path('artifacts')
async execute() {
const api = new fdir()
.withFullPaths()
.exclude((dirPath) => dirPath.includes('node_modules'))
.filter((filePath) => filePath.endsWith('package.json'))
.crawl(join(process.cwd(), this.targetDir))
const { platforms, binaryName, packageJsonPath } = getNapiConfig(
this.configFileName,
)
const packageJsonDir = parse(packageJsonPath).dir
const sourceApi = new fdir()
.withFullPaths()
.crawl(join(process.cwd(), this.sourceDir))
const distDirs = await api.withPromise().then(
(output) =>
(output as string[])
.map((packageJsonPath) => {
const { dir } = parse(packageJsonPath)
const { napi } = require(packageJsonPath)
if (!napi) {
return null
}
const napiName: string = napi?.name ?? 'index'
debug(
`Scan dir: [${chalk.yellowBright(
dir,
)}], napi name: ${chalk.greenBright(napiName)}`,
)
return {
dir,
name: napiName,
}
})
.filter(Boolean) as {
name: string
dir: string
}[],
const distDirs = platforms.map((platform) =>
join(process.cwd(), this.distDir, platform.platformArchABI),
)
await sourceApi.withPromise().then((output) =>
@ -58,14 +42,26 @@ export class ArtifactsCommand extends Command {
debug(`Read [${chalk.yellowBright(filePath)}]`)
const sourceContent = await readFileAsync(filePath)
const parsedName = parse(filePath)
const [fileName] = parsedName.name.split('.')
const { dir } = distDirs.find(({ name }) => name === fileName) ?? {}
const [_binaryName, platformArchABI] = parsedName.name.split('.')
if (_binaryName !== binaryName) {
debug(
`[${chalk.yellowBright(
_binaryName,
)}] is not matched with [${chalk.greenBright(binaryName)}], skip`,
)
}
const dir = distDirs.find((dir) => dir.includes(platformArchABI))
if (!dir) {
throw new TypeError(`No dist dir found for ${filePath}`)
}
const distFilePath = join(dir, parsedName.base)
debug(`Write file content to [${chalk.yellowBright(distFilePath)}]`)
await writeFileAsync(distFilePath, sourceContent)
const distFilePathLocal = join(packageJsonDir, parsedName.base)
debug(
`Write file content to [${chalk.yellowBright(distFilePathLocal)}]`,
)
await writeFileAsync(distFilePathLocal, sourceContent)
}),
),
)

View file

@ -1,3 +1,4 @@
import { execSync } from 'child_process'
import os from 'os'
import { join, parse, sep } from 'path'
@ -7,6 +8,7 @@ import toml from 'toml'
import { getNapiConfig } from './consts'
import { debugFactory } from './debug'
import { getDefaultTargetTriple, parseTriple } from './parse-triple'
import { existsAsync, readFileAsync, writeFileAsync } from './utils'
const debug = debugFactory('build')
@ -17,23 +19,26 @@ export class BuildCommand extends Command {
})
@Command.Boolean(`--platform`)
appendPlatformToFilename!: boolean
appendPlatformToFilename = false
@Command.Boolean(`--release`)
isRelease = false
@Command.Boolean('--musl')
isMusl = false
@Command.String('--config,-c')
configFileName?: string
@Command.String('--cargo-name')
cargoName?: string
@Command.String('--target-triple')
@Command.String('--target')
targetTripleDir = ''
@Command.String('--features')
features?: string
@Command.String('--cargo-flags')
cargoFlags = ''
@Command.String({
required: false,
})
@ -41,6 +46,33 @@ export class BuildCommand extends Command {
@Command.Path('build')
async execute() {
const releaseFlag = this.isRelease ? `--release` : ''
const targetFLag = this.targetTripleDir
? `--target ${this.targetTripleDir}`
: ''
const featuresFlag = this.features ? `--features ${this.features}` : ''
const triple = this.targetTripleDir
? parseTriple(this.targetTripleDir)
: getDefaultTargetTriple(
execSync('rustup show active-toolchain', {
env: process.env,
}).toString('utf8'),
)
debug(`Current triple is: ${chalk.green(triple.raw)}`)
const externalFlags = [
releaseFlag,
targetFLag,
featuresFlag,
this.cargoFlags,
]
.filter((flag) => Boolean(flag))
.join(' ')
const cargoCommand = `cargo build ${externalFlags}`
debug(`Run ${chalk.green(cargoCommand)}`)
execSync(cargoCommand, {
env: process.env,
stdio: 'inherit',
})
const { binaryName } = getNapiConfig(this.configFileName)
let dylibName = this.cargoName
if (!dylibName) {
@ -88,6 +120,8 @@ export class BuildCommand extends Command {
break
case 'linux':
case 'freebsd':
case 'openbsd':
case 'sunos':
dylibName = `lib${dylibName}`
libExt = '.so'
break
@ -102,21 +136,11 @@ export class BuildCommand extends Command {
this.isRelease ? 'release' : 'debug',
)
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`
? `.${triple.platformArchABI}`
: ''
debug(
`Platform name: ${
platformName || chalk.green('[Empty]')
}, musl: ${chalk.greenBright(this.isMusl)}`,
)
debug(`Platform name: ${platformName || chalk.green('[Empty]')}`)
let distModulePath = this.target
? join(this.target, `${binaryName}${platformName}.node`)

View file

@ -1,14 +1,18 @@
import { join } from 'path'
import { DefaultPlatforms, PlatformDetail, parseTriple } from './parse-triple'
export function getNapiConfig(packageJson = 'package.json') {
const packageJsonPath = join(process.cwd(), packageJson)
const pkgJson = require(packageJsonPath)
const { version: packageVersion, os, napi, name } = pkgJson
const muslPlatforms: string[] = (napi?.musl ?? []).map(
(platform: string) => `${platform}-musl`,
)
const platforms = os
const { version: packageVersion, napi, name } = pkgJson
const additionPlatforms: PlatformDetail[] = (
napi?.triples?.additional ?? []
).map(parseTriple)
const defaultPlatforms =
napi?.triples?.defaults === false ? [] : [...DefaultPlatforms]
const platforms = [...defaultPlatforms, ...additionPlatforms]
const releaseVersion = process.env.RELEASE_VERSION
const releaseVersionWithoutPrefix = releaseVersion?.startsWith('v')
? releaseVersion.substr(1)
@ -16,10 +20,9 @@ export function getNapiConfig(packageJson = 'package.json') {
const version = releaseVersionWithoutPrefix ?? packageVersion
const packageName = name
const binaryName = napi?.name ?? 'index'
const binaryName: string = napi?.name ?? 'index'
return {
muslPlatforms,
platforms,
version,
packageName,

View file

@ -6,6 +6,7 @@ import { pick } from 'lodash'
import { getNapiConfig } from './consts'
import { debugFactory } from './debug'
import { PlatformDetail } from './parse-triple'
import { spawn } from './spawn'
import { writeFileAsync } from './utils'
@ -15,32 +16,40 @@ export class CreateNpmDirCommand extends Command {
@Command.String('-t,--target')
targetDir!: string
@Command.String('-c,--config')
config = 'package.json'
@Command.Path('create-npm-dir')
async execute() {
const pkgJsonDir = join(this.targetDir, 'package.json')
const pkgJsonDir = this.config
debug(`Read content from [${chalk.yellowBright(pkgJsonDir)}]`)
const {
platforms,
muslPlatforms,
packageName,
version,
binaryName,
content,
} = getNapiConfig(pkgJsonDir)
for (const platform of [...platforms, ...muslPlatforms]) {
const targetDir = join(process.cwd(), this.targetDir, 'npm', platform)
for (const platformDetail of platforms) {
const targetDir = join(
process.cwd(),
this.targetDir,
'npm',
`${platformDetail.platformArchABI}`,
)
await spawn(`mkdir -p ${targetDir}`)
const binaryFileName = `${binaryName}.${platform}.node`
const binaryFileName = `${binaryName}.${platformDetail.platformArchABI}.node`
const targetPackageJson = join(targetDir, 'package.json')
debug(`Write file [${chalk.yellowBright(targetPackageJson)}]`)
await writeFileAsync(
targetPackageJson,
JSON.stringify(
{
name: `${packageName}-${platform}`,
name: `${packageName}-${platformDetail.platformArchABI}`,
version,
os: [platform.replace('-musl', '')],
os: [platformDetail.platform],
cpu: [platformDetail.arch],
main: binaryFileName,
files: [binaryFileName],
...pick(
@ -50,7 +59,6 @@ export class CreateNpmDirCommand extends Command {
'author',
'homepage',
'license',
'cpu',
'engines',
'publishConfig',
'repository',
@ -63,14 +71,14 @@ export class CreateNpmDirCommand extends Command {
)
const targetReadme = join(targetDir, 'README.md')
debug(`Write target README.md [${chalk.yellowBright(targetReadme)}]`)
await writeFileAsync(targetReadme, readme(packageName, platform))
await writeFileAsync(targetReadme, readme(packageName, platformDetail))
}
}
}
function readme(packageName: string, platform: string) {
return `# \`${packageName}-${platform}\`
function readme(packageName: string, platformDetail: PlatformDetail) {
return `# \`${packageName}-${platformDetail.platformArchABI}\`
This is the **${platform}** 64-bit binary for \`${packageName}\`
This is the **${platformDetail.raw}** binary for \`${packageName}\`
`
}

124
cli/src/parse-triple.ts Normal file
View file

@ -0,0 +1,124 @@
import { execSync } from 'child_process'
// https://nodejs.org/api/process.html#process_process_arch
type NodeJSArch =
| 'arm'
| 'arm64'
| 'ia32'
| 'mips'
| 'mipsel'
| 'ppc'
| 'ppc64'
| 's390'
| 's390x'
| 'x32'
| 'x64'
const CpuToNodeArch: { [index: string]: NodeJSArch } = {
x86_64: 'x64',
aarch64: 'arm64',
i686: 'ia32',
armv7: 'arm',
}
const SysToNodePlatform: { [index: string]: NodeJS.Platform } = {
linux: 'linux',
freebsd: 'freebsd',
darwin: 'darwin',
windows: 'win32',
}
export interface PlatformDetail {
platform: NodeJS.Platform
platformArchABI: string
arch: NodeJSArch
raw: string
abi: string | null
}
export const DefaultPlatforms: PlatformDetail[] = [
{
platform: 'win32',
arch: 'x64',
abi: 'msvc',
platformArchABI: 'win32-x64-msvc',
raw: 'x86_64-pc-windows-msvc',
},
{
platform: 'darwin',
arch: 'x64',
abi: null,
platformArchABI: 'darwin-x64',
raw: 'x86_64-apple-darwin',
},
{
platform: 'linux',
arch: 'x64',
abi: 'gnu',
platformArchABI: 'linux-x64-gnu',
raw: 'x86_64-unknown-linux-gnu',
},
]
/**
* A triple is a specific format for specifying a target architecture.
* Triples may be referred to as a target triple which is the architecture for the artifact produced, and the host triple which is the architecture that the compiler is running on.
* The general format of the triple is `<arch><sub>-<vendor>-<sys>-<abi>` where:
* - `arch` = The base CPU architecture, for example `x86_64`, `i686`, `arm`, `thumb`, `mips`, etc.
* - `sub` = The CPU sub-architecture, for example `arm` has `v7`, `v7s`, `v5te`, etc.
* - `vendor` = The vendor, for example `unknown`, `apple`, `pc`, `nvidia`, etc.
* - `sys` = The system name, for example `linux`, `windows`, `darwin`, etc. none is typically used for bare-metal without an OS.
* - `abi` = The ABI, for example `gnu`, `android`, `eabi`, etc.
*/
export function parseTriple(triple: string): PlatformDetail {
const triples = triple.split('-')
let cpu: string
let sys: string
let abi: string | null = null
if (triples.length === 4) {
;[cpu, , sys, abi = null] = triples
} else if (triples.length === 3) {
;[cpu, , sys] = triples
} else {
;[cpu, sys] = triples
}
const platformName = SysToNodePlatform[sys] ?? sys
const arch = CpuToNodeArch[cpu] ?? cpu
return {
platform: platformName,
arch,
abi,
platformArchABI: abi
? `${platformName}-${arch}-${abi}`
: `${platformName}-${arch}`,
raw: triple,
}
}
// x86_64-unknown-linux-gnu (directory override for '/home/runner/work/fast-escape/fast-escape')
// stable-x86_64-apple-darwin (default)
// nightly-2020-08-29-x86_64-apple-darwin (default)
export function getDefaultTargetTriple(rustcfg: string): PlatformDetail {
const currentTriple = rustcfg
.trim()
.replace(/\(.*?\)/, '')
.trim()
const allTriples = execSync(`rustup target list`, {
env: process.env,
})
.toString('utf8')
.split('\n')
.map((line) =>
line
.trim()
// remove (installed) from x86_64-apple-darwin (installed)
.replace(/\(.*?\)/, '')
.trim(),
)
.filter((line) => line.length)
const triple = allTriples.find((triple) => currentTriple.indexOf(triple) > -1)
if (!triple) {
throw new TypeError(`Can not parse target triple from ${currentTriple}`)
}
return parseTriple(triple)
}

View file

@ -8,7 +8,7 @@ import { getNapiConfig } from './consts'
import { debugFactory } from './debug'
import { spawn } from './spawn'
import { updatePackageJson } from './update-package'
import { readFileAsync, writeFileAsync } from './utils'
import { existsAsync } from './utils'
import { VersionCommand } from './version'
const debug = debugFactory('prepublish')
@ -43,7 +43,6 @@ export class PrePublishCommand extends Command {
packageJsonPath,
platforms,
version,
muslPlatforms,
packageName,
binaryName,
} = getNapiConfig(this.configFileName)
@ -52,8 +51,8 @@ export class PrePublishCommand extends Command {
await VersionCommand.updatePackageJson(this.prefix, this.configFileName)
await updatePackageJson(packageJsonPath, {
optionalDependencies: platforms.reduce(
(acc: Record<string, string>, cur: NodeJS.Platform) => {
acc[`${packageName}-${cur}`] = `^${version}`
(acc: Record<string, string>, cur) => {
acc[`${packageName}-${cur.platformArchABI}`] = `^${version}`
return acc
},
{},
@ -66,26 +65,29 @@ export class PrePublishCommand extends Command {
version,
)
for (const name of [...platforms, ...muslPlatforms]) {
const pkgDir = join(process.cwd(), this.prefix, name)
const filename = `${binaryName}.${name}.node`
debug(`Read [${chalk.greenBright(filename)}] content`)
const bindingFile = await readFileAsync(join(process.cwd(), filename))
for (const platformDetail of platforms) {
const pkgDir = join(
process.cwd(),
this.prefix,
`${platformDetail.platformArchABI}`,
)
const filename = `${binaryName}.${platformDetail.platformArchABI}.node`
const dstPath = join(pkgDir, filename)
await writeFileAsync(dstPath, bindingFile)
debug(`Write [${chalk.yellowBright(dstPath)}] content`)
if (!this.isDryRun) {
await spawn('npm publish', {
cwd: pkgDir,
env: process.env,
})
}
debug(
`Start upload [${chalk.greenBright(
dstPath,
)}] to Github release, [${chalk.greenBright(pkgInfo.tag)}]`,
)
if (!this.isDryRun) {
if (!(await existsAsync(dstPath))) {
console.warn(`[${chalk.yellowBright(dstPath)}] is not existed`)
continue
}
await spawn('npm publish', {
cwd: pkgDir,
env: process.env,
})
const putasset = require('putasset')
try {
const downloadUrl = await putasset(process.env.GITHUB_TOKEN, {

View file

@ -12,9 +12,9 @@ const debug = debugFactory('version')
export class VersionCommand extends Command {
static async updatePackageJson(prefix: string, configFileName?: string) {
const { muslPlatforms, version, platforms } = getNapiConfig(configFileName)
for (const name of [...platforms, ...muslPlatforms]) {
const pkgDir = join(process.cwd(), prefix, name)
const { version, platforms } = getNapiConfig(configFileName)
for (const platformDetail of platforms) {
const pkgDir = join(process.cwd(), prefix, platformDetail.platformArchABI)
debug(
`Update version to ${chalk.greenBright(
version,

40
generate-triplelist.js Normal file
View file

@ -0,0 +1,40 @@
const { readFileSync, writeFileSync } = require('fs')
const { join } = require('path')
const { groupBy, mapValues } = require('lodash')
const prettier = require('prettier')
const { parseTriple } = require('./cli/scripts/parse-triple')
const rawLists = readFileSync(join(__dirname, 'triples', 'target-list'), 'utf8')
const tripleLists = rawLists
.trim()
.split('\n')
.filter((line) => !line.startsWith('wasm') && line.trim().length)
.map(parseTriple)
.reduce((acc, cur) => {
acc[cur.raw] = cur
return acc
}, {})
const platformArchTriples = mapValues(
groupBy([...Object.values(tripleLists)], 'platform'),
(v) => groupBy(v, 'arch'),
)
const fileContent = `
module.exports = ${JSON.stringify(tripleLists, null, 2)}
module.exports.platformArchTriples = ${JSON.stringify(platformArchTriples)}
`
writeFileSync(
join(__dirname, 'triples', 'index.js'),
prettier.format(fileContent, {
semi: false,
singleQuote: true,
trailingComma: 'es5',
parser: 'typescript',
}),
)

10
lerna.json Normal file
View file

@ -0,0 +1,10 @@
{
"packages": [
"cli",
"triples"
],
"version": "independent",
"useWorkspaces": true,
"npmClient": "yarn",
"message": "chore: publish"
}

View file

@ -1,28 +1,20 @@
{
"name": "napi-rs",
"version": "0.3.9",
"version": "0.0.0",
"description": "A minimal library for building compiled Node add-ons in Rust.",
"bin": {
"napi": "scripts/index.js"
},
"engines": {
"node": ">= 10"
},
"private": "true",
"workspaces": [
"cli",
"triples"
],
"repository": {
"type": "git",
"url": "git@github.com:Brooooooklyn/napi-rs.git"
},
"maintainers": [
{
"name": "LongYinan",
"email": "lynweklm@gmail.com",
"homepage": "https://github.com/Brooooooklyn"
}
],
"license": "MIT",
"scripts": {
"bench": "cross-env SWC_NODE_PROJECT='./bench/tsconfig.json' node -r ts-node/register/transpile-only bench/bench.ts",
"build": "tsc -p tsconfig.json && chmod 777 scripts/index.js",
"bench": "cross-env TS_NODE_PROJECT='./bench/tsconfig.json' node -r ts-node/register/transpile-only bench/bench.ts",
"build": "tsc -p tsconfig.json && shx chmod 777 cli/scripts/index.js && node generate-triplelist.js",
"build:bench": "yarn --cwd ./bench build",
"build:test": "yarn --cwd ./test_module build",
"build:test:aarch64": "yarn --cwd ./test_module build-aarch64",
@ -32,7 +24,7 @@
"format:rs": "cargo fmt",
"format:source": "prettier --config ./package.json --write './**/*.{js,ts}'",
"format:yaml": "prettier --parser yaml --write './**/*.{yml,yaml}'",
"lint": "eslint -c .eslintrc.yml './src/**/*.ts' './test_module/**/*.{ts,js}'",
"lint": "eslint -c .eslintrc.yml './cli/**/*.ts' './test_module/**/*.{ts,js}'",
"prepublishOnly": "npm run build",
"test": "ava"
},
@ -40,18 +32,6 @@
"url": "https://github.com/napi-rs/napi-rs/issues"
},
"homepage": "https://github.com/napi-rs/napi-rs#readme",
"dependencies": {
"@octokit/rest": "^18.0.10",
"chalk": "^4.1.0",
"clipanion": "^2.6.2",
"debug": "^4.3.1",
"fdir": "^4.1.0",
"inquirer": "^7.3.3",
"lodash": "^4.17.20",
"putasset": "^5.0.3",
"toml": "^3.0.0",
"tslib": "^2.0.3"
},
"prettier": {
"printWidth": 80,
"semi": false,
@ -59,12 +39,19 @@
"trailingComma": "all",
"arrowParens": "always"
},
"files": ["scripts", "LICENSE"],
"lint-staged": {
"*.js": ["prettier --write"],
"*.@(yml|yaml)": ["prettier --parser yaml --write"],
"*.json": ["prettier --parser json --write"],
"*.md": ["prettier --parser markdown --write"]
"*.js": [
"prettier --write"
],
"*.@(yml|yaml)": [
"prettier --parser yaml --write"
],
"*.json": [
"prettier --parser json --write"
],
"*.md": [
"prettier --parser markdown --write"
]
},
"husky": {
"hooks": {
@ -88,13 +75,16 @@
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-prettier": "^3.1.4",
"husky": "^4.3.0",
"lerna": "^3.22.1",
"lint-staged": "^10.5.2",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"prettier": "^2.2.1",
"shx": "^0.3.3",
"sinon": "^9.2.1",
"source-map-support": "^0.5.19",
"ts-node": "^9.0.0",
"tslib": "^2.0.3",
"typescript": "^4.1.2"
}
}
}

View file

@ -2,12 +2,12 @@
"name": "test-module",
"version": "1.0.0",
"scripts": {
"build": "cargo build --features \"latest\" && node ../scripts/index.js build",
"build-napi3": "cargo build --features \"napi3\" && node ../scripts/index.js build",
"build-aarch64": "cargo build --features \"latest\" --target aarch64-unknown-linux-gnu && node ../scripts/index.js build --target-triple aarch64-unknown-linux-gnu",
"build-i686": "cargo build --features \"latest\" --target i686-pc-windows-msvc && node ../scripts/index.js build --target-triple i686-pc-windows-msvc",
"build-i686-release": "cargo build --release --features \"latest\" --target i686-pc-windows-msvc && node ../scripts/index.js build --release --target-triple i686-pc-windows-msvc",
"build-release": "cargo build --features \"latest\" --release && node ../scripts/index.js build --release",
"build": "node ../cli/scripts/index.js build --features \"latest\"",
"build-napi3": "node ../cli/scripts/index.js build --features \"napi3\"",
"build-aarch64": "node ../cli/scripts/index.js build --features \"latest\" --target aarch64-unknown-linux-gnu",
"build-i686": "node ../cli/scripts/index.js build --features \"latest\" --target i686-pc-windows-msvc",
"build-i686-release": "node ../cli/scripts/index.js build --release --features \"latest\" --target i686-pc-windows-msvc",
"build-release": "node ../cli/scripts/index.js build --features \"latest\" --release",
"test": "node ./index.js"
}
}
}

21
triples/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 LongYinan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

72
triples/README.md Normal file
View file

@ -0,0 +1,72 @@
# `@napi-rs/triples`
> Rust build triples definitions
## Usage
```js
const triples = require('@napi-rs/triples');
console.log(triples)
[
...
'aarch64-apple-ios': {
platform: 'ios',
arch: 'arm64',
abi: null,
platformArchABI: 'ios-arm64',
raw: 'aarch64-apple-ios',
},
'aarch64-fuchsia': {
platform: 'fuchsia',
arch: 'arm64',
abi: null,
platformArchABI: 'fuchsia-arm64',
raw: 'aarch64-fuchsia',
},
'aarch64-linux-android': {
platform: 'android',
arch: 'arm64',
abi: null,
platformArchABI: 'android-arm64',
raw: 'aarch64-linux-android',
},
'aarch64-pc-windows-msvc': {
platform: 'win32',
arch: 'arm64',
abi: 'msvc',
platformArchABI: 'win32-arm64-msvc',
raw: 'aarch64-pc-windows-msvc',
},
'aarch64-unknown-linux-gnu': {
platform: 'linux',
arch: 'arm64',
abi: 'gnu',
platformArchABI: 'linux-arm64-gnu',
raw: 'aarch64-unknown-linux-gnu',
},
'aarch64-unknown-linux-musl': {
platform: 'linux',
arch: 'arm64',
abi: 'musl',
platformArchABI: 'linux-arm64-musl',
raw: 'aarch64-unknown-linux-musl',
},
'aarch64-unknown-none': {
platform: 'none',
arch: 'arm64',
abi: null,
platformArchABI: 'none-arm64',
raw: 'aarch64-unknown-none',
},
'aarch64-unknown-none-softfloat': {
platform: 'none',
arch: 'arm64',
abi: 'softfloat',
platformArchABI: 'none-arm64-softfloat',
raw: 'aarch64-unknown-none-softfloat',
}
...
]
```

17
triples/index.d.ts vendored Normal file
View file

@ -0,0 +1,17 @@
interface Triple {
platform: string
arch: string
abi: string | null
platformArchABI: string
raw: string
}
declare const Triples: Triple[] & {
platformArchTriples: {
[index: string]: {
[index: string]: Triple[]
}
}
}
export = Triples

1309
triples/index.js Normal file

File diff suppressed because it is too large Load diff

23
triples/package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "@napi-rs/triples",
"version": "1.0.2",
"description": "Rust target triples objects",
"keywords": ["Rust", "cross-compile", "napi", "n-api", "node-rs", "napi-rs"],
"author": "LongYinan <lynweklm@gmail.com>",
"homepage": "https://github.com/napi-rs/napi-rs/tree/master/triples#readme",
"license": "MIT",
"main": "./index.js",
"types": "./index.d.ts",
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"files": ["index.js", "index.d.ts", "target-list"],
"repository": {
"type": "git",
"url": "git+https://github.com/napi-rs/napi-rs.git"
},
"bugs": {
"url": "https://github.com/napi-rs/napi-rs/issues"
}
}

85
triples/target-list Normal file
View file

@ -0,0 +1,85 @@
aarch64-apple-darwin
aarch64-apple-ios
aarch64-fuchsia
aarch64-linux-android
aarch64-pc-windows-msvc
aarch64-unknown-linux-gnu
aarch64-unknown-linux-musl
aarch64-unknown-none
aarch64-unknown-none-softfloat
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf
arm-unknown-linux-musleabi
arm-unknown-linux-musleabihf
armebv7r-none-eabi
armebv7r-none-eabihf
armv5te-unknown-linux-gnueabi
armv5te-unknown-linux-musleabi
armv7-linux-androideabi
armv7-unknown-linux-gnueabi
armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabi
armv7-unknown-linux-musleabihf
armv7a-none-eabi
armv7r-none-eabi
armv7r-none-eabihf
asmjs-unknown-emscripten
i586-pc-windows-msvc
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-freebsd
i686-unknown-linux-gnu
i686-unknown-linux-musl
mips-unknown-linux-gnu
mips-unknown-linux-musl
mips64-unknown-linux-gnuabi64
mips64-unknown-linux-muslabi64
mips64el-unknown-linux-gnuabi64
mips64el-unknown-linux-muslabi64
mipsel-unknown-linux-gnu
mipsel-unknown-linux-musl
nvptx64-nvidia-cuda
powerpc-unknown-linux-gnu
powerpc64-unknown-linux-gnu
powerpc64le-unknown-linux-gnu
riscv32i-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imc-unknown-none-elf
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-none-elf
riscv64imac-unknown-none-elf
s390x-unknown-linux-gnu
sparc64-unknown-linux-gnu
sparcv9-sun-solaris
thumbv6m-none-eabi
thumbv7em-none-eabi
thumbv7em-none-eabihf
thumbv7m-none-eabi
thumbv7neon-linux-androideabi
thumbv7neon-unknown-linux-gnueabihf
thumbv8m.base-none-eabi
thumbv8m.main-none-eabi
thumbv8m.main-none-eabihf
wasm32-unknown-emscripten
wasm32-unknown-unknown
wasm32-wasi
x86_64-apple-darwin
x86_64-apple-ios
x86_64-fortanix-unknown-sgx
x86_64-fuchsia
x86_64-linux-android
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc
x86_64-rumprun-netbsd
x86_64-sun-solaris
x86_64-unknown-freebsd
x86_64-unknown-illumos
x86_64-unknown-linux-gnu
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-netbsd
x86_64-unknown-redox

View file

@ -1,6 +1,5 @@
{
"compilerOptions": {
"jsx": "react",
"allowSyntheticDefaultImports": true,
"declaration": true,
"downlevelIteration": true,
@ -26,9 +25,10 @@
"stripInternal": true,
"resolveJsonModule": true,
"importsNotUsedAsValues": "remove",
"outDir": "./scripts",
"rootDir": "./cli/src",
"outDir": "./cli/scripts",
"lib": ["dom", "DOM.Iterable", "ES2019", "ES2020", "esnext"]
},
"include": ["./src"],
"exclude": ["node_modules", "bench"]
"include": ["cli"],
"exclude": ["node_modules", "bench", "cli/scripts"]
}

View file

@ -1,4 +1,4 @@
{
"extends": "./tsconfig.json",
"files": ["./ava.config.js"]
"files": ["./ava.config.js", "./generate-triplelist.js", "triples/index.js"]
}

4512
yarn.lock

File diff suppressed because it is too large Load diff