feat: modularize justfile and fix collection/packaging scripts
- Modularize justfile system with dedicated modules: * alias.just: Command aliases (h, b, c, s) * build.just: Build and cross-compilation commands * distro.just: Collection and packaging commands * help.just: Comprehensive help system with areas * qa.just: Testing and quality assurance * tools.just: Development tools and utilities * upstream.just: Repository tracking and sync - Fix platform detection in collect script: * Use actual platform names (darwin-arm64) instead of generic "host" * Support both "host" argument and auto-detection * Filter out .d dependency files from distribution - Fix packaging script issues: * Correct uname command syntax (^uname -m) * Fix string interpolation and environment parsing * Include plugin binaries in archives (was only packaging metadata) * Use proper path join instead of string interpolation * Add --force flag to avoid interactive prompts - Fix justfile absolute paths: * Replace relative paths with {{justfile_directory()}} function * Enable commands to work from any directory 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5949bfade6
commit
c5b510b939
307
.github/workflows/build.yml
vendored
Normal file
307
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
name: Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
targets:
|
||||||
|
description: 'Comma-separated list of targets to build (e.g., linux-amd64,darwin-arm64)'
|
||||||
|
required: false
|
||||||
|
default: 'host'
|
||||||
|
test:
|
||||||
|
description: 'Run tests'
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Job to validate nushell version consistency
|
||||||
|
validate:
|
||||||
|
name: Validate Setup
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
nushell-version: ${{ steps.version.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: '0.107.1'
|
||||||
|
|
||||||
|
- name: Validate nushell version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
echo "Validating nushell version consistency..."
|
||||||
|
nu scripts/check_version.nu --quiet || {
|
||||||
|
echo "Version mismatch detected, attempting fix..."
|
||||||
|
nu scripts/check_version.nu --fix
|
||||||
|
}
|
||||||
|
echo "version=0.107.1" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Check repository structure
|
||||||
|
run: |
|
||||||
|
echo "Checking repository structure..."
|
||||||
|
ls -la
|
||||||
|
echo "Plugin directories:"
|
||||||
|
ls -d nu_plugin_* || echo "No plugin directories found"
|
||||||
|
echo "Configuration files:"
|
||||||
|
ls -la etc/ || echo "No etc directory found"
|
||||||
|
|
||||||
|
# Build matrix for different platforms
|
||||||
|
build:
|
||||||
|
name: Build (${{ matrix.target }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: validate
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# Linux builds
|
||||||
|
- target: linux-amd64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: x86_64-unknown-linux-gnu
|
||||||
|
cross-compile: false
|
||||||
|
- target: linux-arm64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: aarch64-unknown-linux-gnu
|
||||||
|
cross-compile: true
|
||||||
|
|
||||||
|
# macOS builds
|
||||||
|
- target: darwin-amd64
|
||||||
|
os: macos-13 # Intel macOS
|
||||||
|
rust-target: x86_64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
- target: darwin-arm64
|
||||||
|
os: macos-latest # Apple Silicon
|
||||||
|
rust-target: aarch64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
|
||||||
|
# Windows builds
|
||||||
|
- target: windows-amd64
|
||||||
|
os: windows-latest
|
||||||
|
rust-target: x86_64-pc-windows-msvc
|
||||||
|
cross-compile: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.rust-target }}
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Set up cross-compilation (Linux ARM64)
|
||||||
|
if: matrix.cross-compile && matrix.target == 'linux-arm64'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||||
|
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cache Cargo dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
target
|
||||||
|
key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-${{ matrix.target }}-cargo-
|
||||||
|
${{ runner.os }}-cargo-
|
||||||
|
|
||||||
|
- name: Check code formatting
|
||||||
|
run: |
|
||||||
|
echo "Checking code formatting..."
|
||||||
|
nu scripts/run.sh format_check.nu || {
|
||||||
|
echo "Code formatting check failed. Run 'just fmt' to fix."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Run Clippy linting
|
||||||
|
run: |
|
||||||
|
echo "Running Clippy linting..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Linting $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo clippy --target ${{ matrix.rust-target }} -- -D warnings
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Build plugins
|
||||||
|
run: |
|
||||||
|
echo "Building plugins for ${{ matrix.target }}..."
|
||||||
|
if [ "${{ matrix.cross-compile }}" = "true" ]; then
|
||||||
|
nu scripts/build_cross.nu --targets ${{ matrix.target }} --verbose
|
||||||
|
else
|
||||||
|
nu scripts/build_all.nu --target ${{ matrix.rust-target }} --verbose
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
if: github.event.inputs.test != 'false' && !matrix.cross-compile
|
||||||
|
run: |
|
||||||
|
echo "Running tests..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Testing $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo test --target ${{ matrix.rust-target }}
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Collect build artifacts
|
||||||
|
run: |
|
||||||
|
echo "Collecting build artifacts..."
|
||||||
|
nu scripts/collect_install.nu --platform ${{ matrix.target }} --force
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: plugins-${{ matrix.target }}
|
||||||
|
path: |
|
||||||
|
distribution/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- name: Upload build logs
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-logs-${{ matrix.target }}
|
||||||
|
path: |
|
||||||
|
target/*/build/*/out
|
||||||
|
target/*/build/*/stderr
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
# Security audit
|
||||||
|
audit:
|
||||||
|
name: Security Audit
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: validate
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Install cargo-audit
|
||||||
|
run: cargo install cargo-audit
|
||||||
|
|
||||||
|
- name: Run security audit
|
||||||
|
run: |
|
||||||
|
echo "Running security audit..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Auditing $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo audit
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Collect and package results
|
||||||
|
package:
|
||||||
|
name: Package Results
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [validate, build]
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: artifacts/
|
||||||
|
|
||||||
|
- name: Organize artifacts
|
||||||
|
run: |
|
||||||
|
echo "Organizing build artifacts..."
|
||||||
|
mkdir -p distribution
|
||||||
|
for artifact in artifacts/plugins-*; do
|
||||||
|
if [ -d "$artifact" ]; then
|
||||||
|
target=$(basename "$artifact" | sed 's/plugins-//')
|
||||||
|
echo "Processing $target..."
|
||||||
|
cp -r "$artifact"/* distribution/
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Create packages
|
||||||
|
run: |
|
||||||
|
echo "Creating distribution packages..."
|
||||||
|
nu scripts/pack_dist.nu --all-platforms --force --checksums
|
||||||
|
|
||||||
|
- name: Upload packages
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: distribution-packages
|
||||||
|
path: |
|
||||||
|
bin_archives/
|
||||||
|
retention-days: 90
|
||||||
|
|
||||||
|
# Quality gate
|
||||||
|
quality-gate:
|
||||||
|
name: Quality Gate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build, audit]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Check build results
|
||||||
|
run: |
|
||||||
|
echo "Build results:"
|
||||||
|
echo "Build status: ${{ needs.build.result }}"
|
||||||
|
echo "Audit status: ${{ needs.audit.result }}"
|
||||||
|
|
||||||
|
if [ "${{ needs.build.result }}" != "success" ]; then
|
||||||
|
echo "❌ Build failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${{ needs.audit.result }}" != "success" ]; then
|
||||||
|
echo "⚠️ Security audit failed"
|
||||||
|
# Don't fail the build for audit issues, but warn
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Quality gate passed"
|
||||||
|
|
||||||
|
- name: Report status
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
if [ "${{ job.status }}" = "success" ]; then
|
||||||
|
echo "🎉 All checks passed!"
|
||||||
|
else
|
||||||
|
echo "❌ Some checks failed"
|
||||||
|
fi
|
429
.github/workflows/nightly.yml
vendored
Normal file
429
.github/workflows/nightly.yml
vendored
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
name: Nightly Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Run every day at 2 AM UTC
|
||||||
|
- cron: '0 2 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
targets:
|
||||||
|
description: 'Comma-separated list of targets to build (leave empty for all)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
skip_tests:
|
||||||
|
description: 'Skip running tests'
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
create_prerelease:
|
||||||
|
description: 'Create pre-release with nightly builds'
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Check if we should skip nightly (no changes since last nightly)
|
||||||
|
check-changes:
|
||||||
|
name: Check for Changes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
should_build: ${{ steps.changes.outputs.should_build }}
|
||||||
|
commit_sha: ${{ steps.changes.outputs.commit_sha }}
|
||||||
|
commit_message: ${{ steps.changes.outputs.commit_message }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check for changes since last nightly
|
||||||
|
id: changes
|
||||||
|
run: |
|
||||||
|
# Get the last nightly tag or fall back to a week ago
|
||||||
|
LAST_NIGHTLY=$(git tag -l "nightly-*" | sort -V | tail -1)
|
||||||
|
|
||||||
|
if [ -z "$LAST_NIGHTLY" ]; then
|
||||||
|
# No previous nightly, check for changes in the last week
|
||||||
|
SINCE="$(date -d '7 days ago' '+%Y-%m-%d')"
|
||||||
|
echo "No previous nightly found, checking changes since $SINCE"
|
||||||
|
CHANGES=$(git log --since="$SINCE" --oneline | wc -l)
|
||||||
|
else
|
||||||
|
echo "Last nightly: $LAST_NIGHTLY"
|
||||||
|
CHANGES=$(git rev-list --count "$LAST_NIGHTLY"..HEAD)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Changes found: $CHANGES"
|
||||||
|
|
||||||
|
if [ "$CHANGES" -gt 0 ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
echo "should_build=true" >> $GITHUB_OUTPUT
|
||||||
|
echo "commit_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "commit_message=$(git log -1 --pretty=format:'%s')" >> $GITHUB_OUTPUT
|
||||||
|
echo "✅ Changes detected, will build nightly"
|
||||||
|
else
|
||||||
|
echo "should_build=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "❌ No changes since last nightly, skipping build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate setup
|
||||||
|
validate:
|
||||||
|
name: Validate Setup
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: check-changes
|
||||||
|
if: needs.check-changes.outputs.should_build == 'true'
|
||||||
|
outputs:
|
||||||
|
nushell-version: ${{ steps.version.outputs.version }}
|
||||||
|
nightly-tag: ${{ steps.tag.outputs.tag }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: '0.107.1'
|
||||||
|
|
||||||
|
- name: Generate nightly tag
|
||||||
|
id: tag
|
||||||
|
run: |
|
||||||
|
NIGHTLY_TAG="nightly-$(date '+%Y%m%d')"
|
||||||
|
echo "tag=$NIGHTLY_TAG" >> $GITHUB_OUTPUT
|
||||||
|
echo "Nightly tag: $NIGHTLY_TAG"
|
||||||
|
|
||||||
|
- name: Validate nushell version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
echo "Validating nushell version consistency..."
|
||||||
|
nu scripts/check_version.nu --quiet || {
|
||||||
|
echo "Version mismatch detected, attempting fix..."
|
||||||
|
nu scripts/check_version.nu --fix
|
||||||
|
}
|
||||||
|
echo "version=0.107.1" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Check upstream changes
|
||||||
|
run: |
|
||||||
|
echo "Checking for upstream changes..."
|
||||||
|
nu scripts/check_upstream_changes.nu || {
|
||||||
|
echo "⚠️ Upstream changes detected but not failing nightly build"
|
||||||
|
echo "Consider reviewing and merging upstream changes"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build matrix for nightly builds
|
||||||
|
build-nightly:
|
||||||
|
name: Nightly Build (${{ matrix.target }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: [check-changes, validate]
|
||||||
|
if: needs.check-changes.outputs.should_build == 'true'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# Core platforms for nightly
|
||||||
|
- target: linux-amd64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: x86_64-unknown-linux-gnu
|
||||||
|
cross-compile: false
|
||||||
|
priority: high
|
||||||
|
- target: darwin-arm64
|
||||||
|
os: macos-latest
|
||||||
|
rust-target: aarch64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
priority: high
|
||||||
|
- target: windows-amd64
|
||||||
|
os: windows-latest
|
||||||
|
rust-target: x86_64-pc-windows-msvc
|
||||||
|
cross-compile: false
|
||||||
|
priority: medium
|
||||||
|
|
||||||
|
# Additional targets (can be disabled for faster nightly)
|
||||||
|
- target: linux-arm64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: aarch64-unknown-linux-gnu
|
||||||
|
cross-compile: true
|
||||||
|
priority: low
|
||||||
|
- target: darwin-amd64
|
||||||
|
os: macos-13
|
||||||
|
rust-target: x86_64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
priority: low
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.rust-target }}
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Set up cross-compilation (Linux ARM64)
|
||||||
|
if: matrix.cross-compile && matrix.target == 'linux-arm64'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||||
|
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cache Cargo dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
target
|
||||||
|
key: nightly-${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
nightly-${{ runner.os }}-${{ matrix.target }}-cargo-
|
||||||
|
${{ runner.os }}-${{ matrix.target }}-cargo-
|
||||||
|
|
||||||
|
- name: Build nightly binaries
|
||||||
|
run: |
|
||||||
|
echo "Building nightly binaries for ${{ matrix.target }}..."
|
||||||
|
if [ "${{ matrix.cross-compile }}" = "true" ]; then
|
||||||
|
nu scripts/build_cross.nu --targets ${{ matrix.target }}
|
||||||
|
else
|
||||||
|
nu scripts/build_all.nu --target ${{ matrix.rust-target }}
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
if: github.event.inputs.skip_tests != 'true' && !matrix.cross-compile
|
||||||
|
run: |
|
||||||
|
echo "Running tests for ${{ matrix.target }}..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Testing $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo test --target ${{ matrix.rust-target }} || {
|
||||||
|
echo "⚠️ Tests failed for $plugin but continuing nightly build"
|
||||||
|
}
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Collect nightly artifacts
|
||||||
|
run: |
|
||||||
|
echo "Collecting nightly artifacts..."
|
||||||
|
nu scripts/collect_install.nu --platform ${{ matrix.target }} --force
|
||||||
|
|
||||||
|
- name: Package nightly build
|
||||||
|
run: |
|
||||||
|
echo "Creating nightly package..."
|
||||||
|
nu scripts/pack_dist.nu --platform ${{ matrix.target }} --force
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Upload nightly artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nightly-${{ matrix.target }}
|
||||||
|
path: |
|
||||||
|
bin_archives/*${{ matrix.target }}*
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
# Create nightly pre-release
|
||||||
|
create-nightly-release:
|
||||||
|
name: Create Nightly Pre-release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [check-changes, validate, build-nightly]
|
||||||
|
if: needs.check-changes.outputs.should_build == 'true' && (github.event.inputs.create_prerelease == 'true' || github.event_name == 'schedule')
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Download nightly artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: nightly-artifacts/
|
||||||
|
|
||||||
|
- name: Organize nightly assets
|
||||||
|
run: |
|
||||||
|
echo "Organizing nightly assets..."
|
||||||
|
mkdir -p nightly-assets
|
||||||
|
|
||||||
|
# Copy all archives
|
||||||
|
find nightly-artifacts/ -name "*.tar.gz" -o -name "*.zip" | while read file; do
|
||||||
|
# Rename to include nightly tag
|
||||||
|
basename=$(basename "$file")
|
||||||
|
nightly_name=$(echo "$basename" | sed "s/nushell-plugins/${{ needs.validate.outputs.nightly-tag }}-nushell-plugins/")
|
||||||
|
cp "$file" "nightly-assets/$nightly_name"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Nightly assets:"
|
||||||
|
ls -la nightly-assets/
|
||||||
|
|
||||||
|
- name: Generate checksums for nightly
|
||||||
|
run: |
|
||||||
|
cd nightly-assets
|
||||||
|
sha256sum * > checksums.txt
|
||||||
|
echo "Generated checksums:"
|
||||||
|
cat checksums.txt
|
||||||
|
|
||||||
|
- name: Delete previous nightly release
|
||||||
|
run: |
|
||||||
|
# Delete previous nightly release if it exists
|
||||||
|
if gh release view "${{ needs.validate.outputs.nightly-tag }}" >/dev/null 2>&1; then
|
||||||
|
echo "Deleting previous nightly release..."
|
||||||
|
gh release delete "${{ needs.validate.outputs.nightly-tag }}" --yes
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Create nightly pre-release
|
||||||
|
run: |
|
||||||
|
cat > nightly_notes.md << 'EOF'
|
||||||
|
## Nightly Build - ${{ needs.validate.outputs.nightly-tag }}
|
||||||
|
|
||||||
|
**⚠️ This is an automated nightly build and may be unstable.**
|
||||||
|
|
||||||
|
### Build Information
|
||||||
|
- **Commit**: ${{ needs.check-changes.outputs.commit_sha }}
|
||||||
|
- **Commit Message**: ${{ needs.check-changes.outputs.commit_message }}
|
||||||
|
- **Build Date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
|
||||||
|
- **Nushell Version**: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```bash
|
||||||
|
# Quick install (replace PLATFORM with your platform)
|
||||||
|
curl -L https://github.com/${{ github.repository }}/releases/download/${{ needs.validate.outputs.nightly-tag }}/PLATFORM-${{ needs.validate.outputs.nightly-tag }}-nushell-plugins.tar.gz | tar -xz
|
||||||
|
cd PLATFORM-${{ needs.validate.outputs.nightly-tag }}-nushell-plugins
|
||||||
|
nu install_nu_plugins.nu
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available Platforms
|
||||||
|
$(ls nightly-assets/*.tar.gz nightly-assets/*.zip 2>/dev/null | sed 's/nightly-assets\///g' | sed 's/^/- /' || echo "- Check release assets below")
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- Nightly builds are automatically created when changes are detected
|
||||||
|
- Previous nightly builds are automatically cleaned up
|
||||||
|
- For stable releases, see [Releases](https://github.com/${{ github.repository }}/releases)
|
||||||
|
- Report issues with nightly builds in [Issues](https://github.com/${{ github.repository }}/issues)
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
All nightly assets include SHA256 checksums:
|
||||||
|
```bash
|
||||||
|
sha256sum -c checksums.txt
|
||||||
|
```
|
||||||
|
EOF
|
||||||
|
|
||||||
|
gh release create "${{ needs.validate.outputs.nightly-tag }}" \
|
||||||
|
--title "Nightly Build - ${{ needs.validate.outputs.nightly-tag }}" \
|
||||||
|
--notes-file nightly_notes.md \
|
||||||
|
--prerelease \
|
||||||
|
nightly-assets/*
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Clean up old nightly releases
|
||||||
|
run: |
|
||||||
|
echo "Cleaning up old nightly releases (keeping last 7)..."
|
||||||
|
gh release list --limit 50 | grep "nightly-" | tail -n +8 | while read line; do
|
||||||
|
tag=$(echo "$line" | awk '{print $1}')
|
||||||
|
echo "Deleting old nightly release: $tag"
|
||||||
|
gh release delete "$tag" --yes || echo "Failed to delete $tag"
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Notification and status
|
||||||
|
notify:
|
||||||
|
name: Notify Build Status
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [check-changes, build-nightly]
|
||||||
|
if: always() && needs.check-changes.outputs.should_build == 'true'
|
||||||
|
steps:
|
||||||
|
- name: Report nightly build status
|
||||||
|
run: |
|
||||||
|
echo "Nightly Build Status Report"
|
||||||
|
echo "========================="
|
||||||
|
echo "Commit: ${{ needs.check-changes.outputs.commit_sha }}"
|
||||||
|
echo "Message: ${{ needs.check-changes.outputs.commit_message }}"
|
||||||
|
echo "Build Status: ${{ needs.build-nightly.result }}"
|
||||||
|
|
||||||
|
if [ "${{ needs.build-nightly.result }}" = "success" ]; then
|
||||||
|
echo "✅ Nightly build completed successfully"
|
||||||
|
elif [ "${{ needs.build-nightly.result }}" = "failure" ]; then
|
||||||
|
echo "❌ Nightly build failed"
|
||||||
|
echo "Check the build logs for details"
|
||||||
|
else
|
||||||
|
echo "⚠️ Nightly build status: ${{ needs.build-nightly.result }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Could add webhook notifications here for Discord/Slack etc.
|
||||||
|
|
||||||
|
# Maintenance tasks during nightly
|
||||||
|
maintenance:
|
||||||
|
name: Nightly Maintenance
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [check-changes, validate]
|
||||||
|
if: needs.check-changes.outputs.should_build == 'true'
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Check for dependency updates
|
||||||
|
run: |
|
||||||
|
echo "Checking for outdated dependencies..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Checking $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo outdated || echo "⚠️ cargo-outdated not available"
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Generate dependency report
|
||||||
|
run: |
|
||||||
|
echo "Generating dependency report..."
|
||||||
|
echo "# Dependency Status Report - $(date)" > dependency_report.md
|
||||||
|
echo "" >> dependency_report.md
|
||||||
|
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "## $plugin" >> dependency_report.md
|
||||||
|
echo "" >> dependency_report.md
|
||||||
|
cd "$plugin"
|
||||||
|
echo "\`\`\`" >> ../dependency_report.md
|
||||||
|
cargo tree --depth 1 >> ../dependency_report.md || echo "Failed to generate tree" >> ../dependency_report.md
|
||||||
|
echo "\`\`\`" >> ../dependency_report.md
|
||||||
|
echo "" >> ../dependency_report.md
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload dependency report
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nightly-dependency-report
|
||||||
|
path: dependency_report.md
|
||||||
|
continue-on-error: true
|
365
.github/workflows/release.yml
vendored
Normal file
365
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version to release (e.g., v1.2.3)'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
prerelease:
|
||||||
|
description: 'Mark as pre-release'
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
draft:
|
||||||
|
description: 'Create as draft release'
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Validate release version and setup
|
||||||
|
validate-release:
|
||||||
|
name: Validate Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.version.outputs.version }}
|
||||||
|
tag: ${{ steps.version.outputs.tag }}
|
||||||
|
nushell-version: ${{ steps.nushell.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Determine version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
VERSION="${{ github.event.inputs.version }}"
|
||||||
|
else
|
||||||
|
VERSION="${{ github.ref_name }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
|
||||||
|
echo "tag=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "Release version: ${VERSION}"
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: '0.107.1'
|
||||||
|
|
||||||
|
- name: Validate nushell version
|
||||||
|
id: nushell
|
||||||
|
run: |
|
||||||
|
echo "Validating nushell version consistency..."
|
||||||
|
nu scripts/check_version.nu --quiet || {
|
||||||
|
echo "Version mismatch detected, attempting fix..."
|
||||||
|
nu scripts/check_version.nu --fix
|
||||||
|
}
|
||||||
|
echo "version=0.107.1" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Check for existing release
|
||||||
|
run: |
|
||||||
|
if gh release view "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
|
||||||
|
echo "❌ Release ${{ steps.version.outputs.tag }} already exists"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ Release tag is available"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Validate changelog
|
||||||
|
run: |
|
||||||
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
|
if grep -q "${{ steps.version.outputs.version }}" CHANGELOG.md; then
|
||||||
|
echo "✅ Changelog entry found for version ${{ steps.version.outputs.version }}"
|
||||||
|
else
|
||||||
|
echo "⚠️ No changelog entry found for version ${{ steps.version.outputs.version }}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ No CHANGELOG.md file found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cross-platform release builds
|
||||||
|
build-release:
|
||||||
|
name: Build Release (${{ matrix.target }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: validate-release
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# Linux builds
|
||||||
|
- target: linux-amd64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: x86_64-unknown-linux-gnu
|
||||||
|
cross-compile: false
|
||||||
|
- target: linux-arm64
|
||||||
|
os: ubuntu-latest
|
||||||
|
rust-target: aarch64-unknown-linux-gnu
|
||||||
|
cross-compile: true
|
||||||
|
|
||||||
|
# macOS builds
|
||||||
|
- target: darwin-amd64
|
||||||
|
os: macos-13
|
||||||
|
rust-target: x86_64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
- target: darwin-arm64
|
||||||
|
os: macos-latest
|
||||||
|
rust-target: aarch64-apple-darwin
|
||||||
|
cross-compile: false
|
||||||
|
|
||||||
|
# Windows builds
|
||||||
|
- target: windows-amd64
|
||||||
|
os: windows-latest
|
||||||
|
rust-target: x86_64-pc-windows-msvc
|
||||||
|
cross-compile: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.rust-target }}
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate-release.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Set up cross-compilation (Linux ARM64)
|
||||||
|
if: matrix.cross-compile && matrix.target == 'linux-arm64'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||||||
|
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Cache Cargo dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
target
|
||||||
|
key: release-${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
release-${{ runner.os }}-${{ matrix.target }}-cargo-
|
||||||
|
${{ runner.os }}-${{ matrix.target }}-cargo-
|
||||||
|
|
||||||
|
- name: Build release binaries
|
||||||
|
run: |
|
||||||
|
echo "Building release binaries for ${{ matrix.target }}..."
|
||||||
|
if [ "${{ matrix.cross-compile }}" = "true" ]; then
|
||||||
|
nu scripts/build_cross.nu --targets ${{ matrix.target }} --verbose
|
||||||
|
else
|
||||||
|
nu scripts/build_all.nu --target ${{ matrix.rust-target }} --verbose
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run tests (native only)
|
||||||
|
if: "!matrix.cross-compile"
|
||||||
|
run: |
|
||||||
|
echo "Running tests for ${{ matrix.target }}..."
|
||||||
|
for plugin in nu_plugin_*; do
|
||||||
|
if [ -d "$plugin" ]; then
|
||||||
|
echo "Testing $plugin..."
|
||||||
|
cd "$plugin"
|
||||||
|
cargo test --target ${{ matrix.rust-target }} --release
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Collect and package release artifacts
|
||||||
|
run: |
|
||||||
|
echo "Collecting release artifacts for ${{ matrix.target }}..."
|
||||||
|
nu scripts/collect_install.nu --platform ${{ matrix.target }} --force
|
||||||
|
|
||||||
|
echo "Creating release package..."
|
||||||
|
nu scripts/pack_dist.nu --platform ${{ matrix.target }} --force --checksums
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Upload release artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-${{ matrix.target }}
|
||||||
|
path: |
|
||||||
|
bin_archives/*${{ matrix.target }}*
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
# Create GitHub release
|
||||||
|
create-release:
|
||||||
|
name: Create GitHub Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [validate-release, build-release]
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
outputs:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
release_id: ${{ steps.create_release.outputs.id }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install Nushell
|
||||||
|
uses: hustcer/setup-nu@v3
|
||||||
|
with:
|
||||||
|
version: ${{ needs.validate-release.outputs.nushell-version }}
|
||||||
|
|
||||||
|
- name: Download all release artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: release-artifacts/
|
||||||
|
|
||||||
|
- name: Organize release assets
|
||||||
|
run: |
|
||||||
|
echo "Organizing release assets..."
|
||||||
|
mkdir -p release-assets
|
||||||
|
|
||||||
|
# Copy all archives to release assets
|
||||||
|
find release-artifacts/ -name "*.tar.gz" -o -name "*.zip" | while read file; do
|
||||||
|
cp "$file" release-assets/
|
||||||
|
done
|
||||||
|
|
||||||
|
# Copy checksums
|
||||||
|
find release-artifacts/ -name "checksums.txt" | head -1 | while read file; do
|
||||||
|
cp "$file" release-assets/checksums.txt
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Release assets:"
|
||||||
|
ls -la release-assets/
|
||||||
|
|
||||||
|
- name: Generate release notes
|
||||||
|
id: release_notes
|
||||||
|
run: |
|
||||||
|
echo "Generating release notes..."
|
||||||
|
|
||||||
|
# Extract changelog for this version if available
|
||||||
|
RELEASE_NOTES="## Nushell Plugins ${{ needs.validate-release.outputs.version }}
|
||||||
|
|
||||||
|
### Changes in this Release
|
||||||
|
"
|
||||||
|
|
||||||
|
if [ -f "CHANGELOG.md" ]; then
|
||||||
|
# Try to extract changelog section for this version
|
||||||
|
awk "/^## \[?${{ needs.validate-release.outputs.version }}\]?/,/^## \[?[0-9]/" CHANGELOG.md | head -n -1 | tail -n +2 >> release_notes.md || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add generic content if no specific changelog found
|
||||||
|
if [ ! -s release_notes.md ]; then
|
||||||
|
cat >> release_notes.md << 'EOF'
|
||||||
|
This release includes the latest versions of all nushell plugins with bug fixes and improvements.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
#### Quick Install (Unix-like systems)
|
||||||
|
```bash
|
||||||
|
curl -L https://github.com/${{ github.repository }}/releases/download/${{ needs.validate-release.outputs.tag }}/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manual Install
|
||||||
|
1. Download the appropriate archive for your platform
|
||||||
|
2. Extract the archive
|
||||||
|
3. Run the installation script: `nu install_nu_plugins.nu`
|
||||||
|
|
||||||
|
### Platform Support
|
||||||
|
- **Linux**: x86_64 (amd64) and ARM64
|
||||||
|
- **macOS**: Intel (x86_64) and Apple Silicon (ARM64)
|
||||||
|
- **Windows**: x86_64 (amd64)
|
||||||
|
|
||||||
|
### Available Plugins
|
||||||
|
- `nu_plugin_clipboard` - Clipboard integration
|
||||||
|
- `nu_plugin_desktop_notifications` - Desktop notifications
|
||||||
|
- `nu_plugin_hashes` - Hashing utilities
|
||||||
|
- `nu_plugin_highlight` - Syntax highlighting
|
||||||
|
- `nu_plugin_image` - Image processing
|
||||||
|
- `nu_plugin_kcl` - KCL configuration language support
|
||||||
|
- `nu_plugin_port_extension` - Port utilities
|
||||||
|
- `nu_plugin_qr_maker` - QR code generation
|
||||||
|
- `nu_plugin_tera` - Tera templating
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
All release assets include SHA256 checksums. Verify downloads using:
|
||||||
|
```bash
|
||||||
|
sha256sum -c checksums.txt
|
||||||
|
```
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat release_notes.md
|
||||||
|
|
||||||
|
# Set output for use in create-release step
|
||||||
|
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
|
||||||
|
cat release_notes.md >> $GITHUB_ENV
|
||||||
|
echo "EOF" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create GitHub release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ needs.validate-release.outputs.tag }}
|
||||||
|
release_name: Nushell Plugins ${{ needs.validate-release.outputs.version }}
|
||||||
|
body: ${{ env.RELEASE_NOTES }}
|
||||||
|
draft: ${{ github.event.inputs.draft == 'true' }}
|
||||||
|
prerelease: ${{ github.event.inputs.prerelease == 'true' }}
|
||||||
|
|
||||||
|
- name: Upload release assets
|
||||||
|
run: |
|
||||||
|
echo "Uploading release assets..."
|
||||||
|
for asset in release-assets/*; do
|
||||||
|
if [ -f "$asset" ]; then
|
||||||
|
echo "Uploading $(basename "$asset")..."
|
||||||
|
gh release upload "${{ needs.validate-release.outputs.tag }}" "$asset"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Post-release actions
|
||||||
|
post-release:
|
||||||
|
name: Post-Release Actions
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [validate-release, create-release]
|
||||||
|
if: always() && needs.create-release.result == 'success'
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Notify success
|
||||||
|
run: |
|
||||||
|
echo "🎉 Release ${{ needs.validate-release.outputs.version }} created successfully!"
|
||||||
|
echo "📦 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-release.outputs.tag }}"
|
||||||
|
|
||||||
|
- name: Update installation documentation
|
||||||
|
run: |
|
||||||
|
echo "Consider updating:"
|
||||||
|
echo "- README.md with new version information"
|
||||||
|
echo "- Installation instructions"
|
||||||
|
echo "- Compatibility matrix"
|
||||||
|
|
||||||
|
- name: Create follow-up issue for next release
|
||||||
|
if: "!contains(needs.validate-release.outputs.version, 'rc') && !contains(needs.validate-release.outputs.version, 'beta')"
|
||||||
|
run: |
|
||||||
|
NEXT_VERSION=$(echo "${{ needs.validate-release.outputs.version }}" | awk -F. '{print $1"."($2+1)".0"}')
|
||||||
|
echo "Consider creating planning issue for next release: v$NEXT_VERSION"
|
210
Dockerfile.cross
Normal file
210
Dockerfile.cross
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
# Multi-Architecture Cross-Compilation Docker Image for Nushell Plugins
|
||||||
|
# Based on Ubuntu 22.04 LTS for stability and broad compatibility
|
||||||
|
|
||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
# Prevent interactive prompts during package installation
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Set timezone to UTC
|
||||||
|
ENV TZ=UTC
|
||||||
|
|
||||||
|
# Install system dependencies and cross-compilation toolchains
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y \
|
||||||
|
# Build essentials
|
||||||
|
build-essential \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
git \
|
||||||
|
pkg-config \
|
||||||
|
# SSL and crypto libraries
|
||||||
|
libssl-dev \
|
||||||
|
# Cross-compilation toolchains
|
||||||
|
gcc-x86-64-linux-gnu \
|
||||||
|
gcc-aarch64-linux-gnu \
|
||||||
|
gcc-arm-linux-gnueabihf \
|
||||||
|
# Additional libraries for nushell plugins
|
||||||
|
libc6-dev-amd64-cross \
|
||||||
|
libc6-dev-arm64-cross \
|
||||||
|
libc6-dev-armhf-cross \
|
||||||
|
# For clipboard plugin
|
||||||
|
libx11-dev \
|
||||||
|
libxcb1-dev \
|
||||||
|
libxcb-render0-dev \
|
||||||
|
libxcb-shape0-dev \
|
||||||
|
libxcb-xfixes0-dev \
|
||||||
|
# For image processing
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
# General development tools
|
||||||
|
unzip \
|
||||||
|
zip \
|
||||||
|
tar \
|
||||||
|
gzip \
|
||||||
|
file \
|
||||||
|
# Clean up to reduce image size
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& apt-get clean
|
||||||
|
|
||||||
|
# Install Rust with rustup
|
||||||
|
ENV RUST_VERSION=1.75.0
|
||||||
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_VERSION}
|
||||||
|
|
||||||
|
# Add Rust to PATH
|
||||||
|
ENV PATH="/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
# Install cross-compilation targets
|
||||||
|
RUN rustup target add \
|
||||||
|
x86_64-unknown-linux-gnu \
|
||||||
|
aarch64-unknown-linux-gnu \
|
||||||
|
armv7-unknown-linux-gnueabihf \
|
||||||
|
x86_64-pc-windows-gnu \
|
||||||
|
x86_64-pc-windows-msvc \
|
||||||
|
aarch64-pc-windows-msvc
|
||||||
|
|
||||||
|
# Install additional Rust components
|
||||||
|
RUN rustup component add \
|
||||||
|
rustfmt \
|
||||||
|
clippy \
|
||||||
|
rust-src
|
||||||
|
|
||||||
|
# Install cargo tools useful for cross-compilation
|
||||||
|
RUN cargo install \
|
||||||
|
cross \
|
||||||
|
cargo-audit \
|
||||||
|
cargo-outdated \
|
||||||
|
cargo-edit
|
||||||
|
|
||||||
|
# Set up cross-compilation environment variables and linkers
|
||||||
|
ENV CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc
|
||||||
|
ENV CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++
|
||||||
|
ENV AR_x86_64_unknown_linux_gnu=x86_64-linux-gnu-ar
|
||||||
|
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc
|
||||||
|
|
||||||
|
ENV CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
|
||||||
|
ENV CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
|
||||||
|
ENV AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar
|
||||||
|
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
ENV CC_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc
|
||||||
|
ENV CXX_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++
|
||||||
|
ENV AR_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar
|
||||||
|
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||||
|
|
||||||
|
# Set up pkg-config for cross-compilation
|
||||||
|
ENV PKG_CONFIG_ALLOW_CROSS=1
|
||||||
|
ENV PKG_CONFIG_PATH_x86_64_unknown_linux_gnu=/usr/lib/x86_64-linux-gnu/pkgconfig
|
||||||
|
ENV PKG_CONFIG_PATH_aarch64_unknown_linux_gnu=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||||
|
ENV PKG_CONFIG_PATH_armv7_unknown_linux_gnueabihf=/usr/lib/arm-linux-gnueabihf/pkgconfig
|
||||||
|
|
||||||
|
# Install Windows cross-compilation dependencies
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y \
|
||||||
|
mingw-w64 \
|
||||||
|
wine \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& apt-get clean
|
||||||
|
|
||||||
|
# Set up Windows cross-compilation
|
||||||
|
ENV CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc
|
||||||
|
ENV CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++
|
||||||
|
ENV AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar
|
||||||
|
ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc
|
||||||
|
|
||||||
|
# Create workspace directory
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# Set up cargo configuration for cross-compilation
|
||||||
|
RUN mkdir -p /root/.cargo && \
|
||||||
|
echo '[target.x86_64-unknown-linux-gnu]' >> /root/.cargo/config.toml && \
|
||||||
|
echo 'linker = "x86_64-linux-gnu-gcc"' >> /root/.cargo/config.toml && \
|
||||||
|
echo '' >> /root/.cargo/config.toml && \
|
||||||
|
echo '[target.aarch64-unknown-linux-gnu]' >> /root/.cargo/config.toml && \
|
||||||
|
echo 'linker = "aarch64-linux-gnu-gcc"' >> /root/.cargo/config.toml && \
|
||||||
|
echo '' >> /root/.cargo/config.toml && \
|
||||||
|
echo '[target.armv7-unknown-linux-gnueabihf]' >> /root/.cargo/config.toml && \
|
||||||
|
echo 'linker = "arm-linux-gnueabihf-gcc"' >> /root/.cargo/config.toml && \
|
||||||
|
echo '' >> /root/.cargo/config.toml && \
|
||||||
|
echo '[target.x86_64-pc-windows-gnu]' >> /root/.cargo/config.toml && \
|
||||||
|
echo 'linker = "x86_64-w64-mingw32-gcc"' >> /root/.cargo/config.toml
|
||||||
|
|
||||||
|
# Set default environment variables for better build experience
|
||||||
|
ENV RUST_BACKTRACE=1
|
||||||
|
ENV CARGO_INCREMENTAL=0
|
||||||
|
ENV CARGO_NET_RETRY=10
|
||||||
|
ENV CARGO_NET_TIMEOUT=30
|
||||||
|
|
||||||
|
# Create a build script that can be used as entry point
|
||||||
|
RUN echo '#!/bin/bash' > /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'set -e' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'if [ -z "$1" ]; then' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo ' echo "Usage: build-plugin.sh <target> [plugin_dir]"' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo ' echo "Available targets:"' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo ' rustup target list --installed' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo ' exit 1' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'fi' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'TARGET=$1' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'PLUGIN_DIR=${2:-.}' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'echo "Building $PLUGIN_DIR for target $TARGET..."' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'cd "$PLUGIN_DIR"' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'cargo build --release --target "$TARGET"' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
echo 'echo "Build completed successfully!"' >> /usr/local/bin/build-plugin.sh && \
|
||||||
|
chmod +x /usr/local/bin/build-plugin.sh
|
||||||
|
|
||||||
|
# Create a helper script to list available targets
|
||||||
|
RUN echo '#!/bin/bash' > /usr/local/bin/list-targets.sh && \
|
||||||
|
echo 'echo "Installed Rust targets:"' >> /usr/local/bin/list-targets.sh && \
|
||||||
|
echo 'rustup target list --installed' >> /usr/local/bin/list-targets.sh && \
|
||||||
|
echo '' >> /usr/local/bin/list-targets.sh && \
|
||||||
|
echo 'echo "Available cross-compilation linkers:"' >> /usr/local/bin/list-targets.sh && \
|
||||||
|
echo 'ls -1 /usr/bin/*-gcc | grep -E "(x86_64|aarch64|arm)-.*-gcc$" || true' >> /usr/local/bin/list-targets.sh && \
|
||||||
|
chmod +x /usr/local/bin/list-targets.sh
|
||||||
|
|
||||||
|
# Create a helper script for environment information
|
||||||
|
RUN echo '#!/bin/bash' > /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'echo "=== Rust Environment ==="' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'rustc --version' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'cargo --version' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo '' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'echo "=== Installed Targets ==="' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'rustup target list --installed' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo '' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'echo "=== Cross-Compilation Toolchains ==="' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'echo "GCC versions:"' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'x86_64-linux-gnu-gcc --version 2>/dev/null | head -1 || echo "x86_64-linux-gnu-gcc: not found"' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'aarch64-linux-gnu-gcc --version 2>/dev/null | head -1 || echo "aarch64-linux-gnu-gcc: not found"' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'arm-linux-gnueabihf-gcc --version 2>/dev/null | head -1 || echo "arm-linux-gnueabihf-gcc: not found"' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'x86_64-w64-mingw32-gcc --version 2>/dev/null | head -1 || echo "x86_64-w64-mingw32-gcc: not found"' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo '' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'echo "=== Environment Variables ==="' >> /usr/local/bin/env-info.sh && \
|
||||||
|
echo 'env | grep -E "(CC_|CXX_|AR_|CARGO_TARGET_|PKG_CONFIG)" | sort' >> /usr/local/bin/env-info.sh && \
|
||||||
|
chmod +x /usr/local/bin/env-info.sh
|
||||||
|
|
||||||
|
# Add helpful aliases to bashrc
|
||||||
|
RUN echo 'alias ll="ls -la"' >> /root/.bashrc && \
|
||||||
|
echo 'alias targets="list-targets.sh"' >> /root/.bashrc && \
|
||||||
|
echo 'alias envinfo="env-info.sh"' >> /root/.bashrc && \
|
||||||
|
echo 'alias build="build-plugin.sh"' >> /root/.bashrc
|
||||||
|
|
||||||
|
# Verify installation and show information
|
||||||
|
RUN echo "=== Docker Image Build Complete ===" && \
|
||||||
|
echo "Rust version:" && rustc --version && \
|
||||||
|
echo "Cargo version:" && cargo --version && \
|
||||||
|
echo "Installed targets:" && rustup target list --installed && \
|
||||||
|
echo "Cross-compilation toolchains:" && \
|
||||||
|
(x86_64-linux-gnu-gcc --version | head -1) && \
|
||||||
|
(aarch64-linux-gnu-gcc --version | head -1) && \
|
||||||
|
(arm-linux-gnueabihf-gcc --version | head -1) && \
|
||||||
|
(x86_64-w64-mingw32-gcc --version | head -1) && \
|
||||||
|
echo "=== Ready for cross-compilation! ==="
|
||||||
|
|
||||||
|
# Set default command to show environment info
|
||||||
|
CMD ["env-info.sh"]
|
||||||
|
|
||||||
|
# Metadata labels
|
||||||
|
LABEL maintainer="Nushell Plugins Team"
|
||||||
|
LABEL description="Cross-compilation environment for Nushell plugins"
|
||||||
|
LABEL version="1.0.0"
|
||||||
|
LABEL rust.version="1.75.0"
|
||||||
|
LABEL targets="x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,x86_64-pc-windows-gnu"
|
89
README.md
89
README.md
@ -7,6 +7,7 @@ A comprehensive collection of nushell plugins with automated upstream tracking,
|
|||||||
- [Quick Start](#-quick-start)
|
- [Quick Start](#-quick-start)
|
||||||
- [Why This Repository?](#-why-this-repository)
|
- [Why This Repository?](#-why-this-repository)
|
||||||
- [Plugin Collection](#-plugin-collection)
|
- [Plugin Collection](#-plugin-collection)
|
||||||
|
- [Building and Cross-Compilation](#-building-and-cross-compilation)
|
||||||
- [Development Workflows](#-development-workflows)
|
- [Development Workflows](#-development-workflows)
|
||||||
- [Upstream Tracking System](#-upstream-tracking-system)
|
- [Upstream Tracking System](#-upstream-tracking-system)
|
||||||
- [Scripts and Tools](#-scripts-and-tools)
|
- [Scripts and Tools](#-scripts-and-tools)
|
||||||
@ -95,6 +96,82 @@ This repository provides:
|
|||||||
- 🏠 **Local**: Developed locally without upstream
|
- 🏠 **Local**: Developed locally without upstream
|
||||||
- 🔒 **Private**: Private repository with tracking (requires authentication)
|
- 🔒 **Private**: Private repository with tracking (requires authentication)
|
||||||
|
|
||||||
|
## 🏗️ Building and Cross-Compilation
|
||||||
|
|
||||||
|
This repository includes a comprehensive cross-platform build system that supports building plugins for multiple platforms from a single machine.
|
||||||
|
|
||||||
|
### 🚀 Quick Build Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build for your current platform
|
||||||
|
just build
|
||||||
|
|
||||||
|
# Build for all supported platforms
|
||||||
|
just build-cross-all
|
||||||
|
|
||||||
|
# Build for specific platform
|
||||||
|
just build-cross linux-amd64
|
||||||
|
just build-cross darwin-arm64
|
||||||
|
just build-cross windows-amd64
|
||||||
|
|
||||||
|
# Complete cross-platform release
|
||||||
|
just release-cross
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🎯 Supported Platforms
|
||||||
|
|
||||||
|
| Platform | Architecture | Native | Docker | Status |
|
||||||
|
|----------|-------------|--------|---------|--------|
|
||||||
|
| **Linux** | AMD64 | ✅ | ✅ | Full support |
|
||||||
|
| **Linux** | ARM64 | ⚠️ | ✅ | Docker recommended |
|
||||||
|
| **macOS** | Intel | 🍎 | ❌ | macOS host only |
|
||||||
|
| **macOS** | Apple Silicon | 🍎 | ❌ | macOS host only |
|
||||||
|
| **Windows** | AMD64 | 🪟 | ✅ | Windows host or Docker |
|
||||||
|
|
||||||
|
### 🐳 Docker Cross-Compilation
|
||||||
|
|
||||||
|
For consistent builds across all platforms:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build Docker cross-compilation environment
|
||||||
|
just build-docker-image
|
||||||
|
|
||||||
|
# Use Docker for specific targets
|
||||||
|
just build-docker linux-arm64
|
||||||
|
just build-docker windows-amd64
|
||||||
|
|
||||||
|
# Complete Docker workflow
|
||||||
|
just docker-flow
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📦 Distribution
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Collect binaries for all platforms
|
||||||
|
just collect-all
|
||||||
|
|
||||||
|
# Package with checksums
|
||||||
|
just pack-checksums
|
||||||
|
|
||||||
|
# One-liner: build, collect, and package everything
|
||||||
|
just release-cross
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📖 Comprehensive Guide
|
||||||
|
|
||||||
|
For detailed instructions, platform-specific setup, troubleshooting, and advanced topics, see:
|
||||||
|
|
||||||
|
**➡️ [Complete Building and Cross-Compilation Guide](docs/BUILDING.md)**
|
||||||
|
|
||||||
|
The guide covers:
|
||||||
|
- Platform-specific setup and dependencies
|
||||||
|
- Native vs Docker cross-compilation
|
||||||
|
- Configuration and customization
|
||||||
|
- Troubleshooting common issues
|
||||||
|
- Performance optimization
|
||||||
|
- CI/CD integration
|
||||||
|
- Custom target addition
|
||||||
|
|
||||||
## 🔄 Development Workflows
|
## 🔄 Development Workflows
|
||||||
|
|
||||||
### Daily Development (Using Just)
|
### Daily Development (Using Just)
|
||||||
@ -117,13 +194,17 @@ just test-plugin nu_plugin_clipboard
|
|||||||
### Release Workflow
|
### Release Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Complete release pipeline
|
# Complete release pipeline (native)
|
||||||
just release-flow
|
just release-flow
|
||||||
|
|
||||||
|
# Cross-platform release pipeline
|
||||||
|
just release-flow-cross
|
||||||
|
|
||||||
# Or step by step:
|
# Or step by step:
|
||||||
just build # Build all plugins
|
just build # Build all plugins (native)
|
||||||
just collect # Collect binaries
|
just build-cross-all # Build all plugins (all platforms)
|
||||||
just pack # Create distribution archive
|
just collect-all # Collect binaries (all platforms)
|
||||||
|
just pack-checksums # Create distribution archives with checksums
|
||||||
```
|
```
|
||||||
|
|
||||||
### Quality Assurance
|
### Quality Assurance
|
||||||
|
850
docs/BUILDING.md
Normal file
850
docs/BUILDING.md
Normal file
@ -0,0 +1,850 @@
|
|||||||
|
# Building and Cross-Compilation Guide
|
||||||
|
|
||||||
|
This comprehensive guide covers everything you need to know about building nushell plugins, including cross-compilation for multiple platforms.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Quick Start](#quick-start)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Build Methods](#build-methods)
|
||||||
|
- [Cross-Compilation](#cross-compilation)
|
||||||
|
- [Docker Builds](#docker-builds)
|
||||||
|
- [Platform Support](#platform-support)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Workflows](#workflows)
|
||||||
|
- [Distribution](#distribution)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [FAQ](#faq)
|
||||||
|
- [Advanced Topics](#advanced-topics)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Native Build (Host Platform Only)
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone https://github.com/YOUR_ORG/nushell-plugins.git
|
||||||
|
cd nushell-plugins
|
||||||
|
|
||||||
|
# Build all plugins for your platform
|
||||||
|
just build
|
||||||
|
|
||||||
|
# Or using the script directly
|
||||||
|
./scripts/run.sh build_all.nu
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cross-Platform Build
|
||||||
|
```bash
|
||||||
|
# Build for all supported platforms
|
||||||
|
just build-cross-all
|
||||||
|
|
||||||
|
# Build for specific platform
|
||||||
|
just build-cross linux-amd64
|
||||||
|
|
||||||
|
# Build and create distribution packages
|
||||||
|
just release-cross
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### Required Tools
|
||||||
|
|
||||||
|
1. **Rust Toolchain** (1.70.0+)
|
||||||
|
```bash
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Nushell** (0.107.1)
|
||||||
|
```bash
|
||||||
|
# Install via cargo
|
||||||
|
cargo install nu
|
||||||
|
|
||||||
|
# Or download from https://github.com/nushell/nushell/releases
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Just** (optional but recommended)
|
||||||
|
```bash
|
||||||
|
cargo install just
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Git** with submodules
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/YOUR_ORG/nushell-plugins.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional Tools
|
||||||
|
|
||||||
|
- **Docker** - For Docker-based cross-compilation
|
||||||
|
- **Cross-compilation toolchains** - For native cross-compilation
|
||||||
|
|
||||||
|
## Build Methods
|
||||||
|
|
||||||
|
### 1. Native Compilation
|
||||||
|
|
||||||
|
Build plugins for your current platform using the standard Rust toolchain.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic build
|
||||||
|
just build
|
||||||
|
|
||||||
|
# Verbose output
|
||||||
|
just build-verbose
|
||||||
|
|
||||||
|
# Parallel build (experimental)
|
||||||
|
just build-parallel
|
||||||
|
|
||||||
|
# Build specific plugins
|
||||||
|
./scripts/run.sh build_all.nu --plugins nu_plugin_clipboard,nu_plugin_image
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Fast compilation
|
||||||
|
- Native debugging support
|
||||||
|
- Simple setup
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Only builds for current platform
|
||||||
|
- Limited cross-compilation support
|
||||||
|
|
||||||
|
### 2. Cross-Compilation
|
||||||
|
|
||||||
|
Build plugins for different platforms using Rust's cross-compilation features.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List available targets
|
||||||
|
just build-targets
|
||||||
|
|
||||||
|
# Build for specific target
|
||||||
|
just build-cross linux-amd64
|
||||||
|
just build-cross darwin-arm64
|
||||||
|
just build-cross windows-amd64
|
||||||
|
|
||||||
|
# Build for all targets
|
||||||
|
just build-cross-all
|
||||||
|
|
||||||
|
# Parallel cross-compilation
|
||||||
|
just build-cross-parallel
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Multiple platforms from single machine
|
||||||
|
- Fast execution
|
||||||
|
- No Docker dependency
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- May require target-specific toolchains
|
||||||
|
- Some targets may not work on all hosts
|
||||||
|
|
||||||
|
### 3. Docker-Based Cross-Compilation
|
||||||
|
|
||||||
|
Use Docker containers with pre-configured cross-compilation environments.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build Docker image
|
||||||
|
just build-docker-image
|
||||||
|
|
||||||
|
# Build specific target with Docker
|
||||||
|
just build-docker linux-arm64
|
||||||
|
|
||||||
|
# Force Docker for all builds
|
||||||
|
./scripts/run.sh build_cross.nu --all-targets --docker
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Consistent build environment
|
||||||
|
- All toolchains pre-installed
|
||||||
|
- Works on any Docker-capable host
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Slower than native compilation
|
||||||
|
- Requires Docker
|
||||||
|
- Larger resource usage
|
||||||
|
|
||||||
|
## Cross-Compilation
|
||||||
|
|
||||||
|
### Supported Platforms
|
||||||
|
|
||||||
|
| Platform | Target Triple | Native | Docker | Notes |
|
||||||
|
|----------|---------------|--------|---------|-------|
|
||||||
|
| **Linux AMD64** | `x86_64-unknown-linux-gnu` | ✅ | ✅ | Most common Linux |
|
||||||
|
| **Linux ARM64** | `aarch64-unknown-linux-gnu` | ⚠️ | ✅ | Requires cross toolchain |
|
||||||
|
| **macOS Intel** | `x86_64-apple-darwin` | 🍎 | ❌ | macOS host only |
|
||||||
|
| **macOS Apple Silicon** | `aarch64-apple-darwin` | 🍎 | ❌ | macOS host only |
|
||||||
|
| **Windows AMD64** | `x86_64-pc-windows-msvc` | 🪟 | ✅ | Windows host or Docker |
|
||||||
|
|
||||||
|
**Legend:**
|
||||||
|
- ✅ Fully supported
|
||||||
|
- ⚠️ Requires additional setup
|
||||||
|
- 🍎 macOS host required
|
||||||
|
- 🪟 Windows host required
|
||||||
|
- ❌ Not supported
|
||||||
|
|
||||||
|
### Setting Up Cross-Compilation
|
||||||
|
|
||||||
|
#### Linux → Linux ARM64
|
||||||
|
```bash
|
||||||
|
# Install cross-compilation toolchain (Ubuntu/Debian)
|
||||||
|
sudo apt-get install gcc-aarch64-linux-gnu
|
||||||
|
|
||||||
|
# Add Rust target
|
||||||
|
rustup target add aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
# Configure environment
|
||||||
|
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
|
||||||
|
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
# Build
|
||||||
|
just build-cross linux-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Any → Windows (Docker)
|
||||||
|
```bash
|
||||||
|
# Build Docker image with Windows toolchain
|
||||||
|
just build-docker-image
|
||||||
|
|
||||||
|
# Cross-compile to Windows
|
||||||
|
just build-docker windows-amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Files
|
||||||
|
|
||||||
|
#### Build Targets (`etc/build_targets.toml`)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[targets.linux-amd64]
|
||||||
|
rust_target = "x86_64-unknown-linux-gnu"
|
||||||
|
platform_name = "linux-amd64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
native_build = true
|
||||||
|
description = "Linux x86_64 (64-bit Intel/AMD)"
|
||||||
|
|
||||||
|
[targets.linux-arm64]
|
||||||
|
rust_target = "aarch64-unknown-linux-gnu"
|
||||||
|
platform_name = "linux-arm64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = true
|
||||||
|
native_build = false
|
||||||
|
description = "Linux ARM64 (64-bit ARM)"
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Environment Variables
|
||||||
|
```bash
|
||||||
|
# Cross-compilation linkers
|
||||||
|
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
|
||||||
|
export CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
|
||||||
|
export AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar
|
||||||
|
|
||||||
|
# Cargo configuration
|
||||||
|
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Builds
|
||||||
|
|
||||||
|
### Docker Image
|
||||||
|
|
||||||
|
The cross-compilation Docker image includes:
|
||||||
|
- **Rust toolchain** (1.75.0)
|
||||||
|
- **Cross-compilation targets** for all supported platforms
|
||||||
|
- **System toolchains** (GCC, MinGW, etc.)
|
||||||
|
- **Build tools** (cargo, rustfmt, clippy)
|
||||||
|
|
||||||
|
### Docker Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build Docker image
|
||||||
|
just build-docker-image
|
||||||
|
|
||||||
|
# Rebuild from scratch
|
||||||
|
just build-docker-image-fresh
|
||||||
|
|
||||||
|
# Show Docker environment info
|
||||||
|
just docker-info
|
||||||
|
|
||||||
|
# Build specific plugin with Docker
|
||||||
|
just build-docker-plugin nu_plugin_clipboard linux-arm64
|
||||||
|
|
||||||
|
# Clean up Docker artifacts
|
||||||
|
just docker-cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Complete Docker-based workflow
|
||||||
|
just docker-flow
|
||||||
|
|
||||||
|
# This runs:
|
||||||
|
# 1. just validate-nushell
|
||||||
|
# 2. just build-docker-image
|
||||||
|
# 3. just build-cross-all --docker
|
||||||
|
# 4. just collect-all
|
||||||
|
# 5. just pack-all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Docker Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run interactive Docker container
|
||||||
|
docker run -it --rm \
|
||||||
|
-v $(pwd):/workspace \
|
||||||
|
-w /workspace \
|
||||||
|
nushell-plugins-cross:latest \
|
||||||
|
bash
|
||||||
|
|
||||||
|
# Build specific target in container
|
||||||
|
docker run --rm \
|
||||||
|
-v $(pwd):/workspace \
|
||||||
|
-w /workspace/nu_plugin_clipboard \
|
||||||
|
nushell-plugins-cross:latest \
|
||||||
|
cargo build --release --target aarch64-unknown-linux-gnu
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform Support
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
**Supported Architectures:**
|
||||||
|
- x86_64 (AMD64) - Native and Docker
|
||||||
|
- ARM64 (AArch64) - Docker recommended
|
||||||
|
- ARM32 (ARMv7) - Docker only, disabled by default
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
```bash
|
||||||
|
# Ubuntu/Debian
|
||||||
|
sudo apt-get install build-essential libssl-dev pkg-config
|
||||||
|
|
||||||
|
# Cross-compilation toolchains
|
||||||
|
sudo apt-get install gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf
|
||||||
|
```
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
**Supported Architectures:**
|
||||||
|
- Intel (x86_64) - Native only
|
||||||
|
- Apple Silicon (ARM64) - Native only
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
```bash
|
||||||
|
# Install Xcode command line tools
|
||||||
|
xcode-select --install
|
||||||
|
|
||||||
|
# Add Rust targets
|
||||||
|
rustup target add x86_64-apple-darwin aarch64-apple-darwin
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cross-compilation:**
|
||||||
|
```bash
|
||||||
|
# On Apple Silicon, build for Intel
|
||||||
|
just build-cross darwin-amd64
|
||||||
|
|
||||||
|
# On Intel, build for Apple Silicon (may not work)
|
||||||
|
just build-cross darwin-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
**Supported Architectures:**
|
||||||
|
- x86_64 (AMD64) - Native and Docker
|
||||||
|
|
||||||
|
**Native Dependencies:**
|
||||||
|
- Visual Studio Build Tools or Visual Studio Community
|
||||||
|
- Windows SDK
|
||||||
|
|
||||||
|
**Docker Alternative:**
|
||||||
|
```bash
|
||||||
|
# Use Docker for Windows builds on any platform
|
||||||
|
just build-docker windows-amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Global Configuration
|
||||||
|
|
||||||
|
The main configuration file is `etc/build_targets.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[metadata]
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "Cross-compilation targets for nushell plugins"
|
||||||
|
|
||||||
|
[defaults]
|
||||||
|
docker_image = "nushell-plugins-cross:latest"
|
||||||
|
strip_binaries = true
|
||||||
|
optimize_size = true
|
||||||
|
|
||||||
|
[targets.custom-target]
|
||||||
|
rust_target = "x86_64-unknown-linux-musl"
|
||||||
|
platform_name = "linux-amd64-musl"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
description = "Linux x86_64 with musl libc"
|
||||||
|
enabled = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Configuration
|
||||||
|
|
||||||
|
Create an `env` file for local overrides:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# env file
|
||||||
|
TARGET_PATH=distribution
|
||||||
|
INSTALL_BIN_PATH=/usr/local/bin
|
||||||
|
BIN_ARCHIVES_DIR_PATH=bin_archives
|
||||||
|
APP_NAME=nushell-plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
### Plugin-Specific Configuration
|
||||||
|
|
||||||
|
Some plugins may require special build configurations:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# In plugin's Cargo.toml
|
||||||
|
[package.metadata.cross]
|
||||||
|
image = "ghcr.io/cross-rs/cross:aarch64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
[target.aarch64-unknown-linux-gnu]
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflows
|
||||||
|
|
||||||
|
### Development Workflows
|
||||||
|
|
||||||
|
#### Standard Development
|
||||||
|
```bash
|
||||||
|
just dev-flow
|
||||||
|
# 1. Validate nushell version
|
||||||
|
# 2. Check upstream changes
|
||||||
|
# 3. Build for host platform
|
||||||
|
# 4. Run tests
|
||||||
|
# 5. Show status
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cross-Platform Development
|
||||||
|
```bash
|
||||||
|
just dev-flow-cross
|
||||||
|
# 1. Validate nushell version
|
||||||
|
# 2. Check upstream changes
|
||||||
|
# 3. Build for all platforms
|
||||||
|
# 4. Show status
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Quality Assurance
|
||||||
|
```bash
|
||||||
|
just quality-flow
|
||||||
|
# 1. Validate nushell version
|
||||||
|
# 2. Format code
|
||||||
|
# 3. Run clippy linting
|
||||||
|
# 4. Run tests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Release Workflows
|
||||||
|
|
||||||
|
#### Standard Release
|
||||||
|
```bash
|
||||||
|
just release-flow
|
||||||
|
# 1. Validate nushell version
|
||||||
|
# 2. Build for host platform
|
||||||
|
# 3. Collect binaries
|
||||||
|
# 4. Create packages
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cross-Platform Release
|
||||||
|
```bash
|
||||||
|
just release-flow-cross
|
||||||
|
# 1. Validate nushell version
|
||||||
|
# 2. Build for all platforms
|
||||||
|
# 3. Collect all binaries
|
||||||
|
# 4. Create packages with checksums
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CI Simulation
|
||||||
|
```bash
|
||||||
|
just ci-flow
|
||||||
|
# Simulates exactly what GitHub Actions will run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Workflows
|
||||||
|
|
||||||
|
You can create custom workflows by combining individual commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Custom workflow for testing
|
||||||
|
just validate-nushell
|
||||||
|
just build-cross linux-amd64
|
||||||
|
just build-cross darwin-arm64
|
||||||
|
just test
|
||||||
|
just collect-platform linux-amd64
|
||||||
|
just pack-platform linux-amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Distribution
|
||||||
|
|
||||||
|
### Collection
|
||||||
|
|
||||||
|
Collect built binaries for distribution:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Collect all platforms
|
||||||
|
just collect-all
|
||||||
|
|
||||||
|
# Collect specific platform
|
||||||
|
just collect-platform linux-amd64
|
||||||
|
|
||||||
|
# List what can be collected
|
||||||
|
just collect-platforms
|
||||||
|
```
|
||||||
|
|
||||||
|
### Packaging
|
||||||
|
|
||||||
|
Create distribution archives:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Package all platforms
|
||||||
|
just pack-all
|
||||||
|
|
||||||
|
# Package with checksums
|
||||||
|
just pack-checksums
|
||||||
|
|
||||||
|
# Package specific platform
|
||||||
|
just pack-platform darwin-arm64
|
||||||
|
|
||||||
|
# List packaging options
|
||||||
|
just pack-platforms
|
||||||
|
```
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
|
||||||
|
After building and packaging:
|
||||||
|
|
||||||
|
```
|
||||||
|
distribution/
|
||||||
|
├── linux-amd64/
|
||||||
|
│ ├── nu_plugin_clipboard
|
||||||
|
│ ├── nu_plugin_image
|
||||||
|
│ ├── install_nu_plugins.nu
|
||||||
|
│ ├── LICENSE
|
||||||
|
│ └── README
|
||||||
|
├── darwin-arm64/
|
||||||
|
│ └── [same structure]
|
||||||
|
└── windows-amd64/
|
||||||
|
├── nu_plugin_clipboard.exe
|
||||||
|
└── [same structure]
|
||||||
|
|
||||||
|
bin_archives/
|
||||||
|
├── linux-amd64-nushell-plugins.tar.gz
|
||||||
|
├── darwin-arm64-nushell-plugins.tar.gz
|
||||||
|
├── windows-amd64-nushell-plugins.zip
|
||||||
|
└── checksums.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Checksums
|
||||||
|
|
||||||
|
All distribution packages include SHA256 checksums:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate checksums
|
||||||
|
just pack-checksums
|
||||||
|
|
||||||
|
# Verify downloaded archive
|
||||||
|
sha256sum -c checksums.txt
|
||||||
|
|
||||||
|
# Manual verification
|
||||||
|
sha256sum linux-amd64-nushell-plugins.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### Version Mismatch
|
||||||
|
```bash
|
||||||
|
# Error: Nushell version mismatch detected
|
||||||
|
# Fix: Update versions automatically
|
||||||
|
just fix-nushell
|
||||||
|
|
||||||
|
# Or manually check and fix
|
||||||
|
./scripts/run.sh check_version.nu --fix
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Missing Cross-Compilation Target
|
||||||
|
```bash
|
||||||
|
# Error: target 'aarch64-unknown-linux-gnu' not found
|
||||||
|
# Fix: Install the target
|
||||||
|
rustup target add aarch64-unknown-linux-gnu
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cross-Compilation Linker Error
|
||||||
|
```bash
|
||||||
|
# Error: linker 'aarch64-linux-gnu-gcc' not found
|
||||||
|
# Fix: Install cross-compilation toolchain
|
||||||
|
sudo apt-get install gcc-aarch64-linux-gnu
|
||||||
|
|
||||||
|
# Set environment variable
|
||||||
|
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Docker Build Failures
|
||||||
|
```bash
|
||||||
|
# Error: Docker daemon not running
|
||||||
|
# Fix: Start Docker service
|
||||||
|
sudo systemctl start docker
|
||||||
|
|
||||||
|
# Error: Docker image not found
|
||||||
|
# Fix: Build the image
|
||||||
|
just build-docker-image
|
||||||
|
|
||||||
|
# Error: Permission denied in Docker
|
||||||
|
# Fix: Add user to docker group
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Build Failures
|
||||||
|
|
||||||
|
**Plugin-specific failures:**
|
||||||
|
```bash
|
||||||
|
# Debug specific plugin
|
||||||
|
cd nu_plugin_clipboard
|
||||||
|
cargo build --release --verbose
|
||||||
|
|
||||||
|
# Check plugin dependencies
|
||||||
|
cargo tree
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cross-compilation failures:**
|
||||||
|
```bash
|
||||||
|
# Use Docker instead of native cross-compilation
|
||||||
|
just build-docker linux-arm64
|
||||||
|
|
||||||
|
# Check target support
|
||||||
|
rustup target list | grep installed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
Enable verbose output for troubleshooting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verbose build output
|
||||||
|
just build-verbose
|
||||||
|
|
||||||
|
# Verbose cross-compilation
|
||||||
|
./scripts/run.sh build_cross.nu --all-targets --verbose
|
||||||
|
|
||||||
|
# Debug Docker builds
|
||||||
|
./scripts/run.sh build_docker_cross.nu --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log Files
|
||||||
|
|
||||||
|
Build logs are preserved for debugging:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View recent build logs
|
||||||
|
ls -la target/*/build/*/out/
|
||||||
|
|
||||||
|
# Search for specific errors
|
||||||
|
grep -r "error" target/*/build/*/stderr
|
||||||
|
```
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### General Questions
|
||||||
|
|
||||||
|
**Q: What platforms are supported?**
|
||||||
|
A: Linux (AMD64, ARM64), macOS (Intel, Apple Silicon), and Windows (AMD64). See the [Platform Support](#platform-support) section for details.
|
||||||
|
|
||||||
|
**Q: Do I need Docker for cross-compilation?**
|
||||||
|
A: Not always. Native cross-compilation works for many targets, but Docker provides a more consistent environment and supports more target combinations.
|
||||||
|
|
||||||
|
**Q: How long does cross-compilation take?**
|
||||||
|
A: Building all platforms takes 10-30 minutes depending on your hardware. Parallel builds (`just build-cross-parallel`) can significantly reduce this time.
|
||||||
|
|
||||||
|
**Q: Can I add new platforms?**
|
||||||
|
A: Yes! Edit `etc/build_targets.toml` to add new targets. See [Configuration](#configuration) for details.
|
||||||
|
|
||||||
|
### Build Questions
|
||||||
|
|
||||||
|
**Q: Why do some builds fail on my platform?**
|
||||||
|
A: Cross-compilation has limitations. macOS targets can only be built on macOS, and some Linux ARM64 builds require specific toolchains. Use Docker builds as a fallback.
|
||||||
|
|
||||||
|
**Q: How can I speed up builds?**
|
||||||
|
A: Use parallel builds (`--parallel`), enable incremental compilation, and use Docker layer caching. Consider building only the platforms you need.
|
||||||
|
|
||||||
|
**Q: Can I build just one plugin?**
|
||||||
|
A: Yes! Use `./scripts/run.sh build_all.nu --plugins nu_plugin_clipboard` or build manually in the plugin directory.
|
||||||
|
|
||||||
|
**Q: Why are Windows binaries so large?**
|
||||||
|
A: Windows binaries include the MSVC runtime. You can reduce size by using the GNU toolchain or enabling link-time optimization.
|
||||||
|
|
||||||
|
### Docker Questions
|
||||||
|
|
||||||
|
**Q: How much disk space does the Docker image use?**
|
||||||
|
A: The cross-compilation image is approximately 2-3 GB, including all toolchains and dependencies.
|
||||||
|
|
||||||
|
**Q: Can I use my own Docker image?**
|
||||||
|
A: Yes! Modify the `docker.image_tag` setting in `etc/build_targets.toml` to use a custom image.
|
||||||
|
|
||||||
|
**Q: How do I update the Docker image?**
|
||||||
|
A: Run `just build-docker-image-fresh` to rebuild from scratch with the latest dependencies.
|
||||||
|
|
||||||
|
### Distribution Questions
|
||||||
|
|
||||||
|
**Q: How do I install the plugins?**
|
||||||
|
A: Use the universal installer: `curl -L https://github.com/YOUR_ORG/nushell-plugins/releases/latest/download/install.sh | sh`
|
||||||
|
|
||||||
|
**Q: Can I distribute individual plugins?**
|
||||||
|
A: Yes! Each plugin binary is self-contained. Just copy the `nu_plugin_*` files to the target system.
|
||||||
|
|
||||||
|
**Q: What's the difference between tar.gz and zip archives?**
|
||||||
|
A: Unix-like systems (Linux, macOS) use tar.gz for better compression and permission preservation. Windows uses zip for compatibility.
|
||||||
|
|
||||||
|
### Troubleshooting Questions
|
||||||
|
|
||||||
|
**Q: Build fails with "permission denied" errors**
|
||||||
|
A: Check that you have write permissions to the target directory and that antivirus software isn't blocking the builds.
|
||||||
|
|
||||||
|
**Q: Cross-compilation fails with "unsupported target"**
|
||||||
|
A: Install the target with `rustup target add TARGET_NAME` or use Docker builds instead.
|
||||||
|
|
||||||
|
**Q: Docker builds are very slow**
|
||||||
|
A: Make sure Docker has sufficient resources allocated. Consider using Docker BuildKit for faster builds.
|
||||||
|
|
||||||
|
## Advanced Topics
|
||||||
|
|
||||||
|
### Custom Build Targets
|
||||||
|
|
||||||
|
Add support for new platforms by editing `etc/build_targets.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[targets.linux-musl]
|
||||||
|
rust_target = "x86_64-unknown-linux-musl"
|
||||||
|
platform_name = "linux-amd64-musl"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
description = "Linux x86_64 with musl libc"
|
||||||
|
strip_binaries = true
|
||||||
|
|
||||||
|
[environment.linux-musl]
|
||||||
|
CC = "musl-gcc"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Optimization
|
||||||
|
|
||||||
|
#### Link-Time Optimization (LTO)
|
||||||
|
```toml
|
||||||
|
# In Cargo.toml
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
strip = "symbols"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Size Optimization
|
||||||
|
```toml
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "z" # Optimize for size
|
||||||
|
lto = true
|
||||||
|
strip = "symbols"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Build Scripts
|
||||||
|
|
||||||
|
Create custom build scripts for complex scenarios:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# scripts/custom_build.sh
|
||||||
|
|
||||||
|
# Custom build with specific optimizations
|
||||||
|
export RUSTFLAGS="-C target-cpu=native"
|
||||||
|
cargo build --release --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
|
# Strip debug symbols
|
||||||
|
strip target/x86_64-unknown-linux-gnu/release/nu_plugin_*
|
||||||
|
```
|
||||||
|
|
||||||
|
### Continuous Integration
|
||||||
|
|
||||||
|
The repository includes GitHub Actions workflows for:
|
||||||
|
|
||||||
|
- **Build & Test** (`.github/workflows/build.yml`)
|
||||||
|
- **Release** (`.github/workflows/release.yml`)
|
||||||
|
- **Nightly Builds** (`.github/workflows/nightly.yml`)
|
||||||
|
|
||||||
|
To set up in your own repository:
|
||||||
|
|
||||||
|
1. Copy the `.github/workflows/` directory
|
||||||
|
2. Update the repository references
|
||||||
|
3. Configure GitHub secrets if needed
|
||||||
|
4. Customize the build matrix for your needs
|
||||||
|
|
||||||
|
### Plugin Development
|
||||||
|
|
||||||
|
When developing new plugins:
|
||||||
|
|
||||||
|
1. **Use the template:**
|
||||||
|
```bash
|
||||||
|
just make-plugin nu_plugin_yourname
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Follow the plugin structure:**
|
||||||
|
```
|
||||||
|
nu_plugin_yourname/
|
||||||
|
├── Cargo.toml
|
||||||
|
├── src/
|
||||||
|
│ ├── main.rs
|
||||||
|
│ └── lib.rs
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Test cross-compilation early:**
|
||||||
|
```bash
|
||||||
|
just build-cross-all
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Add to the registry:**
|
||||||
|
Update `etc/plugin_registry.toml` if the plugin has an upstream repository.
|
||||||
|
|
||||||
|
### Performance Tuning
|
||||||
|
|
||||||
|
#### Parallel Compilation
|
||||||
|
```bash
|
||||||
|
# Set number of parallel jobs
|
||||||
|
export CARGO_BUILD_JOBS=8
|
||||||
|
|
||||||
|
# Use parallel cross-compilation
|
||||||
|
just build-cross-parallel
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Caching
|
||||||
|
```bash
|
||||||
|
# Use sccache for distributed compilation caching
|
||||||
|
cargo install sccache
|
||||||
|
export RUSTC_WRAPPER=sccache
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Memory Usage
|
||||||
|
```bash
|
||||||
|
# Limit memory usage for large builds
|
||||||
|
export CARGO_BUILD_RUSTFLAGS="-C link-arg=-Wl,--no-keep-memory"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **Issues**: [GitHub Issues](https://github.com/YOUR_ORG/nushell-plugins/issues)
|
||||||
|
- **Discussions**: [GitHub Discussions](https://github.com/YOUR_ORG/nushell-plugins/discussions)
|
||||||
|
- **Documentation**: [Repository Wiki](https://github.com/YOUR_ORG/nushell-plugins/wiki)
|
||||||
|
- **Nushell Community**: [Discord](https://discord.gg/NtAbbGn) | [Reddit](https://www.reddit.com/r/Nushell/)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on contributing to the build system and adding new platforms or features.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This documentation is maintained by the nushell-plugins team. Last updated: 2024-09-20*
|
173
etc/build_targets.toml
Normal file
173
etc/build_targets.toml
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
# Build Targets Configuration for Nushell Plugins
|
||||||
|
# Defines supported cross-compilation targets and their requirements
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "Cross-compilation targets for nushell plugins"
|
||||||
|
last_updated = "2024-09-20"
|
||||||
|
|
||||||
|
# Default settings applied to all targets unless overridden
|
||||||
|
[defaults]
|
||||||
|
docker_image = "nushell-plugins-cross:latest"
|
||||||
|
strip_binaries = true
|
||||||
|
optimize_size = true
|
||||||
|
|
||||||
|
# Linux AMD64 - Most common Linux target
|
||||||
|
[targets.linux-amd64]
|
||||||
|
rust_target = "x86_64-unknown-linux-gnu"
|
||||||
|
platform_name = "linux-amd64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
native_build = true
|
||||||
|
description = "Linux x86_64 (64-bit Intel/AMD)"
|
||||||
|
|
||||||
|
# Linux ARM64 - Growing in popularity with cloud instances
|
||||||
|
[targets.linux-arm64]
|
||||||
|
rust_target = "aarch64-unknown-linux-gnu"
|
||||||
|
platform_name = "linux-arm64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = true
|
||||||
|
native_build = false
|
||||||
|
description = "Linux ARM64 (64-bit ARM)"
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
|
||||||
|
# macOS AMD64 - Intel Macs
|
||||||
|
[targets.darwin-amd64]
|
||||||
|
rust_target = "x86_64-apple-darwin"
|
||||||
|
platform_name = "darwin-amd64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
native_build = true
|
||||||
|
host_required = "darwin"
|
||||||
|
description = "macOS x86_64 (Intel Macs)"
|
||||||
|
|
||||||
|
# macOS ARM64 - Apple Silicon Macs
|
||||||
|
[targets.darwin-arm64]
|
||||||
|
rust_target = "aarch64-apple-darwin"
|
||||||
|
platform_name = "darwin-arm64"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = false
|
||||||
|
native_build = true
|
||||||
|
host_required = "darwin"
|
||||||
|
description = "macOS ARM64 (Apple Silicon)"
|
||||||
|
|
||||||
|
# Windows AMD64 - Standard Windows target
|
||||||
|
[targets.windows-amd64]
|
||||||
|
rust_target = "x86_64-pc-windows-msvc"
|
||||||
|
platform_name = "windows-amd64"
|
||||||
|
archive_format = "zip"
|
||||||
|
docker_required = true
|
||||||
|
native_build = false
|
||||||
|
description = "Windows x86_64 (64-bit)"
|
||||||
|
binary_extension = ".exe"
|
||||||
|
|
||||||
|
# Additional targets that can be enabled
|
||||||
|
[targets.linux-arm32]
|
||||||
|
rust_target = "armv7-unknown-linux-gnueabihf"
|
||||||
|
platform_name = "linux-arm32"
|
||||||
|
archive_format = "tar.gz"
|
||||||
|
docker_required = true
|
||||||
|
native_build = false
|
||||||
|
enabled = false
|
||||||
|
description = "Linux ARM32 (32-bit ARM)"
|
||||||
|
|
||||||
|
[targets.windows-arm64]
|
||||||
|
rust_target = "aarch64-pc-windows-msvc"
|
||||||
|
platform_name = "windows-arm64"
|
||||||
|
archive_format = "zip"
|
||||||
|
docker_required = true
|
||||||
|
native_build = false
|
||||||
|
enabled = false
|
||||||
|
description = "Windows ARM64"
|
||||||
|
binary_extension = ".exe"
|
||||||
|
|
||||||
|
# Docker configuration for cross-compilation
|
||||||
|
[docker]
|
||||||
|
dockerfile = "Dockerfile.cross"
|
||||||
|
image_tag = "nushell-plugins-cross:latest"
|
||||||
|
cache_from = ["nushell-plugins-cross:cache"]
|
||||||
|
build_args = []
|
||||||
|
|
||||||
|
# Platform-specific configurations
|
||||||
|
[platform_configs.linux]
|
||||||
|
package_formats = ["tar.gz", "deb", "rpm"]
|
||||||
|
install_prefix = "/usr/local/bin"
|
||||||
|
config_dir = "/etc/nushell-plugins"
|
||||||
|
|
||||||
|
[platform_configs.darwin]
|
||||||
|
package_formats = ["tar.gz", "dmg"]
|
||||||
|
install_prefix = "/usr/local/bin"
|
||||||
|
config_dir = "/usr/local/etc/nushell-plugins"
|
||||||
|
|
||||||
|
[platform_configs.windows]
|
||||||
|
package_formats = ["zip", "msi"]
|
||||||
|
install_prefix = "C:\\Program Files\\nushell-plugins"
|
||||||
|
config_dir = "C:\\ProgramData\\nushell-plugins"
|
||||||
|
|
||||||
|
# Build optimization settings
|
||||||
|
[optimization]
|
||||||
|
# Enable link-time optimization for release builds
|
||||||
|
lto = true
|
||||||
|
# Code generation units for parallel compilation
|
||||||
|
codegen_units = 1
|
||||||
|
# Panic strategy (abort for smaller binaries)
|
||||||
|
panic_strategy = "abort"
|
||||||
|
# Strip debug symbols
|
||||||
|
strip = "symbols"
|
||||||
|
|
||||||
|
# Environment variables for cross-compilation
|
||||||
|
[environment]
|
||||||
|
# Common variables for all builds
|
||||||
|
RUST_BACKTRACE = "1"
|
||||||
|
CARGO_INCREMENTAL = "0"
|
||||||
|
|
||||||
|
# Target-specific environment variables
|
||||||
|
[environment.linux-arm64]
|
||||||
|
CC = "aarch64-linux-gnu-gcc"
|
||||||
|
CXX = "aarch64-linux-gnu-g++"
|
||||||
|
AR = "aarch64-linux-gnu-ar"
|
||||||
|
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = "aarch64-linux-gnu-gcc"
|
||||||
|
|
||||||
|
[environment.windows-amd64]
|
||||||
|
# Windows-specific environment setup would go here
|
||||||
|
# Usually handled by the Docker container
|
||||||
|
|
||||||
|
# Feature flags for conditional compilation
|
||||||
|
[features]
|
||||||
|
# Default features to enable for all builds
|
||||||
|
default = ["clipboard", "image", "networking"]
|
||||||
|
|
||||||
|
# Optional features that can be disabled for smaller binaries
|
||||||
|
optional = ["crypto", "database", "desktop-notifications"]
|
||||||
|
|
||||||
|
# Platform-specific features
|
||||||
|
[features.linux]
|
||||||
|
available = ["clipboard", "image", "networking", "desktop-notifications"]
|
||||||
|
|
||||||
|
[features.darwin]
|
||||||
|
available = ["clipboard", "image", "networking", "desktop-notifications"]
|
||||||
|
|
||||||
|
[features.windows]
|
||||||
|
available = ["clipboard", "image", "networking"]
|
||||||
|
|
||||||
|
# Validation rules for targets
|
||||||
|
[validation]
|
||||||
|
# Minimum required Rust version
|
||||||
|
min_rust_version = "1.70.0"
|
||||||
|
|
||||||
|
# Required tools for native compilation
|
||||||
|
required_tools = ["cargo", "rustc"]
|
||||||
|
|
||||||
|
# Required tools for Docker compilation
|
||||||
|
docker_tools = ["docker"]
|
||||||
|
|
||||||
|
# Testing configuration
|
||||||
|
[testing]
|
||||||
|
# Run tests for these targets during CI
|
||||||
|
ci_targets = ["linux-amd64", "darwin-amd64", "darwin-arm64"]
|
||||||
|
|
||||||
|
# Quick test targets for development
|
||||||
|
dev_targets = ["linux-amd64"]
|
||||||
|
|
||||||
|
# Full integration test targets
|
||||||
|
integration_targets = ["linux-amd64", "darwin-arm64"]
|
@ -59,7 +59,7 @@ has_local_changes = true
|
|||||||
description = "Desktop notifications plugin for nushell (local development)"
|
description = "Desktop notifications plugin for nushell (local development)"
|
||||||
|
|
||||||
[plugins.nu_plugin_fluent]
|
[plugins.nu_plugin_fluent]
|
||||||
upstream_url = "https://github.com/YourUsername/nu_plugin_fluent"
|
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_fluent.git"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = ""
|
last_checked_commit = ""
|
||||||
last_checked_date = ""
|
last_checked_date = ""
|
||||||
@ -118,7 +118,7 @@ notify_on_pending_changes = true
|
|||||||
upstream_url = "https://github.com/cptpiepmatz/nu-plugin-highlight"
|
upstream_url = "https://github.com/cptpiepmatz/nu-plugin-highlight"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = "ee5c049314cae074dffffddac5c1d4f7a6374b6a"
|
last_checked_commit = "ee5c049314cae074dffffddac5c1d4f7a6374b6a"
|
||||||
last_checked_date = "2025-09-20 14:35:04"
|
last_checked_date = "2025-09-20 18:38:38"
|
||||||
status = "pending"
|
status = "pending"
|
||||||
auto_ok_on_nu_deps_only = true
|
auto_ok_on_nu_deps_only = true
|
||||||
local_path = "nu_plugin_highlight"
|
local_path = "nu_plugin_highlight"
|
||||||
@ -129,7 +129,7 @@ description = "Syntax highlighting plugin for nushell"
|
|||||||
upstream_url = "https://github.com/FMotalleb/nu_plugin_clipboard"
|
upstream_url = "https://github.com/FMotalleb/nu_plugin_clipboard"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = "ffb98a64720ac18329f578eac9a751dbc99951b5"
|
last_checked_commit = "ffb98a64720ac18329f578eac9a751dbc99951b5"
|
||||||
last_checked_date = "2025-09-20 14:35:06"
|
last_checked_date = "2025-09-20 18:38:39"
|
||||||
status = "pending"
|
status = "pending"
|
||||||
auto_ok_on_nu_deps_only = true
|
auto_ok_on_nu_deps_only = true
|
||||||
local_path = "nu_plugin_clipboard"
|
local_path = "nu_plugin_clipboard"
|
||||||
@ -141,7 +141,7 @@ upstream_url = ""
|
|||||||
upstream_branch = ""
|
upstream_branch = ""
|
||||||
last_checked_commit = ""
|
last_checked_commit = ""
|
||||||
last_checked_date = ""
|
last_checked_date = ""
|
||||||
status = "local_only"
|
status = "ok"
|
||||||
auto_ok_on_nu_deps_only = false
|
auto_ok_on_nu_deps_only = false
|
||||||
local_path = "nu_plugin_image"
|
local_path = "nu_plugin_image"
|
||||||
has_local_changes = true
|
has_local_changes = true
|
||||||
@ -152,7 +152,7 @@ upstream_url = ""
|
|||||||
upstream_branch = ""
|
upstream_branch = ""
|
||||||
last_checked_commit = ""
|
last_checked_commit = ""
|
||||||
last_checked_date = ""
|
last_checked_date = ""
|
||||||
status = "local_only"
|
status = "ok"
|
||||||
auto_ok_on_nu_deps_only = false
|
auto_ok_on_nu_deps_only = false
|
||||||
local_path = "nu_plugin_hashes"
|
local_path = "nu_plugin_hashes"
|
||||||
has_local_changes = true
|
has_local_changes = true
|
||||||
@ -163,18 +163,18 @@ upstream_url = ""
|
|||||||
upstream_branch = ""
|
upstream_branch = ""
|
||||||
last_checked_commit = ""
|
last_checked_commit = ""
|
||||||
last_checked_date = ""
|
last_checked_date = ""
|
||||||
status = "local_only"
|
status = "ok"
|
||||||
auto_ok_on_nu_deps_only = false
|
auto_ok_on_nu_deps_only = false
|
||||||
local_path = "nu_plugin_desktop_notifications"
|
local_path = "nu_plugin_desktop_notifications"
|
||||||
has_local_changes = true
|
has_local_changes = true
|
||||||
description = "Desktop notifications plugin for nushell (local development)"
|
description = "Desktop notifications plugin for nushell (local development)"
|
||||||
|
|
||||||
["plugins.nu_plugin_fluent"]
|
["plugins.nu_plugin_fluent"]
|
||||||
upstream_url = "https://github.com/YourUsername/nu_plugin_fluent"
|
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_fluent.git"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = ""
|
last_checked_commit = "7f11208aef1ad6db0530ce5e15402d52e326daea"
|
||||||
last_checked_date = ""
|
last_checked_date = "2025-09-20 18:38:40"
|
||||||
status = "error"
|
status = "pending"
|
||||||
auto_ok_on_nu_deps_only = true
|
auto_ok_on_nu_deps_only = true
|
||||||
local_path = "nu_plugin_fluent"
|
local_path = "nu_plugin_fluent"
|
||||||
has_local_changes = true
|
has_local_changes = true
|
||||||
@ -183,8 +183,8 @@ description = "Fluent localization plugin for nushell"
|
|||||||
["plugins.nu_plugin_tera"]
|
["plugins.nu_plugin_tera"]
|
||||||
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_tera.git"
|
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_tera.git"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = "da1ee63a250bfa4ee3c32e846f22b53c00a1385f"
|
last_checked_commit = "714e70e5593243b4bf6e25724c1d4aab308d3aab"
|
||||||
last_checked_date = "2025-09-20 14:35:07"
|
last_checked_date = "2025-09-20 18:38:40"
|
||||||
status = "ok"
|
status = "ok"
|
||||||
auto_ok_on_nu_deps_only = true
|
auto_ok_on_nu_deps_only = true
|
||||||
local_path = "nu_plugin_tera"
|
local_path = "nu_plugin_tera"
|
||||||
@ -194,8 +194,8 @@ description = "Tera templating plugin for nushell (private repo)"
|
|||||||
["plugins.nu_plugin_kcl"]
|
["plugins.nu_plugin_kcl"]
|
||||||
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_kcl.git"
|
upstream_url = "ssh://git@repo.jesusperez.pro:32225/jesus/nu_plugin_kcl.git"
|
||||||
upstream_branch = "main"
|
upstream_branch = "main"
|
||||||
last_checked_commit = "02870456387c94bfd68fd26f6bf0cfaf8b3accff"
|
last_checked_commit = "1e6df05931fb6f771e4805fd7d71a841ee301b62"
|
||||||
last_checked_date = "2025-09-20 14:35:08"
|
last_checked_date = "2025-09-20 18:38:41"
|
||||||
status = "ok"
|
status = "ok"
|
||||||
auto_ok_on_nu_deps_only = true
|
auto_ok_on_nu_deps_only = true
|
||||||
local_path = "nu_plugin_kcl"
|
local_path = "nu_plugin_kcl"
|
||||||
|
476
install.sh
Executable file
476
install.sh
Executable file
@ -0,0 +1,476 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Universal Installer for Nushell Plugins
|
||||||
|
# Downloads and installs the latest release of nushell plugins for your platform
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
REPO_OWNER="YOUR_ORG" # Replace with actual GitHub org/user
|
||||||
|
REPO_NAME="nushell-plugins"
|
||||||
|
GITHUB_REPO="${REPO_OWNER}/${REPO_NAME}"
|
||||||
|
BASE_URL="https://github.com/${GITHUB_REPO}"
|
||||||
|
API_URL="https://api.github.com/repos/${GITHUB_REPO}"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
INSTALL_DIR="/usr/local/bin"
|
||||||
|
VERSION=""
|
||||||
|
PLATFORM=""
|
||||||
|
FORCE=false
|
||||||
|
DRY_RUN=false
|
||||||
|
QUIET=false
|
||||||
|
TEMP_DIR=""
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
log() {
|
||||||
|
if [ "$QUIET" != "true" ]; then
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat << EOF
|
||||||
|
Universal Installer for Nushell Plugins
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
$0 [OPTIONS]
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-d, --install-dir DIR Installation directory (default: /usr/local/bin)
|
||||||
|
-v, --version VERSION Specific version to install (default: latest)
|
||||||
|
-p, --platform PLATFORM Force specific platform (auto-detected by default)
|
||||||
|
-f, --force Force installation even if already installed
|
||||||
|
--dry-run Show what would be done without doing it
|
||||||
|
--quiet Suppress non-essential output
|
||||||
|
-h, --help Show this help message
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
# Install latest version to default location
|
||||||
|
$0
|
||||||
|
|
||||||
|
# Install to custom directory
|
||||||
|
$0 --install-dir ~/.local/bin
|
||||||
|
|
||||||
|
# Install specific version
|
||||||
|
$0 --version v1.2.3
|
||||||
|
|
||||||
|
# Force specific platform
|
||||||
|
$0 --platform linux-amd64
|
||||||
|
|
||||||
|
PLATFORMS:
|
||||||
|
linux-amd64 Linux x86_64
|
||||||
|
linux-arm64 Linux ARM64
|
||||||
|
darwin-amd64 macOS Intel
|
||||||
|
darwin-arm64 macOS Apple Silicon
|
||||||
|
windows-amd64 Windows x86_64
|
||||||
|
|
||||||
|
REQUIREMENTS:
|
||||||
|
- curl or wget
|
||||||
|
- tar (for Unix-like systems)
|
||||||
|
- nushell (nu command should be available)
|
||||||
|
- Write permissions to installation directory
|
||||||
|
|
||||||
|
MORE INFO:
|
||||||
|
Repository: ${BASE_URL}
|
||||||
|
Releases: ${BASE_URL}/releases
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Platform detection
|
||||||
|
detect_platform() {
|
||||||
|
local os=""
|
||||||
|
local arch=""
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux*) os="linux" ;;
|
||||||
|
Darwin*) os="darwin" ;;
|
||||||
|
CYGWIN*|MINGW*|MSYS*) os="windows" ;;
|
||||||
|
*)
|
||||||
|
error "Unsupported operating system: $(uname -s)"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Detect architecture
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) arch="amd64" ;;
|
||||||
|
aarch64|arm64) arch="arm64" ;;
|
||||||
|
armv7l) arch="arm32" ;;
|
||||||
|
*)
|
||||||
|
error "Unsupported architecture: $(uname -m)"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "${os}-${arch}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if command exists
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
check_prerequisites() {
|
||||||
|
log "Checking prerequisites..."
|
||||||
|
|
||||||
|
# Check for download tools
|
||||||
|
if ! command_exists curl && ! command_exists wget; then
|
||||||
|
error "Neither curl nor wget found. Please install one of them."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for tar (Unix-like systems)
|
||||||
|
if [ "$PLATFORM" != "windows-amd64" ] && ! command_exists tar; then
|
||||||
|
error "tar command not found. Please install tar."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for nushell
|
||||||
|
if ! command_exists nu; then
|
||||||
|
warn "nushell (nu) not found in PATH. You'll need to install nushell to use these plugins."
|
||||||
|
warn "Visit: https://www.nushell.sh/book/installation.html"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check write permissions
|
||||||
|
if [ ! -w "$(dirname "$INSTALL_DIR")" ]; then
|
||||||
|
error "No write permission to $(dirname "$INSTALL_DIR")"
|
||||||
|
error "Try running with sudo or choose a different directory with --install-dir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download file
|
||||||
|
download_file() {
|
||||||
|
local url="$1"
|
||||||
|
local output="$2"
|
||||||
|
|
||||||
|
log "Downloading: $url"
|
||||||
|
|
||||||
|
if command_exists curl; then
|
||||||
|
curl -L --fail --progress-bar "$url" -o "$output"
|
||||||
|
elif command_exists wget; then
|
||||||
|
wget --progress=bar:force:noscroll "$url" -O "$output"
|
||||||
|
else
|
||||||
|
error "No download tool available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get latest release info
|
||||||
|
get_latest_release() {
|
||||||
|
local api_url="${API_URL}/releases/latest"
|
||||||
|
|
||||||
|
log "Fetching latest release information..."
|
||||||
|
|
||||||
|
if command_exists curl; then
|
||||||
|
curl -s "$api_url"
|
||||||
|
elif command_exists wget; then
|
||||||
|
wget -qO- "$api_url"
|
||||||
|
else
|
||||||
|
error "No download tool available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get specific release info
|
||||||
|
get_release_info() {
|
||||||
|
local version="$1"
|
||||||
|
local api_url="${API_URL}/releases/tags/${version}"
|
||||||
|
|
||||||
|
log "Fetching release information for ${version}..."
|
||||||
|
|
||||||
|
if command_exists curl; then
|
||||||
|
curl -s "$api_url"
|
||||||
|
elif command_exists wget; then
|
||||||
|
wget -qO- "$api_url"
|
||||||
|
else
|
||||||
|
error "No download tool available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse JSON (simple parsing for our needs)
|
||||||
|
parse_json_value() {
|
||||||
|
local json="$1"
|
||||||
|
local key="$2"
|
||||||
|
|
||||||
|
echo "$json" | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find download URL for platform
|
||||||
|
find_download_url() {
|
||||||
|
local release_json="$1"
|
||||||
|
local platform="$2"
|
||||||
|
|
||||||
|
# Look for asset with platform name
|
||||||
|
echo "$release_json" | grep -o '"browser_download_url":"[^"]*"' | \
|
||||||
|
grep "$platform" | \
|
||||||
|
head -1 | \
|
||||||
|
sed 's/"browser_download_url":"\([^"]*\)"/\1/'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract archive
|
||||||
|
extract_archive() {
|
||||||
|
local archive="$1"
|
||||||
|
local dest_dir="$2"
|
||||||
|
|
||||||
|
log "Extracting archive to $dest_dir..."
|
||||||
|
|
||||||
|
case "$archive" in
|
||||||
|
*.tar.gz)
|
||||||
|
tar -xzf "$archive" -C "$dest_dir"
|
||||||
|
;;
|
||||||
|
*.zip)
|
||||||
|
if command_exists unzip; then
|
||||||
|
unzip -q "$archive" -d "$dest_dir"
|
||||||
|
else
|
||||||
|
error "unzip command not found. Please install unzip to extract .zip files."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unsupported archive format: $archive"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install plugins
|
||||||
|
install_plugins() {
|
||||||
|
local extract_dir="$1"
|
||||||
|
|
||||||
|
log "Installing plugins to $INSTALL_DIR..."
|
||||||
|
|
||||||
|
# Find the extracted directory (might be nested)
|
||||||
|
local plugin_dir=""
|
||||||
|
if [ -d "$extract_dir" ]; then
|
||||||
|
# Look for nu_plugin_* files directly or in subdirectories
|
||||||
|
plugin_dir=$(find "$extract_dir" -name "nu_plugin_*" -type f -executable | head -1 | xargs dirname)
|
||||||
|
|
||||||
|
if [ -z "$plugin_dir" ]; then
|
||||||
|
# Try to find a directory with plugins
|
||||||
|
plugin_dir=$(find "$extract_dir" -type d -name "*nushell-plugins*" | head -1)
|
||||||
|
if [ -z "$plugin_dir" ]; then
|
||||||
|
plugin_dir="$extract_dir"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$plugin_dir" ]; then
|
||||||
|
error "Could not find plugin directory in extracted archive"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Found plugins in: $plugin_dir"
|
||||||
|
|
||||||
|
# Create install directory if it doesn't exist
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
|
||||||
|
# Copy plugin binaries
|
||||||
|
local installed_count=0
|
||||||
|
for plugin in "$plugin_dir"/nu_plugin_*; do
|
||||||
|
if [ -f "$plugin" ] && [ -x "$plugin" ]; then
|
||||||
|
local plugin_name=$(basename "$plugin")
|
||||||
|
local dest_path="$INSTALL_DIR/$plugin_name"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
log "Would install: $plugin_name -> $dest_path"
|
||||||
|
else
|
||||||
|
log "Installing: $plugin_name"
|
||||||
|
cp "$plugin" "$dest_path"
|
||||||
|
chmod +x "$dest_path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
installed_count=$((installed_count + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $installed_count -eq 0 ]; then
|
||||||
|
error "No plugin binaries found to install"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
success "Installed $installed_count plugins"
|
||||||
|
|
||||||
|
# Copy installation script if available
|
||||||
|
if [ -f "$plugin_dir/install_nu_plugins.nu" ] && [ "$DRY_RUN" != "true" ]; then
|
||||||
|
log "Running nushell installation script..."
|
||||||
|
if command_exists nu; then
|
||||||
|
cd "$plugin_dir"
|
||||||
|
nu install_nu_plugins.nu --bin-path "$INSTALL_DIR" || {
|
||||||
|
warn "Installation script failed, but binaries were copied"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
warn "Nushell not available, skipping automatic plugin registration"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup temporary files
|
||||||
|
cleanup() {
|
||||||
|
if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
|
||||||
|
log "Cleaning up temporary files..."
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main installation function
|
||||||
|
main() {
|
||||||
|
# Set up cleanup trap
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
log "Nushell Plugins Universal Installer"
|
||||||
|
log "Repository: $GITHUB_REPO"
|
||||||
|
|
||||||
|
# Auto-detect platform if not specified
|
||||||
|
if [ -z "$PLATFORM" ]; then
|
||||||
|
PLATFORM=$(detect_platform)
|
||||||
|
log "Detected platform: $PLATFORM"
|
||||||
|
else
|
||||||
|
log "Using specified platform: $PLATFORM"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
check_prerequisites
|
||||||
|
|
||||||
|
# Get release information
|
||||||
|
local release_json=""
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
log "Getting latest release..."
|
||||||
|
release_json=$(get_latest_release)
|
||||||
|
VERSION=$(parse_json_value "$release_json" "tag_name")
|
||||||
|
else
|
||||||
|
log "Getting release $VERSION..."
|
||||||
|
release_json=$(get_release_info "$VERSION")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$release_json" ] || [ "$release_json" = "null" ]; then
|
||||||
|
error "Failed to get release information"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Version: $VERSION"
|
||||||
|
|
||||||
|
# Find download URL
|
||||||
|
local download_url=$(find_download_url "$release_json" "$PLATFORM")
|
||||||
|
|
||||||
|
if [ -z "$download_url" ]; then
|
||||||
|
error "No download found for platform: $PLATFORM"
|
||||||
|
error "Available platforms can be found at: ${BASE_URL}/releases/tag/${VERSION}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Download URL: $download_url"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
log "DRY RUN: Would download and install from $download_url"
|
||||||
|
log "DRY RUN: Would install to $INSTALL_DIR"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create temporary directory
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
local archive_name=$(basename "$download_url")
|
||||||
|
local archive_path="$TEMP_DIR/$archive_name"
|
||||||
|
|
||||||
|
# Download archive
|
||||||
|
download_file "$download_url" "$archive_path"
|
||||||
|
|
||||||
|
# Verify download
|
||||||
|
if [ ! -f "$archive_path" ]; then
|
||||||
|
error "Download failed: $archive_path not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract archive
|
||||||
|
extract_archive "$archive_path" "$TEMP_DIR"
|
||||||
|
|
||||||
|
# Install plugins
|
||||||
|
install_plugins "$TEMP_DIR"
|
||||||
|
|
||||||
|
success "Installation completed successfully!"
|
||||||
|
|
||||||
|
# Show next steps
|
||||||
|
echo ""
|
||||||
|
echo "🎉 Nushell plugins have been installed to: $INSTALL_DIR"
|
||||||
|
echo ""
|
||||||
|
echo "📝 Next steps:"
|
||||||
|
echo " 1. Make sure $INSTALL_DIR is in your PATH"
|
||||||
|
echo " 2. In nushell, register plugins with:"
|
||||||
|
|
||||||
|
# List installed plugins
|
||||||
|
for plugin in "$INSTALL_DIR"/nu_plugin_*; do
|
||||||
|
if [ -f "$plugin" ] && [ -x "$plugin" ]; then
|
||||||
|
echo " plugin add $plugin"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "💡 Or run this one-liner in nushell:"
|
||||||
|
echo " ls $INSTALL_DIR/nu_plugin_* | each { |plugin| plugin add \$plugin.name }"
|
||||||
|
echo ""
|
||||||
|
echo "🔗 More info: ${BASE_URL}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-d|--install-dir)
|
||||||
|
INSTALL_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v|--version)
|
||||||
|
VERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-p|--platform)
|
||||||
|
PLATFORM="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-f|--force)
|
||||||
|
FORCE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
DRY_RUN=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--quiet)
|
||||||
|
QUIET=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown option: $1"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
464
scripts/build_cross.nu
Normal file
464
scripts/build_cross.nu
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
#!/usr/bin/env nu
|
||||||
|
|
||||||
|
# Cross-Platform Build Script for Nushell Plugins
|
||||||
|
# Orchestrates cross-compilation for multiple platforms using Rust targets and Docker
|
||||||
|
|
||||||
|
# Version check - mandatory for all plugin operations
|
||||||
|
def version_check [] {
|
||||||
|
try {
|
||||||
|
nu scripts/check_version.nu --quiet | ignore
|
||||||
|
} catch {
|
||||||
|
print "❌ Nushell version mismatch detected!"
|
||||||
|
print "🔧 Run: nu scripts/check_version.nu --fix"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load build targets configuration
|
||||||
|
def load_targets_config [] {
|
||||||
|
if not ("etc/build_targets.toml" | path exists) {
|
||||||
|
error make {msg: "Build targets configuration not found: etc/build_targets.toml"}
|
||||||
|
}
|
||||||
|
|
||||||
|
open etc/build_targets.toml
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get host platform information
|
||||||
|
def get_host_info [] {
|
||||||
|
let arch = match (uname -m) {
|
||||||
|
"x86_64" => "amd64",
|
||||||
|
"aarch64" => "arm64",
|
||||||
|
"arm64" => "arm64",
|
||||||
|
$arch if ($arch | str starts-with "arm") => "arm64",
|
||||||
|
$other => $other
|
||||||
|
}
|
||||||
|
|
||||||
|
let platform = match (uname -s | str downcase) {
|
||||||
|
$os if ($os | str contains "linux") => "linux",
|
||||||
|
$os if ($os | str contains "darwin") => "darwin",
|
||||||
|
$os if ($os | str contains "windows") => "windows",
|
||||||
|
$other => $other
|
||||||
|
}
|
||||||
|
|
||||||
|
{platform: $platform, arch: $arch, full: $"($platform)-($arch)"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate if target can be built on current host
|
||||||
|
def validate_target [target: record, host_info: record] {
|
||||||
|
# Check if target requires specific host
|
||||||
|
if ($target | get host_required? | default null) != null {
|
||||||
|
if $target.host_required != $host_info.platform {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: $"Target requires ($target.host_required) host, but running on ($host_info.platform)"
|
||||||
|
suggestion: "Use Docker build or switch to appropriate host"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if native build is possible
|
||||||
|
if $target.native_build and not $target.docker_required {
|
||||||
|
# Check if rust target is installed
|
||||||
|
let installed_targets = (rustup target list --installed | lines)
|
||||||
|
if not ($target.rust_target in $installed_targets) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: $"Rust target ($target.rust_target) not installed"
|
||||||
|
suggestion: $"Run: rustup target add ($target.rust_target)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{valid: true, reason: null, suggestion: null}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get all plugin directories
|
||||||
|
def get_plugin_directories [] {
|
||||||
|
glob "nu_plugin_*" | where ($it | path type) == "dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build a single plugin for a specific target
|
||||||
|
def build_plugin_for_target [
|
||||||
|
plugin_dir: string,
|
||||||
|
target: record,
|
||||||
|
use_docker: bool = false,
|
||||||
|
verbose: bool = false
|
||||||
|
] {
|
||||||
|
print $"🔨 Building ($plugin_dir) for ($target.platform_name)..."
|
||||||
|
|
||||||
|
let start_time = date now
|
||||||
|
let original_dir = pwd
|
||||||
|
|
||||||
|
try {
|
||||||
|
cd $plugin_dir
|
||||||
|
|
||||||
|
mut build_cmd = ["cargo", "build", "--release"]
|
||||||
|
|
||||||
|
if not $use_docker {
|
||||||
|
$build_cmd = ($build_cmd | append ["--target", $target.rust_target])
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set environment variables if specified
|
||||||
|
let config = load_targets_config
|
||||||
|
let env_vars = $config.environment? | default {}
|
||||||
|
let target_env = $env_vars | get $target.platform_name? | default {}
|
||||||
|
|
||||||
|
mut env_settings = []
|
||||||
|
for var in ($target_env | transpose key value) {
|
||||||
|
$env_settings = ($env_settings | append $"($var.key)=($var.value)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if $verbose {
|
||||||
|
print $" Command: ($build_cmd | str join ' ')"
|
||||||
|
if ($env_settings | length) > 0 {
|
||||||
|
print $" Environment: ($env_settings | str join ', ')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute build command
|
||||||
|
if $use_docker {
|
||||||
|
# Docker build will be handled by build_docker_cross.nu
|
||||||
|
let docker_result = nu ../scripts/build_docker_cross.nu --target $target.platform_name --plugin $plugin_dir
|
||||||
|
if $docker_result.exit_code != 0 {
|
||||||
|
error make {msg: $"Docker build failed for ($plugin_dir)"}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Native cross-compilation
|
||||||
|
with-env ($target_env) {
|
||||||
|
run-external "cargo" ...$build_cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cd $original_dir
|
||||||
|
let end_time = date now
|
||||||
|
let duration = $end_time - $start_time
|
||||||
|
|
||||||
|
print $"✅ Built ($plugin_dir) for ($target.platform_name) in ($duration)"
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin: $plugin_dir,
|
||||||
|
target: $target.platform_name,
|
||||||
|
status: "success",
|
||||||
|
duration: $duration,
|
||||||
|
error: null
|
||||||
|
}
|
||||||
|
} catch {|err|
|
||||||
|
cd $original_dir
|
||||||
|
print $"❌ Error building ($plugin_dir) for ($target.platform_name): ($err.msg)"
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin: $plugin_dir,
|
||||||
|
target: $target.platform_name,
|
||||||
|
status: "error",
|
||||||
|
duration: null,
|
||||||
|
error: $err.msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Docker is available and running
|
||||||
|
def check_docker [] {
|
||||||
|
try {
|
||||||
|
docker --version | ignore
|
||||||
|
docker info | ignore
|
||||||
|
true
|
||||||
|
} catch {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install missing Rust targets
|
||||||
|
def install_rust_targets [targets: list<string>] {
|
||||||
|
print "🦀 Installing missing Rust targets..."
|
||||||
|
|
||||||
|
let installed = (rustup target list --installed | lines)
|
||||||
|
let missing = ($targets | where $it not-in $installed)
|
||||||
|
|
||||||
|
if ($missing | length) > 0 {
|
||||||
|
print $"📥 Installing targets: ($missing | str join ', ')"
|
||||||
|
for target in $missing {
|
||||||
|
print $" Installing ($target)..."
|
||||||
|
rustup target add $target
|
||||||
|
}
|
||||||
|
print "✅ All targets installed"
|
||||||
|
} else {
|
||||||
|
print "✅ All required targets already installed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get binary path for a plugin and target
|
||||||
|
def get_binary_path [plugin_dir: string, target: record] {
|
||||||
|
let binary_name = if ($target | get binary_extension? | default "") != "" {
|
||||||
|
$"($plugin_dir)($target.binary_extension)"
|
||||||
|
} else {
|
||||||
|
$plugin_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
$"($plugin_dir)/target/($target.rust_target)/release/($binary_name)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify built binaries exist
|
||||||
|
def verify_built_binaries [results: list<record>] {
|
||||||
|
print "🔍 Verifying built binaries..."
|
||||||
|
|
||||||
|
let config = load_targets_config
|
||||||
|
mut verification_results = []
|
||||||
|
|
||||||
|
for result in $results {
|
||||||
|
if $result.status == "success" {
|
||||||
|
let target_config = $config.targets | get $result.target
|
||||||
|
let binary_path = get_binary_path $result.plugin $target_config
|
||||||
|
|
||||||
|
if ($binary_path | path exists) {
|
||||||
|
let size = (ls $binary_path | get 0.size)
|
||||||
|
print $" ✅ ($result.plugin) → ($result.target): ($size)"
|
||||||
|
$verification_results = ($verification_results | append {
|
||||||
|
plugin: $result.plugin,
|
||||||
|
target: $result.target,
|
||||||
|
binary_path: $binary_path,
|
||||||
|
size: $size,
|
||||||
|
verified: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
print $" ❌ ($result.plugin) → ($result.target): Binary not found at ($binary_path)"
|
||||||
|
$verification_results = ($verification_results | append {
|
||||||
|
plugin: $result.plugin,
|
||||||
|
target: $result.target,
|
||||||
|
binary_path: $binary_path,
|
||||||
|
size: null,
|
||||||
|
verified: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$verification_results
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main function
|
||||||
|
def main [
|
||||||
|
--targets (-t): list<string> = [] # Specific targets to build (e.g., linux-amd64, darwin-arm64)
|
||||||
|
--all-targets (-a) # Build for all enabled targets
|
||||||
|
--plugins (-p): list<string> = [] # Specific plugins to build
|
||||||
|
--docker (-d) # Force use of Docker for all builds
|
||||||
|
--native (-n) # Force native compilation (fail if not possible)
|
||||||
|
--parallel # Build plugins in parallel (experimental)
|
||||||
|
--install-targets # Install missing Rust targets automatically
|
||||||
|
--verbose (-v) # Verbose output
|
||||||
|
--dry-run # Show what would be built without building
|
||||||
|
--list-targets (-l) # List available targets and exit
|
||||||
|
] {
|
||||||
|
# Mandatory version check
|
||||||
|
version_check
|
||||||
|
|
||||||
|
# Ensure we're in the repository root
|
||||||
|
if not ("nu_plugin_clipboard" | path exists) {
|
||||||
|
error make {msg: "Please run this script from the nushell-plugins repository root directory"}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "🚀 Nushell Plugins Cross-Platform Build System"
|
||||||
|
|
||||||
|
# Load configuration
|
||||||
|
let config = load_targets_config
|
||||||
|
let host_info = get_host_info
|
||||||
|
|
||||||
|
print $"🖥️ Host: ($host_info.full)"
|
||||||
|
|
||||||
|
# List targets mode
|
||||||
|
if $list_targets {
|
||||||
|
print "\n📋 Available build targets:"
|
||||||
|
for target_name in ($config.targets | transpose name config | get name) {
|
||||||
|
let target_config = $config.targets | get $target_name
|
||||||
|
let enabled = $target_config | get enabled? | default true
|
||||||
|
let status = if $enabled { "✅" } else { "❌" }
|
||||||
|
print $" ($status) ($target_name): ($target_config.description)"
|
||||||
|
print $" Rust target: ($target_config.rust_target)"
|
||||||
|
print $" Docker required: ($target_config.docker_required)"
|
||||||
|
print $" Native build: ($target_config.native_build)"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine targets to build
|
||||||
|
let available_targets = $config.targets | transpose name config
|
||||||
|
let enabled_targets = $available_targets | where ($it.config | get enabled? | default true)
|
||||||
|
|
||||||
|
mut targets_to_build = if $all_targets {
|
||||||
|
$enabled_targets
|
||||||
|
} else if ($targets | length) > 0 {
|
||||||
|
$enabled_targets | where $it.name in $targets
|
||||||
|
} else {
|
||||||
|
# Default to host platform if available
|
||||||
|
let host_target = $enabled_targets | where $it.name == $host_info.full
|
||||||
|
if ($host_target | length) > 0 {
|
||||||
|
$host_target
|
||||||
|
} else {
|
||||||
|
# Fallback to first enabled target
|
||||||
|
$enabled_targets | first 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($targets_to_build | length) == 0 {
|
||||||
|
print "❓ No targets to build"
|
||||||
|
if ($targets | length) > 0 {
|
||||||
|
print $"💡 Available targets: ($enabled_targets | get name | str join ', ')"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine plugins to build
|
||||||
|
let all_plugins = get_plugin_directories
|
||||||
|
let plugins_to_build = if ($plugins | length) > 0 {
|
||||||
|
$all_plugins | where $it in $plugins
|
||||||
|
} else {
|
||||||
|
$all_plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($plugins_to_build | length) == 0 {
|
||||||
|
print "❓ No plugins to build"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"\n📦 Plugins to build: ($plugins_to_build | length)"
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
print $" - ($plugin)"
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"\n🎯 Targets to build: ($targets_to_build | length)"
|
||||||
|
for target in $targets_to_build {
|
||||||
|
print $" - ($target.name): ($target.config.description)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dry run mode
|
||||||
|
if $dry_run {
|
||||||
|
print "\n🔍 Dry run - showing build matrix:"
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for target in $targets_to_build {
|
||||||
|
let method = if $docker or $target.config.docker_required { "Docker" } else { "Native" }
|
||||||
|
print $" ($plugin) × ($target.name) → ($method)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
let docker_available = check_docker
|
||||||
|
print $"\n🔧 Prerequisites:"
|
||||||
|
print $" Docker: (if $docker_available { '✅' } else { '❌' })"
|
||||||
|
print $" Rust: ✅"
|
||||||
|
|
||||||
|
# Validate targets and collect required Rust targets
|
||||||
|
mut rust_targets_needed = []
|
||||||
|
mut valid_builds = []
|
||||||
|
|
||||||
|
for target in $targets_to_build {
|
||||||
|
let validation = validate_target $target.config $host_info
|
||||||
|
let use_docker = $docker or $target.config.docker_required or (not $validation.valid)
|
||||||
|
|
||||||
|
if $native and $use_docker {
|
||||||
|
print $"❌ Cannot build ($target.name) natively: ($validation.reason)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if $use_docker and not $docker_available {
|
||||||
|
print $"❌ Docker required for ($target.name) but Docker not available"
|
||||||
|
print $"💡 ($validation.suggestion)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if not $use_docker and $validation.valid {
|
||||||
|
$rust_targets_needed = ($rust_targets_needed | append $target.config.rust_target)
|
||||||
|
}
|
||||||
|
|
||||||
|
$valid_builds = ($valid_builds | append {
|
||||||
|
target: $target,
|
||||||
|
use_docker: $use_docker,
|
||||||
|
validation: $validation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install missing Rust targets
|
||||||
|
if ($rust_targets_needed | length) > 0 and $install_targets {
|
||||||
|
install_rust_targets $rust_targets_needed
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build plugins
|
||||||
|
print $"\n🔨 Starting builds..."
|
||||||
|
let start_time = date now
|
||||||
|
mut all_results = []
|
||||||
|
|
||||||
|
if $parallel {
|
||||||
|
print "⚡ Building in parallel mode..."
|
||||||
|
# Build all plugin-target combinations in parallel
|
||||||
|
let build_jobs = []
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for build in $valid_builds {
|
||||||
|
$build_jobs = ($build_jobs | append {
|
||||||
|
plugin: $plugin,
|
||||||
|
target: $build.target.config,
|
||||||
|
use_docker: $build.use_docker
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_results = ($build_jobs | par-each {|job|
|
||||||
|
build_plugin_for_target $job.plugin $job.target $job.use_docker $verbose
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
# Sequential builds
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for build in $valid_builds {
|
||||||
|
let result = build_plugin_for_target $plugin $build.target.config $build.use_docker $verbose
|
||||||
|
$all_results = ($all_results | append $result)
|
||||||
|
print "---"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let end_time = date now
|
||||||
|
let total_duration = $end_time - $start_time
|
||||||
|
|
||||||
|
# Verify binaries
|
||||||
|
print "\n🔍 Verification:"
|
||||||
|
let verification = verify_built_binaries $all_results
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print "\n📊 Build Summary:"
|
||||||
|
let successful = $all_results | where status == "success"
|
||||||
|
let failed = $all_results | where status == "error"
|
||||||
|
let verified = $verification | where verified == true
|
||||||
|
|
||||||
|
print $"✅ Successful builds: ($successful | length)"
|
||||||
|
print $"❌ Failed builds: ($failed | length)"
|
||||||
|
print $"🔍 Verified binaries: ($verified | length)"
|
||||||
|
print $"⏱️ Total time: ($total_duration)"
|
||||||
|
|
||||||
|
if ($failed | length) > 0 {
|
||||||
|
print "\n❌ Failed builds:"
|
||||||
|
for failure in $failed {
|
||||||
|
print $" - ($failure.plugin) → ($failure.target): ($failure.error)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($verified | length) > 0 {
|
||||||
|
print "\n✅ Built binaries:"
|
||||||
|
for binary in $verified {
|
||||||
|
print $" - ($binary.plugin) → ($binary.target): ($binary.size)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit with error if any builds failed
|
||||||
|
if ($failed | length) > 0 {
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
print "\n🎉 All builds completed successfully!"
|
||||||
|
print "💡 Next steps:"
|
||||||
|
print " - Collect binaries: just collect"
|
||||||
|
print " - Create packages: just pack"
|
||||||
|
print " - Test binaries: just test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
|
||||||
|
main
|
||||||
|
}
|
476
scripts/build_docker_cross.nu
Normal file
476
scripts/build_docker_cross.nu
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
#!/usr/bin/env nu
|
||||||
|
|
||||||
|
# Docker Cross-Compilation Manager for Nushell Plugins
|
||||||
|
# Manages Docker-based cross-compilation environment and builds
|
||||||
|
|
||||||
|
# Load build targets configuration
|
||||||
|
def load_targets_config [] {
|
||||||
|
if not ("etc/build_targets.toml" | path exists) {
|
||||||
|
error make {msg: "Build targets configuration not found: etc/build_targets.toml"}
|
||||||
|
}
|
||||||
|
open etc/build_targets.toml
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Docker is available and running
|
||||||
|
def check_docker [] {
|
||||||
|
try {
|
||||||
|
let version = (docker --version | complete)
|
||||||
|
if $version.exit_code != 0 {
|
||||||
|
return {available: false, reason: "Docker command failed"}
|
||||||
|
}
|
||||||
|
|
||||||
|
let info = (docker info | complete)
|
||||||
|
if $info.exit_code != 0 {
|
||||||
|
return {available: false, reason: "Docker daemon not running"}
|
||||||
|
}
|
||||||
|
|
||||||
|
{available: true, reason: null}
|
||||||
|
} catch {|err|
|
||||||
|
{available: false, reason: $"Docker not found: ($err.msg)"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build the Docker cross-compilation image
|
||||||
|
def build_docker_image [
|
||||||
|
--force (-f) # Force rebuild of image
|
||||||
|
--no-cache # Don't use Docker build cache
|
||||||
|
--verbose (-v) # Verbose output
|
||||||
|
] {
|
||||||
|
let config = load_targets_config
|
||||||
|
let docker_config = $config.docker
|
||||||
|
let dockerfile = $docker_config.dockerfile
|
||||||
|
let image_tag = $docker_config.image_tag
|
||||||
|
|
||||||
|
print $"🐳 Building Docker cross-compilation image..."
|
||||||
|
print $"📄 Dockerfile: ($dockerfile)"
|
||||||
|
print $"🏷️ Tag: ($image_tag)"
|
||||||
|
|
||||||
|
# Check if Dockerfile exists
|
||||||
|
if not ($dockerfile | path exists) {
|
||||||
|
error make {msg: $"Dockerfile not found: ($dockerfile)"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if image already exists
|
||||||
|
let existing_image = (docker images $image_tag --format "{{.Repository}}:{{.Tag}}" | complete)
|
||||||
|
if $existing_image.exit_code == 0 and ($existing_image.stdout | str trim | str length) > 0 and not $force {
|
||||||
|
print $"✅ Docker image already exists: ($image_tag)"
|
||||||
|
print "💡 Use --force to rebuild or --no-cache for fresh build"
|
||||||
|
return {success: true, image: $image_tag, rebuilt: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_time = date now
|
||||||
|
|
||||||
|
try {
|
||||||
|
mut build_args = ["docker", "build", "-f", $dockerfile, "-t", $image_tag]
|
||||||
|
|
||||||
|
if $no_cache {
|
||||||
|
$build_args = ($build_args | append "--no-cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add cache-from if specified
|
||||||
|
if ($docker_config.cache_from? | default [] | length) > 0 {
|
||||||
|
for cache in $docker_config.cache_from {
|
||||||
|
$build_args = ($build_args | append ["--cache-from", $cache])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add build args if specified
|
||||||
|
if ($docker_config.build_args? | default [] | length) > 0 {
|
||||||
|
for arg in $docker_config.build_args {
|
||||||
|
$build_args = ($build_args | append ["--build-arg", $arg])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$build_args = ($build_args | append ".")
|
||||||
|
|
||||||
|
if $verbose {
|
||||||
|
print $"🔨 Build command: ($build_args | str join ' ')"
|
||||||
|
}
|
||||||
|
|
||||||
|
print "🔨 Building Docker image (this may take several minutes)..."
|
||||||
|
let result = (run-external "docker" ...($build_args | skip 1))
|
||||||
|
|
||||||
|
let end_time = date now
|
||||||
|
let duration = $end_time - $start_time
|
||||||
|
|
||||||
|
print $"✅ Docker image built successfully: ($image_tag)"
|
||||||
|
print $"⏱️ Build time: ($duration)"
|
||||||
|
|
||||||
|
# Show image info
|
||||||
|
let image_info = (docker images $image_tag --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}")
|
||||||
|
print $"📊 Image info:"
|
||||||
|
print $image_info
|
||||||
|
|
||||||
|
{success: true, image: $image_tag, rebuilt: true, duration: $duration}
|
||||||
|
} catch {|err|
|
||||||
|
print $"❌ Failed to build Docker image: ($err.msg)"
|
||||||
|
{success: false, image: null, error: $err.msg}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get all plugin directories
|
||||||
|
def get_plugin_directories [] {
|
||||||
|
glob "nu_plugin_*" | where ($it | path type) == "dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build a single plugin in Docker for a specific target
|
||||||
|
def build_plugin_in_docker [
|
||||||
|
plugin_dir: string,
|
||||||
|
target_name: string,
|
||||||
|
image_tag: string,
|
||||||
|
verbose: bool = false
|
||||||
|
] {
|
||||||
|
let config = load_targets_config
|
||||||
|
let target_config = $config.targets | get $target_name
|
||||||
|
|
||||||
|
print $"🐳 Building ($plugin_dir) for ($target_name) in Docker..."
|
||||||
|
|
||||||
|
let start_time = date now
|
||||||
|
let work_dir = "/workspace"
|
||||||
|
let source_dir = $"/workspace/($plugin_dir)"
|
||||||
|
|
||||||
|
# Prepare Docker run command
|
||||||
|
mut docker_args = [
|
||||||
|
"docker", "run", "--rm",
|
||||||
|
"-v", $"(pwd):($work_dir)",
|
||||||
|
"-w", $source_dir,
|
||||||
|
$image_tag
|
||||||
|
]
|
||||||
|
|
||||||
|
# Set environment variables for the target
|
||||||
|
let env_vars = $config.environment? | default {}
|
||||||
|
let target_env = $env_vars | get $target_name? | default {}
|
||||||
|
|
||||||
|
for var in ($target_env | transpose key value) {
|
||||||
|
$docker_args = ($docker_args | append ["-e", $"($var.key)=($var.value)"])
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add common environment variables
|
||||||
|
$docker_args = ($docker_args | append [
|
||||||
|
"-e", "RUST_BACKTRACE=1",
|
||||||
|
"-e", "CARGO_INCREMENTAL=0"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Build command
|
||||||
|
let build_cmd = ["cargo", "build", "--release", "--target", $target_config.rust_target]
|
||||||
|
$docker_args = ($docker_args | append $build_cmd)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if $verbose {
|
||||||
|
print $" 🔨 Docker command: ($docker_args | str join ' ')"
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = (run-external "docker" ...($docker_args | skip 1))
|
||||||
|
|
||||||
|
let end_time = date now
|
||||||
|
let duration = $end_time - $start_time
|
||||||
|
|
||||||
|
# Check if binary was created
|
||||||
|
let binary_name = if ($target_config | get binary_extension? | default "") != "" {
|
||||||
|
$"($plugin_dir)($target_config.binary_extension)"
|
||||||
|
} else {
|
||||||
|
$plugin_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
let binary_path = $"($plugin_dir)/target/($target_config.rust_target)/release/($binary_name)"
|
||||||
|
|
||||||
|
if ($binary_path | path exists) {
|
||||||
|
let size = (ls $binary_path | get 0.size)
|
||||||
|
print $"✅ Built ($plugin_dir) for ($target_name) in ($duration) → ($size)"
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin: $plugin_dir,
|
||||||
|
target: $target_name,
|
||||||
|
status: "success",
|
||||||
|
duration: $duration,
|
||||||
|
binary_path: $binary_path,
|
||||||
|
size: $size,
|
||||||
|
error: null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error make {msg: $"Binary not found at expected path: ($binary_path)"}
|
||||||
|
}
|
||||||
|
} catch {|err|
|
||||||
|
let end_time = date now
|
||||||
|
let duration = $end_time - $start_time
|
||||||
|
|
||||||
|
print $"❌ Error building ($plugin_dir) for ($target_name): ($err.msg)"
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin: $plugin_dir,
|
||||||
|
target: $target_name,
|
||||||
|
status: "error",
|
||||||
|
duration: $duration,
|
||||||
|
binary_path: null,
|
||||||
|
size: null,
|
||||||
|
error: $err.msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean up Docker build artifacts
|
||||||
|
def cleanup_docker [
|
||||||
|
--images (-i) # Remove Docker images
|
||||||
|
--containers (-c) # Remove stopped containers
|
||||||
|
--volumes (-v) # Remove unused volumes
|
||||||
|
--all (-a) # Clean everything
|
||||||
|
] {
|
||||||
|
print "🧹 Cleaning up Docker artifacts..."
|
||||||
|
|
||||||
|
if $all or $containers {
|
||||||
|
print "🗑️ Removing stopped containers..."
|
||||||
|
try {
|
||||||
|
docker container prune -f
|
||||||
|
} catch {
|
||||||
|
print "⚠️ No containers to remove"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if $all or $volumes {
|
||||||
|
print "🗑️ Removing unused volumes..."
|
||||||
|
try {
|
||||||
|
docker volume prune -f
|
||||||
|
} catch {
|
||||||
|
print "⚠️ No volumes to remove"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if $all or $images {
|
||||||
|
print "🗑️ Removing unused images..."
|
||||||
|
try {
|
||||||
|
docker image prune -f
|
||||||
|
} catch {
|
||||||
|
print "⚠️ No images to remove"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "✅ Docker cleanup completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show Docker environment information
|
||||||
|
def show_docker_info [] {
|
||||||
|
let docker_status = check_docker
|
||||||
|
|
||||||
|
print "🐳 Docker Environment Information"
|
||||||
|
print $"Status: (if $docker_status.available { '✅ Available' } else { '❌ Not available' })"
|
||||||
|
|
||||||
|
if not $docker_status.available {
|
||||||
|
print $"Reason: ($docker_status.reason)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
print "\n📊 Docker Version:"
|
||||||
|
docker --version
|
||||||
|
|
||||||
|
print "\n💾 Docker System Info:"
|
||||||
|
docker system df
|
||||||
|
|
||||||
|
print "\n🖼️ Available Images:"
|
||||||
|
docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"
|
||||||
|
|
||||||
|
let config = load_targets_config
|
||||||
|
let image_tag = $config.docker.image_tag
|
||||||
|
|
||||||
|
print $"\n🎯 Cross-compilation Image Status:"
|
||||||
|
let image_exists = (docker images $image_tag --format "{{.Repository}}:{{.Tag}}" | complete)
|
||||||
|
if $image_exists.exit_code == 0 and ($image_exists.stdout | str trim | str length) > 0 {
|
||||||
|
print $"✅ Image exists: ($image_tag)"
|
||||||
|
let image_info = (docker images $image_tag --format "table {{.Size}}\t{{.CreatedAt}}")
|
||||||
|
print $image_info
|
||||||
|
} else {
|
||||||
|
print $"❌ Image not found: ($image_tag)"
|
||||||
|
print "💡 Run with --build-image to create it"
|
||||||
|
}
|
||||||
|
} catch {|err|
|
||||||
|
print $"❌ Error getting Docker info: ($err.msg)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main function
|
||||||
|
def main [
|
||||||
|
--target (-t): string = "" # Specific target to build for
|
||||||
|
--plugin (-p): string = "" # Specific plugin to build
|
||||||
|
--build-image (-b) # Build Docker image before building
|
||||||
|
--force-rebuild (-f) # Force rebuild of Docker image
|
||||||
|
--no-cache # Don't use Docker build cache
|
||||||
|
--parallel # Build plugins in parallel
|
||||||
|
--cleanup # Clean up Docker artifacts after build
|
||||||
|
--info (-i) # Show Docker environment info
|
||||||
|
--verbose (-v) # Verbose output
|
||||||
|
--dry-run # Show what would be built
|
||||||
|
] {
|
||||||
|
# Ensure we're in the repository root
|
||||||
|
if not ("nu_plugin_clipboard" | path exists) {
|
||||||
|
error make {msg: "Please run this script from the nushell-plugins repository root directory"}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "🐳 Docker Cross-Compilation Manager for Nushell Plugins"
|
||||||
|
|
||||||
|
# Check Docker availability
|
||||||
|
let docker_status = check_docker
|
||||||
|
if not $docker_status.available {
|
||||||
|
print $"❌ Docker not available: ($docker_status.reason)"
|
||||||
|
print "💡 Please install and start Docker to use cross-compilation"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Info mode
|
||||||
|
if $info {
|
||||||
|
show_docker_info
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = load_targets_config
|
||||||
|
let image_tag = $config.docker.image_tag
|
||||||
|
|
||||||
|
# Build Docker image if requested or if it doesn't exist
|
||||||
|
let image_exists = (docker images $image_tag --format "{{.Repository}}:{{.Tag}}" | complete)
|
||||||
|
let should_build_image = $build_image or $force_rebuild or (
|
||||||
|
$image_exists.exit_code != 0 or ($image_exists.stdout | str trim | str length) == 0
|
||||||
|
)
|
||||||
|
|
||||||
|
if $should_build_image {
|
||||||
|
let build_result = build_docker_image --force=$force_rebuild --no-cache=$no_cache --verbose=$verbose
|
||||||
|
if not $build_result.success {
|
||||||
|
print "❌ Failed to build Docker image, cannot proceed"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine targets and plugins
|
||||||
|
let available_targets = $config.targets | transpose name config | where ($it.config | get enabled? | default true)
|
||||||
|
let docker_targets = $available_targets | where $it.config.docker_required
|
||||||
|
|
||||||
|
let targets_to_build = if ($target | str length) > 0 {
|
||||||
|
let selected = $docker_targets | where $it.name == $target
|
||||||
|
if ($selected | length) == 0 {
|
||||||
|
print $"❌ Target not found or doesn't require Docker: ($target)"
|
||||||
|
print $"💡 Available Docker targets: ($docker_targets | get name | str join ', ')"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$selected
|
||||||
|
} else {
|
||||||
|
$docker_targets
|
||||||
|
}
|
||||||
|
|
||||||
|
let all_plugins = get_plugin_directories
|
||||||
|
let plugins_to_build = if ($plugin | str length) > 0 {
|
||||||
|
let selected = $all_plugins | where $it == $plugin
|
||||||
|
if ($selected | length) == 0 {
|
||||||
|
print $"❌ Plugin not found: ($plugin)"
|
||||||
|
print $"💡 Available plugins: ($all_plugins | str join ', ')"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$selected
|
||||||
|
} else {
|
||||||
|
$all_plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($targets_to_build | length) == 0 {
|
||||||
|
print "❓ No Docker targets to build"
|
||||||
|
print $"💡 Available Docker targets: ($docker_targets | get name | str join ', ')"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($plugins_to_build | length) == 0 {
|
||||||
|
print "❓ No plugins to build"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"\n📦 Plugins to build: ($plugins_to_build | length)"
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
print $" - ($plugin)"
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"\n🎯 Docker targets: ($targets_to_build | length)"
|
||||||
|
for target in $targets_to_build {
|
||||||
|
print $" - ($target.name): ($target.config.description)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dry run mode
|
||||||
|
if $dry_run {
|
||||||
|
print "\n🔍 Dry run - showing build matrix:"
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for target in $targets_to_build {
|
||||||
|
print $" 🐳 ($plugin) × ($target.name)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build plugins
|
||||||
|
print $"\n🔨 Starting Docker builds..."
|
||||||
|
let start_time = date now
|
||||||
|
mut all_results = []
|
||||||
|
|
||||||
|
if $parallel {
|
||||||
|
print "⚡ Building in parallel mode..."
|
||||||
|
let build_jobs = []
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for target in $targets_to_build {
|
||||||
|
$build_jobs = ($build_jobs | append {
|
||||||
|
plugin: $plugin,
|
||||||
|
target: $target.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_results = ($build_jobs | par-each {|job|
|
||||||
|
build_plugin_in_docker $job.plugin $job.target $image_tag $verbose
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
# Sequential builds
|
||||||
|
for plugin in $plugins_to_build {
|
||||||
|
for target in $targets_to_build {
|
||||||
|
let result = build_plugin_in_docker $plugin $target.name $image_tag $verbose
|
||||||
|
$all_results = ($all_results | append $result)
|
||||||
|
print "---"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let end_time = date now
|
||||||
|
let total_duration = $end_time - $start_time
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print "\n📊 Docker Build Summary:"
|
||||||
|
let successful = $all_results | where status == "success"
|
||||||
|
let failed = $all_results | where status == "error"
|
||||||
|
|
||||||
|
print $"✅ Successful builds: ($successful | length)"
|
||||||
|
print $"❌ Failed builds: ($failed | length)"
|
||||||
|
print $"⏱️ Total time: ($total_duration)"
|
||||||
|
|
||||||
|
if ($successful | length) > 0 {
|
||||||
|
print "\n✅ Built binaries:"
|
||||||
|
for success in $successful {
|
||||||
|
print $" - ($success.plugin) → ($success.target): ($success.size)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($failed | length) > 0 {
|
||||||
|
print "\n❌ Failed builds:"
|
||||||
|
for failure in $failed {
|
||||||
|
print $" - ($failure.plugin) → ($failure.target): ($failure.error)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup if requested
|
||||||
|
if $cleanup {
|
||||||
|
print ""
|
||||||
|
cleanup_docker --containers --volumes
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit with error if any builds failed
|
||||||
|
if ($failed | length) > 0 {
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
print "\n🎉 All Docker builds completed successfully!"
|
||||||
|
print "💡 Binaries are available in plugin/target/RUST_TARGET/release/ directories"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
|
||||||
|
main
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user