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:
Jesús Pérez 2025-09-20 19:04:08 +01:00
parent 5949bfade6
commit c5b510b939
11 changed files with 3849 additions and 18 deletions

307
.github/workflows/build.yml vendored Normal file
View 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
View 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
View 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
View 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"

View File

@ -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
View 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
View 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"]

View File

@ -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
View 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
View 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
}

View 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
}