\n\n```'",
"dryRunCommand": true,
"pipe": true
},
{
"command": "pnpm publish --access public",
"dryRunCommand": "npm publish --dry-run --access public",
"pipe": true
},
{
"command": "echo '```\n\n\n'",
"dryRunCommand": true,
"pipe": true
}
],
"postpublish": [
"git tag ${ pkg.pkg }-v${ pkgFile.versionMajor } -f",
"git tag ${ pkg.pkg }-v${ pkgFile.versionMajor }.${ pkgFile.versionMinor } -f",
"git push --tags -f"
]
}
},
"packages": {
"cargo-packager-utils": {
"path": "./crates/utils",
"manager": "rust"
},
"cargo-packager": {
"path": "./crates/packager",
"manager": "rust",
"dependencies": ["cargo-packager-utils"]
},
"@crabnebula/packager": {
"path": "./bindings/packager/nodejs",
"manager": "javascript",
"dependencies": ["cargo-packager", "cargo-packager-utils"],
"prepublish": [],
"publish": [],
"postpublish": []
},
"cargo-packager-updater": {
"path": "./crates/updater",
"dependencies": ["cargo-packager-utils"],
"manager": "rust"
},
"@crabnebula/updater": {
"path": "./bindings/updater/nodejs",
"manager": "javascript",
"dependencies": ["cargo-packager-updater", "cargo-packager-utils"],
"prepublish": [],
"publish": [],
"postpublish": []
},
"cargo-packager-resource-resolver": {
"path": "./crates/resource-resolver",
"dependencies": ["cargo-packager-utils"],
"manager": "rust"
},
"@crabnebula/packager-resource-resolver": {
"path": "./bindings/resource-resolver/nodejs",
"manager": "javascript",
"dependencies": [
"cargo-packager-resource-resolver",
"cargo-packager-utils"
],
"prepublish": [],
"publish": [],
"postpublish": []
}
}
}
================================================
FILE: .changes/readme.md
================================================
# Changes
##### via https://github.com/jbolda/covector
As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version _number_, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend it represents the overall change for our sanity.
When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process.
Use the following format:
```md
---
"cargo-packager": patch
---
Change summary goes here
```
Summaries do not have a specific character limit, but are text only. These summaries are used within the (future implementation of) changelogs. They will give context to the change and also point back to the original PR if more details and context are needed.
Changes will be designated as a `major`, `minor` or `patch` as further described in [semver](https://semver.org/).
Given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards compatible manner, and
- PATCH version when you make backwards compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format, but will be discussed prior to usage (as extra steps will be necessary in consideration of merging and publishing).
================================================
FILE: .github/workflows/audit.yml
================================================
name: Audit Rust
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
push:
branches:
- main
paths:
- ".github/workflows/audit.yml"
- "**/Cargo.lock"
- "**/Cargo.toml"
pull_request:
branches:
- main
paths:
- ".github/workflows/audit.yml"
- "**/Cargo.lock"
- "**/Cargo.toml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: rustsec/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/build-examples.yml
================================================
name: Package examples
on:
pull_request:
branches:
- main
paths:
- ".github/workflows/build-examples.yml"
- "crates/**"
- "examples/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
package:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-22.04, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v6
- name: install webkit2gtk
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.1 webkit2gtk-4.0 libayatana-appindicator3-dev libxdo-dev
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-go@v6
with:
go-version: "stable"
- uses: denoland/setup-deno@v1
- uses: Swatinem/rust-cache@v2
- run: go install github.com/wailsapp/wails/v2/cmd/wails@latest
- run: cargo install cargo-binstall --locked
- run: cargo binstall tauri-cli --locked --force
- run: cargo r --package cargo-packager -- signer generate --password '123' --path ./signing-key -vvv
- run: cargo r --package cargo-packager -- --release --private-key ./signing-key --password '123' --formats all -vvv
================================================
FILE: .github/workflows/check-nodejs-bindings.yml
================================================
name: Check Node.js bindings
on:
push:
branches:
- main
paths:
- ".github/workflows/check-nodejs-bindings.yml"
- "crates/packager/**"
- "crates/updater/**"
- "crates/resource-resolver/**"
- "bindings/*/nodejs/**"
pull_request:
branches:
- main
paths:
- ".github/workflows/check-nodejs-bindings.yml"
- "crates/packager/**"
- "crates/updater/**"
- "crates/resource-resolver/**"
- "bindings/*/nodejs/**"
env:
RUST_BACKTRACE: 1
CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: pnpm/action-setup@v4
with:
version: latest
- uses: actions/setup-node@v6
- uses: Swatinem/rust-cache@v2
- run: pnpm install
- run: pnpm build
================================================
FILE: .github/workflows/check.yml
================================================
name: Check
on:
push:
branches:
- main
paths:
- ".github/workflows/check.yml"
- "**/*.rs"
- "**/Cargo.toml"
pull_request:
branches:
- main
paths:
- ".github/workflows/check.yml"
- "**/*.rs"
- "**/Cargo.toml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
prettier:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
version: latest
- run: pnpm install
- run: pnpm format:check
rustfmt:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
clippy:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: install webkit2gtk
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev libxdo-dev
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
rust-test:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v6
- name: install webkit2gtk
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev libxdo-dev
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --workspace --lib --bins --tests --benches --all-features --no-fail-fast
deny:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: EmbarkStudios/cargo-deny-action@v2
================================================
FILE: .github/workflows/covector-status.yml
================================================
name: Covector Status
on: [pull_request]
jobs:
covector:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: covector status
uses: jbolda/covector/packages/action@covector-v0
id: covector
with:
command: "status"
================================================
FILE: .github/workflows/covector-version-or-publish.yml
================================================
name: Covector Version or Publish
on:
push:
branches:
- main
jobs:
version-or-publish:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
timeout-minutes: 65
outputs:
change: ${{ steps.covector.outputs.change }}
commandRan: ${{ steps.covector.outputs.commandRan }}
successfulPublish: ${{ steps.covector.outputs.successfulPublish }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: cargo login
run: cargo login ${{ secrets.CRATES_IO_TOKEN }}
- name: git config
run: |
git config --global user.name "${{ github.event.pusher.name }}"
git config --global user.email "${{ github.event.pusher.email }}"
- name: covector version or publish (publish when no change files present)
uses: jbolda/covector/packages/action@covector-v0
id: covector
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: "version-or-publish"
createRelease: true
- name: Create Pull Request With Versions Bumped
if: steps.covector.outputs.commandRan == 'version'
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: release/version-updates
title: "release: apply version updates from current changes"
commit-message: "release: apply version updates from current changes"
labels: "version updates"
body: ${{ steps.covector.outputs.change }}
sign-commits: true
- name: Trigger `@crabnebula/packager` publishing workflow
if: |
steps.covector.outputs.successfulPublish == 'true' &&
contains(steps.covector.outputs.packagesPublished, '@crabnebula/packager')
uses: peter-evans/repository-dispatch@v3
with:
event-type: publish-packager-nodejs
client-payload: >-
{"releaseId": "${{ steps.covector.outputs['-crabnebula-packager-releaseId'] }}" }
- name: Trigger `@crabnebula/updater` publishing workflow
if: |
steps.covector.outputs.successfulPublish == 'true' &&
contains(steps.covector.outputs.packagesPublished, '@crabnebula/updater')
uses: peter-evans/repository-dispatch@v3
with:
event-type: publish-updater-nodejs
client-payload: >-
{"releaseId": "${{ steps.covector.outputs['-crabnebula-updater-releaseId'] }}" }
- name: Trigger `@crabnebula/packager-resource-resolver` publishing workflow
if: |
steps.covector.outputs.successfulPublish == 'true' &&
contains(steps.covector.outputs.packagesPublished, '@crabnebula/packager-resource-resolver')
uses: peter-evans/repository-dispatch@v3
with:
event-type: publish-packager-resource-resolver-nodejs
client-payload: >-
{"releaseId": "${{ steps.covector.outputs['-crabnebula-packager-resource-resolver-releaseId'] }}" }
================================================
FILE: .github/workflows/integration-tests.yml
================================================
name: integration tests
on:
push:
branches:
- main
pull_request:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test-rust:
if: ${{ !startsWith(github.head_ref, 'renovate/') }}
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: install fuse
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y fuse libfuse2
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --test '*' -- --ignored --nocapture
test-nodejs:
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: pnpm/action-setup@v4
with:
version: latest
- uses: actions/setup-node@v6
- uses: Swatinem/rust-cache@v2
- run: pnpm install
- run: pnpm build
- name: packager integration tests
run: |
cd bindings/packager/nodejs
pnpm test
timeout-minutes: 30
- name: install fuse
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y fuse libfuse2
- name: updater integration tests
run: |
cd bindings/updater/nodejs
pnpm test
timeout-minutes: 30
================================================
FILE: .github/workflows/publish-packager-nodejs.yml
================================================
name: Publish `@crabnebula/packager`
env:
DEBUG: napi:*
APP_NAME: packager
MACOSX_DEPLOYMENT_TARGET: "10.13"
permissions:
contents: write
id-token: write
on:
workflow_dispatch:
inputs:
releaseId:
description: "ID of the `@crabnebula/packager` release"
required: true
repository_dispatch:
types: [publish-packager-nodejs]
defaults:
run:
working-directory: bindings/packager/nodejs
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: |
pnpm build
strip -x *.node
- host: windows-latest
build: pnpm build
target: x86_64-pc-windows-msvc
- host: windows-latest
build: pnpm build --target i686-pc-windows-msvc
target: i686-pc-windows-msvc
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
build: |
npm i -g --force corepack
cd bindings/packager/nodejs
set -e &&
pnpm build --target x86_64-unknown-linux-gnu &&
strip *.node
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
cd bindings/packager/nodejs
set -e
pnpm build
strip *.node
- host: macos-latest
target: aarch64-apple-darwin
build: |
pnpm build --target aarch64-apple-darwin --features native-tls-vendored --cargo-flags="--no-default-features"
strip -x *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: |
npm i -g --force corepack
cd bindings/packager/nodejs
set -e &&
pnpm build --target aarch64-unknown-linux-gnu &&
aarch64-unknown-linux-gnu-strip *.node
- host: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
setup: |
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf -y
build: |
pnpm build --target armv7-unknown-linux-gnueabihf
arm-linux-gnueabihf-strip *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
cd bindings/packager/nodejs
set -e &&
rustup target add aarch64-unknown-linux-musl &&
pnpm build --target aarch64-unknown-linux-musl &&
/aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
- host: windows-latest
target: aarch64-pc-windows-msvc
build: pnpm build --target aarch64-pc-windows-msvc --features native-tls-vendored --cargo-flags="--no-default-features"
name: stable - ${{ matrix.settings.target }} - node@18
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- uses: actions/setup-node@v6
if: ${{ !matrix.settings.docker }}
- name: Install
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
- uses: goto-bus-stop/setup-zig@v2
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
with:
version: 0.11.0
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Setup node x86
if: matrix.settings.target == 'i686-pc-windows-msvc'
run: pnpm config set supportedArchitectures.cpu "ia32"
shell: bash
- run: pnpm install
- name: Setup node x86
uses: actions/setup-node@v6
if: matrix.settings.target == 'i686-pc-windows-msvc'
with:
node-version: 18
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: "--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build"
run: ${{ matrix.settings.build }}
- name: Build
run: ${{ matrix.settings.build }}
if: ${{ !matrix.settings.docker }}
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/packager/nodejs/${{ env.APP_NAME }}.*.node
if-no-files-found: error
test-macOS-windows-binding:
name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
- host: windows-latest
target: x86_64-pc-windows-msvc
node:
- "18"
- "20"
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: |
pnpm postbuild
pnpm test
test-linux-x64-gnu-binding:
name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-gnu
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
working-directory: .
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim sh -c "cd bindings/packager/nodejs && yarn postbuild && PACKAGER_FORMATS=deb yarn test"
test-linux-x64-musl-binding:
name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.libc "musl"
pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-musl
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
working-directory: .
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine sh -c "cd bindings/packager/nodejs && yarn postbuild && PACKAGER_FORMATS=deb yarn test"
test-linux-aarch64-gnu-binding:
name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-gnu
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm64"
pnpm config set supportedArchitectures.libc "glibc"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-slim
options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
run: |
export PACKAGER_FORMATS=deb
set -e
cd bindings/packager/nodejs
yarn postbuild
yarn test
ls -la
test-linux-aarch64-musl-binding:
name: Test bindings on aarch64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-musl
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm64"
pnpm config set supportedArchitectures.libc "musl"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:lts-alpine
options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
run: |
export PACKAGER_FORMATS=deb
set -e
cd bindings/packager/nodejs
yarn postbuild
yarn test
test-linux-arm-gnueabihf-binding:
name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-armv7-unknown-linux-gnueabihf
path: bindings/packager/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-bullseye-slim
options: "--platform linux/arm/v7 -v ${{ github.workspace }}:/build -w /build"
run: |
export PACKAGER_FORMATS=deb
set -e
cd bindings/packager/nodejs
yarn postbuild
yarn test
ls -la
publish:
name: Publish
runs-on: ubuntu-latest
needs:
- test-macOS-windows-binding
- test-linux-x64-gnu-binding
- test-linux-x64-musl-binding
- test-linux-aarch64-gnu-binding
- test-linux-aarch64-musl-binding
- test-linux-arm-gnueabihf-binding
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/packager/nodejs
- uses: actions/setup-node@v6
- run: pnpm install
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: bindings/packager/nodejs/artifacts
- name: Move artifacts
run: pnpm artifacts
- name: List packages
run: ls -R ./npm
shell: bash
- name: build TS binding
run: pnpm postbuild
- name: Publish
run: |
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
npm publish --access public
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
RELEASE_ID: ${{ github.event.client_payload.releaseId || inputs.releaseId }}
================================================
FILE: .github/workflows/publish-packager-resource-resolver-nodejs.yml
================================================
name: Publish `@crabnebula/packager-resource-resolver`
env:
DEBUG: napi:*
APP_NAME: packager-resource-resolver
MACOSX_DEPLOYMENT_TARGET: "10.13"
permissions:
contents: write
id-token: write
on:
workflow_dispatch:
inputs:
releaseId:
description: "ID of the `@crabnebula/packager-resource-resolver` release"
required: true
repository_dispatch:
types: [publish-packager-resource-resolver-nodejs]
defaults:
run:
working-directory: bindings/resource-resolver/nodejs
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: |
pnpm build
strip -x *.node
- host: windows-latest
build: pnpm build
target: x86_64-pc-windows-msvc
- host: windows-latest
build: pnpm build --target i686-pc-windows-msvc
target: i686-pc-windows-msvc
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
build: |
npm i -g --force corepack
cd bindings/resource-resolver/nodejs
set -e &&
pnpm build --target x86_64-unknown-linux-gnu &&
strip *.node
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
cd bindings/resource-resolver/nodejs
set -e
pnpm build
strip *.node
- host: macos-latest
target: aarch64-apple-darwin
build: |
pnpm build --target aarch64-apple-darwin
strip -x *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: |
npm i -g --force corepack
cd bindings/resource-resolver/nodejs
set -e &&
pnpm build --target aarch64-unknown-linux-gnu &&
aarch64-unknown-linux-gnu-strip *.node
- host: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
setup: |
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf -y
build: |
npm i -g --force corepack
pnpm build --target armv7-unknown-linux-gnueabihf
arm-linux-gnueabihf-strip *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
npm i -g --force corepack
cd bindings/resource-resolver/nodejs
set -e &&
rustup target add aarch64-unknown-linux-musl &&
pnpm build --target aarch64-unknown-linux-musl &&
/aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
- host: windows-latest
target: aarch64-pc-windows-msvc
build: pnpm build --target aarch64-pc-windows-msvc
name: stable - ${{ matrix.settings.target }} - node@18
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- uses: actions/setup-node@v6
if: ${{ !matrix.settings.docker }}
- name: Install
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
- uses: goto-bus-stop/setup-zig@v2
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
with:
version: 0.11.0
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Setup node x86
if: matrix.settings.target == 'i686-pc-windows-msvc'
run: pnpm config set supportedArchitectures.cpu "ia32"
shell: bash
- run: pnpm install
- name: Setup node x86
uses: actions/setup-node@v6
if: matrix.settings.target == 'i686-pc-windows-msvc'
with:
node-version: 18
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: "--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build"
run: ${{ matrix.settings.build }}
- name: Build
run: ${{ matrix.settings.build }}
if: ${{ !matrix.settings.docker }}
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/resource-resolver/nodejs/${{ env.APP_NAME }}.*.node
if-no-files-found: error
test-macOS-windows-binding:
name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
- host: windows-latest
target: x86_64-pc-windows-msvc
node:
- "18"
- "20"
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: pnpm test
test-linux-x64-gnu-binding:
name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-gnu
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
working-directory: .
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim sh -c "cd bindings/resource-resolver/nodejs && yarn test"
test-linux-x64-musl-binding:
name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.libc "musl"
pnpm install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-musl
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
working-directory: .
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine sh -c "cd bindings/resource-resolver/nodejs && yarn test"
test-linux-aarch64-gnu-binding:
name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-gnu
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm64"
pnpm config set supportedArchitectures.libc "glibc"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-slim
options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
run: |
set -e
cd bindings/resource-resolver/nodejs
yarn test
ls -la
test-linux-aarch64-musl-binding:
name: Test bindings on aarch64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-musl
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm64"
pnpm config set supportedArchitectures.libc "musl"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:lts-alpine
options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
run: |
set -e
cd bindings/resource-resolver/nodejs
yarn test
test-linux-arm-gnueabihf-binding:
name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- "18"
- "20"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-armv7-unknown-linux-gnueabihf
path: bindings/resource-resolver/nodejs
- name: List packages
run: ls -R .
shell: bash
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- name: Install dependencies
run: |
pnpm config set supportedArchitectures.cpu "arm"
pnpm install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-bullseye-slim
options: "--platform linux/arm/v7 -v ${{ github.workspace }}:/build -w /build"
run: |
set -e
cd bindings/resource-resolver/nodejs
yarn test
ls -la
publish:
name: Publish
runs-on: ubuntu-latest
needs:
- build
- test-macOS-windows-binding
- test-linux-x64-gnu-binding
- test-linux-x64-musl-binding
- test-linux-aarch64-gnu-binding
- test-linux-aarch64-musl-binding
- test-linux-arm-gnueabihf-binding
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/resource-resolver/nodejs
- uses: actions/setup-node@v6
- run: pnpm install
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: bindings/resource-resolver/nodejs/artifacts
- name: Move artifacts
run: pnpm artifacts
- name: List packages
run: ls -R ./npm
shell: bash
- name: Publish
run: |
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
npm publish --access public
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
RELEASE_ID: ${{ github.event.client_payload.releaseId || inputs.releaseId }}
================================================
FILE: .github/workflows/publish-updater-nodejs.yml
================================================
name: Publish `@crabnebula/updater`
env:
DEBUG: napi:*
APP_NAME: updater
MACOSX_DEPLOYMENT_TARGET: "10.13"
permissions:
contents: write
id-token: write
on:
workflow_dispatch:
inputs:
releaseId:
description: "ID of the `@crabnebula/updater` release"
required: true
repository_dispatch:
types: [publish-updater-nodejs]
defaults:
run:
working-directory: bindings/updater/nodejs
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: |
pnpm build
strip -x *.node
- host: windows-latest
build: pnpm build
target: x86_64-pc-windows-msvc
- host: windows-latest
build: pnpm build --target i686-pc-windows-msvc
target: i686-pc-windows-msvc
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
build: |
npm i -g --force corepack
cd bindings/updater/nodejs
set -e &&
pnpm build --target x86_64-unknown-linux-gnu &&
strip *.node
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
cd bindings/updater/nodejs
set -e
pnpm build
strip *.node
- host: macos-latest
target: aarch64-apple-darwin
build: |
pnpm build --target aarch64-apple-darwin --features native-tls-vendored --cargo-flags="--no-default-features"
strip -x *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: |
npm i -g --force corepack
cd bindings/updater/nodejs
set -e &&
pnpm build --target aarch64-unknown-linux-gnu &&
aarch64-unknown-linux-gnu-strip *.node
- host: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
setup: |
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf -y
build: |
pnpm build --target armv7-unknown-linux-gnueabihf
arm-linux-gnueabihf-strip *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
cd bindings/updater/nodejs
set -e &&
rustup target add aarch64-unknown-linux-musl &&
pnpm build --target aarch64-unknown-linux-musl &&
/aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
- host: windows-latest
target: aarch64-pc-windows-msvc
build: pnpm build --target aarch64-pc-windows-msvc --features native-tls-vendored --cargo-flags="--no-default-features"
name: stable - ${{ matrix.settings.target }} - node@18
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/updater/nodejs
- uses: actions/setup-node@v6
if: ${{ !matrix.settings.docker }}
- name: Install
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
- uses: goto-bus-stop/setup-zig@v2
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
with:
version: 0.11.0
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Setup node x86
if: matrix.settings.target == 'i686-pc-windows-msvc'
run: pnpm config set supportedArchitectures.cpu "ia32"
shell: bash
- run: pnpm install
- name: Setup node x86
uses: actions/setup-node@v6
if: matrix.settings.target == 'i686-pc-windows-msvc'
with:
node-version: 18
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: "--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build"
run: ${{ matrix.settings.build }}
- name: Build
run: ${{ matrix.settings.build }}
if: ${{ !matrix.settings.docker }}
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/updater/nodejs/${{ env.APP_NAME }}.*.node
if-no-files-found: error
# FIXME: updater tests needs packager to be build first
# so we need to figure how to build the packager here as well without duplicating
# the publish-packager-nodejs workflow here
# test-macOS-windows-binding:
# name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
# needs:
# - build
# strategy:
# fail-fast: false
# matrix:
# settings:
# - host: macos-latest
# target: x86_64-apple-darwin
# - host: windows-latest
# target: x86_64-pc-windows-msvc
# node:
# - "18"
# - "20"
# runs-on: ${{ matrix.settings.host }}
# steps:
# - uses: actions/checkout@v4
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - uses: actions/setup-node@v4
# with:
# node-version: ${{ matrix.node }}
# - run: pnpm install
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-${{ matrix.settings.target }}
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - name: Test bindings
# run: pnpm test
# test-linux-x64-gnu-binding:
# name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }}
# needs:
# - build
# strategy:
# fail-fast: false
# matrix:
# node:
# - "18"
# - "20"
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - uses: actions/setup-node@v4
# with:
# node-version: ${{ matrix.node }}
# - run: pnpm install
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-x86_64-unknown-linux-gnu
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - name: Test bindings
# working-directory: .
# run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim sh -c "cd bindings/updater/nodejs && yarn test"
# test-linux-x64-musl-binding:
# name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
# needs:
# - build
# strategy:
# fail-fast: false
# matrix:
# node:
# - "18"
# - "20"
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - uses: actions/setup-node@v4
# with:
# node-version: ${{ matrix.node }}
# - name: Install dependencies
# run: |
# pnpm config set supportedArchitectures.libc "musl"
# pnpm install
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-x86_64-unknown-linux-musl
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - name: Test bindings
# working-directory: .
# run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine sh -c "cd bindings/updater/nodejs && yarn test"
# test-linux-aarch64-gnu-binding:
# name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
# needs:
# - build
# strategy:
# fail-fast: false
# matrix:
# node:
# - "18"
# - "20"
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-aarch64-unknown-linux-gnu
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - name: Install dependencies
# run: |
# pnpm config set supportedArchitectures.cpu "arm64"
# pnpm config set supportedArchitectures.libc "glibc"
# pnpm install
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
# with:
# platforms: arm64
# - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# - name: Setup and run tests
# uses: addnab/docker-run-action@v3
# with:
# image: node:${{ matrix.node }}-slim
# options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
# run: |
# set -e
# cd bindings/updater/nodejs
# yarn test
# ls -la
# test-linux-aarch64-musl-binding:
# name: Test bindings on aarch64-unknown-linux-musl - node@${{ matrix.node }}
# needs:
# - build
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-aarch64-unknown-linux-musl
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - name: Install dependencies
# run: |
# pnpm config set supportedArchitectures.cpu "arm64"
# pnpm config set supportedArchitectures.libc "musl"
# pnpm install
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
# with:
# platforms: arm64
# - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# - name: Setup and run tests
# uses: addnab/docker-run-action@v3
# with:
# image: node:lts-alpine
# options: "--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build"
# run: |
# set -e
# cd bindings/updater/nodejs
# yarn test
# test-linux-arm-gnueabihf-binding:
# name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }}
# needs:
# - build
# strategy:
# fail-fast: false
# matrix:
# node:
# - "18"
# - "20"
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Download artifacts
# uses: actions/download-artifact@v3
# with:
# name: bindings-armv7-unknown-linux-gnueabihf
# path: bindings/updater/nodejs
# - name: List packages
# run: ls -R .
# shell: bash
# - uses: pnpm/action-setup@v2
# with:
# version: latest
# package_json_file: bindings/updater/nodejs
# - name: Install dependencies
# run: |
# pnpm config set supportedArchitectures.cpu "arm"
# pnpm install
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
# with:
# platforms: arm
# - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# - name: Setup and run tests
# uses: addnab/docker-run-action@v3
# with:
# image: node:${{ matrix.node }}-bullseye-slim
# options: "--platform linux/arm/v7 -v ${{ github.workspace }}:/build -w /build"
# run: |
# set -e
# cd bindings/updater/nodejs
# yarn test
# ls -la
publish:
name: Publish
runs-on: ubuntu-latest
needs:
- build
# - test-macOS-windows-binding
# - test-linux-x64-gnu-binding
# - test-linux-x64-musl-binding
# - test-linux-aarch64-gnu-binding
# - test-linux-aarch64-musl-binding
# - test-linux-arm-gnueabihf-binding
steps:
- uses: actions/checkout@v6
- run: npm i -g --force corepack && corepack enable
- uses: pnpm/action-setup@v4
with:
version: latest
package_json_file: bindings/updater/nodejs
- uses: actions/setup-node@v6
- run: pnpm install
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: bindings/updater/nodejs/artifacts
- name: Move artifacts
run: pnpm artifacts
- name: List packages
run: ls -R ./npm
shell: bash
- name: Publish
run: |
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
npm publish --access public
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
RELEASE_ID: ${{ github.event.client_payload.releaseId || inputs.releaseId }}
================================================
FILE: .gitignore
================================================
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
node_modules/
*.tgz
.yarn-integrity
.env
.env.test
dist
build
.DS_Store
/target
Cargo.lock
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
*.node
*.node.bak
yarn.lock
package-lock.json
.idea
================================================
FILE: .npmrc
================================================
enable-pre-post-scripts=true
update-notifier=false
engine-strict=true
resolution-mode=highest
================================================
FILE: .prettierignore
================================================
dist
build
*.wxs
*.nsi
*.nsh
*.sh
*.desktop
*.xml
*.md
pnpm-lock.yaml
schema.json
bindings/updater/nodejs/index.js
bindings/updater/nodejs/index.d.ts
bindings/packager/nodejs/index.js
bindings/packager/nodejs/index.d.ts
bindings/packager/nodejs/src-ts/config.d.ts
================================================
FILE: Cargo.toml
================================================
[workspace]
members = [
"crates/*",
"examples/*",
"bindings/*/nodejs",
"crates/updater/tests/app",
]
exclude = ["examples/deno", "examples/wails", "examples/electron"]
resolver = "2"
[workspace.package]
authors = ["CrabNebula Ltd."]
edition = "2021"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/crabnebula-dev/cargo-packager"
[workspace.dependencies]
thiserror = "2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
dunce = "1"
schemars = { version = "0.8", features = ["url", "preserve_order", "derive"] }
clap = { version = "4.5", features = ["derive"] }
dirs = "6.0"
semver = "1"
base64 = "0.22"
tracing = "0.1"
time = "0.3"
tar = "0.4"
napi = { version = "2.16", default-features = false }
napi-derive = "2.16"
napi-build = "2.1"
[profile.release-size-optimized]
inherits = "release"
codegen-units = 1
lto = true
incremental = false
opt-level = "s"
================================================
FILE: LICENSE.spdx
================================================
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
PackageName: cargo-packager
DataFormat: SPDXRef-1
PackageSupplier: Organization: CrabNebula Ltd.
PackageHomePage: https://github.com/crabnebula-dev/cargo-packager
PackageLicenseDeclared: Apache-2.0
PackageLicenseDeclared: MIT
PackageCopyrightText: 2023-2023, CrabNebula Ltd.
PackageSummary: Rust executable packager, bundler and updater. A tool and library to generate installers or app bundles for your executables.
It also has a comptabile updater through cargo-packager-updater crate.
PackageComment: The package includes the following libraries; see
Relationship information.
Created: 2023-09-30T09:00:00Z
PackageDownloadLocation: git://github.com/crabnebula-dev/cargo-packager
PackageDownloadLocation: git+https://github.com/crabnebula-dev/cargo-packager.git
PackageDownloadLocation: git+ssh://github.com/crabnebula-dev/cargo-packager.git
================================================
FILE: LICENSE_APACHE-2.0
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
================================================
FILE: LICENSE_MIT
================================================
MIT License
Copyright (c) 2023 - Present CrabNebula Ltd.
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.
================================================
FILE: README.md
================================================
# cargo-packager
Executable packager, bundler and updater. A cli tool and library to generate installers or app bundles for your executables.
It also has a compatible updater through [cargo-packager-updater](./crates/updater/).
#### Supported packages:
- macOS
- DMG (.dmg)
- Bundle (.app)
- Linux
- Debian package (.deb)
- AppImage (.AppImage)
- Pacman (.tar.gz and PKGBUILD)
- Windows
- NSIS (.exe)
- MSI using WiX Toolset (.msi)
## Rust
### CLI
The packager is distributed on crates.io as a cargo subcommand, you can install it using cargo:
```sh
cargo install cargo-packager --locked
```
You then need to configure your app so the cli can recognize it. Configuration can be done in `Packager.toml` or `packager.json` in your project or modify Cargo.toml and include this snippet:
```toml
[package.metadata.packager]
before-packaging-command = "cargo build --release"
```
Once, you are done configuring your app, run:
```sh
cargo packager --release
```
### Configuration
By default, the packager reads its configuration from `Packager.toml` or `packager.json` if it exists, and from `package.metadata.packager` table in `Cargo.toml`.
You can also specify a custom configuration using the `-c/--config` cli argument.
For a full list of configuration options, see https://docs.rs/cargo-packager/latest/cargo_packager/config/struct.Config.html.
You could also use the [schema](./crates/packager/schema.json) file from GitHub to validate your configuration or have auto completions in your IDE.
### Building your application before packaging
By default, the packager doesn't build your application, so if your app requires a compilation step, the packager has an option to specify a shell command to be executed before packaing your app, `beforePackagingCommand`.
### Cargo profiles
By default, the packager looks for binaries built using the `debug` profile, if your `beforePackagingCommand` builds your app using `cargo build --release`, you will also need to
run the packager in release mode `cargo packager --release`, otherwise, if you have a custom cargo profile, you will need to specify it using `--profile` cli arg `cargo packager --profile custom-release-profile`.
### Library
This crate is also published to crates.io as a library that you can integrate into your tooling, just make sure to disable the default-feature flags.
```sh
cargo add cargo-packager --no-default-features
```
#### Feature flags
- **`cli`**: Enables the cli specifc features and dependencies. Enabled by default.
- **`tracing`**: Enables `tracing` crate integration.
## NPM (Node.js)
Checkout the packager NPM cli [README](./bindings/packager/nodejs/README.md)
## Examples
The [`examples`](./examples/) directory contains a number of varying examples, if you want to build them all run `cargo r -p cargo-packager -- --release` in the root of this repository. Just make sure to have the tooling for each example installed on your system. You can find what tooling they require by checking the README in each example. The README also contains a command to build this example alone if you wish.
Examples list (non-exhaustive):
- [`tauri`](./examples/tauri/)
- [`wry`](./examples/wry/)
- [`dioxus`](./examples/dioxus/)
- [`egui`](./examples/egui/)
- [`deno`](./examples/deno/)
- [`slint`](./examples/slint/)
- [`wails`](./examples/wails)
## Licenses
MIT or MIT/Apache 2.0 where applicable.
================================================
FILE: SECURITY.md
================================================
# Security Policy
**Do not report security vulnerabilities through public GitHub issues.**
**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
Alternatively, you can also send them by email to security@crabnebula.dev.
You can encrypt your mail using GnuPG if you want.
See the [security.txt](https://crabnebula.dev/.well-known/security.txt) from CrabNebula
```
Contact: mailto:security@crabnebula.dev
Expires: 2025-01-30T06:30:00.000Z
Encryption: https://crabnebula.dev/.well-known/pgp.txt
Preferred-Languages: en,de,fr
Canonical: https://crabnebula.dev/.well-known/security.txt
```
Include as much of the following information:
- Type of issue (e.g. buffer overflow, privilege escalation, etc.)
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- The distribution affected or used for reproduction.
- Step-by-step instructions to reproduce the issue
- Impact of the issue, including how an attacker might exploit the issue
- Preferred Languages
We prefer to receive reports in English. If necessary, we also understand French and German.
================================================
FILE: bindings/packager/nodejs/.cargo/config.toml
================================================
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=-crt-static"]
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
================================================
FILE: bindings/packager/nodejs/.npmignore
================================================
target
Cargo.lock
.cargo
.github
npm
.eslintrc
.prettierignore
rustfmt.toml
yarn.lock
*.node
.yarn
__test__
renovate.json
================================================
FILE: bindings/packager/nodejs/.npmrc
================================================
enable-pre-post-scripts=true
================================================
FILE: bindings/packager/nodejs/CHANGELOG.md
================================================
# Changelog
## \[0.11.8]
- [`6e6a10c`](https://www.github.com/crabnebula-dev/cargo-packager/commit/6e6a10cc1692973293966034dc4b798e3976d094) ([#321](https://www.github.com/crabnebula-dev/cargo-packager/pull/321)) Allow explicitly specifying the Package name for the .deb bundle.
- [`8488d86`](https://www.github.com/crabnebula-dev/cargo-packager/commit/8488d868935166e873474743c346c2724205d73e) ([#377](https://www.github.com/crabnebula-dev/cargo-packager/pull/377)) Fixed a bug where "binaries" parameter in Cargo.toml would be ignored and all targets would be packaged.
- [`b2b4916`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b2b4916d1b062272fc7e34b5ed55b4fe8c8cd03a) ([#376](https://www.github.com/crabnebula-dev/cargo-packager/pull/376)) Fix bug that prevents reading macos signing certificates from environment variables.
- [`c34de36`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c34de365705db150eb101caa94adf42eff74f71a) ([#365](https://www.github.com/crabnebula-dev/cargo-packager/pull/365)) Change nsi template from using `association.ext` to `association.extensions`, to match struct field in `FileAssociation`.
This allows file associations to be generated in `.nsi` files, and therefore in the final NSIS installer.
### Dependencies
- Upgraded to `cargo-packager@0.11.8`
## \[0.11.7]
- [`d49b606`](https://www.github.com/crabnebula-dev/cargo-packager/commit/d49b606ba8a612c833233ec8a6061481a2118639) ([#353](https://www.github.com/crabnebula-dev/cargo-packager/pull/353)) Allow using notarization credentials stored on the Keychain by providing the `APPLE_KEYCHAIN_PROFILE` environment variable. See `xcrun notarytool store-credentials` for more information.
- [`b337564`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b337564c0e5a9de966b4124890dddea1e353acb4) ([#362](https://www.github.com/crabnebula-dev/cargo-packager/pull/362)) Updated linuxdeploy's AppImage plugin to not require libfuse on the user's system anymore.
### Dependencies
- Upgraded to `cargo-packager@0.11.7`
## \[0.11.6]
- [`b81b81f`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b81b81fbd7fd185edfc7652f535d0cfacb786ac9) ([#354](https://www.github.com/crabnebula-dev/cargo-packager/pull/354)) Changed the download URL of a dependency of the AppImage bundler to Tauri's mirror to resolve 404 errors.
- [`5205088`](https://www.github.com/crabnebula-dev/cargo-packager/commit/5205088cd78412fb6cbe5e48a715524fcc5a2ee7) ([#340](https://www.github.com/crabnebula-dev/cargo-packager/pull/340)) Enhance sign error message.
### Dependencies
- Upgraded to `cargo-packager@0.11.6`
## \[0.11.5]
- [`17194a9`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17194a92aabd59c9e075105072ff939f5d55a107) ([#313](https://www.github.com/crabnebula-dev/cargo-packager/pull/313)) Added `linux > generateDesktopEntry` config to allow disabling generating a .desktop file on Linux bundles (defaults to true).
- [`17c52f0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17c52f057d78340983689af3c00b1f2aeff3c417) ([#289](https://www.github.com/crabnebula-dev/cargo-packager/pull/289)) Added support to embedding additional apps in the macOS app bundle.
- [`17c52f0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17c52f057d78340983689af3c00b1f2aeff3c417) ([#289](https://www.github.com/crabnebula-dev/cargo-packager/pull/289)) Added support to adding an `embedded.provisionprofile` file to the macOS bundle.
- [`e010574`](https://www.github.com/crabnebula-dev/cargo-packager/commit/e010574c2efa4a1aa6b8e475a62bec46f24f2bc5) ([#318](https://www.github.com/crabnebula-dev/cargo-packager/pull/318)) Add `background-app` config setting for macOS to set `LSUIElement` to `true`.
### Dependencies
- Upgraded to `cargo-packager@0.11.5`
## \[0.11.4]
### Dependencies
- Upgraded to `cargo-packager@0.11.4`
## \[0.11.3]
### Dependencies
- Upgraded to `cargo-packager@0.11.3`
## \[0.11.2]
- [`fea80d5`](https://www.github.com/crabnebula-dev/cargo-packager/commit/fea80d5760882e6cdc21c8ed2f82d323e0598926) ([#264](https://www.github.com/crabnebula-dev/cargo-packager/pull/264)) Fix `pacman` package failing to install when source directory contained whitespace.
### Dependencies
- Upgraded to `cargo-packager@0.11.2`
## \[0.11.1]
- [`4523722`](https://www.github.com/crabnebula-dev/cargo-packager/commit/4523722d0808faef4a91dbb227badd0354f4c71a) ([#283](https://www.github.com/crabnebula-dev/cargo-packager/pull/283)) Fixes resources paths on NSIS when cross compiling.
### Dependencies
- Upgraded to `cargo-packager@0.11.1`
## \[0.11.0]
- [`41b05d0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/41b05d08a635d593df4cf4eefbe921b92ace77b7) ([#277](https://www.github.com/crabnebula-dev/cargo-packager/pull/277)) Add `--target` flag to specify target triple to package.
### Dependencies
- Upgraded to `cargo-packager@0.11.0`
## \[0.10.3]
### Dependencies
- Upgraded to `cargo-packager@0.10.3`
## \[0.10.2]
### Dependencies
- Upgraded to `cargo-packager@0.10.2`
- Upgraded to `cargo-packager-utils@0.1.1`
## \[0.10.1]
- [`522f23b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/522f23bd867b037eeec81c43295aafd38ebe60ec) ([#258](https://www.github.com/crabnebula-dev/cargo-packager/pull/258)) Update NSIS installer template URL.
- [`bce99ae`](https://www.github.com/crabnebula-dev/cargo-packager/commit/bce99aecb4160291a026dcd4750055f9079099f8) ([#260](https://www.github.com/crabnebula-dev/cargo-packager/pull/260)) Fix NSIS uninstaller removing the uninstall directory even if it was not empty.
### Dependencies
- Upgraded to `cargo-packager@0.10.1`
## \[0.10.0]
- [`c6207bb`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c6207bba042a8a0184ddb7e12650a4cd8f415c23) ([#254](https://www.github.com/crabnebula-dev/cargo-packager/pull/254)) Allow Linux dependencies to be specified via a file path instead of just a direct String.
This enables the list of dependencies to by dynamically generated for both Debian `.deb` packages and pacman packages,
which can relieve the app developer from the burden of manually maintaining a fixed list of dependencies.
- [`de4dcca`](https://www.github.com/crabnebula-dev/cargo-packager/commit/de4dccaca4ae758d3adde517cc415a002873e642) ([#256](https://www.github.com/crabnebula-dev/cargo-packager/pull/256)) Automatically add an Exec arg (field code) in the `.desktop` file.
This adds an `{exec_arg}` field to the default `main.desktop` template.
This field is populated with a sane default value, based on the
`deep_link_protocols` or `file_associations` in the `Config` struct.
This allows an installed Debian package to be invoked by other
applications with URLs or files as arguments, as expected.
### Dependencies
- Upgraded to `cargo-packager@0.10.0`
## \[0.9.1]
- [`44a19ea`](https://www.github.com/crabnebula-dev/cargo-packager/commit/44a19eae1f5f26b1bd10ba84dd6eb3d856609a67) ([#246](https://www.github.com/crabnebula-dev/cargo-packager/pull/246)) On macOS, fix notarization skipping needed environment variables when macos specific config has been specified in the config file.
### Dependencies
- Upgraded to `cargo-packager@0.9.1`
## \[0.9.0]
- [`ab53974`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ab53974b683ce282202e1a550c551eed951e9ca7) ([#235](https://www.github.com/crabnebula-dev/cargo-packager/pull/235)) Added deep link support.
### Dependencies
- Upgraded to `cargo-packager@0.9.0`
## \[0.8.1]
- [`1375380`](https://www.github.com/crabnebula-dev/cargo-packager/commit/1375380c7c9d2adf55ab18a2ce23917849967995)([#196](https://www.github.com/crabnebula-dev/cargo-packager/pull/196)) Always show shell commands output for `beforePackageCommand` and `beforeEachPackagingCommand` .
### Dependencies
- Upgraded to `cargo-packager@0.8.1`
## \[0.8.0]
- [`2164d02`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2164d022f5705e59a189007aec7c99cce98136d8)([#198](https://www.github.com/crabnebula-dev/cargo-packager/pull/198)) Allow packaging the macOS app bundle on Linux and Windows hosts (without codesign support).
- [`3057a4a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3057a4a8440bc4dc897f3038ac821ed181644d43)([#197](https://www.github.com/crabnebula-dev/cargo-packager/pull/197)) Added `Config::binaries_dir` and `--binaries-dir` so you can specify the location of the binaries without modifying the output directory.
- [`4c4d919`](https://www.github.com/crabnebula-dev/cargo-packager/commit/4c4d9194fb0bd2a814f46336747e643b1e208b52)([#195](https://www.github.com/crabnebula-dev/cargo-packager/pull/195)) Error out if we cannot find a configuration file.
- [`b04332c`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b04332c8fc61427dc002a40d9d46bc5f930025c2)([#194](https://www.github.com/crabnebula-dev/cargo-packager/pull/194)) Fixes a crash when packaging `.app` if an empty file is included in the bundle.
- [`3057a4a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3057a4a8440bc4dc897f3038ac821ed181644d43)([#197](https://www.github.com/crabnebula-dev/cargo-packager/pull/197)) Added `--out-dir/-o` flags and removed the positional argument to specify where to ouput packages, use the newly added flags instead.
### Dependencies
- Upgraded to `cargo-packager@0.8.0`
## \[0.7.0]
- [`cd8898a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/cd8898a93b66a4aae050fa1006089c3c3b5646f9)([#187](https://www.github.com/crabnebula-dev/cargo-packager/pull/187)) Added codesign certificate and notarization credentials configuration options under the `macos` config (for programatic usage, taking precedence over environment variables).
### Dependencies
- Upgraded to `cargo-packager@0.7.0`
## \[0.6.1]
### Dependencies
- Upgraded to `cargo-packager@0.6.1`
## \[0.6.0]
- [`57b379a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/57b379ad1d9029e767848fda99d4eb6415afe51a)([#148](https://www.github.com/crabnebula-dev/cargo-packager/pull/148)) Added config option to control excluded libs when packaging AppImage
- [`947e032`](https://www.github.com/crabnebula-dev/cargo-packager/commit/947e0328c89d6f043c3ef1b1db5d2252d4f072a5) Fix CLI failing with `Failed to read cargo metadata: cargo metadata` for non-rust projects.
- Bumpt to `0.6.0` version directly to match the Rust crate version.
### Dependencies
- Upgraded to `cargo-packager@0.6.0`
## \[0.2.0]
- [`9bdb953`](https://www.github.com/crabnebula-dev/cargo-packager/commit/9bdb953f1b48c8d69d86e9e42295cd36453c1648)([#137](https://www.github.com/crabnebula-dev/cargo-packager/pull/137)) Add Arch Linux package manager, `pacman` support for cargo packager.
- [`a29943e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/a29943e8c95d70e8b77c23021ce52f6ee13314c8)([#140](https://www.github.com/crabnebula-dev/cargo-packager/pull/140)) Fix codesigning failing on macOS under certain circumstances when the order in which files were signed was not
deterministic and nesting required signing files nested more deeply first.
### Dependencies
- Upgraded to `cargo-packager@0.5.0`
- Upgraded to `cargo-packager-utils@0.1.0`
## \[0.1.5]
- [`f08e4b8`](https://www.github.com/crabnebula-dev/cargo-packager/commit/f08e4b8972b072617fdb78f11e222427e49ebe8e) Fix the signing and notarization process for MacOS bundles
- [`bfa3b00`](https://www.github.com/crabnebula-dev/cargo-packager/commit/bfa3b00cf1087b2ee1e93d9c57b6b577f6294891)([#126](https://www.github.com/crabnebula-dev/cargo-packager/pull/126)) Add `priority` and `section` options in Debian config
### Dependencies
- Upgraded to `cargo-packager@0.4.5`
## \[0.1.4]
- [`3b3ce76`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3b3ce76da0581cf8d553d6edeb0df24f896c62a6)([#128](https://www.github.com/crabnebula-dev/cargo-packager/pull/128)) Fix file download not working on macOS and Windows (arm).
### Dependencies
- Upgraded to `cargo-packager@0.4.4`
## \[0.1.3]
- [`2a50c8e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2a50c8ea734193036db0ab461f9005ea904cf4b7)([#124](https://www.github.com/crabnebula-dev/cargo-packager/pull/124)) Fix packaing of external binaries.
### Dependencies
- Upgraded to `cargo-packager@0.4.3`
## \[0.1.2]
- [`bd7e6fc`](https://www.github.com/crabnebula-dev/cargo-packager/commit/bd7e6fc102a74dc4da39848f44d04968b498b3cf)([#123](https://www.github.com/crabnebula-dev/cargo-packager/pull/123)) Fixes published package not including the build folder.
### Dependencies
- Upgraded to `cargo-packager@0.4.2`
## \[0.1.1]
- [`7e05d24`](https://www.github.com/crabnebula-dev/cargo-packager/commit/7e05d24a697230b1f53ee5ee2f7d217047089d97)([#109](https://www.github.com/crabnebula-dev/cargo-packager/pull/109)) Check if required files/tools for packaging are outdated or mis-hashed and redownload them.
- [`ea6c31b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ea6c31b1a3b56bb5408a78f1b2d6b2a2d9ce1161)([#114](https://www.github.com/crabnebula-dev/cargo-packager/pull/114)) Fix NSIS uninstaller leaving resources behind and failing to remove the installation directory.
### Dependencies
- Upgraded to `cargo-packager@0.4.1`
## \[0.1.0]
- [`c4fa8fd`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c4fa8fd6334b7fd0c32710ea2df0b54aa6bde713) Initial release.
### Dependencies
- Upgraded to `cargo-packager@0.4.0`
================================================
FILE: bindings/packager/nodejs/Cargo.toml
================================================
[package]
name = "crabnebula_packager"
version = "0.0.0"
publish = false
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { workspace = true, features = ["napi4"] }
napi-derive = { workspace = true }
cargo-packager = { path = "../../../crates/packager/", default-features = false, features = ["cli"] }
tracing = { workspace = true }
serde_json = { workspace = true }
[build-dependencies]
napi-build = { workspace = true }
[features]
default = ["cargo-packager/rustls-tls"]
native-tls = ["cargo-packager/native-tls"]
native-tls-vendored = ["cargo-packager/native-tls-vendored"]
================================================
FILE: bindings/packager/nodejs/README.md
================================================
# @crabnebula/packager
Executable packager, bundler and updater. A cli tool and library to generate installers or app bundles for your executables.
It also comes with useful addons:
- an [updater](https://www.npmjs.com/package/@crabnebula/updater)
- a [resource resolver](https://www.npmjs.com/package/@crabnebula/packager-resource-resolver)
#### Supported packages:
- macOS
- DMG (.dmg)
- Bundle (.app)
- Linux
- Debian package (.deb)
- AppImage (.AppImage)
- Pacman (.tar.gz and PKGBUILD)
- Windows
- NSIS (.exe)
- MSI using WiX Toolset (.msi)
### CLI
The packager is distributed on NPM as a CLI, you can install it:
```sh
# pnpm
pnpm add -D @crabnebula/packager
# yarn
yarn add -D @crabnebula/packager
# npm
npm i -D @crabnebula/packager
```
You then need to configure your app so the CLI can recognize it.
Configuration can be done in `Packager.toml` or `packager.json` in your project or `packager` key in `packager.json`
Once, you are done configuring your app, run:
```sh
# pnpm
pnpm packager
# yarn
yarn packager
# npm
npx packager
```
### Configuration
By default, the packager reads its configuration from `Packager.toml` or `packager.json` if it exists, and from `packager.json` key in `packager.json`,
You can also specify a custom configuration using the `-c/--config` cli argument.
For a full list of configuration options, see https://docs.rs/cargo-packager/latest/cargo_packager/config/struct.Config.html.
You could also use the [schema](./schema.json) file from GitHub to validate your configuration or have auto completions in your IDE.
### Building your application before packaging
By default, the packager doesn't build your application, so if your app requires a compilation step, the packager has an option to specify a shell command to be executed before packaing your app, `beforePackagingCommand`.
### Library
The packager is also a library that you can import and integrate into your tooling.
## Licenses
MIT or MIT/Apache 2.0 where applicable.
================================================
FILE: bindings/packager/nodejs/__test__/index.spec.mjs
================================================
import test from "ava";
import process from "process";
import { execSync } from "child_process";
import { packageApp } from "../build/index.js";
test("log error", async (t) => {
process.env.CI = true;
process.chdir("../../../examples/electron");
execSync("yarn install");
t.is(
await packageApp(
{
formats: process.env.PACKAGER_FORMATS
? process.env.PACKAGER_FORMATS.split(",")
: null,
},
{ verbosity: 2 },
),
undefined,
);
});
================================================
FILE: bindings/packager/nodejs/build.rs
================================================
extern crate napi_build;
fn main() {
napi_build::setup();
}
================================================
FILE: bindings/packager/nodejs/generate-config-type.js
================================================
const { compileFromFile } = require("json-schema-to-typescript");
const fs = require("fs");
const path = require("path");
// compile from file
compileFromFile(
path.join(__dirname, "../../../crates/packager/schema.json"),
).then((ts) => {
for (const dir of ["src-ts", "build"]) {
try {
fs.mkdirSync(dir);
} catch (_) {}
fs.writeFileSync(path.join(dir, "config.d.ts"), ts);
}
});
================================================
FILE: bindings/packager/nodejs/index.d.ts
================================================
/* tslint:disable */
/* eslint-disable */
/* auto-generated by NAPI-RS */
export function cli(args: Array, binName?: string | undefined | null): void
export function packageApp(config: string): void
export function packageAndSignApp(config: string, signingConfig: string): void
export function initTracingSubscriber(verbosity: number): void
export function logError(error: string): void
================================================
FILE: bindings/packager/nodejs/index.js
================================================
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
const { platform, arch } = process
let nativeBinding = null
let localFileExisted = false
let loadError = null
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim()
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'packager.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./packager.android-arm64.node')
} else {
nativeBinding = require('@crabnebula/packager-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'packager.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./packager.android-arm-eabi.node')
} else {
nativeBinding = require('@crabnebula/packager-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'packager.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.win32-x64-msvc.node')
} else {
nativeBinding = require('@crabnebula/packager-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'packager.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.win32-ia32-msvc.node')
} else {
nativeBinding = require('@crabnebula/packager-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'packager.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.win32-arm64-msvc.node')
} else {
nativeBinding = require('@crabnebula/packager-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'packager.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./packager.darwin-universal.node')
} else {
nativeBinding = require('@crabnebula/packager-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'packager.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./packager.darwin-x64.node')
} else {
nativeBinding = require('@crabnebula/packager-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'packager.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.darwin-arm64.node')
} else {
nativeBinding = require('@crabnebula/packager-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'packager.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./packager.freebsd-x64.node')
} else {
nativeBinding = require('@crabnebula/packager-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-x64-musl.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-x64-gnu.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-arm64-musl.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-arm64-gnu.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
localFileExisted = existsSync(
join(__dirname, 'packager.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
break
case 'riscv64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-riscv64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-riscv64-musl.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-riscv64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'packager.linux-riscv64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-riscv64-gnu.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-riscv64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 's390x':
localFileExisted = existsSync(
join(__dirname, 'packager.linux-s390x-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./packager.linux-s390x-gnu.node')
} else {
nativeBinding = require('@crabnebula/packager-linux-s390x-gnu')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}
if (!nativeBinding) {
if (loadError) {
throw loadError
}
throw new Error(`Failed to load native binding`)
}
const { cli, packageApp, packageAndSignApp, initTracingSubscriber, logError } = nativeBinding
module.exports.cli = cli
module.exports.packageApp = packageApp
module.exports.packageAndSignApp = packageAndSignApp
module.exports.initTracingSubscriber = initTracingSubscriber
module.exports.logError = logError
================================================
FILE: bindings/packager/nodejs/npm/darwin-arm64/README.md
================================================
# `@crabnebula/packager-darwin-arm64`
This is the **aarch64-apple-darwin** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/darwin-arm64/package.json
================================================
{
"name": "@crabnebula/packager-darwin-arm64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"main": "packager.darwin-arm64.node",
"files": [
"packager.darwin-arm64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/npm/darwin-x64/README.md
================================================
# `@crabnebula/packager-darwin-x64`
This is the **x86_64-apple-darwin** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/darwin-x64/package.json
================================================
{
"name": "@crabnebula/packager-darwin-x64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"main": "packager.darwin-x64.node",
"files": [
"packager.darwin-x64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/npm/linux-arm-gnueabihf/README.md
================================================
# `@crabnebula/packager-linux-arm-gnueabihf`
This is the **armv7-unknown-linux-gnueabihf** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/linux-arm-gnueabihf/package.json
================================================
{
"name": "@crabnebula/packager-linux-arm-gnueabihf",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm"
],
"main": "packager.linux-arm-gnueabihf.node",
"files": [
"packager.linux-arm-gnueabihf.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/npm/linux-arm64-gnu/README.md
================================================
# `@crabnebula/packager-linux-arm64-gnu`
This is the **aarch64-unknown-linux-gnu** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/linux-arm64-gnu/package.json
================================================
{
"name": "@crabnebula/packager-linux-arm64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "packager.linux-arm64-gnu.node",
"files": [
"packager.linux-arm64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/packager/nodejs/npm/linux-arm64-musl/README.md
================================================
# `@crabnebula/packager-linux-arm64-musl`
This is the **aarch64-unknown-linux-musl** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/linux-arm64-musl/package.json
================================================
{
"name": "@crabnebula/packager-linux-arm64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "packager.linux-arm64-musl.node",
"files": [
"packager.linux-arm64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/packager/nodejs/npm/linux-x64-gnu/README.md
================================================
# `@crabnebula/packager-linux-x64-gnu`
This is the **x86_64-unknown-linux-gnu** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/linux-x64-gnu/package.json
================================================
{
"name": "@crabnebula/packager-linux-x64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "packager.linux-x64-gnu.node",
"files": [
"packager.linux-x64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/packager/nodejs/npm/linux-x64-musl/README.md
================================================
# `@crabnebula/packager-linux-x64-musl`
This is the **x86_64-unknown-linux-musl** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/linux-x64-musl/package.json
================================================
{
"name": "@crabnebula/packager-linux-x64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "packager.linux-x64-musl.node",
"files": [
"packager.linux-x64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/packager/nodejs/npm/win32-arm64-msvc/README.md
================================================
# `@crabnebula/packager-win32-arm64-msvc`
This is the **aarch64-pc-windows-msvc** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/win32-arm64-msvc/package.json
================================================
{
"name": "@crabnebula/packager-win32-arm64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"arm64"
],
"main": "packager.win32-arm64-msvc.node",
"files": [
"packager.win32-arm64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/npm/win32-ia32-msvc/README.md
================================================
# `@crabnebula/packager-win32-ia32-msvc`
This is the **i686-pc-windows-msvc** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/win32-ia32-msvc/package.json
================================================
{
"name": "@crabnebula/packager-win32-ia32-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"ia32"
],
"main": "packager.win32-ia32-msvc.node",
"files": [
"packager.win32-ia32-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/npm/win32-x64-msvc/README.md
================================================
# `@crabnebula/packager-win32-x64-msvc`
This is the **x86_64-pc-windows-msvc** binary for `@crabnebula/packager`
================================================
FILE: bindings/packager/nodejs/npm/win32-x64-msvc/package.json
================================================
{
"name": "@crabnebula/packager-win32-x64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "packager.win32-x64-msvc.node",
"files": [
"packager.win32-x64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/package.json
================================================
{
"name": "@crabnebula/packager",
"version": "0.11.8",
"main": "build/index.js",
"module": "build/index.js",
"types": "build/index.d.ts",
"author": {
"name": "CrabNebula Ltd."
},
"description": "Executable packager and bundler distributed as a CLI and library",
"bin": {
"packager": "./packager.js"
},
"napi": {
"name": "packager",
"triples": {
"additional": [
"aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-pc-windows-msvc",
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-musl",
"i686-pc-windows-msvc"
]
}
},
"license": "MIT",
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --platform --profile release-size-optimized",
"build:debug": "napi build --platform && pnpm run postbuild",
"postbuild": "rm -rf ./build && node generate-config-type.js && tsc",
"prepublishOnly": "napi prepublish -t npm --gh-release-id $RELEASE_ID",
"test": "ava --no-worker-threads",
"universal": "napi universal",
"version": "napi version"
},
"dependencies": {
"@electron/get": "^3.0.0",
"deepmerge": "^4.3.1",
"extract-zip": "^2.0.1",
"fs-extra": "^11.1.1",
"galactus": "^1.0.0"
},
"devDependencies": {
"@napi-rs/cli": "^2.18.1",
"@types/fs-extra": "^11.0.3",
"@types/node": "^20.8.10",
"ava": "^6.2.0",
"json-schema-to-typescript": "^15.0.0",
"typescript": "^5.4.5"
},
"ava": {
"timeout": "3m"
},
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/packager/nodejs/packager.js
================================================
#!/usr/bin/env node
const cli = require("./build");
const path = require("path");
const [bin, script, ...args] = process.argv;
const binStem = path.parse(bin).name.toLowerCase();
// We want to make a helpful binary name for the underlying CLI helper, if we
// can successfully detect what command likely started the execution.
let binName;
// deno run -A --unstable --node-modules-dir npm:@crabnebula/packager
if (bin === "@crabnebula/packager") {
binName = "@crabnebula/packager";
}
// Even if started by a package manager, the binary will be NodeJS.
// Some distribution still use "nodejs" as the binary name.
else if (binStem.match(/(nodejs|node|bun)\-?([0-9]*)*$/g)) {
const managerStem = process.env.npm_execpath
? path.parse(process.env.npm_execpath).name.toLowerCase()
: null;
if (managerStem) {
let manager;
switch (managerStem) {
// Only supported package manager that has a different filename is npm.
case "npm-cli":
manager = "npm";
break;
// Yarn, pnpm, and bun have the same stem name as their bin.
// We assume all unknown package managers do as well.
default:
manager = managerStem;
break;
}
binName = `${manager} run ${process.env.npm_lifecycle_event}`;
} else {
// Assume running NodeJS if we didn't detect a manager from the env.
// We normalize the path to prevent the script's absolute path being used.
const scriptNormal = path.normalize(path.relative(process.cwd(), script));
binName = `${binStem} ${scriptNormal}`;
}
} else {
// We don't know what started it, assume it's already stripped.
args.unshift(bin);
}
cli.cli(args, binName).catch((err) => {
cli.logError(err.message);
process.exit(1);
});
================================================
FILE: bindings/packager/nodejs/schema.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config",
"description": "The packaging config.",
"type": "object",
"properties": {
"$schema": {
"description": "The JSON schema for the config.\n\nSetting this field has no effect, this just exists so we can parse the JSON correctly when it has `$schema` field set.",
"type": [
"string",
"null"
]
},
"name": {
"description": "The app name, this is just an identifier that could be used to filter which app to package using `--packages` cli arg when there is multiple apps in the workspace or in the same config.\n\nThis field resembles, the `name` field in `Cargo.toml` or `package.json`\n\nIf `unset`, the CLI will try to auto-detect it from `Cargo.toml` or `package.json` otherwise, it will keep it unset.",
"type": [
"string",
"null"
]
},
"enabled": {
"description": "Whether this config is enabled or not. Defaults to `true`.",
"default": true,
"type": "boolean"
},
"productName": {
"description": "The package's product name, for example \"My Awesome App\".",
"default": "",
"type": "string"
},
"version": {
"description": "The package's version.",
"default": "",
"type": "string"
},
"binaries": {
"description": "The binaries to package.",
"default": [],
"type": "array",
"items": {
"$ref": "#/definitions/Binary"
}
},
"identifier": {
"description": "The application identifier in reverse domain name notation (e.g. `com.packager.example`). This string must be unique across applications since it is used in some system configurations. This string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).",
"type": [
"string",
"null"
],
"pattern": "^[a-zA-Z0-9-\\.]*$"
},
"beforePackagingCommand": {
"description": "The command to run before starting to package an application.\n\nThis runs only once.",
"anyOf": [
{
"$ref": "#/definitions/HookCommand"
},
{
"type": "null"
}
]
},
"beforeEachPackageCommand": {
"description": "The command to run before packaging each format for an application.\n\nThis will run multiple times depending on the formats specifed.",
"anyOf": [
{
"$ref": "#/definitions/HookCommand"
},
{
"type": "null"
}
]
},
"logLevel": {
"description": "The logging level.",
"anyOf": [
{
"$ref": "#/definitions/LogLevel"
},
{
"type": "null"
}
]
},
"formats": {
"description": "The packaging formats to create, if not present, [`PackageFormat::platform_default`] is used.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/PackageFormat"
}
},
"outDir": {
"description": "The directory where the generated packages will be placed.\n\nIf [`Config::binaries_dir`] is not set, this is also where the [`Config::binaries`] exist.",
"default": "",
"type": "string"
},
"binariesDir": {
"description": "The directory where the [`Config::binaries`] exist.\n\nDefaults to [`Config::out_dir`].",
"default": null,
"type": [
"string",
"null"
]
},
"targetTriple": {
"description": "The target triple we are packaging for.\n\nDefaults to the current OS target triple.",
"type": [
"string",
"null"
]
},
"description": {
"description": "The package's description.",
"type": [
"string",
"null"
]
},
"longDescription": {
"description": "The app's long description.",
"type": [
"string",
"null"
]
},
"homepage": {
"description": "The package's homepage.",
"type": [
"string",
"null"
]
},
"authors": {
"description": "The package's authors.",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"publisher": {
"description": "The app's publisher. Defaults to the second element in [`Config::identifier`](Config::identifier) string. Currently maps to the Manufacturer property of the Windows Installer.",
"type": [
"string",
"null"
]
},
"licenseFile": {
"description": "A path to the license file.",
"type": [
"string",
"null"
]
},
"copyright": {
"description": "The app's copyright.",
"type": [
"string",
"null"
]
},
"category": {
"description": "The app's category.",
"anyOf": [
{
"$ref": "#/definitions/AppCategory"
},
{
"type": "null"
}
]
},
"icons": {
"description": "The app's icon list. Supports glob patterns.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fileAssociations": {
"description": "The file associations",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/FileAssociation"
}
},
"deepLinkProtocols": {
"description": "Deep-link protocols.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/DeepLinkProtocol"
}
},
"resources": {
"description": "The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory or an object of `src` and `target` paths. In the case of using an object, the `src` could be either a glob pattern, path to a file, path to a directory, and the `target` is a path inside the final resources folder in the installed package.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Resource"
}
},
"externalBinaries": {
"description": "Paths to external binaries to add to the package.\n\nThe path specified should not include `-<.exe>` suffix, it will be auto-added when by the packager when reading these paths, so the actual binary name should have the target platform's target triple appended, as well as `.exe` for Windows.\n\nFor example, if you're packaging an external binary called `sqlite3`, the packager expects a binary named `sqlite3-x86_64-unknown-linux-gnu` on linux, and `sqlite3-x86_64-pc-windows-gnu.exe` on windows.\n\nIf you are building a universal binary for MacOS, the packager expects your external binary to also be universal, and named after the target triple, e.g. `sqlite3-universal-apple-darwin`. See ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"windows": {
"description": "Windows-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/WindowsConfig"
},
{
"type": "null"
}
]
},
"macos": {
"description": "MacOS-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/MacOsConfig"
},
{
"type": "null"
}
]
},
"linux": {
"description": "Linux-specific configuration",
"anyOf": [
{
"$ref": "#/definitions/LinuxConfig"
},
{
"type": "null"
}
]
},
"deb": {
"description": "Debian-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/DebianConfig"
},
{
"type": "null"
}
]
},
"appimage": {
"description": "AppImage configuration.",
"anyOf": [
{
"$ref": "#/definitions/AppImageConfig"
},
{
"type": "null"
}
]
},
"pacman": {
"description": "Pacman configuration.",
"anyOf": [
{
"$ref": "#/definitions/PacmanConfig"
},
{
"type": "null"
}
]
},
"wix": {
"description": "WiX configuration.",
"anyOf": [
{
"$ref": "#/definitions/WixConfig"
},
{
"type": "null"
}
]
},
"nsis": {
"description": "Nsis configuration.",
"anyOf": [
{
"$ref": "#/definitions/NsisConfig"
},
{
"type": "null"
}
]
},
"dmg": {
"description": "Dmg configuration.",
"anyOf": [
{
"$ref": "#/definitions/DmgConfig"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Binary": {
"description": "A binary to package within the final package.",
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"description": "Path to the binary (without `.exe` on Windows). If it's relative, it will be resolved from [`Config::out_dir`].",
"type": "string"
},
"main": {
"description": "Whether this is the main binary or not",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"HookCommand": {
"description": "Describes a shell command to be executed when a CLI hook is triggered.",
"anyOf": [
{
"description": "Run the given script with the default options.",
"type": "string"
},
{
"description": "Run the given script with custom options.",
"type": "object",
"required": [
"script"
],
"properties": {
"script": {
"description": "The script to execute.",
"type": "string"
},
"dir": {
"description": "The working directory.",
"type": [
"string",
"null"
]
}
}
}
]
},
"LogLevel": {
"description": "An enum representing the available verbosity levels of the logger.",
"oneOf": [
{
"description": "The \"error\" level.\n\nDesignates very serious errors.",
"type": "string",
"enum": [
"error"
]
},
{
"description": "The \"warn\" level.\n\nDesignates hazardous situations.",
"type": "string",
"enum": [
"warn"
]
},
{
"description": "The \"info\" level.\n\nDesignates useful information.",
"type": "string",
"enum": [
"info"
]
},
{
"description": "The \"debug\" level.\n\nDesignates lower priority information.",
"type": "string",
"enum": [
"debug"
]
},
{
"description": "The \"trace\" level.\n\nDesignates very low priority, often extremely verbose, information.",
"type": "string",
"enum": [
"trace"
]
}
]
},
"PackageFormat": {
"description": "Types of supported packages by [`cargo-packager`](https://docs.rs/cargo-packager).",
"oneOf": [
{
"description": "All available package formats for the current platform.\n\nSee [`PackageFormat::platform_all`]",
"type": "string",
"enum": [
"all"
]
},
{
"description": "The default list of package formats for the current platform.\n\nSee [`PackageFormat::platform_default`]",
"type": "string",
"enum": [
"default"
]
},
{
"description": "The macOS application bundle (.app).",
"type": "string",
"enum": [
"app"
]
},
{
"description": "The macOS DMG package (.dmg).",
"type": "string",
"enum": [
"dmg"
]
},
{
"description": "The Microsoft Software Installer (.msi) through WiX Toolset.",
"type": "string",
"enum": [
"wix"
]
},
{
"description": "The NSIS installer (.exe).",
"type": "string",
"enum": [
"nsis"
]
},
{
"description": "The Linux Debian package (.deb).",
"type": "string",
"enum": [
"deb"
]
},
{
"description": "The Linux AppImage package (.AppImage).",
"type": "string",
"enum": [
"appimage"
]
},
{
"description": "The Linux Pacman package (.tar.gz and PKGBUILD)",
"type": "string",
"enum": [
"pacman"
]
}
]
},
"AppCategory": {
"description": "The possible app categories. Corresponds to `LSApplicationCategoryType` on macOS and the GNOME desktop categories on Debian.",
"type": "string",
"enum": [
"Business",
"DeveloperTool",
"Education",
"Entertainment",
"Finance",
"Game",
"ActionGame",
"AdventureGame",
"ArcadeGame",
"BoardGame",
"CardGame",
"CasinoGame",
"DiceGame",
"EducationalGame",
"FamilyGame",
"KidsGame",
"MusicGame",
"PuzzleGame",
"RacingGame",
"RolePlayingGame",
"SimulationGame",
"SportsGame",
"StrategyGame",
"TriviaGame",
"WordGame",
"GraphicsAndDesign",
"HealthcareAndFitness",
"Lifestyle",
"Medical",
"Music",
"News",
"Photography",
"Productivity",
"Reference",
"SocialNetworking",
"Sports",
"Travel",
"Utility",
"Video",
"Weather"
]
},
"FileAssociation": {
"description": "A file association configuration.",
"type": "object",
"required": [
"extensions"
],
"properties": {
"extensions": {
"description": "File extensions to associate with this app. e.g. 'png'",
"type": "array",
"items": {
"type": "string"
}
},
"mimeType": {
"description": "The mime-type e.g. 'image/png' or 'text/plain'. **Linux-only**.",
"type": [
"string",
"null"
]
},
"description": {
"description": "The association description. **Windows-only**. It is displayed on the `Type` column on Windows Explorer.",
"type": [
"string",
"null"
]
},
"name": {
"description": "The name. Maps to `CFBundleTypeName` on macOS. Defaults to the first item in `ext`",
"type": [
"string",
"null"
]
},
"role": {
"description": "The app's role with respect to the type. Maps to `CFBundleTypeRole` on macOS. Defaults to [`BundleTypeRole::Editor`]",
"default": "editor",
"allOf": [
{
"$ref": "#/definitions/BundleTypeRole"
}
]
}
},
"additionalProperties": false
},
"BundleTypeRole": {
"description": "*macOS-only**. Corresponds to CFBundleTypeRole",
"oneOf": [
{
"description": "CFBundleTypeRole.Editor. Files can be read and edited.",
"type": "string",
"enum": [
"editor"
]
},
{
"description": "CFBundleTypeRole.Viewer. Files can be read.",
"type": "string",
"enum": [
"viewer"
]
},
{
"description": "CFBundleTypeRole.Shell",
"type": "string",
"enum": [
"shell"
]
},
{
"description": "CFBundleTypeRole.QLGenerator",
"type": "string",
"enum": [
"qLGenerator"
]
},
{
"description": "CFBundleTypeRole.None",
"type": "string",
"enum": [
"none"
]
}
]
},
"DeepLinkProtocol": {
"description": "Deep link protocol",
"type": "object",
"required": [
"schemes"
],
"properties": {
"schemes": {
"description": "URL schemes to associate with this app without `://`. For example `my-app`",
"type": "array",
"items": {
"type": "string"
}
},
"name": {
"description": "The protocol name. **macOS-only** and maps to `CFBundleTypeName`. Defaults to `.`",
"type": [
"string",
"null"
]
},
"role": {
"description": "The app's role for these schemes. **macOS-only** and maps to `CFBundleTypeRole`.",
"default": "editor",
"allOf": [
{
"$ref": "#/definitions/BundleTypeRole"
}
]
}
},
"additionalProperties": false
},
"Resource": {
"description": "A path to a resource (with optional glob pattern) or an object of `src` and `target` paths.",
"anyOf": [
{
"description": "Supports glob patterns",
"type": "string"
},
{
"description": "An object descriping the src file or directory and its target location in the final package.",
"type": "object",
"required": [
"src",
"target"
],
"properties": {
"src": {
"description": "The src file or directory, supports glob patterns.",
"type": "string"
},
"target": {
"description": "A relative path from the root of the final package.\n\nIf `src` is a glob, this will always be treated as a directory where all globbed files will be placed under.",
"type": "string"
}
}
}
]
},
"WindowsConfig": {
"description": "The Windows configuration.",
"type": "object",
"properties": {
"digestAlgorithm": {
"description": "The file digest algorithm to use for creating file signatures. Required for code signing. SHA-256 is recommended.",
"type": [
"string",
"null"
]
},
"certificateThumbprint": {
"description": "The SHA1 hash of the signing certificate.",
"type": [
"string",
"null"
]
},
"tsp": {
"description": "Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.",
"default": false,
"type": "boolean"
},
"timestampUrl": {
"description": "Server to use during timestamping.",
"type": [
"string",
"null"
]
},
"allowDowngrades": {
"description": "Whether to validate a second app installation, blocking the user from installing an older version if set to `false`.\n\nFor instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.\n\nThe default value of this flag is `true`.",
"default": true,
"type": "boolean"
},
"signCommand": {
"description": "Specify a custom command to sign the binaries. This command needs to have a `%1` in it which is just a placeholder for the binary path, which we will detect and replace before calling the command.\n\nBy Default we use `signtool.exe` which can be found only on Windows so if you are on another platform and want to cross-compile and sign you will need to use another tool like `osslsigncode`.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"MacOsConfig": {
"description": "The macOS configuration.",
"type": "object",
"properties": {
"frameworks": {
"description": "MacOS frameworks that need to be packaged with the app.\n\nEach string can either be the name of a framework (without the `.framework` extension, e.g. `\"SDL2\"`), in which case we will search for that framework in the standard install locations (`~/Library/Frameworks/`, `/Library/Frameworks/`, and `/Network/Library/Frameworks/`), or a path to a specific framework bundle (e.g. `./data/frameworks/SDL2.framework`). Note that this setting just makes cargo-packager copy the specified frameworks into the OS X app bundle (under `Foobar.app/Contents/Frameworks/`); you are still responsible for:\n\n- arranging for the compiled binary to link against those frameworks (e.g. by emitting lines like `cargo:rustc-link-lib=framework=SDL2` from your `build.rs` script)\n\n- embedding the correct rpath in your binary (e.g. by running `install_name_tool -add_rpath \"@executable_path/../Frameworks\" path/to/binary` after compiling)",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"minimumSystemVersion": {
"description": "A version string indicating the minimum MacOS version that the packaged app supports (e.g. `\"10.11\"`). If you are using this config field, you may also want have your `build.rs` script emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.11`.",
"type": [
"string",
"null"
]
},
"exceptionDomain": {
"description": "The exception domain to use on the macOS .app package.\n\nThis allows communication to the outside world e.g. a web server you're shipping.",
"type": [
"string",
"null"
]
},
"signingIdentity": {
"description": "Code signing identity.\n\nThis is typically of the form: `\"Developer ID Application: TEAM_NAME (TEAM_ID)\"`.",
"type": [
"string",
"null"
]
},
"providerShortName": {
"description": "Provider short name for notarization.",
"type": [
"string",
"null"
]
},
"entitlements": {
"description": "Path to the entitlements.plist file.",
"type": [
"string",
"null"
]
},
"infoPlistPath": {
"description": "Path to the Info.plist file for the package.",
"type": [
"string",
"null"
]
},
"embeddedProvisionprofilePath": {
"description": "Path to the embedded.provisionprofile file for the package.",
"type": [
"string",
"null"
]
},
"embeddedApps": {
"description": "Apps that need to be packaged within the app.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"backgroundApp": {
"description": "Whether this is a background application. If true, the app will not appear in the Dock.\n\nSets the `LSUIElement` flag in the macOS plist file.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"LinuxConfig": {
"description": "Linux configuration",
"type": "object",
"properties": {
"generateDesktopEntry": {
"description": "Flag to indicate if desktop entry should be generated.",
"default": true,
"type": "boolean"
}
},
"additionalProperties": false
},
"DebianConfig": {
"description": "The Linux Debian configuration.",
"type": "object",
"properties": {
"depends": {
"description": "The list of Debian dependencies.",
"anyOf": [
{
"$ref": "#/definitions/Dependencies"
},
{
"type": "null"
}
]
},
"desktopTemplate": {
"description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```\n\nThe `{{exec_arg}}` will be set to: * \"%F\", if at least one [Config::file_associations] was specified but no deep link protocols were given. * The \"%F\" arg means that your application can be invoked with multiple file paths. * \"%U\", if at least one [Config::deep_link_protocols] was specified. * The \"%U\" arg means that your application can be invoked with multiple URLs. * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, the \"%U\" arg will be used, causing the file paths to be passed to your app as `file://` URLs. * An empty string \"\" (nothing) if neither are given. * This means that your application will never be invoked with any URLs or file paths.\n\nTo specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: ```text Exec={{exec}} %u ```\n\nSee more here: .",
"type": [
"string",
"null"
]
},
"section": {
"description": "Define the section in Debian Control file. See : ",
"type": [
"string",
"null"
]
},
"priority": {
"description": "Change the priority of the Debian Package. By default, it is set to `optional`. Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`",
"type": [
"string",
"null"
]
},
"files": {
"description": "List of custom files to add to the deb package. Maps a dir/file to a dir/file inside the debian package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"packageName": {
"description": "Name to use for the `Package` field in the Debian Control file. Defaults to [`Config::product_name`] converted to kebab-case.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"Dependencies": {
"description": "A list of dependencies specified as either a list of Strings or as a path to a file that lists the dependencies, one per line.",
"anyOf": [
{
"description": "The list of dependencies provided directly as a vector of Strings.",
"type": "array",
"items": {
"type": "string"
}
},
{
"description": "A path to the file containing the list of dependences, formatted as one per line: ```text libc6 libxcursor1 libdbus-1-3 libasyncns0 ... ```",
"type": "string"
}
]
},
"AppImageConfig": {
"description": "The Linux AppImage configuration.",
"type": "object",
"properties": {
"libs": {
"description": "List of libs that exist in `/usr/lib*` to be include in the final AppImage. The libs will be searched for, using the command `find -L /usr/lib* -name `",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"bins": {
"description": "List of binary paths to include in the final AppImage. For example, if you want `xdg-open`, you'd specify `/usr/bin/xdg-open`",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"files": {
"description": "List of custom files to add to the appimage package. Maps a dir/file to a dir/file inside the appimage package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"linuxdeployPlugins": {
"description": "A map of [`linuxdeploy`](https://github.com/linuxdeploy/linuxdeploy) plugin name and its URL to be downloaded and executed while packaing the appimage. For example, if you want to use the [`gtk`](https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh) plugin, you'd specify `gtk` as the key and its url as the value.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"excludedLibs": {
"description": "List of globs of libraries to exclude from the final AppImage. For example, to exclude libnss3.so, you'd specify `libnss3*`",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"PacmanConfig": {
"description": "The Linux pacman configuration.",
"type": "object",
"properties": {
"files": {
"description": "List of custom files to add to the pacman package. Maps a dir/file to a dir/file inside the pacman package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"depends": {
"description": "List of softwares that must be installed for the app to build and run.\n\nSee : ",
"anyOf": [
{
"$ref": "#/definitions/Dependencies"
},
{
"type": "null"
}
]
},
"provides": {
"description": "Additional packages that are provided by this app.\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"conflicts": {
"description": "Packages that conflict or cause problems with the app. All these packages and packages providing this item will need to be removed\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"replaces": {
"description": "Only use if this app replaces some obsolete packages. For example, if you rename any package.\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"source": {
"description": "Source of the package to be stored at PKGBUILD. PKGBUILD is a bash script, so version can be referred as ${pkgver}",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"WixConfig": {
"description": "The wix format configuration",
"type": "object",
"properties": {
"languages": {
"description": "The app languages to build. See .",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/WixLanguage"
}
},
"template": {
"description": "By default, the packager uses an internal template. This option allows you to define your own wix file.",
"type": [
"string",
"null"
]
},
"mergeModules": {
"description": "List of merge modules to include in your installer. For example, if you want to include [C++ Redis merge modules]\n\n[C++ Redis merge modules]: https://wixtoolset.org/docs/v3/howtos/redistributables_and_install_checks/install_vcredist/",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fragmentPaths": {
"description": "A list of paths to .wxs files with WiX fragments to use.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fragments": {
"description": "List of WiX fragments as strings. This is similar to `config.wix.fragments_paths` but is a string so you can define it inline in your config.\n\n```text ```",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"componentGroupRefs": {
"description": "The ComponentGroup element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"componentRefs": {
"description": "The Component element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"customActionRefs": {
"description": "The CustomAction element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"featureGroupRefs": {
"description": "The FeatureGroup element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"featureRefs": {
"description": "The Feature element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"mergeRefs": {
"description": "The Merge element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"bannerPath": {
"description": "Path to a bitmap file to use as the installation user interface banner. This bitmap will appear at the top of all but the first page of the installer.\n\nThe required dimensions are 493px × 58px.",
"type": [
"string",
"null"
]
},
"dialogImagePath": {
"description": "Path to a bitmap file to use on the installation user interface dialogs. It is used on the welcome and completion dialogs. The required dimensions are 493px × 312px.",
"type": [
"string",
"null"
]
},
"fipsCompliant": {
"description": "Enables FIPS compliant algorithms.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"WixLanguage": {
"description": "A wix language.",
"anyOf": [
{
"description": "Built-in wix language identifier.",
"type": "string"
},
{
"description": "Custom wix language.",
"type": "object",
"required": [
"identifier"
],
"properties": {
"identifier": {
"description": "Idenitifier of this language, for example `en-US`",
"type": "string"
},
"path": {
"description": "The path to a locale (`.wxl`) file. See .",
"type": [
"string",
"null"
]
}
}
}
]
},
"NsisConfig": {
"description": "The NSIS format configuration.",
"type": "object",
"properties": {
"compression": {
"description": "Set the compression algorithm used to compress files in the installer.\n\nSee ",
"anyOf": [
{
"$ref": "#/definitions/NsisCompression"
},
{
"type": "null"
}
]
},
"template": {
"description": "A custom `.nsi` template to use.\n\nSee the default template here ",
"type": [
"string",
"null"
]
},
"preinstallSection": {
"description": "Logic of an NSIS section that will be ran before the install section.\n\nSee the available libraries, dlls and global variables here \n\n### Example ```toml [package.metadata.packager.nsis] preinstall-section = \"\"\" ; Setup custom messages LangString webview2AbortError ${LANG_ENGLISH} \"Failed to install WebView2! The app can't run without it. Try restarting the installer.\" LangString webview2DownloadError ${LANG_ARABIC} \"خطأ: فشل تنزيل WebView2 - $0\"\n\nSection PreInstall ; SectionEnd\n\nSection AnotherPreInstall ; SectionEnd \"\"\" ```",
"type": [
"string",
"null"
]
},
"headerImage": {
"description": "The path to a bitmap file to display on the header of installers pages.\n\nThe recommended dimensions are 150px x 57px.",
"type": [
"string",
"null"
]
},
"sidebarImage": {
"description": "The path to a bitmap file for the Welcome page and the Finish page.\n\nThe recommended dimensions are 164px x 314px.",
"type": [
"string",
"null"
]
},
"installerIcon": {
"description": "The path to an icon file used as the installer icon.",
"type": [
"string",
"null"
]
},
"installMode": {
"description": "Whether the installation will be for all users or just the current user.",
"default": "currentUser",
"allOf": [
{
"$ref": "#/definitions/NSISInstallerMode"
}
]
},
"languages": {
"description": "A list of installer languages. By default the OS language is used. If the OS language is not in the list of languages, the first language will be used. To allow the user to select the language, set `display_language_selector` to `true`.\n\nSee for the complete list of languages.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"customLanguageFiles": {
"description": "An key-value pair where the key is the language and the value is the path to a custom `.nsi` file that holds the translated text for cargo-packager's custom messages.\n\nSee for an example `.nsi` file.\n\n**Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`]languages array,",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"displayLanguageSelector": {
"description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not. By default the OS language is selected, with a fallback to the first language in the `languages` array.",
"default": false,
"type": "boolean"
},
"appdataPaths": {
"description": "List of paths where your app stores data. This options tells the uninstaller to provide the user with an option (disabled by default) whether they want to rmeove your app data or keep it.\n\nThe path should use a constant from in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your app data in `C:\\\\Users\\\\\\\\AppData\\\\Local\\\\\\\\` you'd need to specify ```toml [package.metadata.packager.nsis] appdata-paths = [\"$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME\"] ```",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"NsisCompression": {
"description": "Compression algorithms used in the NSIS installer.\n\nSee ",
"oneOf": [
{
"description": "ZLIB uses the deflate algorithm, it is a quick and simple method. With the default compression level it uses about 300 KB of memory.",
"type": "string",
"enum": [
"zlib"
]
},
{
"description": "BZIP2 usually gives better compression ratios than ZLIB, but it is a bit slower and uses more memory. With the default compression level it uses about 4 MB of memory.",
"type": "string",
"enum": [
"bzip2"
]
},
{
"description": "LZMA (default) is a new compression method that gives very good compression ratios. The decompression speed is high (10-20 MB/s on a 2 GHz CPU), the compression speed is lower. The memory size that will be used for decompression is the dictionary size plus a few KBs, the default is 8 MB.",
"type": "string",
"enum": [
"lzma"
]
},
{
"description": "Disable compression.",
"type": "string",
"enum": [
"off"
]
}
]
},
"NSISInstallerMode": {
"description": "Install Modes for the NSIS installer.",
"oneOf": [
{
"description": "Default mode for the installer.\n\nInstall the app by default in a directory that doesn't require Administrator access.\n\nInstaller metadata will be saved under the `HKCU` registry path.",
"type": "string",
"enum": [
"currentUser"
]
},
{
"description": "Install the app by default in the `Program Files` folder directory requires Administrator access for the installation.\n\nInstaller metadata will be saved under the `HKLM` registry path.",
"type": "string",
"enum": [
"perMachine"
]
},
{
"description": "Combines both modes and allows the user to choose at install time whether to install for the current user or per machine. Note that this mode will require Administrator access even if the user wants to install it for the current user only.\n\nInstaller metadata will be saved under the `HKLM` or `HKCU` registry path based on the user's choice.",
"type": "string",
"enum": [
"both"
]
}
]
},
"DmgConfig": {
"description": "The Apple Disk Image (.dmg) configuration.",
"type": "object",
"properties": {
"background": {
"description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.",
"type": [
"string",
"null"
]
},
"windowPosition": {
"description": "Position of volume window on screen.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
},
"windowSize": {
"description": "Size of volume window.",
"anyOf": [
{
"$ref": "#/definitions/Size"
},
{
"type": "null"
}
]
},
"appPosition": {
"description": "Position of application file on window.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
},
"appFolderPosition": {
"description": "Position of application folder on window.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"Position": {
"description": "Position coordinates struct.",
"type": "object",
"required": [
"x",
"y"
],
"properties": {
"x": {
"description": "X coordinate.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"y": {
"description": "Y coordinate.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"Size": {
"description": "Size struct.",
"type": "object",
"required": [
"height",
"width"
],
"properties": {
"width": {
"description": "Width.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"height": {
"description": "Height.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
}
================================================
FILE: bindings/packager/nodejs/src/lib.rs
================================================
use napi::{Error, Result, Status};
#[napi_derive::napi]
pub fn cli(args: Vec, bin_name: Option) -> Result<()> {
cargo_packager::cli::try_run(args, bin_name)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))
}
#[napi_derive::napi]
pub fn package_app(config: String) -> Result<()> {
let config = serde_json::from_str(&config)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
cargo_packager::package(&config)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
Ok(())
}
#[napi_derive::napi]
pub fn package_and_sign_app(config: String, signing_config: String) -> Result<()> {
let config = serde_json::from_str(&config)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let signing_config = serde_json::from_str(&signing_config)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
cargo_packager::package_and_sign(&config, &signing_config)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
Ok(())
}
#[napi_derive::napi]
pub fn init_tracing_subscriber(verbosity: u8) {
cargo_packager::init_tracing_subscriber(verbosity);
}
#[napi_derive::napi]
pub fn log_error(error: String) {
tracing::error!("{}", error);
}
================================================
FILE: bindings/packager/nodejs/src-ts/config.d.ts
================================================
/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
/**
* Describes a shell command to be executed when a CLI hook is triggered.
*/
export type HookCommand =
| string
| {
/**
* The script to execute.
*/
script: string;
/**
* The working directory.
*/
dir?: string | null;
[k: string]: unknown;
};
/**
* An enum representing the available verbosity levels of the logger.
*/
export type LogLevel = "error" | "warn" | "info" | "debug" | "trace";
/**
* Types of supported packages by [`cargo-packager`](https://docs.rs/cargo-packager).
*/
export type PackageFormat = "all" | "default" | "app" | "dmg" | "wix" | "nsis" | "deb" | "appimage" | "pacman";
/**
* The possible app categories. Corresponds to `LSApplicationCategoryType` on macOS and the GNOME desktop categories on Debian.
*/
export type AppCategory =
| "Business"
| "DeveloperTool"
| "Education"
| "Entertainment"
| "Finance"
| "Game"
| "ActionGame"
| "AdventureGame"
| "ArcadeGame"
| "BoardGame"
| "CardGame"
| "CasinoGame"
| "DiceGame"
| "EducationalGame"
| "FamilyGame"
| "KidsGame"
| "MusicGame"
| "PuzzleGame"
| "RacingGame"
| "RolePlayingGame"
| "SimulationGame"
| "SportsGame"
| "StrategyGame"
| "TriviaGame"
| "WordGame"
| "GraphicsAndDesign"
| "HealthcareAndFitness"
| "Lifestyle"
| "Medical"
| "Music"
| "News"
| "Photography"
| "Productivity"
| "Reference"
| "SocialNetworking"
| "Sports"
| "Travel"
| "Utility"
| "Video"
| "Weather";
/**
* *macOS-only**. Corresponds to CFBundleTypeRole
*/
export type BundleTypeRole = "editor" | "viewer" | "shell" | "qLGenerator" | "none";
/**
* A path to a resource (with optional glob pattern) or an object of `src` and `target` paths.
*/
export type Resource =
| string
| {
/**
* The src file or directory, supports glob patterns.
*/
src: string;
/**
* A relative path from the root of the final package.
*
* If `src` is a glob, this will always be treated as a directory where all globbed files will be placed under.
*/
target: string;
[k: string]: unknown;
};
/**
* A list of dependencies specified as either a list of Strings or as a path to a file that lists the dependencies, one per line.
*/
export type Dependencies = string[] | string;
/**
* A wix language.
*/
export type WixLanguage =
| string
| {
/**
* Idenitifier of this language, for example `en-US`
*/
identifier: string;
/**
* The path to a locale (`.wxl`) file. See .
*/
path?: string | null;
[k: string]: unknown;
};
/**
* Compression algorithms used in the NSIS installer.
*
* See
*/
export type NsisCompression = "zlib" | "bzip2" | "lzma" | "off";
/**
* Install Modes for the NSIS installer.
*/
export type NSISInstallerMode = "currentUser" | "perMachine" | "both";
/**
* The packaging config.
*/
export interface Config {
/**
* The JSON schema for the config.
*
* Setting this field has no effect, this just exists so we can parse the JSON correctly when it has `$schema` field set.
*/
$schema?: string | null;
/**
* The app name, this is just an identifier that could be used to filter which app to package using `--packages` cli arg when there is multiple apps in the workspace or in the same config.
*
* This field resembles, the `name` field in `Cargo.toml` or `package.json`
*
* If `unset`, the CLI will try to auto-detect it from `Cargo.toml` or `package.json` otherwise, it will keep it unset.
*/
name?: string | null;
/**
* Whether this config is enabled or not. Defaults to `true`.
*/
enabled?: boolean;
/**
* The package's product name, for example "My Awesome App".
*/
productName?: string;
/**
* The package's version.
*/
version?: string;
/**
* The binaries to package.
*/
binaries?: Binary[];
/**
* The application identifier in reverse domain name notation (e.g. `com.packager.example`). This string must be unique across applications since it is used in some system configurations. This string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).
*/
identifier?: string | null;
/**
* The command to run before starting to package an application.
*
* This runs only once.
*/
beforePackagingCommand?: HookCommand | null;
/**
* The command to run before packaging each format for an application.
*
* This will run multiple times depending on the formats specifed.
*/
beforeEachPackageCommand?: HookCommand | null;
/**
* The logging level.
*/
logLevel?: LogLevel | null;
/**
* The packaging formats to create, if not present, [`PackageFormat::platform_default`] is used.
*/
formats?: PackageFormat[] | null;
/**
* The directory where the generated packages will be placed.
*
* If [`Config::binaries_dir`] is not set, this is also where the [`Config::binaries`] exist.
*/
outDir?: string;
/**
* The directory where the [`Config::binaries`] exist.
*
* Defaults to [`Config::out_dir`].
*/
binariesDir?: string | null;
/**
* The target triple we are packaging for.
*
* Defaults to the current OS target triple.
*/
targetTriple?: string | null;
/**
* The package's description.
*/
description?: string | null;
/**
* The app's long description.
*/
longDescription?: string | null;
/**
* The package's homepage.
*/
homepage?: string | null;
/**
* The package's authors.
*/
authors?: string[] | null;
/**
* The app's publisher. Defaults to the second element in [`Config::identifier`](Config::identifier) string. Currently maps to the Manufacturer property of the Windows Installer.
*/
publisher?: string | null;
/**
* A path to the license file.
*/
licenseFile?: string | null;
/**
* The app's copyright.
*/
copyright?: string | null;
/**
* The app's category.
*/
category?: AppCategory | null;
/**
* The app's icon list. Supports glob patterns.
*/
icons?: string[] | null;
/**
* The file associations
*/
fileAssociations?: FileAssociation[] | null;
/**
* Deep-link protocols.
*/
deepLinkProtocols?: DeepLinkProtocol[] | null;
/**
* The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory or an object of `src` and `target` paths. In the case of using an object, the `src` could be either a glob pattern, path to a file, path to a directory, and the `target` is a path inside the final resources folder in the installed package.
*
* ## Format-specific:
*
* - **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.
*/
resources?: Resource[] | null;
/**
* Paths to external binaries to add to the package.
*
* The path specified should not include `-<.exe>` suffix, it will be auto-added when by the packager when reading these paths, so the actual binary name should have the target platform's target triple appended, as well as `.exe` for Windows.
*
* For example, if you're packaging an external binary called `sqlite3`, the packager expects a binary named `sqlite3-x86_64-unknown-linux-gnu` on linux, and `sqlite3-x86_64-pc-windows-gnu.exe` on windows.
*
* If you are building a universal binary for MacOS, the packager expects your external binary to also be universal, and named after the target triple, e.g. `sqlite3-universal-apple-darwin`. See
*/
externalBinaries?: string[] | null;
/**
* Windows-specific configuration.
*/
windows?: WindowsConfig | null;
/**
* MacOS-specific configuration.
*/
macos?: MacOsConfig | null;
/**
* Linux-specific configuration
*/
linux?: LinuxConfig | null;
/**
* Debian-specific configuration.
*/
deb?: DebianConfig | null;
/**
* AppImage configuration.
*/
appimage?: AppImageConfig | null;
/**
* Pacman configuration.
*/
pacman?: PacmanConfig | null;
/**
* WiX configuration.
*/
wix?: WixConfig | null;
/**
* Nsis configuration.
*/
nsis?: NsisConfig | null;
/**
* Dmg configuration.
*/
dmg?: DmgConfig | null;
}
/**
* A binary to package within the final package.
*/
export interface Binary {
/**
* Path to the binary (without `.exe` on Windows). If it's relative, it will be resolved from [`Config::out_dir`].
*/
path: string;
/**
* Whether this is the main binary or not
*/
main?: boolean;
}
/**
* A file association configuration.
*/
export interface FileAssociation {
/**
* File extensions to associate with this app. e.g. 'png'
*/
extensions: string[];
/**
* The mime-type e.g. 'image/png' or 'text/plain'. **Linux-only**.
*/
mimeType?: string | null;
/**
* The association description. **Windows-only**. It is displayed on the `Type` column on Windows Explorer.
*/
description?: string | null;
/**
* The name. Maps to `CFBundleTypeName` on macOS. Defaults to the first item in `ext`
*/
name?: string | null;
/**
* The app's role with respect to the type. Maps to `CFBundleTypeRole` on macOS. Defaults to [`BundleTypeRole::Editor`]
*/
role?: BundleTypeRole & string;
}
/**
* Deep link protocol
*/
export interface DeepLinkProtocol {
/**
* URL schemes to associate with this app without `://`. For example `my-app`
*/
schemes: string[];
/**
* The protocol name. **macOS-only** and maps to `CFBundleTypeName`. Defaults to `.`
*/
name?: string | null;
/**
* The app's role for these schemes. **macOS-only** and maps to `CFBundleTypeRole`.
*/
role?: BundleTypeRole & string;
}
/**
* The Windows configuration.
*/
export interface WindowsConfig {
/**
* The file digest algorithm to use for creating file signatures. Required for code signing. SHA-256 is recommended.
*/
digestAlgorithm?: string | null;
/**
* The SHA1 hash of the signing certificate.
*/
certificateThumbprint?: string | null;
/**
* Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.
*/
tsp?: boolean;
/**
* Server to use during timestamping.
*/
timestampUrl?: string | null;
/**
* Whether to validate a second app installation, blocking the user from installing an older version if set to `false`.
*
* For instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.
*
* The default value of this flag is `true`.
*/
allowDowngrades?: boolean;
/**
* Specify a custom command to sign the binaries. This command needs to have a `%1` in it which is just a placeholder for the binary path, which we will detect and replace before calling the command.
*
* By Default we use `signtool.exe` which can be found only on Windows so if you are on another platform and want to cross-compile and sign you will need to use another tool like `osslsigncode`.
*/
signCommand?: string | null;
}
/**
* The macOS configuration.
*/
export interface MacOsConfig {
/**
* MacOS frameworks that need to be packaged with the app.
*
* Each string can either be the name of a framework (without the `.framework` extension, e.g. `"SDL2"`), in which case we will search for that framework in the standard install locations (`~/Library/Frameworks/`, `/Library/Frameworks/`, and `/Network/Library/Frameworks/`), or a path to a specific framework bundle (e.g. `./data/frameworks/SDL2.framework`). Note that this setting just makes cargo-packager copy the specified frameworks into the OS X app bundle (under `Foobar.app/Contents/Frameworks/`); you are still responsible for:
*
* - arranging for the compiled binary to link against those frameworks (e.g. by emitting lines like `cargo:rustc-link-lib=framework=SDL2` from your `build.rs` script)
*
* - embedding the correct rpath in your binary (e.g. by running `install_name_tool -add_rpath "@executable_path/../Frameworks" path/to/binary` after compiling)
*/
frameworks?: string[] | null;
/**
* A version string indicating the minimum MacOS version that the packaged app supports (e.g. `"10.11"`). If you are using this config field, you may also want have your `build.rs` script emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.11`.
*/
minimumSystemVersion?: string | null;
/**
* The exception domain to use on the macOS .app package.
*
* This allows communication to the outside world e.g. a web server you're shipping.
*/
exceptionDomain?: string | null;
/**
* Code signing identity.
*
* This is typically of the form: `"Developer ID Application: TEAM_NAME (TEAM_ID)"`.
*/
signingIdentity?: string | null;
/**
* Provider short name for notarization.
*/
providerShortName?: string | null;
/**
* Path to the entitlements.plist file.
*/
entitlements?: string | null;
/**
* Path to the Info.plist file for the package.
*/
infoPlistPath?: string | null;
/**
* Path to the embedded.provisionprofile file for the package.
*/
embeddedProvisionprofilePath?: string | null;
/**
* Apps that need to be packaged within the app.
*/
embeddedApps?: string[] | null;
/**
* Whether this is a background application. If true, the app will not appear in the Dock.
*
* Sets the `LSUIElement` flag in the macOS plist file.
*/
backgroundApp?: boolean;
}
/**
* Linux configuration
*/
export interface LinuxConfig {
/**
* Flag to indicate if desktop entry should be generated.
*/
generateDesktopEntry?: boolean;
}
/**
* The Linux Debian configuration.
*/
export interface DebianConfig {
/**
* The list of Debian dependencies.
*/
depends?: Dependencies | null;
/**
* Path to a custom desktop file Handlebars template.
*
* Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.
*
* Default file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```
*
* The `{{exec_arg}}` will be set to: * "%F", if at least one [Config::file_associations] was specified but no deep link protocols were given. * The "%F" arg means that your application can be invoked with multiple file paths. * "%U", if at least one [Config::deep_link_protocols] was specified. * The "%U" arg means that your application can be invoked with multiple URLs. * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, the "%U" arg will be used, causing the file paths to be passed to your app as `file://` URLs. * An empty string "" (nothing) if neither are given. * This means that your application will never be invoked with any URLs or file paths.
*
* To specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: ```text Exec={{exec}} %u ```
*
* See more here: .
*/
desktopTemplate?: string | null;
/**
* Define the section in Debian Control file. See :
*/
section?: string | null;
/**
* Change the priority of the Debian Package. By default, it is set to `optional`. Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`
*/
priority?: string | null;
/**
* List of custom files to add to the deb package. Maps a dir/file to a dir/file inside the debian package.
*/
files?: {
[k: string]: string;
} | null;
/**
* Name to use for the `Package` field in the Debian Control file. Defaults to [`Config::product_name`] converted to kebab-case.
*/
packageName?: string | null;
}
/**
* The Linux AppImage configuration.
*/
export interface AppImageConfig {
/**
* List of libs that exist in `/usr/lib*` to be include in the final AppImage. The libs will be searched for, using the command `find -L /usr/lib* -name `
*/
libs?: string[] | null;
/**
* List of binary paths to include in the final AppImage. For example, if you want `xdg-open`, you'd specify `/usr/bin/xdg-open`
*/
bins?: string[] | null;
/**
* List of custom files to add to the appimage package. Maps a dir/file to a dir/file inside the appimage package.
*/
files?: {
[k: string]: string;
} | null;
/**
* A map of [`linuxdeploy`](https://github.com/linuxdeploy/linuxdeploy) plugin name and its URL to be downloaded and executed while packaing the appimage. For example, if you want to use the [`gtk`](https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh) plugin, you'd specify `gtk` as the key and its url as the value.
*/
linuxdeployPlugins?: {
[k: string]: string;
} | null;
/**
* List of globs of libraries to exclude from the final AppImage. For example, to exclude libnss3.so, you'd specify `libnss3*`
*/
excludedLibs?: string[] | null;
}
/**
* The Linux pacman configuration.
*/
export interface PacmanConfig {
/**
* List of custom files to add to the pacman package. Maps a dir/file to a dir/file inside the pacman package.
*/
files?: {
[k: string]: string;
} | null;
/**
* List of softwares that must be installed for the app to build and run.
*
* See :
*/
depends?: Dependencies | null;
/**
* Additional packages that are provided by this app.
*
* See :
*/
provides?: string[] | null;
/**
* Packages that conflict or cause problems with the app. All these packages and packages providing this item will need to be removed
*
* See :
*/
conflicts?: string[] | null;
/**
* Only use if this app replaces some obsolete packages. For example, if you rename any package.
*
* See :
*/
replaces?: string[] | null;
/**
* Source of the package to be stored at PKGBUILD. PKGBUILD is a bash script, so version can be referred as ${pkgver}
*/
source?: string[] | null;
}
/**
* The wix format configuration
*/
export interface WixConfig {
/**
* The app languages to build. See .
*/
languages?: WixLanguage[] | null;
/**
* By default, the packager uses an internal template. This option allows you to define your own wix file.
*/
template?: string | null;
/**
* List of merge modules to include in your installer. For example, if you want to include [C++ Redis merge modules]
*
* [C++ Redis merge modules]: https://wixtoolset.org/docs/v3/howtos/redistributables_and_install_checks/install_vcredist/
*/
mergeModules?: string[] | null;
/**
* A list of paths to .wxs files with WiX fragments to use.
*/
fragmentPaths?: string[] | null;
/**
* List of WiX fragments as strings. This is similar to `config.wix.fragments_paths` but is a string so you can define it inline in your config.
*
* ```text ```
*/
fragments?: string[] | null;
/**
* The ComponentGroup element ids you want to reference from the fragments.
*/
componentGroupRefs?: string[] | null;
/**
* The Component element ids you want to reference from the fragments.
*/
componentRefs?: string[] | null;
/**
* The CustomAction element ids you want to reference from the fragments.
*/
customActionRefs?: string[] | null;
/**
* The FeatureGroup element ids you want to reference from the fragments.
*/
featureGroupRefs?: string[] | null;
/**
* The Feature element ids you want to reference from the fragments.
*/
featureRefs?: string[] | null;
/**
* The Merge element ids you want to reference from the fragments.
*/
mergeRefs?: string[] | null;
/**
* Path to a bitmap file to use as the installation user interface banner. This bitmap will appear at the top of all but the first page of the installer.
*
* The required dimensions are 493px × 58px.
*/
bannerPath?: string | null;
/**
* Path to a bitmap file to use on the installation user interface dialogs. It is used on the welcome and completion dialogs. The required dimensions are 493px × 312px.
*/
dialogImagePath?: string | null;
/**
* Enables FIPS compliant algorithms.
*/
fipsCompliant?: boolean;
}
/**
* The NSIS format configuration.
*/
export interface NsisConfig {
/**
* Set the compression algorithm used to compress files in the installer.
*
* See
*/
compression?: NsisCompression | null;
/**
* A custom `.nsi` template to use.
*
* See the default template here
*/
template?: string | null;
/**
* Logic of an NSIS section that will be ran before the install section.
*
* See the available libraries, dlls and global variables here
*
* ### Example ```toml [package.metadata.packager.nsis] preinstall-section = """ ; Setup custom messages LangString webview2AbortError ${LANG_ENGLISH} "Failed to install WebView2! The app can't run without it. Try restarting the installer." LangString webview2DownloadError ${LANG_ARABIC} "خطأ: فشل تنزيل WebView2 - $0"
*
* Section PreInstall ; SectionEnd
*
* Section AnotherPreInstall ; SectionEnd """ ```
*/
preinstallSection?: string | null;
/**
* The path to a bitmap file to display on the header of installers pages.
*
* The recommended dimensions are 150px x 57px.
*/
headerImage?: string | null;
/**
* The path to a bitmap file for the Welcome page and the Finish page.
*
* The recommended dimensions are 164px x 314px.
*/
sidebarImage?: string | null;
/**
* The path to an icon file used as the installer icon.
*/
installerIcon?: string | null;
/**
* Whether the installation will be for all users or just the current user.
*/
installMode?: NSISInstallerMode & string;
/**
* A list of installer languages. By default the OS language is used. If the OS language is not in the list of languages, the first language will be used. To allow the user to select the language, set `display_language_selector` to `true`.
*
* See for the complete list of languages.
*/
languages?: string[] | null;
/**
* An key-value pair where the key is the language and the value is the path to a custom `.nsi` file that holds the translated text for cargo-packager's custom messages.
*
* See for an example `.nsi` file.
*
* **Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`]languages array,
*/
customLanguageFiles?: {
[k: string]: string;
} | null;
/**
* Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not. By default the OS language is selected, with a fallback to the first language in the `languages` array.
*/
displayLanguageSelector?: boolean;
/**
* List of paths where your app stores data. This options tells the uninstaller to provide the user with an option (disabled by default) whether they want to rmeove your app data or keep it.
*
* The path should use a constant from in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your app data in `C:\\Users\\\\AppData\\Local\\\\` you'd need to specify ```toml [package.metadata.packager.nsis] appdata-paths = ["$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME"] ```
*/
appdataPaths?: string[] | null;
}
/**
* The Apple Disk Image (.dmg) configuration.
*/
export interface DmgConfig {
/**
* Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.
*/
background?: string | null;
/**
* Position of volume window on screen.
*/
windowPosition?: Position | null;
/**
* Size of volume window.
*/
windowSize?: Size | null;
/**
* Position of application file on window.
*/
appPosition?: Position | null;
/**
* Position of application folder on window.
*/
appFolderPosition?: Position | null;
}
/**
* Position coordinates struct.
*/
export interface Position {
/**
* X coordinate.
*/
x: number;
/**
* Y coordinate.
*/
y: number;
}
/**
* Size struct.
*/
export interface Size {
/**
* Width.
*/
width: number;
/**
* Height.
*/
height: number;
}
================================================
FILE: bindings/packager/nodejs/src-ts/index.ts
================================================
import cargoPackager from "../index";
import runPlugins from "./plugins";
import merge from "deepmerge";
import type { Config } from "./config";
let tracingEnabled = false;
export interface Options {
verbosity?: number;
}
export interface SigningConfig {
/** The private key to use for signing. */
privateKey: string;
/**
* The private key password.
*
* If `null`, user will be prompted to write a password.
* You can skip the prompt by specifying an empty string.
*/
password?: string;
}
async function packageApp(config: Config = {}, options?: Options) {
const conf = await runPlugins();
let packagerConfig = config;
if (conf) {
packagerConfig = merge(conf, config);
}
if (!tracingEnabled) {
cargoPackager.initTracingSubscriber(options?.verbosity ?? 0);
tracingEnabled = true;
}
cargoPackager.packageApp(JSON.stringify(packagerConfig));
}
async function packageAndSignApp(
config: Config = {},
signingConfig: SigningConfig,
options?: Options,
) {
const conf = await runPlugins();
let packagerConfig = config;
if (conf) {
packagerConfig = merge(conf, config);
}
if (!tracingEnabled) {
cargoPackager.initTracingSubscriber(options?.verbosity ?? 0);
tracingEnabled = true;
}
cargoPackager.packageAndSignApp(
JSON.stringify(packagerConfig),
JSON.stringify(signingConfig),
);
}
async function cli(args: string[], binName: string) {
const config = await runPlugins();
if (config) {
args.push("--config");
args.push(JSON.stringify(config));
}
cargoPackager.cli(args, binName);
}
function logError(error: string) {
cargoPackager.logError(error);
}
export { cli, packageApp, packageAndSignApp, logError };
================================================
FILE: bindings/packager/nodejs/src-ts/plugins/electron/index.ts
================================================
import type { Config, Resource } from "../../config";
import type { PackageJson } from "..";
import fs from "fs-extra";
import path from "path";
import os from "os";
import { download as downloadElectron } from "@electron/get";
import extractZip from "extract-zip";
import { Pruner, isModule, normalizePath } from "./prune";
export default async function run(
appPath: string,
packageJson: PackageJson,
): Promise | null> {
let electronPath;
try {
electronPath = require.resolve("electron", {
paths: [appPath],
});
} catch (e) {
return null;
}
const userConfig = packageJson.packager || {};
const electronPackageJson = JSON.parse(
(
await fs.readFile(
path.resolve(path.dirname(electronPath), "package.json"),
)
).toString(),
);
const zipPath = await downloadElectron(electronPackageJson.version);
const zipDir = await fs.mkdtemp(path.join(os.tmpdir(), ".packager-electron"));
await extractZip(zipPath, {
dir: zipDir,
});
const platformName = os.platform();
let resources: Resource[] = [];
let frameworks: string[] = [];
let debianFiles: {
[k: string]: string;
} | null = null;
let binaryPath;
const appTempPath = await fs.mkdtemp(
path.join(os.tmpdir(), packageJson.name || "app-temp"),
);
const pruner = new Pruner(appPath, true);
const outDir = userConfig.outDir ? path.resolve(userConfig.outDir) : null;
const ignoredDirs = outDir && outDir !== process.cwd() ? [outDir] : [];
await fs.copy(appPath, appTempPath, {
filter: async (file: string) => {
const fullPath = path.resolve(file);
if (ignoredDirs.includes(fullPath)) {
return false;
}
let name = fullPath.split(appPath)[1];
if (path.sep === "\\") {
name = normalizePath(name);
}
if (name.startsWith("/node_modules/")) {
if (await isModule(file)) {
return await pruner.pruneModule(name);
}
}
return true;
},
});
switch (platformName) {
case "darwin":
var binaryName: string =
userConfig.name ||
packageJson.productName ||
packageJson.name ||
"Electron";
var standaloneElectronPath = path.join(zipDir, "Electron.app");
const resourcesPath = path.join(
standaloneElectronPath,
"Contents/Resources",
);
resources = resources.concat(
(await fs.readdir(resourcesPath))
.filter((p) => p !== "default_app.asar")
.map((p) => path.join(resourcesPath, p)),
);
resources.push({
src: appTempPath,
target: "app",
});
const frameworksPath = path.join(
standaloneElectronPath,
"Contents/Frameworks",
);
frameworks = (await fs.readdir(frameworksPath)).map((p) =>
path.join(frameworksPath, p),
);
binaryPath = path.join(
standaloneElectronPath,
`Contents/MacOS/${binaryName}`,
);
// rename the electron binary
await fs.rename(
path.join(standaloneElectronPath, "Contents/MacOS/Electron"),
binaryPath,
);
break;
case "win32":
var binaryName: string =
userConfig.name ||
packageJson.productName ||
packageJson.name ||
"Electron";
binaryPath = path.join(zipDir, `${binaryName}.exe`);
resources = resources.concat(
(await fs.readdir(zipDir))
// resources only contains the default_app.asar so we ignore it
.filter((p) => p !== "resources" && p !== "electron.exe")
.map((p) => path.join(zipDir, p)),
);
// rename the electron binary
await fs.rename(path.join(zipDir, "electron.exe"), binaryPath);
resources.push({
src: appTempPath,
target: "resources/app",
});
break;
default:
var binaryName = toKebabCase(
userConfig.name ||
packageJson.productName ||
packageJson.name ||
"Electron",
);
// rename the electron binary
await fs.rename(
path.join(zipDir, "electron"),
path.join(zipDir, binaryName),
);
const electronFiles = await fs.readdir(zipDir);
const binTmpDir = await fs.mkdtemp(
path.join(os.tmpdir(), `${packageJson.name || "app-temp"}-bin`),
);
binaryPath = path.join(binTmpDir, binaryName);
await fs.writeFile(binaryPath, binaryScript(binaryName));
await fs.chmod(binaryPath, 0o755);
// make linuxdeploy happy
process.env.LD_LIBRARY_PATH = process.env.LD_LIBRARY_PATH
? `${process.env.LD_LIBRARY_PATH}:${zipDir}`
: zipDir;
// electron needs everything at the same level :)
// resources only contains the default_app.asar so we ignore it
debianFiles = electronFiles
.filter((f) => f !== "resources")
.reduce(
(acc, file) => ({
...acc,
[path.join(zipDir, file)]: `usr/lib/${binaryName}/${file}`,
}),
{},
);
debianFiles[appTempPath] = `usr/lib/${binaryName}/resources/app`;
}
return {
name: packageJson.name,
productName: packageJson.productName || packageJson.name,
version: packageJson.version,
resources,
macos: {
frameworks,
},
deb: {
files: debianFiles,
},
appimage: {
files: debianFiles,
},
binaries: [
{
path: binaryPath,
main: true,
},
],
};
}
const toKebabCase = (str: string) =>
str
.split(/\.?(?=[A-Z])/)
.join("-")
.toLowerCase();
function binaryScript(binaryName: string): string {
return `#!/usr/bin/env sh
full_path=$(realpath $0)
bin_dir_path=$(dirname $full_path)
usr_dir_path=$(dirname $bin_dir_path)
echo $usr_dir_path
$usr_dir_path/lib/${binaryName}/${binaryName}
`;
}
================================================
FILE: bindings/packager/nodejs/src-ts/plugins/electron/prune.ts
================================================
// from https://github.com/electron/electron-packager/blob/741f3c349e7f9e11e5ae14593a3efa79d312dc4d/src/prune.js
import { DestroyerOfModules, ModuleMap, DepType, Module } from "galactus";
import fs from "fs";
import path from "path";
const ELECTRON_MODULES = [
"electron",
"electron-nightly",
"electron-prebuilt",
"electron-prebuilt-compile",
];
export function normalizePath(path: string): string {
return path.replace(/\\/g, "/");
}
class Pruner {
baseDir: string;
quiet: boolean;
galactus: DestroyerOfModules;
walkedTree: boolean;
modules?: Set;
constructor(dir: string, quiet: boolean) {
this.baseDir = normalizePath(dir);
this.quiet = quiet;
this.galactus = new DestroyerOfModules({
rootDirectory: dir,
shouldKeepModuleTest: (module, isDevDep) =>
this.shouldKeepModule(module, isDevDep),
});
this.walkedTree = false;
}
setModules(moduleMap: ModuleMap) {
const modulePaths = Array.from(moduleMap.keys()).map(
(modulePath) => `/${normalizePath(modulePath)}`,
);
this.modules = new Set(modulePaths);
this.walkedTree = true;
}
async pruneModule(name: string) {
if (this.walkedTree) {
return this.isProductionModule(name);
} else {
const moduleMap = await this.galactus.collectKeptModules({
relativePaths: true,
});
this.setModules(moduleMap);
return this.isProductionModule(name);
}
}
shouldKeepModule(module: Module, isDevDep: boolean) {
if (isDevDep || module.depType === DepType.ROOT) {
return false;
}
if (ELECTRON_MODULES.includes(module.name)) {
if (!this.quiet)
console.warn(
`Found '${module.name}' but not as a devDependency, pruning anyway`,
);
return false;
}
return true;
}
isProductionModule(name: string): boolean {
return this.modules?.has(name) ?? false;
}
}
function isNodeModuleFolder(pathToCheck: string) {
return (
path.basename(path.dirname(pathToCheck)) === "node_modules" ||
(path.basename(path.dirname(pathToCheck)).startsWith("@") &&
path.basename(path.resolve(pathToCheck, `..${path.sep}..`)) ===
"node_modules")
);
}
export async function isModule(pathToCheck: string) {
return (
(await fs.existsSync(path.join(pathToCheck, "package.json"))) &&
isNodeModuleFolder(pathToCheck)
);
}
export { Pruner };
================================================
FILE: bindings/packager/nodejs/src-ts/plugins/index.ts
================================================
import path from "path";
import fs from "fs-extra";
import type { Config } from "../config";
import electron from "./electron";
import merge from "deepmerge";
export interface PackageJson {
name?: string;
productName?: string;
version?: string;
packager: Partial | null | undefined;
}
function getPackageJsonPath(): string | null {
let appDir = process.cwd();
while (appDir.length && appDir[appDir.length - 1] !== path.sep) {
const filepath = path.join(appDir, "package.json");
if (fs.existsSync(filepath)) {
return filepath;
}
appDir = path.normalize(path.join(appDir, ".."));
}
return null;
}
export default async function run(): Promise | null> {
const packageJsonPath = getPackageJsonPath();
if (packageJsonPath === null) {
return null;
}
const packageJson = JSON.parse(
(await fs.readFile(packageJsonPath)).toString(),
) as PackageJson;
let config = packageJson.packager || null;
try {
const electronConfig = await electron(
path.dirname(packageJsonPath),
packageJson,
);
if (electronConfig) {
config = config ? merge(electronConfig, config) : electronConfig;
}
if (config?.outDir) {
await fs.ensureDir(config.outDir);
}
return config;
} catch {
return null;
}
}
================================================
FILE: bindings/packager/nodejs/tsconfig.json
================================================
{
"compilerOptions": {
"target": "es2016",
"lib": ["es6"],
"module": "commonjs",
"rootDir": "src-ts",
"resolveJsonModule": true,
"allowJs": true,
"outDir": "build",
"declaration": true,
"declarationDir": "build",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"skipLibCheck": true
},
"exclude": [
"build/",
"__test__/",
"index.js",
"packager.js",
"generate-config-type.js"
]
}
================================================
FILE: bindings/resource-resolver/nodejs/.cargo/config.toml
================================================
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=-crt-static"]
================================================
FILE: bindings/resource-resolver/nodejs/.npmignore
================================================
target
Cargo.lock
.cargo
.github
npm
.eslintrc
.prettierignore
rustfmt.toml
yarn.lock
*.node
.yarn
__test__
renovate.json
================================================
FILE: bindings/resource-resolver/nodejs/CHANGELOG.md
================================================
# Changelog
## \[0.1.2]
### Dependencies
- Upgraded to `cargo-packager-resource-resolver@0.1.2`
- Upgraded to `cargo-packager-utils@0.1.1`
## \[0.1.1]
### Dependencies
- Upgraded to `cargo-packager-resource-resolver@0.1.1`
## \[0.1.0]
- [`cd0242b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/cd0242b8a41b2f7ecb78dfbae04b3a2e1c72c931) Initial Release.
### Dependencies
- Upgraded to `cargo-packager-utils@0.1.0`
- Upgraded to `cargo-packager-resource-resolver@0.1.0`
================================================
FILE: bindings/resource-resolver/nodejs/Cargo.toml
================================================
[package]
name = "crabnebula_packager_resource_resolver"
version = "0.0.0"
publish = false
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { workspace = true, features = ["napi4"] }
napi-derive = { workspace = true }
cargo-packager-resource-resolver = { path = "../../../crates/resource-resolver" }
dunce.workspace = true
[build-dependencies]
napi-build = { workspace = true }
================================================
FILE: bindings/resource-resolver/nodejs/README.md
================================================
# @crabnebula/packager-resource-resolver
Resource resolver for apps that was packaged by [`@crabnebula/packager`](https://www.npmjs.com/package/@crabnebula/packager).
It resolves the root path which contains resources, which was set using the `resources` field of [cargo packager configuration](https://docs.rs/cargo-packager/latest/cargo_packager/config/struct.Config.html).
## Get the resource path
```ts
import {
resourcesDir,
PackageFormat,
} from "@crabnebula/packager-resource-resolver";
const dir = resourcesDir(PackageFormat.Nsis);
```
## Licenses
MIT or MIT/Apache 2.0 where applicable.
================================================
FILE: bindings/resource-resolver/nodejs/__test__/index.spec.mjs
================================================
import test from "ava";
import { resourcesDir, PackageFormat } from "../index.js";
test("resolve resource directory", async (t) => {
const dir = resourcesDir(PackageFormat.Nsis);
t.is(typeof dir, "string");
});
================================================
FILE: bindings/resource-resolver/nodejs/build.rs
================================================
extern crate napi_build;
fn main() {
napi_build::setup();
}
================================================
FILE: bindings/resource-resolver/nodejs/fix-types.js
================================================
// Due to a NAPI-rs bug? still unconfirmed
// index.d.ts will contain a duplicate definition of `PackageFromat` enum
// and we only need the second definition.
// This script sole purpose is to remove the extra definition.
const { readFileSync, writeFileSync } = require("fs");
const { join } = require("path");
const typesPath = join(__dirname, "index.d.ts");
const types = readFileSync(typesPath, "utf8");
let out = "";
let inRemoval = false;
for (const line of types.split("\n")) {
if (inRemoval) {
if (line === "}") inRemoval = false;
continue;
}
const startOfRemoval = line.startsWith(
"/** Types of supported packages by [`cargo-packager`](https://docs.rs/cargo-packager). */",
);
if (startOfRemoval) {
inRemoval = true;
continue;
}
out += line + "\n";
}
writeFileSync(typesPath, out);
const problematicCode = `const { PackageFormat, PackageFormat, resourcesDir } = nativeBinding
module.exports.PackageFormat = PackageFormat
module.exports.PackageFormat = PackageFormat
module.exports.resourcesDir = resourcesDir`;
const correctCode = `const { PackageFormat, resourcesDir } = nativeBinding
module.exports.PackageFormat = PackageFormat
module.exports.resourcesDir = resourcesDir`;
const indexPath = join(__dirname, "index.js");
const indexContent = readFileSync(indexPath, "utf8");
writeFileSync(indexPath, indexContent.replace(problematicCode, correctCode));
================================================
FILE: bindings/resource-resolver/nodejs/index.d.ts
================================================
/* tslint:disable */
/* eslint-disable */
/* auto-generated by NAPI-RS */
/** Types of supported packages by [`@crabnebula/packager`](https://www.npmjs.com/package/@crabnebula/packager) */
export const enum PackageFormat {
/** The macOS application bundle (.app). */
App = "App",
/** The macOS DMG package (.dmg). */
Dmg = "Dmg",
/** The Microsoft Software Installer (.msi) through WiX Toolset. */
Wix = "Wix",
/** The NSIS installer (.exe). */
Nsis = "Nsis",
/** The Linux Debian package (.deb). */
Deb = "Deb",
/** The Linux AppImage package (.AppImage). */
AppImage = "AppImage",
}
/** Retrieve the resource path of your app, packaged with cargo packager. */
export function resourcesDir(packageFormat: PackageFormat): string;
================================================
FILE: bindings/resource-resolver/nodejs/index.js
================================================
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
const { existsSync, readFileSync } = require('fs')
const { join } = require("path");
const { platform, arch } = process;
let nativeBinding = null;
let localFileExisted = false;
let loadError = null;
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== "function") {
try {
const lddPath = require("child_process")
.execSync("which ldd")
.toString()
.trim();
return readFileSync(lddPath, "utf8").includes("musl");
} catch (e) {
return true;
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header;
return !glibcVersionRuntime;
}
}
switch (platform) {
case "android":
switch (arch) {
case "arm64":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.android-arm64.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.android-arm64.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-android-arm64");
}
} catch (e) {
loadError = e;
}
break;
case "arm":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.android-arm-eabi.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.android-arm-eabi.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-android-arm-eabi");
}
} catch (e) {
loadError = e;
}
break;
default:
throw new Error(`Unsupported architecture on Android ${arch}`);
}
break;
case "win32":
switch (arch) {
case "x64":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.win32-x64-msvc.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.win32-x64-msvc.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-win32-x64-msvc");
}
} catch (e) {
loadError = e;
}
break;
case "ia32":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.win32-ia32-msvc.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.win32-ia32-msvc.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-win32-ia32-msvc");
}
} catch (e) {
loadError = e;
}
break;
case "arm64":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.win32-arm64-msvc.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.win32-arm64-msvc.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-win32-arm64-msvc");
}
} catch (e) {
loadError = e;
}
break;
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`);
}
break;
case "darwin":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.darwin-universal.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.darwin-universal.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-darwin-universal");
}
break;
} catch {}
switch (arch) {
case "x64":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.darwin-x64.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.darwin-x64.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-darwin-x64");
}
} catch (e) {
loadError = e;
}
break;
case "arm64":
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.darwin-arm64.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.darwin-arm64.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-darwin-arm64");
}
} catch (e) {
loadError = e;
}
break;
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`);
}
break;
case "freebsd":
if (arch !== "x64") {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`);
}
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.freebsd-x64.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.freebsd-x64.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-freebsd-x64");
}
} catch (e) {
loadError = e;
}
break;
case "linux":
switch (arch) {
case "x64":
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.linux-x64-musl.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.linux-x64-musl.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-linux-x64-musl");
}
} catch (e) {
loadError = e;
}
} else {
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.linux-x64-gnu.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.linux-x64-gnu.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-linux-x64-gnu");
}
} catch (e) {
loadError = e;
}
}
break;
case "arm64":
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.linux-arm64-musl.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.linux-arm64-musl.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-linux-arm64-musl");
}
} catch (e) {
loadError = e;
}
} else {
localFileExisted = existsSync(
join(__dirname, "packager-resource-resolver.linux-arm64-gnu.node"),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.linux-arm64-gnu.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-linux-arm64-gnu");
}
} catch (e) {
loadError = e;
}
}
break;
case "arm":
localFileExisted = existsSync(
join(
__dirname,
"packager-resource-resolver.linux-arm-gnueabihf.node",
),
);
try {
if (localFileExisted) {
nativeBinding = require("./packager-resource-resolver.linux-arm-gnueabihf.node");
} else {
nativeBinding = require("@crabnebula/packager-resource-resolver-linux-arm-gnueabihf");
}
} catch (e) {
loadError = e;
}
break;
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`);
}
break;
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
}
if (!nativeBinding) {
if (loadError) {
throw loadError;
}
throw new Error(`Failed to load native binding`);
}
const { PackageFormat, resourcesDir } = nativeBinding;
module.exports.PackageFormat = PackageFormat;
module.exports.resourcesDir = resourcesDir;
================================================
FILE: bindings/resource-resolver/nodejs/npm/darwin-arm64/README.md
================================================
# `@crabnebula/packager-resource-resolver-darwin-arm64`
This is the **aarch64-apple-darwin** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/darwin-arm64/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-darwin-arm64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"main": "packager-resource-resolver.darwin-arm64.node",
"files": [
"packager-resource-resolver.darwin-arm64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/darwin-x64/README.md
================================================
# `@crabnebula/packager-resource-resolver-darwin-x64`
This is the **x86_64-apple-darwin** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/darwin-x64/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-darwin-x64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"main": "packager-resource-resolver.darwin-x64.node",
"files": [
"packager-resource-resolver.darwin-x64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm-gnueabihf/README.md
================================================
# `@crabnebula/packager-resource-resolver-linux-arm-gnueabihf`
This is the **armv7-unknown-linux-gnueabihf** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm-gnueabihf/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-linux-arm-gnueabihf",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm"
],
"main": "packager-resource-resolver.linux-arm-gnueabihf.node",
"files": [
"packager-resource-resolver.linux-arm-gnueabihf.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm64-gnu/README.md
================================================
# `@crabnebula/packager-resource-resolver-linux-arm64-gnu`
This is the **aarch64-unknown-linux-gnu** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm64-gnu/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-linux-arm64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "packager-resource-resolver.linux-arm64-gnu.node",
"files": [
"packager-resource-resolver.linux-arm64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm64-musl/README.md
================================================
# `@crabnebula/packager-resource-resolver-linux-arm64-musl`
This is the **aarch64-unknown-linux-musl** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-arm64-musl/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-linux-arm64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "packager-resource-resolver.linux-arm64-musl.node",
"files": [
"packager-resource-resolver.linux-arm64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-x64-gnu/README.md
================================================
# `@crabnebula/packager-resource-resolver-linux-x64-gnu`
This is the **x86_64-unknown-linux-gnu** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-x64-gnu/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-linux-x64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "packager-resource-resolver.linux-x64-gnu.node",
"files": [
"packager-resource-resolver.linux-x64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-x64-musl/README.md
================================================
# `@crabnebula/packager-resource-resolver-linux-x64-musl`
This is the **x86_64-unknown-linux-musl** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/linux-x64-musl/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-linux-x64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "packager-resource-resolver.linux-x64-musl.node",
"files": [
"packager-resource-resolver.linux-x64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-arm64-msvc/README.md
================================================
# `@crabnebula/packager-resource-resolver-win32-arm64-msvc`
This is the **aarch64-pc-windows-msvc** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-arm64-msvc/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-win32-arm64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"arm64"
],
"main": "packager-resource-resolver.win32-arm64-msvc.node",
"files": [
"packager-resource-resolver.win32-arm64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-ia32-msvc/README.md
================================================
# `@crabnebula/packager-resource-resolver-win32-ia32-msvc`
This is the **i686-pc-windows-msvc** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-ia32-msvc/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-win32-ia32-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"ia32"
],
"main": "packager-resource-resolver.win32-ia32-msvc.node",
"files": [
"packager-resource-resolver.win32-ia32-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-x64-msvc/README.md
================================================
# `@crabnebula/packager-resource-resolver-win32-x64-msvc`
This is the **x86_64-pc-windows-msvc** binary for `@crabnebula/packager-resource-resolver`
================================================
FILE: bindings/resource-resolver/nodejs/npm/win32-x64-msvc/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver-win32-x64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "packager-resource-resolver.win32-x64-msvc.node",
"files": [
"packager-resource-resolver.win32-x64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/package.json
================================================
{
"name": "@crabnebula/packager-resource-resolver",
"version": "0.1.2",
"main": "./index.js",
"types": "./index.d.ts",
"napi": {
"name": "packager-resource-resolver",
"triples": {
"additional": [
"aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-pc-windows-msvc",
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-musl",
"i686-pc-windows-msvc"
]
}
},
"license": "MIT",
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --platform --profile release-size-optimized",
"postbuild": "node ./fix-types.js",
"build:debug": "napi build --platform",
"prepublishOnly": "napi prepublish -t npm --gh-release-id $RELEASE_ID",
"test": "ava --no-worker-threads --timeout 30m",
"universal": "napi universal",
"version": "napi version"
},
"devDependencies": {
"@napi-rs/cli": "^2.18.1",
"@types/node": "^20.8.10",
"ava": "^6.0.0"
},
"ava": {
"timeout": "3m"
},
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/resource-resolver/nodejs/src/lib.rs
================================================
use napi::{Result, Status};
use cargo_packager_resource_resolver::PackageFormat as ResolverPackageFormat;
/// Types of supported packages by [`@crabnebula/packager`](https://www.npmjs.com/package/@crabnebula/packager)
#[derive(Debug, Eq, PartialEq)]
#[napi_derive::napi(string_enum)]
pub enum PackageFormat {
/// The macOS application bundle (.app).
App,
/// The macOS DMG package (.dmg).
Dmg,
/// The Microsoft Software Installer (.msi) through WiX Toolset.
Wix,
/// The NSIS installer (.exe).
Nsis,
/// The Linux Debian package (.deb).
Deb,
/// The Linux AppImage package (.AppImage).
AppImage,
}
impl From for ResolverPackageFormat {
fn from(value: PackageFormat) -> Self {
match value {
PackageFormat::App => ResolverPackageFormat::App,
PackageFormat::Dmg => ResolverPackageFormat::Dmg,
PackageFormat::Wix => ResolverPackageFormat::Wix,
PackageFormat::Nsis => ResolverPackageFormat::Nsis,
PackageFormat::Deb => ResolverPackageFormat::Deb,
PackageFormat::AppImage => ResolverPackageFormat::AppImage,
}
}
}
/// Retrieve the resource path of your app, packaged with cargo packager.
#[napi_derive::napi]
pub fn resources_dir(package_format: PackageFormat) -> Result {
cargo_packager_resource_resolver::resources_dir(package_format.into())
.map_err(|e| napi::Error::new(Status::GenericFailure, e.to_string()))
.map(|p| dunce::simplified(&p).to_string_lossy().to_string())
}
================================================
FILE: bindings/updater/nodejs/.cargo/config.toml
================================================
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=-crt-static"]
================================================
FILE: bindings/updater/nodejs/.npmignore
================================================
target
Cargo.lock
.cargo
.github
npm
.eslintrc
.prettierignore
rustfmt.toml
yarn.lock
*.node
.yarn
__test__
renovate.json
================================================
FILE: bindings/updater/nodejs/CHANGELOG.md
================================================
# Changelog
## \[0.2.3]
- [`d861f1a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/d861f1a6b1dfe585014e04234b33d49b1a895219) ([#356](https://www.github.com/crabnebula-dev/cargo-packager/pull/356)) Pull enhancements from tauri-plugin-updater.
### Dependencies
- Upgraded to `cargo-packager-updater@0.2.3`
## \[0.2.2]
### Dependencies
- Upgraded to `cargo-packager-updater@0.2.2`
## \[0.2.1]
### Dependencies
- Upgraded to `cargo-packager-updater@0.2.1`
- Upgraded to `cargo-packager-utils@0.1.1`
## \[0.2.0]
- [`c16d17a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c16d17ae190f49be3f9e78c5441bee16c0f8fc69) Enable `rustls-tls` feature flag by default.
### Dependencies
- Upgraded to `cargo-packager-updater@0.2.0`
## \[0.1.4]
- [`3ee2290`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3ee2290df518103056b295dae426b38a65293048)([#147](https://www.github.com/crabnebula-dev/cargo-packager/pull/147)) Prevent powershell window from opening when the msi and nsis installer are executed.
### Dependencies
- Upgraded to `cargo-packager-updater@0.1.4`
## \[0.1.3]
- [`0e00ca2`](https://www.github.com/crabnebula-dev/cargo-packager/commit/0e00ca25fc0e71cad4bb7085edda067a184e5ec7)([#146](https://www.github.com/crabnebula-dev/cargo-packager/pull/146)) Enable native certificates via `rustls-native-certs`.
### Dependencies
- Upgraded to `cargo-packager-updater@0.1.3`
## \[0.1.2]
- [`005a55f`](https://www.github.com/crabnebula-dev/cargo-packager/commit/005a55fb27b92503b3d6f936cffb088ccf346c40)([#143](https://www.github.com/crabnebula-dev/cargo-packager/pull/143)) Fix the download callback parameters to be accurate to typescript definitions
### Dependencies
- Upgraded to `cargo-packager-utils@0.1.0`
- Upgraded to `cargo-packager-updater@0.1.2`
## \[0.1.1]
- [`feb53a2`](https://www.github.com/crabnebula-dev/cargo-packager/commit/feb53a2f16ef2c8d93ff2d73a4eb318490f33471)([#102](https://www.github.com/crabnebula-dev/cargo-packager/pull/102)) Fix NSIS updater failing to launch when using `basicUi` mode.
### Dependencies
- Upgraded to `cargo-packager-updater@0.1.1`
## \[0.1.0]
- [`c4fa8fd`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c4fa8fd6334b7fd0c32710ea2df0b54aa6bde713) Initial release.
### Dependencies
- Upgraded to `cargo-packager-updater@0.1.0`
================================================
FILE: bindings/updater/nodejs/Cargo.toml
================================================
[package]
name = "crabnebula_updater"
version = "0.0.0"
publish = false
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { workspace = true, features = ["napi4", "async"] }
napi-derive = { workspace = true }
cargo-packager-updater = { path = "../../../crates/updater/", default-features = false }
serde_json = { workspace = true }
time = { workspace = true, features = ["formatting"] }
[build-dependencies]
napi-build = { workspace = true }
[features]
default = ["cargo-packager-updater/rustls-tls"]
rustls-tls = ["cargo-packager-updater/rustls-tls"]
native-tls = ["cargo-packager-updater/native-tls"]
native-tls-vendored = ["cargo-packager-updater/native-tls-vendored"]
================================================
FILE: bindings/updater/nodejs/README.md
================================================
# @crabnebula/updater
Updater for apps that was packaged by [`@crabnebula/packager`](https://www.npmjs.com/package/@crabnebula/packager).
```sh
# pnpm
pnpm add @crabnebula/updater
# yarn
yarn add @crabnebula/updater
# npm
npm i @crabnebula/updater
```
## Checking for an update
you can check for an update using `checkUpdate` function which require the current version of the app and
an options object that specifies the endpoints to request updates from and the public key of the update signature.
```js
import { checkUpdate } from "@crabnebula/updater";
let update = await checkUpdate("0.1.0", {
endpoints: ["http://myserver.com/updates"],
pubkey: "",
});
if (update !== null) {
update.downloadAndInstall();
} else {
// there is no updates
}
```
## Endpoints
Each endpoint optionally could have `{{arch}}`, `{{target}}` or `{{current_version}}`
which will be detected and replaced with the appropriate value before making a request to the endpoint.
- `{{current_version}}`: The version of the app that is requesting the update.
- `{{target}}`: The operating system name (one of `linux`, `windows` or `macos`).
- `{{arch}}`: The architecture of the machine (one of `x86_64`, `i686`, `aarch64` or `armv7`).
for example:
```
https://releases.myapp.com/{{target}}/{{arch}}/{{current_version}}
```
will turn into
```
https://releases.myapp.com/windows/x86_64/0.1.0
```
if you need more data, you can set additional request headers in the options object pass to `checkUpdate` to your liking.
## Endpoint Response
The updater expects the endpoint to respond with 2 possible reponses:
1. [`204 No Content`](https://datatracker.ietf.org/doc/html/rfc2616#section-10.2.5) in case there is no updates available.
2. [`200 OK`](https://datatracker.ietf.org/doc/html/rfc2616#section-10.2.1) and a JSON response that could be either a JSON representing all available platform updates
or if using endpoints variables (see above) or a header to attach the current updater target,
then it can just return information for the requested target.
The JSON response is expected to have these fields set:
- `version`: must be a valid semver, with or without a leading `v``, meaning that both `1.0.0`and`v1.0.0`are valid.
- `url`or`platforms.[target].url`: must be a valid url to the update bundle.
- `signature`or`platforms.[target].signature`: must be the content of the generated `.sig`file. The signature may change each time you run build your app so make sure to always update it.
- `format`or`platforms.[target].format`: must be one of `app`, `appimage`, `nsis`or`wix`.
> [!NOTE]
> if using `platforms` object, each key is in the `OS-ARCH` format, where `OS` is one of `linux`, `macos` or `windows`, and `ARCH` is one of `x86_64`, `aarch64`, `i686` or `armv7`, see the example below.
It can also contain these optional fields:
- `notes`: Here you can add notes about the update, like release notes.
- `pub_date`: must be formatted according to [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.8) if present.
Here is an example of the two expected JSON formats:
- **JSON for all platforms**
```json
{
"version": "v1.0.0",
"notes": "Test version",
"pub_date": "2020-06-22T19:25:57Z",
"platforms": {
"macos-x86_64": {
"signature": "Content of app.tar.gz.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-x86_64.app.tar.gz",
"format": "app"
},
"macos-aarch64": {
"signature": "Content of app.tar.gz.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-aarch64.app.tar.gz",
"format": "app"
},
"linux-x86_64": {
"signature": "Content of app.AppImage.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-amd64.AppImage.tar.gz",
"format": "appimage"
},
"windows-x86_64": {
"signature": "Content of app-setup.exe.sig or app.msi.sig, depending on the chosen format",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-x64-setup.nsis.zip",
"format": "nsis or wix depending on the chosen format"
}
}
}
```
- **JSON for one platform**
```json
{
"version": "0.2.0",
"pub_date": "2020-09-18T12:29:53+01:00",
"url": "https://mycompany.example.com/myapp/releases/myrelease.tar.gz",
"signature": "Content of the relevant .sig file",
"format": "app or nsis or wix or appimage depending on the release target and the chosen format",
"notes": "These are some release notes"
}
```
## Update install mode on Windows
You can specify which install mode to use on Windows using `windows.installMode` in the options object which can be one of:
- `"Passive"`: There will be a small window with a progress bar. The update will be installed without requiring any user interaction. Generally recommended and the default mode.
- `"BasicUi"`: There will be a basic user interface shown which requires user interaction to finish the installation.
- `"Quiet"`: There will be no progress feedback to the user. With this mode the installer cannot request admin privileges by itself so it only works in user-wide installations or when your app itself already runs with admin privileges. Generally not recommended.
## Licenses
MIT or MIT/Apache 2.0 where applicable.
================================================
FILE: bindings/updater/nodejs/__test__/app/index.html
================================================
Hello World!
Hello World!
We are using Node.js , Chromium
, and Electron
.
================================================
FILE: bindings/updater/nodejs/__test__/app/main.js
================================================
const { app } = require("electron");
const { join } = require("node:path");
const { checkUpdate } = require("@crabnebula/updater");
const UPDATER_PUB_KEY =
"dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ2Njc0OTE5Mzk2Q0ExODkKUldTSm9XdzVHVWxuUmtJdjB4RnRXZGVqR3NQaU5SVitoTk1qNFFWQ3pjL2hZWFVDOFNrcEVvVlcK";
const CURRENT_VERSION = "{{version}}";
app.whenReady().then(async () => {
console.log(CURRENT_VERSION);
const updaterFormat = process.env["UPDATER_FORMAT"];
const appimg = process.env["APPIMAGE"];
const isLinux = process.platfrom !== "win32" && process.platfrom !== "darwin";
try {
const update = await checkUpdate(CURRENT_VERSION, {
pubkey: UPDATER_PUB_KEY,
endpoints: ["http://localhost:3007"],
executablePath: isLinux && appimg ? appimg : undefined,
windows: {
installerArgs:
// /D sets the default installation directory ($INSTDIR),
// overriding InstallDir and InstallDirRegKey.
// It must be the last parameter used in the command line and must not contain any quotes, even if the path contains spaces.
// Only absolute paths are supported.
// NOTE: we only need this because this is an integration test and we don't want to install the app in the programs folder
updaterFormat === "nsis"
? [`/D=${join(process.execPath, "..")}`]
: undefined,
},
});
if (update) {
try {
await update.downloadAndInstall();
process.exit(0);
} catch (e) {
console.error(e);
process.exit(1);
}
} else {
process.exit(0);
}
} catch (e) {
console.error(e);
process.exit(1);
}
});
================================================
FILE: bindings/updater/nodejs/__test__/app/package.json
================================================
{
"name": "electron-app",
"productName": "ElectronApp",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"repository": {
"type": "git",
"url": "git+https://github.com/crabnebula-dev/cargo-packager.git"
},
"author": "CrabNebula Ltd.",
"license": "MIT",
"bugs": {
"url": "https://github.com/crabnebula-dev/cargo-packager/issues"
},
"homepage": "https://github.com/crabnebula-dev/cargo-packager#readme",
"dependencies": {
"@crabnebula/updater": "../.."
},
"devDependencies": {
"electron": "^35.7.5"
},
"packager": {
"outDir": "./dist",
"identifier": "com.electron.example",
"icons": [
"electron.png"
]
}
}
================================================
FILE: bindings/updater/nodejs/__test__/app/preload.js
================================================
window.addEventListener("DOMContentLoaded", () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector);
if (element) element.innerText = text;
};
for (const dependency of ["chrome", "node", "electron"]) {
replaceText(`${dependency}-version`, process.versions[dependency]);
}
});
================================================
FILE: bindings/updater/nodejs/__test__/index.spec.mjs
================================================
import test from "ava";
import * as fs from "fs/promises";
import { existsSync } from "fs";
import * as path from "path";
import { execa } from "execa";
import { fileURLToPath } from "url";
import { App } from "@tinyhttp/app";
import { packageAndSignApp } from "@crabnebula/packager";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const isWin = process.platform === "win32";
const isMac = process.platform === "darwin";
test("it updates correctly", async (t) => {
const UPDATER_PRIVATE_KEY = await fs.readFile(
path.join(__dirname, "../../../../crates/updater/tests/dummy.key"),
{
encoding: "utf8",
},
);
process.chdir(path.join(__dirname, "app"));
await execa("yarn", ["install"]);
const buildApp = async (version, updaterFormats) => {
const content = await fs.readFile("main.js", {
encoding: "utf8",
});
await fs.writeFile("main.js", content.replace("{{version}}", version));
try {
await packageAndSignApp(
{
formats: updaterFormats,
version,
},
{
privateKey: UPDATER_PRIVATE_KEY,
password: "",
},
{
verbosity: 2,
},
);
} catch (e) {
console.error("failed to package app");
console.error(e);
} finally {
const content = await fs.readFile("main.js", {
encoding: "utf8",
});
await fs.writeFile("main.js", content.replace(version, "{{version}}"));
}
};
// bundle app update
const formats = isWin ? ["nsis", "wix"] : isMac ? ["app"] : ["appimage"];
await buildApp("1.0.0", formats);
const generatedPackages = isWin
? [
["nsis", path.join("dist", `ElectronApp_1.0.0_x64-setup.exe`)],
["wix", path.join("dist", `ElectronApp_1.0.0_x64_en-US.msi`)],
]
: isMac
? [["app", path.join("dist", "ElectronApp.app.tar.gz")]]
: [["appimage", path.join("dist", `electron-app_1.0.0_x86_64.AppImage`)]];
for (let [format, updatePackagePath] of generatedPackages) {
const signaturePath = path.format({
name: updatePackagePath,
ext: ".sig",
});
const signature = await fs.readFile(signaturePath, {
encoding: "utf8",
});
// on macOS, generated bundle doesn't have the version in its name
// so we need to move it otherwise it'll be overwritten when we build the next app
if (isMac) {
const info = path.parse(updatePackagePath);
const newPath = path.format({
dir: info.dir,
base: `update-1.0.0-${info.base}`,
});
await fs.rename(updatePackagePath, newPath);
updatePackagePath = newPath;
}
// start the updater server
const server = new App()
.get("/", (_, res) => {
const platforms = {};
const target = `${isWin ? "windows" : isMac ? "macos" : "linux"}-${
process.arch === "x64"
? "x86_64"
: process.arch === "arm64"
? "aarch64"
: "i686"
}`;
platforms[target] = {
signature,
url: "http://localhost:3007/download",
format,
};
res.status(200).json({
version: "1.0.0",
date: new Date().toISOString(),
platforms,
});
})
.get("/download", (_req, res) => {
res
.status(200)
.sendFile(path.join(__dirname, "app", updatePackagePath));
})
.listen(3007);
// bundle initial app version
await buildApp("0.1.0", [format]);
// install the inital app on Windows to `installdir`
if (isWin) {
const installDir = path.join(__dirname, "app", "dist", "installdir");
if (existsSync(installDir))
await fs.rm(installDir, {
recursive: true,
});
await fs.mkdir(installDir);
const isNsis = format === "nsis";
const installerArg = `"${path.join(
"dist",
isNsis
? `ElectronApp_0.1.0_x64-setup.exe`
: `ElectronApp_0.1.0_x64_en-US.msi`,
)}"`;
await execa("powershell.exe", [
"-NoProfile",
"-WindowStyle",
"Hidden",
"Start-Process",
installerArg,
"-Wait",
"-ArgumentList",
`${isNsis ? "/P" : "/passive"}, ${
isNsis ? "/D" : "INSTALLDIR"
}=${installDir}`,
]);
}
const app = path.join(
"dist",
isWin
? "installdir/ElectronApp.exe"
: isMac
? "ElectronApp.app/Contents/MacOS/ElectronApp"
: `electron-app_0.1.0_x86_64.AppImage`,
);
// save the current creation time
const stats = await fs.stat(app);
const ctime1 = stats.birthtime;
// run initial app
try {
await execa(app, {
stdio: "inherit",
// This is read by the updater app test
env: {
UPDATER_FORMAT: format,
},
});
} catch (e) {
console.error(`failed to start initial app: ${e}`);
}
// the test app is electron which is huge in size
// and the installation takes a who;e
// so wait 30 secs to make sure the installer has finished
await sleep(30000);
// wait until the update is finished and the new version has been installed
// before starting another updater test, this is because we use the same starting binary
// and we can't use it while the updater is installing it
let counter = 0;
while (true) {
// check if the main binary creation time has changed since `ctime1`
const stats = await fs.stat(app);
if (ctime1 !== stats.birthtime) {
try {
const { stdout, stderr } = await execa(app);
const lines = stdout.split(isWin ? "\r\n" : "\n");
const version = lines.filter((l) => l)[0];
if (version === "1.0.0") {
console.log(`app is updated, new version: ${version}`);
break;
}
console.log(`unexpected output (stdout): ${stdout}`);
console.log(`stderr: ${stderr}`);
} catch (e) {
console.error(`failed to check if app was updated: ${e}`);
}
}
counter += 1;
if (counter == 10) {
console.error(
"updater test timedout and couldn't verify the update has happened",
);
break;
}
await sleep(5000);
}
server.close();
}
t.pass("Test successful");
});
================================================
FILE: bindings/updater/nodejs/build.rs
================================================
extern crate napi_build;
fn main() {
napi_build::setup();
}
================================================
FILE: bindings/updater/nodejs/index.d.ts
================================================
/* tslint:disable */
/* eslint-disable */
/* auto-generated by NAPI-RS */
export const enum WindowsUpdateInstallMode {
/** Specifies there's a basic UI during the installation process, including a final dialog box at the end. */
BasicUi = 'BasicUi',
/**
* The quiet mode means there's no user interaction required.
* Requires admin privileges if the installer does.
*/
Quiet = 'Quiet',
/** Specifies unattended mode, which means the installation only shows a progress bar. */
Passive = 'Passive'
}
export interface UpdaterWindowsOptions {
/** Additional arguments given to the NSIS or WiX installer. */
installerArgs?: Array
/** The installation mode for the update on Windows. Defaults to `passive`. */
installMode?: WindowsUpdateInstallMode
}
export interface Options {
/** The updater endpoints. */
endpoints: Array
/** Signature public key. */
pubkey: string
/** The Windows options for the updater. */
windows?: UpdaterWindowsOptions
/** The target of the executable. */
target?: string
/** Path to the executable file. */
executablePath?: string
/** Headers to use when checking and when downloading the update. */
headers?: Record
/** Request timeout in milliseconds. */
timeout?: number
}
/** Supported update format */
export const enum UpdateFormat {
/** The NSIS installer (.exe). */
Nsis = 0,
/** The Microsoft Software Installer (.msi) through WiX Toolset. */
Wix = 1,
/** The Linux AppImage package (.AppImage). */
AppImage = 2,
/** The macOS application bundle (.app). */
App = 3
}
export function checkUpdate(currentVersion: string, options: Options): Promise
export class Update {
/** Signing public key */
pubkey: string
/** Version used to check for update */
currentVersion: string
/** Version announced */
version: string
/** Target */
target: string
/** Extract path */
extractPath: string
/** Download URL announced */
downloadUrl: string
/** Signature announced */
signature: string
/** Request headers */
headers: Record
/** Update format */
format: UpdateFormat
/** The Windows options for the updater. */
windows?: UpdaterWindowsOptions
/** Update description */
body?: string
/** Update publish date */
date?: string
/** Request timeout */
timeout?: number
download(onChunk?: (chunkLength: number, contentLength: number | null) => void, onDownloadFinished?: () => void): Promise
install(buffer: ArrayBuffer): Promise
downloadAndInstall(onChunk?: (chunkLength: number, contentLength?: number) => void, onDownloadFinished?: () => void): Promise
}
================================================
FILE: bindings/updater/nodejs/index.js
================================================
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
const { platform, arch } = process
let nativeBinding = null
let localFileExisted = false
let loadError = null
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim()
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'updater.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./updater.android-arm64.node')
} else {
nativeBinding = require('@crabnebula/updater-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'updater.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./updater.android-arm-eabi.node')
} else {
nativeBinding = require('@crabnebula/updater-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'updater.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.win32-x64-msvc.node')
} else {
nativeBinding = require('@crabnebula/updater-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'updater.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.win32-ia32-msvc.node')
} else {
nativeBinding = require('@crabnebula/updater-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'updater.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.win32-arm64-msvc.node')
} else {
nativeBinding = require('@crabnebula/updater-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'updater.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./updater.darwin-universal.node')
} else {
nativeBinding = require('@crabnebula/updater-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'updater.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./updater.darwin-x64.node')
} else {
nativeBinding = require('@crabnebula/updater-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'updater.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.darwin-arm64.node')
} else {
nativeBinding = require('@crabnebula/updater-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'updater.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./updater.freebsd-x64.node')
} else {
nativeBinding = require('@crabnebula/updater-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'updater.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.linux-x64-musl.node')
} else {
nativeBinding = require('@crabnebula/updater-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'updater.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.linux-x64-gnu.node')
} else {
nativeBinding = require('@crabnebula/updater-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'updater.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.linux-arm64-musl.node')
} else {
nativeBinding = require('@crabnebula/updater-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'updater.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.linux-arm64-gnu.node')
} else {
nativeBinding = require('@crabnebula/updater-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
localFileExisted = existsSync(
join(__dirname, 'updater.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./updater.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@crabnebula/updater-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}
if (!nativeBinding) {
if (loadError) {
throw loadError
}
throw new Error(`Failed to load native binding`)
}
const { WindowsUpdateInstallMode, UpdateFormat, Update, checkUpdate } = nativeBinding
module.exports.WindowsUpdateInstallMode = WindowsUpdateInstallMode
module.exports.UpdateFormat = UpdateFormat
module.exports.Update = Update
module.exports.checkUpdate = checkUpdate
================================================
FILE: bindings/updater/nodejs/npm/darwin-arm64/README.md
================================================
# `@crabnebula/updater-darwin-arm64`
This is the **aarch64-apple-darwin** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/darwin-arm64/package.json
================================================
{
"name": "@crabnebula/updater-darwin-arm64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"main": "updater.darwin-arm64.node",
"files": [
"updater.darwin-arm64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/npm/darwin-x64/README.md
================================================
# `@crabnebula/updater-darwin-x64`
This is the **x86_64-apple-darwin** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/darwin-x64/package.json
================================================
{
"name": "@crabnebula/updater-darwin-x64",
"version": "0.0.0",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"main": "updater.darwin-x64.node",
"files": [
"updater.darwin-x64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/npm/linux-arm-gnueabihf/README.md
================================================
# `@crabnebula/updater-linux-arm-gnueabihf`
This is the **armv7-unknown-linux-gnueabihf** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/linux-arm-gnueabihf/package.json
================================================
{
"name": "@crabnebula/updater-linux-arm-gnueabihf",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm"
],
"main": "updater.linux-arm-gnueabihf.node",
"files": [
"updater.linux-arm-gnueabihf.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/npm/linux-arm64-gnu/README.md
================================================
# `@crabnebula/updater-linux-arm64-gnu`
This is the **aarch64-unknown-linux-gnu** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/linux-arm64-gnu/package.json
================================================
{
"name": "@crabnebula/updater-linux-arm64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "updater.linux-arm64-gnu.node",
"files": [
"updater.linux-arm64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/updater/nodejs/npm/linux-arm64-musl/README.md
================================================
# `@crabnebula/updater-linux-arm64-musl`
This is the **aarch64-unknown-linux-musl** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/linux-arm64-musl/package.json
================================================
{
"name": "@crabnebula/updater-linux-arm64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "updater.linux-arm64-musl.node",
"files": [
"updater.linux-arm64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/updater/nodejs/npm/linux-x64-gnu/README.md
================================================
# `@crabnebula/updater-linux-x64-gnu`
This is the **x86_64-unknown-linux-gnu** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/linux-x64-gnu/package.json
================================================
{
"name": "@crabnebula/updater-linux-x64-gnu",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "updater.linux-x64-gnu.node",
"files": [
"updater.linux-x64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}
================================================
FILE: bindings/updater/nodejs/npm/linux-x64-musl/README.md
================================================
# `@crabnebula/updater-linux-x64-musl`
This is the **x86_64-unknown-linux-musl** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/linux-x64-musl/package.json
================================================
{
"name": "@crabnebula/updater-linux-x64-musl",
"version": "0.0.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "updater.linux-x64-musl.node",
"files": [
"updater.linux-x64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}
================================================
FILE: bindings/updater/nodejs/npm/win32-arm64-msvc/README.md
================================================
# `@crabnebula/updater-win32-arm64-msvc`
This is the **aarch64-pc-windows-msvc** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/win32-arm64-msvc/package.json
================================================
{
"name": "@crabnebula/updater-win32-arm64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"arm64"
],
"main": "updater.win32-arm64-msvc.node",
"files": [
"updater.win32-arm64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/npm/win32-ia32-msvc/README.md
================================================
# `@crabnebula/updater-win32-ia32-msvc`
This is the **i686-pc-windows-msvc** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/win32-ia32-msvc/package.json
================================================
{
"name": "@crabnebula/updater-win32-ia32-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"ia32"
],
"main": "updater.win32-ia32-msvc.node",
"files": [
"updater.win32-ia32-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/npm/win32-x64-msvc/README.md
================================================
# `@crabnebula/updater-win32-x64-msvc`
This is the **x86_64-pc-windows-msvc** binary for `@crabnebula/updater`
================================================
FILE: bindings/updater/nodejs/npm/win32-x64-msvc/package.json
================================================
{
"name": "@crabnebula/updater-win32-x64-msvc",
"version": "0.0.0",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "updater.win32-x64-msvc.node",
"files": [
"updater.win32-x64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/package.json
================================================
{
"name": "@crabnebula/updater",
"version": "0.2.3",
"main": "./index.js",
"types": "./index.d.ts",
"napi": {
"name": "updater",
"triples": {
"additional": [
"aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-pc-windows-msvc",
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-musl",
"i686-pc-windows-msvc"
]
}
},
"license": "MIT",
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --platform --profile release-size-optimized",
"build:debug": "napi build --platform",
"prepublishOnly": "napi prepublish -t npm --gh-release-id $RELEASE_ID",
"test": "ava --no-worker-threads --timeout 30m",
"universal": "napi universal",
"version": "napi version"
},
"devDependencies": {
"@napi-rs/cli": "^2.18.1",
"@tinyhttp/app": "^2.2.1",
"@types/node": "^20.8.10",
"ava": "^6.2.0",
"execa": "^9.0.0",
"@crabnebula/packager": "workspace:"
},
"ava": {
"timeout": "3m"
},
"engines": {
"node": ">= 10"
}
}
================================================
FILE: bindings/updater/nodejs/src/from_impls.rs
================================================
use crate::{Options, Update, UpdateFormat, UpdaterWindowsOptions, WindowsUpdateInstallMode};
impl From for cargo_packager_updater::WindowsUpdateInstallMode {
fn from(value: WindowsUpdateInstallMode) -> Self {
match value {
WindowsUpdateInstallMode::BasicUi => Self::BasicUi,
WindowsUpdateInstallMode::Quiet => Self::Quiet,
WindowsUpdateInstallMode::Passive => Self::Passive,
}
}
}
impl From for WindowsUpdateInstallMode {
fn from(value: cargo_packager_updater::WindowsUpdateInstallMode) -> Self {
match value {
cargo_packager_updater::WindowsUpdateInstallMode::BasicUi => Self::BasicUi,
cargo_packager_updater::WindowsUpdateInstallMode::Quiet => Self::Quiet,
cargo_packager_updater::WindowsUpdateInstallMode::Passive => Self::Passive,
}
}
}
impl From for UpdaterWindowsOptions {
fn from(value: cargo_packager_updater::WindowsConfig) -> Self {
Self {
installer_args: value.installer_args,
install_mode: value.install_mode.map(Into::into),
}
}
}
impl From for cargo_packager_updater::WindowsConfig {
fn from(value: UpdaterWindowsOptions) -> Self {
Self {
installer_args: value.installer_args,
install_mode: value.install_mode.map(Into::into),
}
}
}
impl From for cargo_packager_updater::Config {
fn from(value: Options) -> Self {
Self {
endpoints: value
.endpoints
.into_iter()
.filter_map(|e| e.parse().ok())
.collect(),
pubkey: value.pubkey,
windows: value.windows.map(Into::into),
}
}
}
impl From for UpdateFormat {
fn from(value: cargo_packager_updater::UpdateFormat) -> Self {
match value {
cargo_packager_updater::UpdateFormat::Nsis => Self::Nsis,
cargo_packager_updater::UpdateFormat::Wix => Self::Wix,
cargo_packager_updater::UpdateFormat::AppImage => Self::AppImage,
cargo_packager_updater::UpdateFormat::App => Self::App,
}
}
}
impl From for cargo_packager_updater::UpdateFormat {
fn from(value: UpdateFormat) -> Self {
match value {
UpdateFormat::Nsis => Self::Nsis,
UpdateFormat::Wix => Self::Wix,
UpdateFormat::AppImage => Self::AppImage,
UpdateFormat::App => Self::App,
}
}
}
impl From for Update {
fn from(value: cargo_packager_updater::Update) -> Self {
Self {
pubkey: value.config.pubkey,
body: value.body,
current_version: value.current_version,
version: value.version,
date: value.date.and_then(|d| {
d.format(&time::format_description::well_known::Rfc3339)
.ok()
}),
target: value.target,
extract_path: value.extract_path.to_string_lossy().to_string(),
download_url: value.download_url.to_string(),
signature: value.signature,
timeout: value.timeout.map(|t| t.as_millis() as u32),
headers: value
.headers
.into_iter()
.map(|(k, v)| {
(
k.map(|k| k.to_string()).unwrap_or_default(),
v.to_str().unwrap_or_default().to_string(),
)
})
.collect(),
format: value.format.into(),
windows: value.config.windows.map(Into::into),
}
}
}
================================================
FILE: bindings/updater/nodejs/src/lib.rs
================================================
use std::{collections::HashMap, str::FromStr, time::Duration};
use cargo_packager_updater::{
http::{HeaderMap, HeaderName, HeaderValue},
semver::Version,
Updater, UpdaterBuilder,
};
use napi::{
bindgen_prelude::AsyncTask,
threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode},
Env, Error, JsArrayBuffer, Result, Status, Task,
};
mod from_impls;
#[napi_derive::napi(string_enum)]
#[derive(Default)]
pub enum WindowsUpdateInstallMode {
/// Specifies there's a basic UI during the installation process, including a final dialog box at the end.
BasicUi,
/// The quiet mode means there's no user interaction required.
/// Requires admin privileges if the installer does.
Quiet,
/// Specifies unattended mode, which means the installation only shows a progress bar.
#[default]
Passive,
}
#[derive(Clone)]
#[napi_derive::napi(object)]
pub struct UpdaterWindowsOptions {
/// Additional arguments given to the NSIS or WiX installer.
pub installer_args: Option>,
/// The installation mode for the update on Windows. Defaults to `passive`.
pub install_mode: Option,
}
#[napi_derive::napi(object)]
pub struct Options {
/// The updater endpoints.
pub endpoints: Vec,
/// Signature public key.
pub pubkey: String,
/// The Windows options for the updater.
pub windows: Option,
/// The target of the executable.
pub target: Option,
/// Path to the executable file.
pub executable_path: Option,
/// Headers to use when checking and when downloading the update.
pub headers: Option>,
/// Request timeout in milliseconds.
pub timeout: Option,
}
impl Options {
fn into_updater(mut self, current_version: Version) -> Result {
let target = self.target.take();
let executable_path = self.executable_path.take();
let headers = self.headers.take();
let timeout = self.timeout.take();
let config: cargo_packager_updater::Config = self.into();
let mut builder = UpdaterBuilder::new(current_version, config);
if let Some(target) = target {
builder = builder.target(target);
}
if let Some(executable_path) = executable_path {
builder = builder.executable_path(executable_path);
}
if let Some(timeout) = timeout {
builder = builder.timeout(Duration::from_millis(timeout as u64));
}
if let Some(headers) = headers {
for (key, value) in headers {
builder = builder.header(key, value).map_err(|e| {
Error::new(
Status::InvalidArg,
format!("Failed to set header, probably invalid header values, {e}"),
)
})?;
}
}
builder.build().map_err(|e| {
Error::new(
Status::GenericFailure,
format!("Failed to construct updater, {e}"),
)
})
}
}
/// Supported update format
#[napi_derive::napi]
pub enum UpdateFormat {
/// The NSIS installer (.exe).
Nsis,
/// The Microsoft Software Installer (.msi) through WiX Toolset.
Wix,
/// The Linux AppImage package (.AppImage).
AppImage,
/// The macOS application bundle (.app).
App,
}
#[napi_derive::napi]
pub struct Update {
/// Signing public key
pub pubkey: String,
/// Version used to check for update
pub current_version: String,
/// Version announced
pub version: String,
/// Target
pub target: String,
/// Extract path
pub extract_path: String,
/// Download URL announced
pub download_url: String,
/// Signature announced
pub signature: String,
/// Request headers
pub headers: HashMap,
/// Update format
pub format: UpdateFormat,
/// The Windows options for the updater.
pub windows: Option,
/// Update description
pub body: Option,
/// Update publish date
pub date: Option,
/// Request timeout
pub timeout: Option,
}
impl Update {
fn create_update(&self) -> Result {
Ok(cargo_packager_updater::Update {
config: cargo_packager_updater::Config {
pubkey: self.pubkey.clone(),
windows: self.windows.clone().map(Into::into),
..Default::default()
},
body: self.body.clone(),
current_version: self.current_version.clone(),
version: self.version.clone(),
date: None,
target: self.target.clone(),
extract_path: self.extract_path.clone().into(),
download_url: self.download_url.parse().map_err(|e| {
Error::new(
Status::GenericFailure,
format!("Internal error, couldn't convert string to Url struct, {e}"),
)
})?,
signature: self.signature.clone(),
timeout: self.timeout.map(|t| Duration::from_millis(t as u64)),
headers: {
let mut map = HeaderMap::new();
for (key, value) in &self.headers {
map.insert(HeaderName::from_str(key).map_err(|e| {
Error::new(
Status::GenericFailure,
format!("Internal error, couldn't construct header name from str , {e}"),
)
})?, HeaderValue::from_str(value).map_err(|e| {
Error::new(
Status::GenericFailure,
format!("Internal error, couldn't construct header value from str , {e}"),
)
})?);
}
map
},
format: self.format.into(),
})
}
}
type TaskCallbackFunction = Option>;
pub struct DownloadTask {
update: cargo_packager_updater::Update,
on_chunk: TaskCallbackFunction<(u32, Option)>,
on_download_finished: TaskCallbackFunction<()>,
}
impl DownloadTask {
pub fn create(
update: &Update,
on_chunk: TaskCallbackFunction<(u32, Option)>,
on_download_finished: TaskCallbackFunction<()>,
) -> Result {
Ok(Self {
update: update.create_update()?,
on_chunk,
on_download_finished,
})
}
}
impl Task for DownloadTask {
type Output = Vec;
type JsValue = JsArrayBuffer;
fn compute(&mut self) -> Result {
let on_chunk = |chunk_len: usize, content_len: Option| {
if let Some(on_chunk) = &self.on_chunk {
on_chunk.call(
(chunk_len as _, content_len.map(|v| v as _)),
ThreadsafeFunctionCallMode::NonBlocking,
);
}
};
let on_finish = || {
if let Some(on_download_finished) = &self.on_download_finished {
on_download_finished.call((), ThreadsafeFunctionCallMode::NonBlocking);
}
};
self.update
.download_extended(on_chunk, on_finish)
.map_err(|e| Error::new(Status::GenericFailure, e))
}
fn resolve(&mut self, env: Env, output: Self::Output) -> Result {
let mut buffer = env.create_arraybuffer(output.len())?;
unsafe { std::ptr::copy(output.as_ptr(), buffer.as_mut_ptr(), output.len()) };
Ok(buffer.into_raw())
}
}
pub struct InstallTask {
update: cargo_packager_updater::Update,
bytes: Option>,
}
impl InstallTask {
pub fn create(update: &Update, bytes: Vec) -> Result {
Ok(Self {
update: update.create_update()?,
bytes: Some(bytes),
})
}
}
impl Task for InstallTask {
type Output = ();
type JsValue = ();
fn compute(&mut self) -> Result {
self.update
.install(self.bytes.take().unwrap())
.map_err(|e| Error::new(Status::GenericFailure, e))
}
fn resolve(&mut self, _env: Env, _output: Self::Output) -> Result {
Ok(())
}
}
pub struct DownloadAndInstallTask {
download_task: DownloadTask,
}
impl DownloadAndInstallTask {
pub fn new(download_task: DownloadTask) -> Self {
Self { download_task }
}
}
impl Task for DownloadAndInstallTask {
type Output = ();
type JsValue = ();
fn compute(&mut self) -> Result {
let bytes = self.download_task.compute()?;
self.download_task
.update
.install(bytes)
.map_err(|e| Error::new(Status::GenericFailure, e))
}
fn resolve(&mut self, _env: Env, _output: Self::Output) -> Result {
Ok(())
}
}
pub struct CheckUpdateTask {
updater: Updater,
}
impl CheckUpdateTask {
pub fn create(current_version: String, options: Options) -> Result {
let current_version = current_version.parse().map_err(|e| {
Error::new(
Status::InvalidArg,
format!("Failed to parse string as a valid semver, {e}"),
)
})?;
let updater = options.into_updater(current_version)?;
Ok(Self { updater })
}
}
impl Task for CheckUpdateTask {
type Output = Option;
type JsValue = Option;
fn compute(&mut self) -> Result {
self.updater.check().map_err(|e| {
Error::new(
Status::GenericFailure,
format!("Failed to check for update, {e}"),
)
})
}
fn resolve(&mut self, _env: Env, output: Self::Output) -> Result {
Ok(output.map(Into::into))
}
}
#[napi_derive::napi]
impl Update {
#[napi(
ts_args_type = "onChunk?: (chunkLength: number, contentLength: number | null) => void, onDownloadFinished?: () => void",
ts_return_type = "Promise"
)]
pub fn download(
&self,
on_chunk: TaskCallbackFunction<(u32, Option)>,
on_download_finish: TaskCallbackFunction<()>,
) -> Result> {
DownloadTask::create(self, on_chunk, on_download_finish).map(AsyncTask::new)
}
#[napi(ts_return_type = "Promise", ts_args_type = "buffer: ArrayBuffer")]
pub fn install(&self, bytes: JsArrayBuffer) -> Result> {
let bytes = bytes.into_value()?;
let bytes = bytes.as_ref().to_vec();
InstallTask::create(self, bytes).map(AsyncTask::new)
}
#[napi(
ts_args_type = "onChunk?: (chunkLength: number, contentLength?: number) => void, onDownloadFinished?: () => void",
ts_return_type = "Promise"
)]
pub fn download_and_install(
&self,
on_chunk: TaskCallbackFunction<(u32, Option)>,
on_download_finish: TaskCallbackFunction<()>,
) -> Result> {
let download_task = DownloadTask::create(self, on_chunk, on_download_finish)?;
Ok(AsyncTask::new(DownloadAndInstallTask::new(download_task)))
}
}
#[napi_derive::napi(ts_return_type = "Promise")]
pub fn check_update(
current_version: String,
options: Options,
) -> Result> {
Ok(AsyncTask::new(CheckUpdateTask::create(
current_version,
options,
)?))
}
================================================
FILE: crates/config-schema-generator/Cargo.toml
================================================
[package]
name = "cargo-packager-config-schema-generator"
version = "0.0.0"
publish = false
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
[build-dependencies]
cargo-packager = { path = "../packager", features = ["schema"] }
serde_json = { workspace = true }
schemars = { workspace = true }
================================================
FILE: crates/config-schema-generator/build.rs
================================================
// Copyright 2023-2023 CrabNebula Ltd.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::{
error::Error,
fs::File,
io::{BufWriter, Write},
path::PathBuf,
process::Command,
};
pub fn main() -> Result<(), Box> {
let schema = schemars::schema_for!(cargo_packager::Config);
let schema_str = serde_json::to_string_pretty(&schema).unwrap();
let crate_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?);
for path in [
"../packager/schema.json",
"../../bindings/packager/nodejs/schema.json",
] {
let mut schema_file = BufWriter::new(File::create(crate_dir.join(path))?);
write!(schema_file, "{schema_str}")?;
}
let _ = Command::new("node")
.arg("./generate-config-type.js")
.current_dir("../../bindings/packager/nodejs")
.output();
Ok(())
}
================================================
FILE: crates/config-schema-generator/src/main.rs
================================================
// Copyright 2023-2023 CrabNebula Ltd.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
fn main() {}
================================================
FILE: crates/packager/CHANGELOG.md
================================================
# Changelog
## \[0.11.8]
- [`6e6a10c`](https://www.github.com/crabnebula-dev/cargo-packager/commit/6e6a10cc1692973293966034dc4b798e3976d094) ([#321](https://www.github.com/crabnebula-dev/cargo-packager/pull/321)) Allow explicitly specifying the Package name for the .deb bundle.
- [`8488d86`](https://www.github.com/crabnebula-dev/cargo-packager/commit/8488d868935166e873474743c346c2724205d73e) ([#377](https://www.github.com/crabnebula-dev/cargo-packager/pull/377)) Fixed a bug where "binaries" parameter in Cargo.toml would be ignored and all targets would be packaged.
- [`b2b4916`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b2b4916d1b062272fc7e34b5ed55b4fe8c8cd03a) ([#376](https://www.github.com/crabnebula-dev/cargo-packager/pull/376)) Fix bug that prevents reading macos signing certificates from environment variables.
- [`c34de36`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c34de365705db150eb101caa94adf42eff74f71a) ([#365](https://www.github.com/crabnebula-dev/cargo-packager/pull/365)) Change nsi template from using `association.ext` to `association.extensions`, to match struct field in `FileAssociation`.
This allows file associations to be generated in `.nsi` files, and therefore in the final NSIS installer.
## \[0.11.7]
- [`d49b606`](https://www.github.com/crabnebula-dev/cargo-packager/commit/d49b606ba8a612c833233ec8a6061481a2118639) ([#353](https://www.github.com/crabnebula-dev/cargo-packager/pull/353)) Allow using notarization credentials stored on the Keychain by providing the `APPLE_KEYCHAIN_PROFILE` environment variable. See `xcrun notarytool store-credentials` for more information.
- [`b337564`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b337564c0e5a9de966b4124890dddea1e353acb4) ([#362](https://www.github.com/crabnebula-dev/cargo-packager/pull/362)) Updated linuxdeploy's AppImage plugin to not require libfuse on the user's system anymore.
## \[0.11.6]
- [`b81b81f`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b81b81fbd7fd185edfc7652f535d0cfacb786ac9) ([#354](https://www.github.com/crabnebula-dev/cargo-packager/pull/354)) Changed the download URL of a dependency of the AppImage bundler to Tauri's mirror to resolve 404 errors.
- [`735d6c4`](https://www.github.com/crabnebula-dev/cargo-packager/commit/735d6c4745911793cbcf5d929d8da288840bcf24) ([#345](https://www.github.com/crabnebula-dev/cargo-packager/pull/345)) Fixed a typo on the `digest_algorithm` config (was `digest-algorithim`).
- [`5205088`](https://www.github.com/crabnebula-dev/cargo-packager/commit/5205088cd78412fb6cbe5e48a715524fcc5a2ee7) ([#340](https://www.github.com/crabnebula-dev/cargo-packager/pull/340)) Enhance sign error message.
- [`55924d3`](https://www.github.com/crabnebula-dev/cargo-packager/commit/55924d3522c4ab1cfcb4436044e5ebad8adf241c) ([#334](https://www.github.com/crabnebula-dev/cargo-packager/pull/334)) Migrate from `winreg` crate to `windows-registry`. This adds new variants to the packager's `Error` type.
## \[0.11.5]
- [`17194a9`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17194a92aabd59c9e075105072ff939f5d55a107) ([#313](https://www.github.com/crabnebula-dev/cargo-packager/pull/313)) Added `linux > generateDesktopEntry` config to allow disabling generating a .desktop file on Linux bundles (defaults to true).
- [`17c52f0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17c52f057d78340983689af3c00b1f2aeff3c417) ([#289](https://www.github.com/crabnebula-dev/cargo-packager/pull/289)) Added support to embedding additional apps in the macOS app bundle.
- [`17c52f0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/17c52f057d78340983689af3c00b1f2aeff3c417) ([#289](https://www.github.com/crabnebula-dev/cargo-packager/pull/289)) Added support to adding an `embedded.provisionprofile` file to the macOS bundle.
- [`e010574`](https://www.github.com/crabnebula-dev/cargo-packager/commit/e010574c2efa4a1aa6b8e475a62bec46f24f2bc5) ([#318](https://www.github.com/crabnebula-dev/cargo-packager/pull/318)) Add `background-app` config setting for macOS to set `LSUIElement` to `true`.
## \[0.11.4]
- [`29b60a9`](https://www.github.com/crabnebula-dev/cargo-packager/commit/29b60a97ec14ef87aee7537fa7fbd848f853ac32) ([#305](https://www.github.com/crabnebula-dev/cargo-packager/pull/305)) Fix AppImage bundle when main binary name has spaces.
## \[0.11.3]
- [`82e690d`](https://www.github.com/crabnebula-dev/cargo-packager/commit/82e690dfce6109531391e683c8b486d0f39ea335) ([#300](https://www.github.com/crabnebula-dev/cargo-packager/pull/300)) Fix the `Exec` entry on the Linux .desktop file when the binary name contains spaces.
## \[0.11.2]
- [`fea80d5`](https://www.github.com/crabnebula-dev/cargo-packager/commit/fea80d5760882e6cdc21c8ed2f82d323e0598926) ([#264](https://www.github.com/crabnebula-dev/cargo-packager/pull/264)) Fix `pacman` package failing to install when source directory contained whitespace.
## \[0.11.1]
- [`4523722`](https://www.github.com/crabnebula-dev/cargo-packager/commit/4523722d0808faef4a91dbb227badd0354f4c71a) ([#283](https://www.github.com/crabnebula-dev/cargo-packager/pull/283)) Fixes resources paths on NSIS when cross compiling.
## \[0.11.0]
- [`41b05d0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/41b05d08a635d593df4cf4eefbe921b92ace77b7) ([#277](https://www.github.com/crabnebula-dev/cargo-packager/pull/277)) Respect `target-triple` config option when packaging rust binaries.
- [`41b05d0`](https://www.github.com/crabnebula-dev/cargo-packager/commit/41b05d08a635d593df4cf4eefbe921b92ace77b7) ([#277](https://www.github.com/crabnebula-dev/cargo-packager/pull/277)) Add `--target` flag to specify target triple to package.
## \[0.10.3]
- [`3ee764d`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3ee764d9193ae22331aa5894a1821453e9542992) ([#270](https://www.github.com/crabnebula-dev/cargo-packager/pull/270)) Fixes AppImage bundling failing due to missing `/usr/lib64` directory.
- [`ab41e6d`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ab41e6d94af89ec721a0047636597682bd6d90f6) ([#269](https://www.github.com/crabnebula-dev/cargo-packager/pull/269)) Fix using the crate as a library without `cli` feature flag
## \[0.10.2]
- [`f836afa`](https://www.github.com/crabnebula-dev/cargo-packager/commit/f836afa699b2da8a55432ce9de1cbccbffb705fb) ([#267](https://www.github.com/crabnebula-dev/cargo-packager/pull/267)) Include notarytool log output on error message in case notarization fails.
- [`21441f3`](https://www.github.com/crabnebula-dev/cargo-packager/commit/21441f30c5a258b73926ba7a7d8126d6bf47a662) ([#262](https://www.github.com/crabnebula-dev/cargo-packager/pull/262)) Fixed dmg failed to bundle the application when out-dir does not exist.
### Dependencies
- Upgraded to `cargo-packager-utils@0.1.1`
## \[0.10.1]
- [`522f23b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/522f23bd867b037eeec81c43295aafd38ebe60ec) ([#258](https://www.github.com/crabnebula-dev/cargo-packager/pull/258)) Update NSIS installer template URL.
- [`bce99ae`](https://www.github.com/crabnebula-dev/cargo-packager/commit/bce99aecb4160291a026dcd4750055f9079099f8) ([#260](https://www.github.com/crabnebula-dev/cargo-packager/pull/260)) Fix NSIS uninstaller removing the uninstall directory even if it was not empty.
## \[0.10.0]
- [`c6207bb`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c6207bba042a8a0184ddb7e12650a4cd8f415c23) ([#254](https://www.github.com/crabnebula-dev/cargo-packager/pull/254)) Allow Linux dependencies to be specified via a file path instead of just a direct String.
This enables the list of dependencies to by dynamically generated for both Debian `.deb` packages and pacman packages,
which can relieve the app developer from the burden of manually maintaining a fixed list of dependencies.
- [`de4dcca`](https://www.github.com/crabnebula-dev/cargo-packager/commit/de4dccaca4ae758d3adde517cc415a002873e642) ([#256](https://www.github.com/crabnebula-dev/cargo-packager/pull/256)) Automatically add an Exec arg (field code) in the `.desktop` file.
This adds an `{exec_arg}` field to the default `main.desktop` template.
This field is populated with a sane default value, based on the
`deep_link_protocols` or `file_associations` in the `Config` struct.
This allows an installed Debian package to be invoked by other
applications with URLs or files as arguments, as expected.
## \[0.9.1]
- [`44a19ea`](https://www.github.com/crabnebula-dev/cargo-packager/commit/44a19eae1f5f26b1bd10ba84dd6eb3d856609a67) ([#246](https://www.github.com/crabnebula-dev/cargo-packager/pull/246)) On macOS, fix notarization skipping needed environment variables when macos specific config has been specified in the config file.
## \[0.9.0]
- [`ab53974`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ab53974b683ce282202e1a550c551eed951e9ca7) ([#235](https://www.github.com/crabnebula-dev/cargo-packager/pull/235)) Added deep link support.
## \[0.8.1]
- [`1375380`](https://www.github.com/crabnebula-dev/cargo-packager/commit/1375380c7c9d2adf55ab18a2ce23917849967995)([#196](https://www.github.com/crabnebula-dev/cargo-packager/pull/196)) Always show shell commands output for `beforePackageCommand` and `beforeEachPackagingCommand` .
## \[0.8.0]
- [`2164d02`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2164d022f5705e59a189007aec7c99cce98136d8)([#198](https://www.github.com/crabnebula-dev/cargo-packager/pull/198)) Allow packaging the macOS app bundle on Linux and Windows hosts (without codesign support).
- [`3057a4a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3057a4a8440bc4dc897f3038ac821ed181644d43)([#197](https://www.github.com/crabnebula-dev/cargo-packager/pull/197)) Added `Config::binaries_dir` and `--binaries-dir` so you can specify the location of the binaries without modifying the output directory.
- [`4c4d919`](https://www.github.com/crabnebula-dev/cargo-packager/commit/4c4d9194fb0bd2a814f46336747e643b1e208b52)([#195](https://www.github.com/crabnebula-dev/cargo-packager/pull/195)) Error out if we cannot find a configuration file.
- [`b04332c`](https://www.github.com/crabnebula-dev/cargo-packager/commit/b04332c8fc61427dc002a40d9d46bc5f930025c2)([#194](https://www.github.com/crabnebula-dev/cargo-packager/pull/194)) Fixes a crash when packaging `.app` if an empty file is included in the bundle.
- [`3057a4a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3057a4a8440bc4dc897f3038ac821ed181644d43)([#197](https://www.github.com/crabnebula-dev/cargo-packager/pull/197)) Added `--out-dir/-o` flags and removed the positional argument to specify where to ouput packages, use the newly added flags instead.
- [`2164d02`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2164d022f5705e59a189007aec7c99cce98136d8)([#198](https://www.github.com/crabnebula-dev/cargo-packager/pull/198)) Renamed `PackageOuput` to `PackageOutput` and added `PackageOutput::new`.
## \[0.7.0]
- [`cd8898a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/cd8898a93b66a4aae050fa1006089c3c3b5646f9)([#187](https://www.github.com/crabnebula-dev/cargo-packager/pull/187)) Added codesign certificate and notarization credentials configuration options under the `macos` config (for programatic usage, taking precedence over environment variables).
## \[0.6.1]
- [`2f1029b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2f1029b2032ac44fd3f3df34307554feb17043b7)([#185](https://www.github.com/crabnebula-dev/cargo-packager/pull/185)) Fix bundling NSIS on Linux and macOS failing due to the verbose flag.
## \[0.6.0]
- [`57b379a`](https://www.github.com/crabnebula-dev/cargo-packager/commit/57b379ad1d9029e767848fda99d4eb6415afe51a)([#148](https://www.github.com/crabnebula-dev/cargo-packager/pull/148)) Added config option to control excluded libs when packaging AppImage
- [`947e032`](https://www.github.com/crabnebula-dev/cargo-packager/commit/947e0328c89d6f043c3ef1b1db5d2252d4f072a5) Fix CLI failing with `Failed to read cargo metadata: cargo metadata` for non-rust projects.
## \[0.5.0]
- [`9bdb953`](https://www.github.com/crabnebula-dev/cargo-packager/commit/9bdb953f1b48c8d69d86e9e42295cd36453c1648)([#137](https://www.github.com/crabnebula-dev/cargo-packager/pull/137)) Add Arch Linux package manager, `pacman` support for cargo packager.
- [`a29943e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/a29943e8c95d70e8b77c23021ce52f6ee13314c8)([#140](https://www.github.com/crabnebula-dev/cargo-packager/pull/140)) Fix codesigning failing on macOS under certain circumstances when the order in which files were signed was not
deterministic and nesting required signing files nested more deeply first.
### Dependencies
- Upgraded to `cargo-packager-utils@0.1.0`
## \[0.4.5]
- [`f08e4b8`](https://www.github.com/crabnebula-dev/cargo-packager/commit/f08e4b8972b072617fdb78f11e222427e49ebe8e) Fix the signing and notarization process for MacOS bundles
- [`bfa3b00`](https://www.github.com/crabnebula-dev/cargo-packager/commit/bfa3b00cf1087b2ee1e93d9c57b6b577f6294891)([#126](https://www.github.com/crabnebula-dev/cargo-packager/pull/126)) Add `priority` and `section` options in Debian config
## \[0.4.4]
- [`3b3ce76`](https://www.github.com/crabnebula-dev/cargo-packager/commit/3b3ce76da0581cf8d553d6edeb0df24f896c62a6)([#128](https://www.github.com/crabnebula-dev/cargo-packager/pull/128)) Fix file download not working on macOS and Windows (arm).
## \[0.4.3]
- [`2a50c8e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2a50c8ea734193036db0ab461f9005ea904cf4b7)([#124](https://www.github.com/crabnebula-dev/cargo-packager/pull/124)) Fix packaing of external binaries.
## \[0.4.2]
- [`c18bf3e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/c18bf3e77f91c1c4797992b25902753deee5c986)([#117](https://www.github.com/crabnebula-dev/cargo-packager/pull/117)) Fix the `non-standard-file-perm` and `non-standard-dir-perm` issue in Debian packages
## \[0.4.1]
- [`7b083a8`](https://www.github.com/crabnebula-dev/cargo-packager/commit/7b083a8c2ae709659c03a1069d96c3a8391e0674)([#99](https://www.github.com/crabnebula-dev/cargo-packager/pull/99)) Add glob patterns support for the icons option in config.
- [`7e05d24`](https://www.github.com/crabnebula-dev/cargo-packager/commit/7e05d24a697230b1f53ee5ee2f7d217047089d97)([#109](https://www.github.com/crabnebula-dev/cargo-packager/pull/109)) Check if required files/tools for packaging are outdated or mis-hashed and redownload them.
- [`ea6c31b`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ea6c31b1a3b56bb5408a78f1b2d6b2a2d9ce1161)([#114](https://www.github.com/crabnebula-dev/cargo-packager/pull/114)) Fix NSIS uninstaller leaving resources behind and failing to remove the installation directory.
## \[0.4.0]
- [`ecde3fb`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ecde3fb71a8f120e71d4781c11214db750042cc4)([#58](https://www.github.com/crabnebula-dev/cargo-packager/pull/58)) Added `files` configuration under `AppImageConfig` for adding custom files on the AppImage's AppDir.
- [`ecde3fb`](https://www.github.com/crabnebula-dev/cargo-packager/commit/ecde3fb71a8f120e71d4781c11214db750042cc4)([#58](https://www.github.com/crabnebula-dev/cargo-packager/pull/58)) Renamed binary `filename` property to `path`, which supports absolute paths.
- [`f04c17f`](https://www.github.com/crabnebula-dev/cargo-packager/commit/f04c17f72a4af306f47065aff405c4bd0f7b6442)([#87](https://www.github.com/crabnebula-dev/cargo-packager/pull/87)) Add `config.dmg` to configure the DMG on macOS.
- [`21a6c9e`](https://www.github.com/crabnebula-dev/cargo-packager/commit/21a6c9ef4ddbefe9a6e6c5abf287f2ad993edffb)([#84](https://www.github.com/crabnebula-dev/cargo-packager/pull/84)) Mark most of the types as `non_exhaustive` to allow adding more field later on without having to break downstream users use the newly added helper methods on these types to modify the corresponding fields in-place.
- [`db75777`](https://www.github.com/crabnebula-dev/cargo-packager/commit/db75777d2799ca37217d568befad39b9377cfa2a) Add `config.windows.sign_command` which can be used to override signing command on windows and allows usage of tools other than `signtool.exe`.
## \[0.3.0]
- [`65b8c20`](https://www.github.com/crabnebula-dev/cargo-packager/commit/65b8c20a96877038daa4907b80cd96f96e0bfe33)([#54](https://www.github.com/crabnebula-dev/cargo-packager/pull/54)) Code sign binaries and frameworks on macOS.
- [`7ef6b7c`](https://www.github.com/crabnebula-dev/cargo-packager/commit/7ef6b7c0186e79243240cb2d1a1846fda41a1b54)([#50](https://www.github.com/crabnebula-dev/cargo-packager/pull/50)) Set `root` as the owner of control files and package files in `deb` package.
- [`8cc5b05`](https://www.github.com/crabnebula-dev/cargo-packager/commit/8cc5b05eb3eb124b385d406329eee379349faa86)([#53](https://www.github.com/crabnebula-dev/cargo-packager/pull/53)) Fixed an error message that the source path does not exist when packaging .app
- [`274a6be`](https://www.github.com/crabnebula-dev/cargo-packager/commit/274a6bec553f273934347a18e0d6e2e1ec61bbeb)([#49](https://www.github.com/crabnebula-dev/cargo-packager/pull/49)) Read `HTTP_PROXY` env var when downloading resources.
- [`6ed1312`](https://www.github.com/crabnebula-dev/cargo-packager/commit/6ed1312926d70cf449e7beddacb56a17e51a25ac)([#52](https://www.github.com/crabnebula-dev/cargo-packager/pull/52)) Read the `APPLE_TEAM_ID` environment variable for macOS notarization arguments.
- [`65b8c20`](https://www.github.com/crabnebula-dev/cargo-packager/commit/65b8c20a96877038daa4907b80cd96f96e0bfe33)([#54](https://www.github.com/crabnebula-dev/cargo-packager/pull/54)) Remove extended attributes on the macOS app bundle using `xattr -cr $PATH`.
## \[0.2.0]
- [`dde1ab3`](https://www.github.com/crabnebula-dev/cargo-packager/commit/dde1ab34b59ee614fc24e47a5caa8ebc04d92a08)([#43](https://www.github.com/crabnebula-dev/cargo-packager/pull/43)) Remove the deprecated `cargo-packager-config` dependency.
## \[0.1.2]
- [`1809f10`](https://www.github.com/crabnebula-dev/cargo-packager/commit/1809f10b4fd1720fd740196f67c3c980ade0a6bd) Respect the `config.enabled` option.
### Dependencies
- Upgraded to `cargo-packager-config@0.2.0`
## \[0.1.1]
- [`2d8b8d7`](https://www.github.com/crabnebula-dev/cargo-packager/commit/2d8b8d7c1af73202639449a00dbc51bf171effc7) Initial Release
================================================
FILE: crates/packager/Cargo.toml
================================================
[package]
name = "cargo-packager"
version = "0.11.8"
description = "Executable packager and bundler distributed as a CLI and library."
authors = [
"CrabNebula Ltd.",
"Tauri Programme within The Commons Conservancy",
"George Burton ",
]
keywords = ["bundle", "package", "cargo"]
categories = [
"command-line-interface",
"command-line-utilities",
"development-tools::cargo-plugins",
"development-tools::build-utils",
"os",
]
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
[[bin]]
name = "cargo-packager"
# path = "src/bins/cli.rs"
required-features = ["cli"]
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "doc_cfg"]
default-target = "x86_64-unknown-linux-gnu"
targets = [
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
]
[lints.rust]
# cfg(doc_cfg) is used for docs.rs detection. see above
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_cfg)'] }
[features]
default = ["cli", "rustls-tls"]
cli = ["clap", "dep:tracing-subscriber"]
schema = ["schemars", "cargo-packager-utils/schema"]
clap = ["dep:clap", "cargo-packager-utils/clap"]
native-tls = ["ureq/native-tls"]
native-tls-vendored = ["native-tls", "native-tls/vendored"]
rustls-tls = ["ureq/tls"]
[dependencies]
thiserror = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
dunce = { workspace = true }
dirs = { workspace = true }
semver = { workspace = true }
base64 = { workspace = true }
clap = { workspace = true, optional = true, features = ["env"] }
tracing = { workspace = true }
tracing-subscriber = { version = "0.3", optional = true, features = [
"env-filter",
] }
toml = "0.9"
cargo_metadata = "0.18"
ureq = { version = "2.10", default-features = false }
hex = "0.4"
sha1 = "0.10"
sha2 = "0.10"
zip = { version = "0.6", default-features = false, features = ["deflate"] }
handlebars = "6.0"
glob = "0.3"
relative-path = "2"
walkdir = "2"
os_pipe = "1"
minisign = "0.7"
tar = { workspace = true }
flate2 = "1.0"
strsim = "0.11"
schemars = { workspace = true, optional = true }
native-tls = { version = "0.2", optional = true }
cargo-packager-utils = { version = "0.1.1", path = "../utils", features = [
"serde",
] }
icns = { package = "tauri-icns", version = "0.1" }
time = { workspace = true, features = ["formatting"] }
image = { version = "0.25", default-features = false, features = ["rayon", "bmp", "ico", "png", "jpeg"] }
tempfile = "3"
plist = "1"
[target."cfg(target_os = \"windows\")".dependencies]
windows-registry = "0.6"
once_cell = "1"
uuid = { version = "1", features = ["v4", "v5"] }
regex = "1"
[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
version = "0.61"
features = ["Win32_System_SystemInformation", "Win32_System_Diagnostics_Debug"]
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\"))".dependencies]
md5 = "0.8"
heck = "0.5"
ar = "0.9"
================================================
FILE: crates/packager/LICENSE_APACHE-2.0
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
================================================
FILE: crates/packager/LICENSE_MIT
================================================
MIT License
Copyright (c) 2023 - Present CrabNebula Ltd.
Copyright (c) 2019 - 2023 Tauri Programme within The Commons Conservancy
Copyright (c) 2017 - 2019 Cargo-Bundle developers
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.
================================================
FILE: crates/packager/README.md
================================================
# cargo-packager
Executable packager, bundler and updater. A cli tool and library to generate installers or app bundles for your executables.
It also comes with useful addons:
- an [updater](https://docs.rs/cargo-packager-updater)
- a [resource resolver](https://docs.rs/cargo-packager-resource-resolver)
#### Supported packages:
- macOS
- DMG (.dmg)
- Bundle (.app)
- Linux
- Debian package (.deb)
- AppImage (.AppImage)
- Pacman (.tar.gz and PKGBUILD)
- Windows
- NSIS (.exe)
- MSI using WiX Toolset (.msi)
### CLI
The packager is distributed on crates.io as a cargo subcommand, you can install it using cargo:
```sh
cargo install cargo-packager --locked
```
You then need to configure your app so the cli can recognize it. Configuration can be done in `Packager.toml` or `packager.json` in your project or modify Cargo.toml and include this snippet:
```toml
[package.metadata.packager]
before-packaging-command = "cargo build --release"
```
Once, you are done configuring your app, run:
```sh
cargo packager --release
```
### Configuration
By default, the packager reads its configuration from `Packager.toml` or `packager.json` if it exists, and from `package.metadata.packager` table in `Cargo.toml`.
You can also specify a custom configuration using the `-c/--config` cli argument.
For a full list of configuration options, see https://docs.rs/cargo-packager/latest/cargo_packager/config/struct.Config.html.
You could also use the [schema](./schema.json) file from GitHub to validate your configuration or have auto completions in your IDE.
### Building your application before packaging
By default, the packager doesn't build your application, so if your app requires a compilation step, the packager has an option to specify a shell command to be executed before packaing your app, `beforePackagingCommand`.
### Cargo profiles
By default, the packager looks for binaries built using the `debug` profile, if your `beforePackagingCommand` builds your app using `cargo build --release`, you will also need to
run the packager in release mode `cargo packager --release`, otherwise, if you have a custom cargo profile, you will need to specify it using `--profile` cli arg `cargo packager --profile custom-release-profile`.
### Library
This crate is also published to crates.io as a library that you can integrate into your tooling, just make sure to disable the default-feature flags.
```sh
cargo add cargo-packager --no-default-features
```
#### Feature flags
- **`cli`**: Enables the cli specifc features and dependencies. Enabled by default.
- **`tracing`**: Enables `tracing` crate integration.
## Licenses
MIT or MIT/Apache 2.0 where applicable.
================================================
FILE: crates/packager/schema.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config",
"description": "The packaging config.",
"type": "object",
"properties": {
"$schema": {
"description": "The JSON schema for the config.\n\nSetting this field has no effect, this just exists so we can parse the JSON correctly when it has `$schema` field set.",
"type": [
"string",
"null"
]
},
"name": {
"description": "The app name, this is just an identifier that could be used to filter which app to package using `--packages` cli arg when there is multiple apps in the workspace or in the same config.\n\nThis field resembles, the `name` field in `Cargo.toml` or `package.json`\n\nIf `unset`, the CLI will try to auto-detect it from `Cargo.toml` or `package.json` otherwise, it will keep it unset.",
"type": [
"string",
"null"
]
},
"enabled": {
"description": "Whether this config is enabled or not. Defaults to `true`.",
"default": true,
"type": "boolean"
},
"productName": {
"description": "The package's product name, for example \"My Awesome App\".",
"default": "",
"type": "string"
},
"version": {
"description": "The package's version.",
"default": "",
"type": "string"
},
"binaries": {
"description": "The binaries to package.",
"default": [],
"type": "array",
"items": {
"$ref": "#/definitions/Binary"
}
},
"identifier": {
"description": "The application identifier in reverse domain name notation (e.g. `com.packager.example`). This string must be unique across applications since it is used in some system configurations. This string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).",
"type": [
"string",
"null"
],
"pattern": "^[a-zA-Z0-9-\\.]*$"
},
"beforePackagingCommand": {
"description": "The command to run before starting to package an application.\n\nThis runs only once.",
"anyOf": [
{
"$ref": "#/definitions/HookCommand"
},
{
"type": "null"
}
]
},
"beforeEachPackageCommand": {
"description": "The command to run before packaging each format for an application.\n\nThis will run multiple times depending on the formats specifed.",
"anyOf": [
{
"$ref": "#/definitions/HookCommand"
},
{
"type": "null"
}
]
},
"logLevel": {
"description": "The logging level.",
"anyOf": [
{
"$ref": "#/definitions/LogLevel"
},
{
"type": "null"
}
]
},
"formats": {
"description": "The packaging formats to create, if not present, [`PackageFormat::platform_default`] is used.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/PackageFormat"
}
},
"outDir": {
"description": "The directory where the generated packages will be placed.\n\nIf [`Config::binaries_dir`] is not set, this is also where the [`Config::binaries`] exist.",
"default": "",
"type": "string"
},
"binariesDir": {
"description": "The directory where the [`Config::binaries`] exist.\n\nDefaults to [`Config::out_dir`].",
"default": null,
"type": [
"string",
"null"
]
},
"targetTriple": {
"description": "The target triple we are packaging for.\n\nDefaults to the current OS target triple.",
"type": [
"string",
"null"
]
},
"description": {
"description": "The package's description.",
"type": [
"string",
"null"
]
},
"longDescription": {
"description": "The app's long description.",
"type": [
"string",
"null"
]
},
"homepage": {
"description": "The package's homepage.",
"type": [
"string",
"null"
]
},
"authors": {
"description": "The package's authors.",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"publisher": {
"description": "The app's publisher. Defaults to the second element in [`Config::identifier`](Config::identifier) string. Currently maps to the Manufacturer property of the Windows Installer.",
"type": [
"string",
"null"
]
},
"licenseFile": {
"description": "A path to the license file.",
"type": [
"string",
"null"
]
},
"copyright": {
"description": "The app's copyright.",
"type": [
"string",
"null"
]
},
"category": {
"description": "The app's category.",
"anyOf": [
{
"$ref": "#/definitions/AppCategory"
},
{
"type": "null"
}
]
},
"icons": {
"description": "The app's icon list. Supports glob patterns.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fileAssociations": {
"description": "The file associations",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/FileAssociation"
}
},
"deepLinkProtocols": {
"description": "Deep-link protocols.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/DeepLinkProtocol"
}
},
"resources": {
"description": "The app's resources to package. This a list of either a glob pattern, path to a file, path to a directory or an object of `src` and `target` paths. In the case of using an object, the `src` could be either a glob pattern, path to a file, path to a directory, and the `target` is a path inside the final resources folder in the installed package.\n\n## Format-specific:\n\n- **[PackageFormat::Nsis] / [PackageFormat::Wix]**: The resources are placed next to the executable in the root of the packager. - **[PackageFormat::Deb]**: The resources are placed in `usr/lib` of the package.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Resource"
}
},
"externalBinaries": {
"description": "Paths to external binaries to add to the package.\n\nThe path specified should not include `-<.exe>` suffix, it will be auto-added when by the packager when reading these paths, so the actual binary name should have the target platform's target triple appended, as well as `.exe` for Windows.\n\nFor example, if you're packaging an external binary called `sqlite3`, the packager expects a binary named `sqlite3-x86_64-unknown-linux-gnu` on linux, and `sqlite3-x86_64-pc-windows-gnu.exe` on windows.\n\nIf you are building a universal binary for MacOS, the packager expects your external binary to also be universal, and named after the target triple, e.g. `sqlite3-universal-apple-darwin`. See ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"windows": {
"description": "Windows-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/WindowsConfig"
},
{
"type": "null"
}
]
},
"macos": {
"description": "MacOS-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/MacOsConfig"
},
{
"type": "null"
}
]
},
"linux": {
"description": "Linux-specific configuration",
"anyOf": [
{
"$ref": "#/definitions/LinuxConfig"
},
{
"type": "null"
}
]
},
"deb": {
"description": "Debian-specific configuration.",
"anyOf": [
{
"$ref": "#/definitions/DebianConfig"
},
{
"type": "null"
}
]
},
"appimage": {
"description": "AppImage configuration.",
"anyOf": [
{
"$ref": "#/definitions/AppImageConfig"
},
{
"type": "null"
}
]
},
"pacman": {
"description": "Pacman configuration.",
"anyOf": [
{
"$ref": "#/definitions/PacmanConfig"
},
{
"type": "null"
}
]
},
"wix": {
"description": "WiX configuration.",
"anyOf": [
{
"$ref": "#/definitions/WixConfig"
},
{
"type": "null"
}
]
},
"nsis": {
"description": "Nsis configuration.",
"anyOf": [
{
"$ref": "#/definitions/NsisConfig"
},
{
"type": "null"
}
]
},
"dmg": {
"description": "Dmg configuration.",
"anyOf": [
{
"$ref": "#/definitions/DmgConfig"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Binary": {
"description": "A binary to package within the final package.",
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"description": "Path to the binary (without `.exe` on Windows). If it's relative, it will be resolved from [`Config::out_dir`].",
"type": "string"
},
"main": {
"description": "Whether this is the main binary or not",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"HookCommand": {
"description": "Describes a shell command to be executed when a CLI hook is triggered.",
"anyOf": [
{
"description": "Run the given script with the default options.",
"type": "string"
},
{
"description": "Run the given script with custom options.",
"type": "object",
"required": [
"script"
],
"properties": {
"script": {
"description": "The script to execute.",
"type": "string"
},
"dir": {
"description": "The working directory.",
"type": [
"string",
"null"
]
}
}
}
]
},
"LogLevel": {
"description": "An enum representing the available verbosity levels of the logger.",
"oneOf": [
{
"description": "The \"error\" level.\n\nDesignates very serious errors.",
"type": "string",
"enum": [
"error"
]
},
{
"description": "The \"warn\" level.\n\nDesignates hazardous situations.",
"type": "string",
"enum": [
"warn"
]
},
{
"description": "The \"info\" level.\n\nDesignates useful information.",
"type": "string",
"enum": [
"info"
]
},
{
"description": "The \"debug\" level.\n\nDesignates lower priority information.",
"type": "string",
"enum": [
"debug"
]
},
{
"description": "The \"trace\" level.\n\nDesignates very low priority, often extremely verbose, information.",
"type": "string",
"enum": [
"trace"
]
}
]
},
"PackageFormat": {
"description": "Types of supported packages by [`cargo-packager`](https://docs.rs/cargo-packager).",
"oneOf": [
{
"description": "All available package formats for the current platform.\n\nSee [`PackageFormat::platform_all`]",
"type": "string",
"enum": [
"all"
]
},
{
"description": "The default list of package formats for the current platform.\n\nSee [`PackageFormat::platform_default`]",
"type": "string",
"enum": [
"default"
]
},
{
"description": "The macOS application bundle (.app).",
"type": "string",
"enum": [
"app"
]
},
{
"description": "The macOS DMG package (.dmg).",
"type": "string",
"enum": [
"dmg"
]
},
{
"description": "The Microsoft Software Installer (.msi) through WiX Toolset.",
"type": "string",
"enum": [
"wix"
]
},
{
"description": "The NSIS installer (.exe).",
"type": "string",
"enum": [
"nsis"
]
},
{
"description": "The Linux Debian package (.deb).",
"type": "string",
"enum": [
"deb"
]
},
{
"description": "The Linux AppImage package (.AppImage).",
"type": "string",
"enum": [
"appimage"
]
},
{
"description": "The Linux Pacman package (.tar.gz and PKGBUILD)",
"type": "string",
"enum": [
"pacman"
]
}
]
},
"AppCategory": {
"description": "The possible app categories. Corresponds to `LSApplicationCategoryType` on macOS and the GNOME desktop categories on Debian.",
"type": "string",
"enum": [
"Business",
"DeveloperTool",
"Education",
"Entertainment",
"Finance",
"Game",
"ActionGame",
"AdventureGame",
"ArcadeGame",
"BoardGame",
"CardGame",
"CasinoGame",
"DiceGame",
"EducationalGame",
"FamilyGame",
"KidsGame",
"MusicGame",
"PuzzleGame",
"RacingGame",
"RolePlayingGame",
"SimulationGame",
"SportsGame",
"StrategyGame",
"TriviaGame",
"WordGame",
"GraphicsAndDesign",
"HealthcareAndFitness",
"Lifestyle",
"Medical",
"Music",
"News",
"Photography",
"Productivity",
"Reference",
"SocialNetworking",
"Sports",
"Travel",
"Utility",
"Video",
"Weather"
]
},
"FileAssociation": {
"description": "A file association configuration.",
"type": "object",
"required": [
"extensions"
],
"properties": {
"extensions": {
"description": "File extensions to associate with this app. e.g. 'png'",
"type": "array",
"items": {
"type": "string"
}
},
"mimeType": {
"description": "The mime-type e.g. 'image/png' or 'text/plain'. **Linux-only**.",
"type": [
"string",
"null"
]
},
"description": {
"description": "The association description. **Windows-only**. It is displayed on the `Type` column on Windows Explorer.",
"type": [
"string",
"null"
]
},
"name": {
"description": "The name. Maps to `CFBundleTypeName` on macOS. Defaults to the first item in `ext`",
"type": [
"string",
"null"
]
},
"role": {
"description": "The app's role with respect to the type. Maps to `CFBundleTypeRole` on macOS. Defaults to [`BundleTypeRole::Editor`]",
"default": "editor",
"allOf": [
{
"$ref": "#/definitions/BundleTypeRole"
}
]
}
},
"additionalProperties": false
},
"BundleTypeRole": {
"description": "*macOS-only**. Corresponds to CFBundleTypeRole",
"oneOf": [
{
"description": "CFBundleTypeRole.Editor. Files can be read and edited.",
"type": "string",
"enum": [
"editor"
]
},
{
"description": "CFBundleTypeRole.Viewer. Files can be read.",
"type": "string",
"enum": [
"viewer"
]
},
{
"description": "CFBundleTypeRole.Shell",
"type": "string",
"enum": [
"shell"
]
},
{
"description": "CFBundleTypeRole.QLGenerator",
"type": "string",
"enum": [
"qLGenerator"
]
},
{
"description": "CFBundleTypeRole.None",
"type": "string",
"enum": [
"none"
]
}
]
},
"DeepLinkProtocol": {
"description": "Deep link protocol",
"type": "object",
"required": [
"schemes"
],
"properties": {
"schemes": {
"description": "URL schemes to associate with this app without `://`. For example `my-app`",
"type": "array",
"items": {
"type": "string"
}
},
"name": {
"description": "The protocol name. **macOS-only** and maps to `CFBundleTypeName`. Defaults to `.`",
"type": [
"string",
"null"
]
},
"role": {
"description": "The app's role for these schemes. **macOS-only** and maps to `CFBundleTypeRole`.",
"default": "editor",
"allOf": [
{
"$ref": "#/definitions/BundleTypeRole"
}
]
}
},
"additionalProperties": false
},
"Resource": {
"description": "A path to a resource (with optional glob pattern) or an object of `src` and `target` paths.",
"anyOf": [
{
"description": "Supports glob patterns",
"type": "string"
},
{
"description": "An object descriping the src file or directory and its target location in the final package.",
"type": "object",
"required": [
"src",
"target"
],
"properties": {
"src": {
"description": "The src file or directory, supports glob patterns.",
"type": "string"
},
"target": {
"description": "A relative path from the root of the final package.\n\nIf `src` is a glob, this will always be treated as a directory where all globbed files will be placed under.",
"type": "string"
}
}
}
]
},
"WindowsConfig": {
"description": "The Windows configuration.",
"type": "object",
"properties": {
"digestAlgorithm": {
"description": "The file digest algorithm to use for creating file signatures. Required for code signing. SHA-256 is recommended.",
"type": [
"string",
"null"
]
},
"certificateThumbprint": {
"description": "The SHA1 hash of the signing certificate.",
"type": [
"string",
"null"
]
},
"tsp": {
"description": "Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.",
"default": false,
"type": "boolean"
},
"timestampUrl": {
"description": "Server to use during timestamping.",
"type": [
"string",
"null"
]
},
"allowDowngrades": {
"description": "Whether to validate a second app installation, blocking the user from installing an older version if set to `false`.\n\nFor instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.\n\nThe default value of this flag is `true`.",
"default": true,
"type": "boolean"
},
"signCommand": {
"description": "Specify a custom command to sign the binaries. This command needs to have a `%1` in it which is just a placeholder for the binary path, which we will detect and replace before calling the command.\n\nBy Default we use `signtool.exe` which can be found only on Windows so if you are on another platform and want to cross-compile and sign you will need to use another tool like `osslsigncode`.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"MacOsConfig": {
"description": "The macOS configuration.",
"type": "object",
"properties": {
"frameworks": {
"description": "MacOS frameworks that need to be packaged with the app.\n\nEach string can either be the name of a framework (without the `.framework` extension, e.g. `\"SDL2\"`), in which case we will search for that framework in the standard install locations (`~/Library/Frameworks/`, `/Library/Frameworks/`, and `/Network/Library/Frameworks/`), or a path to a specific framework bundle (e.g. `./data/frameworks/SDL2.framework`). Note that this setting just makes cargo-packager copy the specified frameworks into the OS X app bundle (under `Foobar.app/Contents/Frameworks/`); you are still responsible for:\n\n- arranging for the compiled binary to link against those frameworks (e.g. by emitting lines like `cargo:rustc-link-lib=framework=SDL2` from your `build.rs` script)\n\n- embedding the correct rpath in your binary (e.g. by running `install_name_tool -add_rpath \"@executable_path/../Frameworks\" path/to/binary` after compiling)",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"minimumSystemVersion": {
"description": "A version string indicating the minimum MacOS version that the packaged app supports (e.g. `\"10.11\"`). If you are using this config field, you may also want have your `build.rs` script emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.11`.",
"type": [
"string",
"null"
]
},
"exceptionDomain": {
"description": "The exception domain to use on the macOS .app package.\n\nThis allows communication to the outside world e.g. a web server you're shipping.",
"type": [
"string",
"null"
]
},
"signingIdentity": {
"description": "Code signing identity.\n\nThis is typically of the form: `\"Developer ID Application: TEAM_NAME (TEAM_ID)\"`.",
"type": [
"string",
"null"
]
},
"providerShortName": {
"description": "Provider short name for notarization.",
"type": [
"string",
"null"
]
},
"entitlements": {
"description": "Path to the entitlements.plist file.",
"type": [
"string",
"null"
]
},
"infoPlistPath": {
"description": "Path to the Info.plist file for the package.",
"type": [
"string",
"null"
]
},
"embeddedProvisionprofilePath": {
"description": "Path to the embedded.provisionprofile file for the package.",
"type": [
"string",
"null"
]
},
"embeddedApps": {
"description": "Apps that need to be packaged within the app.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"backgroundApp": {
"description": "Whether this is a background application. If true, the app will not appear in the Dock.\n\nSets the `LSUIElement` flag in the macOS plist file.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"LinuxConfig": {
"description": "Linux configuration",
"type": "object",
"properties": {
"generateDesktopEntry": {
"description": "Flag to indicate if desktop entry should be generated.",
"default": true,
"type": "boolean"
}
},
"additionalProperties": false
},
"DebianConfig": {
"description": "The Linux Debian configuration.",
"type": "object",
"properties": {
"depends": {
"description": "The list of Debian dependencies.",
"anyOf": [
{
"$ref": "#/definitions/Dependencies"
},
{
"type": "null"
}
]
},
"desktopTemplate": {
"description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```\n\nThe `{{exec_arg}}` will be set to: * \"%F\", if at least one [Config::file_associations] was specified but no deep link protocols were given. * The \"%F\" arg means that your application can be invoked with multiple file paths. * \"%U\", if at least one [Config::deep_link_protocols] was specified. * The \"%U\" arg means that your application can be invoked with multiple URLs. * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, the \"%U\" arg will be used, causing the file paths to be passed to your app as `file://` URLs. * An empty string \"\" (nothing) if neither are given. * This means that your application will never be invoked with any URLs or file paths.\n\nTo specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: ```text Exec={{exec}} %u ```\n\nSee more here: .",
"type": [
"string",
"null"
]
},
"section": {
"description": "Define the section in Debian Control file. See : ",
"type": [
"string",
"null"
]
},
"priority": {
"description": "Change the priority of the Debian Package. By default, it is set to `optional`. Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`",
"type": [
"string",
"null"
]
},
"files": {
"description": "List of custom files to add to the deb package. Maps a dir/file to a dir/file inside the debian package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"packageName": {
"description": "Name to use for the `Package` field in the Debian Control file. Defaults to [`Config::product_name`] converted to kebab-case.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"Dependencies": {
"description": "A list of dependencies specified as either a list of Strings or as a path to a file that lists the dependencies, one per line.",
"anyOf": [
{
"description": "The list of dependencies provided directly as a vector of Strings.",
"type": "array",
"items": {
"type": "string"
}
},
{
"description": "A path to the file containing the list of dependences, formatted as one per line: ```text libc6 libxcursor1 libdbus-1-3 libasyncns0 ... ```",
"type": "string"
}
]
},
"AppImageConfig": {
"description": "The Linux AppImage configuration.",
"type": "object",
"properties": {
"libs": {
"description": "List of libs that exist in `/usr/lib*` to be include in the final AppImage. The libs will be searched for, using the command `find -L /usr/lib* -name `",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"bins": {
"description": "List of binary paths to include in the final AppImage. For example, if you want `xdg-open`, you'd specify `/usr/bin/xdg-open`",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"files": {
"description": "List of custom files to add to the appimage package. Maps a dir/file to a dir/file inside the appimage package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"linuxdeployPlugins": {
"description": "A map of [`linuxdeploy`](https://github.com/linuxdeploy/linuxdeploy) plugin name and its URL to be downloaded and executed while packaing the appimage. For example, if you want to use the [`gtk`](https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh) plugin, you'd specify `gtk` as the key and its url as the value.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"excludedLibs": {
"description": "List of globs of libraries to exclude from the final AppImage. For example, to exclude libnss3.so, you'd specify `libnss3*`",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"PacmanConfig": {
"description": "The Linux pacman configuration.",
"type": "object",
"properties": {
"files": {
"description": "List of custom files to add to the pacman package. Maps a dir/file to a dir/file inside the pacman package.",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"depends": {
"description": "List of softwares that must be installed for the app to build and run.\n\nSee : ",
"anyOf": [
{
"$ref": "#/definitions/Dependencies"
},
{
"type": "null"
}
]
},
"provides": {
"description": "Additional packages that are provided by this app.\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"conflicts": {
"description": "Packages that conflict or cause problems with the app. All these packages and packages providing this item will need to be removed\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"replaces": {
"description": "Only use if this app replaces some obsolete packages. For example, if you rename any package.\n\nSee : ",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"source": {
"description": "Source of the package to be stored at PKGBUILD. PKGBUILD is a bash script, so version can be referred as ${pkgver}",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"WixConfig": {
"description": "The wix format configuration",
"type": "object",
"properties": {
"languages": {
"description": "The app languages to build. See .",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/WixLanguage"
}
},
"template": {
"description": "By default, the packager uses an internal template. This option allows you to define your own wix file.",
"type": [
"string",
"null"
]
},
"mergeModules": {
"description": "List of merge modules to include in your installer. For example, if you want to include [C++ Redis merge modules]\n\n[C++ Redis merge modules]: https://wixtoolset.org/docs/v3/howtos/redistributables_and_install_checks/install_vcredist/",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fragmentPaths": {
"description": "A list of paths to .wxs files with WiX fragments to use.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"fragments": {
"description": "List of WiX fragments as strings. This is similar to `config.wix.fragments_paths` but is a string so you can define it inline in your config.\n\n```text ```",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"componentGroupRefs": {
"description": "The ComponentGroup element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"componentRefs": {
"description": "The Component element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"customActionRefs": {
"description": "The CustomAction element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"featureGroupRefs": {
"description": "The FeatureGroup element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"featureRefs": {
"description": "The Feature element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"mergeRefs": {
"description": "The Merge element ids you want to reference from the fragments.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"bannerPath": {
"description": "Path to a bitmap file to use as the installation user interface banner. This bitmap will appear at the top of all but the first page of the installer.\n\nThe required dimensions are 493px × 58px.",
"type": [
"string",
"null"
]
},
"dialogImagePath": {
"description": "Path to a bitmap file to use on the installation user interface dialogs. It is used on the welcome and completion dialogs. The required dimensions are 493px × 312px.",
"type": [
"string",
"null"
]
},
"fipsCompliant": {
"description": "Enables FIPS compliant algorithms.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
},
"WixLanguage": {
"description": "A wix language.",
"anyOf": [
{
"description": "Built-in wix language identifier.",
"type": "string"
},
{
"description": "Custom wix language.",
"type": "object",
"required": [
"identifier"
],
"properties": {
"identifier": {
"description": "Idenitifier of this language, for example `en-US`",
"type": "string"
},
"path": {
"description": "The path to a locale (`.wxl`) file. See .",
"type": [
"string",
"null"
]
}
}
}
]
},
"NsisConfig": {
"description": "The NSIS format configuration.",
"type": "object",
"properties": {
"compression": {
"description": "Set the compression algorithm used to compress files in the installer.\n\nSee ",
"anyOf": [
{
"$ref": "#/definitions/NsisCompression"
},
{
"type": "null"
}
]
},
"template": {
"description": "A custom `.nsi` template to use.\n\nSee the default template here ",
"type": [
"string",
"null"
]
},
"preinstallSection": {
"description": "Logic of an NSIS section that will be ran before the install section.\n\nSee the available libraries, dlls and global variables here \n\n### Example ```toml [package.metadata.packager.nsis] preinstall-section = \"\"\" ; Setup custom messages LangString webview2AbortError ${LANG_ENGLISH} \"Failed to install WebView2! The app can't run without it. Try restarting the installer.\" LangString webview2DownloadError ${LANG_ARABIC} \"خطأ: فشل تنزيل WebView2 - $0\"\n\nSection PreInstall ; SectionEnd\n\nSection AnotherPreInstall ; SectionEnd \"\"\" ```",
"type": [
"string",
"null"
]
},
"headerImage": {
"description": "The path to a bitmap file to display on the header of installers pages.\n\nThe recommended dimensions are 150px x 57px.",
"type": [
"string",
"null"
]
},
"sidebarImage": {
"description": "The path to a bitmap file for the Welcome page and the Finish page.\n\nThe recommended dimensions are 164px x 314px.",
"type": [
"string",
"null"
]
},
"installerIcon": {
"description": "The path to an icon file used as the installer icon.",
"type": [
"string",
"null"
]
},
"installMode": {
"description": "Whether the installation will be for all users or just the current user.",
"default": "currentUser",
"allOf": [
{
"$ref": "#/definitions/NSISInstallerMode"
}
]
},
"languages": {
"description": "A list of installer languages. By default the OS language is used. If the OS language is not in the list of languages, the first language will be used. To allow the user to select the language, set `display_language_selector` to `true`.\n\nSee for the complete list of languages.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"customLanguageFiles": {
"description": "An key-value pair where the key is the language and the value is the path to a custom `.nsi` file that holds the translated text for cargo-packager's custom messages.\n\nSee for an example `.nsi` file.\n\n**Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`]languages array,",
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"displayLanguageSelector": {
"description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not. By default the OS language is selected, with a fallback to the first language in the `languages` array.",
"default": false,
"type": "boolean"
},
"appdataPaths": {
"description": "List of paths where your app stores data. This options tells the uninstaller to provide the user with an option (disabled by default) whether they want to rmeove your app data or keep it.\n\nThe path should use a constant from in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your app data in `C:\\\\Users\\\\\\\\AppData\\\\Local\\\\\\\\` you'd need to specify ```toml [package.metadata.packager.nsis] appdata-paths = [\"$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME\"] ```",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"NsisCompression": {
"description": "Compression algorithms used in the NSIS installer.\n\nSee ",
"oneOf": [
{
"description": "ZLIB uses the deflate algorithm, it is a quick and simple method. With the default compression level it uses about 300 KB of memory.",
"type": "string",
"enum": [
"zlib"
]
},
{
"description": "BZIP2 usually gives better compression ratios than ZLIB, but it is a bit slower and uses more memory. With the default compression level it uses about 4 MB of memory.",
"type": "string",
"enum": [
"bzip2"
]
},
{
"description": "LZMA (default) is a new compression method that gives very good compression ratios. The decompression speed is high (10-20 MB/s on a 2 GHz CPU), the compression speed is lower. The memory size that will be used for decompression is the dictionary size plus a few KBs, the default is 8 MB.",
"type": "string",
"enum": [
"lzma"
]
},
{
"description": "Disable compression.",
"type": "string",
"enum": [
"off"
]
}
]
},
"NSISInstallerMode": {
"description": "Install Modes for the NSIS installer.",
"oneOf": [
{
"description": "Default mode for the installer.\n\nInstall the app by default in a directory that doesn't require Administrator access.\n\nInstaller metadata will be saved under the `HKCU` registry path.",
"type": "string",
"enum": [
"currentUser"
]
},
{
"description": "Install the app by default in the `Program Files` folder directory requires Administrator access for the installation.\n\nInstaller metadata will be saved under the `HKLM` registry path.",
"type": "string",
"enum": [
"perMachine"
]
},
{
"description": "Combines both modes and allows the user to choose at install time whether to install for the current user or per machine. Note that this mode will require Administrator access even if the user wants to install it for the current user only.\n\nInstaller metadata will be saved under the `HKLM` or `HKCU` registry path based on the user's choice.",
"type": "string",
"enum": [
"both"
]
}
]
},
"DmgConfig": {
"description": "The Apple Disk Image (.dmg) configuration.",
"type": "object",
"properties": {
"background": {
"description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.",
"type": [
"string",
"null"
]
},
"windowPosition": {
"description": "Position of volume window on screen.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
},
"windowSize": {
"description": "Size of volume window.",
"anyOf": [
{
"$ref": "#/definitions/Size"
},
{
"type": "null"
}
]
},
"appPosition": {
"description": "Position of application file on window.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
},
"appFolderPosition": {
"description": "Position of application folder on window.",
"anyOf": [
{
"$ref": "#/definitions/Position"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"Position": {
"description": "Position coordinates struct.",
"type": "object",
"required": [
"x",
"y"
],
"properties": {
"x": {
"description": "X coordinate.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"y": {
"description": "Y coordinate.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"Size": {
"description": "Size struct.",
"type": "object",
"required": [
"height",
"width"
],
"properties": {
"width": {
"description": "Width.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"height": {
"description": "Height.",
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
}
================================================
FILE: crates/packager/src/bin/cargo-packager.rs
================================================
// Copyright 2023-2023 CrabNebula Ltd.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::{env::args_os, ffi::OsStr, path::Path, process::exit};
fn main() {
let mut args = args_os().peekable();
let bin_name = match args
.next()
.as_deref()
.map(Path::new)
.and_then(Path::file_stem)
.and_then(OsStr::to_str)
{
Some("cargo-packager") => {
if args.peek().and_then(|s| s.to_str()) == Some("packager") {
// remove the extra cargo subcommand
args.next();
Some("cargo packager".into())
} else {
Some("cargo-packager".into())
}
}
Some(stem) => Some(stem.to_string()),
None => {
eprintln!("cargo-packager wrapper unable to read first argument");
exit(1);
}
};
cargo_packager::cli::run(args, bin_name)
}
================================================
FILE: crates/packager/src/cli/config.rs
================================================
// Copyright 2023-2023 CrabNebula Ltd.
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::{
fmt::Debug,
fs,
path::{Path, PathBuf},
};
use super::{Error, Result};
use crate::{config::Binary, Config};
impl Config {
pub(crate) fn name(&self) -> &str {
self.name.as_deref().unwrap_or_default()
}
/// Whether this config should be packaged or skipped
pub(crate) fn should_pacakge(&self, cli: &super::Cli) -> bool {
// Should be packaged when it is enabled and this package was in the explicit packages list specified on the CLI,
// or the packages list specified on the CLI is empty which means build all
self.enabled
&& cli
.packages
.as_ref()
.map(|packages| packages.iter().any(|p| p == self.name()))
.unwrap_or(true)
}
}
fn find_nearset_pkg_name(path: &Path) -> Result