Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ba50da73c | |||
| 684319983d | |||
| 18bd9f6cda |
183
.github/workflows/npm-publish.yml
vendored
Normal file
183
.github/workflows/npm-publish.yml
vendored
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
name: Publish to npm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version to publish (e.g., 5.0.6)'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checkout the repository
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# Setup Deno
|
||||||
|
- name: Setup Deno
|
||||||
|
uses: denoland/setup-deno@v1
|
||||||
|
with:
|
||||||
|
deno-version: v1.x
|
||||||
|
|
||||||
|
# Setup Node.js for npm publishing
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
registry-url: 'https://registry.npmjs.org/'
|
||||||
|
|
||||||
|
# Compile binaries for all platforms
|
||||||
|
- name: Compile binaries
|
||||||
|
run: |
|
||||||
|
echo "Compiling binaries for all platforms..."
|
||||||
|
deno task compile
|
||||||
|
echo ""
|
||||||
|
echo "Binary sizes:"
|
||||||
|
ls -lh dist/binaries/
|
||||||
|
|
||||||
|
# Update version in package.json if triggered manually
|
||||||
|
- name: Update version in package.json
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
VERSION=${{ github.event.inputs.version }}
|
||||||
|
echo "Updating package.json to version ${VERSION}"
|
||||||
|
npm version ${VERSION} --no-git-tag-version
|
||||||
|
|
||||||
|
# Extract version from tag if triggered by tag push
|
||||||
|
- name: Extract version from tag
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: |
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
|
echo "VERSION=${VERSION}" >> $GITHUB_ENV
|
||||||
|
echo "Extracted version: ${VERSION}"
|
||||||
|
|
||||||
|
# Ensure versions are synchronized
|
||||||
|
- name: Sync versions
|
||||||
|
run: |
|
||||||
|
if [ -n "${VERSION}" ]; then
|
||||||
|
echo "Syncing version ${VERSION} across files..."
|
||||||
|
|
||||||
|
# Update deno.json
|
||||||
|
sed -i "s/\"version\": \".*\"/\"version\": \"${VERSION}\"/" deno.json
|
||||||
|
|
||||||
|
# Update package.json
|
||||||
|
npm version ${VERSION} --no-git-tag-version --allow-same-version
|
||||||
|
|
||||||
|
echo "Updated versions:"
|
||||||
|
echo "deno.json: $(grep '"version"' deno.json)"
|
||||||
|
echo "package.json: $(grep '"version"' package.json | head -1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate SHA256 checksums for binaries
|
||||||
|
- name: Generate checksums
|
||||||
|
run: |
|
||||||
|
cd dist/binaries
|
||||||
|
sha256sum * > SHA256SUMS
|
||||||
|
echo "Checksums generated:"
|
||||||
|
cat SHA256SUMS
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# Create npm package
|
||||||
|
- name: Create npm package
|
||||||
|
run: |
|
||||||
|
echo "Creating npm package..."
|
||||||
|
npm pack
|
||||||
|
echo ""
|
||||||
|
echo "Package created:"
|
||||||
|
ls -lh *.tgz
|
||||||
|
|
||||||
|
# Test package installation locally
|
||||||
|
- name: Test local installation
|
||||||
|
run: |
|
||||||
|
echo "Testing local package installation..."
|
||||||
|
PACKAGE_FILE=$(ls *.tgz)
|
||||||
|
npm install -g ${PACKAGE_FILE}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Testing nupst command:"
|
||||||
|
nupst --version || echo "Note: Binary execution may fail in CI environment"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Checking installed files:"
|
||||||
|
npm ls -g @serve.zone/nupst
|
||||||
|
|
||||||
|
# Publish to npm (only on tag push or manual trigger)
|
||||||
|
- name: Publish to npm
|
||||||
|
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
run: |
|
||||||
|
echo "Publishing to npm registry..."
|
||||||
|
npm publish --access public
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Successfully published @serve.zone/nupst to npm!"
|
||||||
|
echo ""
|
||||||
|
echo "Package info:"
|
||||||
|
npm view @serve.zone/nupst
|
||||||
|
|
||||||
|
# Create GitHub Release (only on tag push)
|
||||||
|
- name: Create GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
dist/binaries/nupst-*
|
||||||
|
dist/binaries/SHA256SUMS
|
||||||
|
*.tgz
|
||||||
|
generate_release_notes: true
|
||||||
|
body: |
|
||||||
|
## NUPST ${{ env.VERSION }}
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
#### Via npm (recommended)
|
||||||
|
```bash
|
||||||
|
npm install -g @serve.zone/nupst
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Direct download
|
||||||
|
Download the appropriate binary for your platform from the assets below.
|
||||||
|
|
||||||
|
### Platform Support
|
||||||
|
- Linux x64 / ARM64
|
||||||
|
- macOS x64 / ARM64 (Apple Silicon)
|
||||||
|
- Windows x64
|
||||||
|
|
||||||
|
### Checksums
|
||||||
|
SHA256 checksums are available in `SHA256SUMS` file.
|
||||||
|
|
||||||
|
# Verify the published package
|
||||||
|
verify:
|
||||||
|
needs: build-and-publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18.x'
|
||||||
|
|
||||||
|
- name: Wait for npm propagation
|
||||||
|
run: sleep 30
|
||||||
|
|
||||||
|
- name: Verify npm package
|
||||||
|
run: |
|
||||||
|
echo "Verifying published package..."
|
||||||
|
npm view @serve.zone/nupst
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Testing installation from npm:"
|
||||||
|
npm install -g @serve.zone/nupst
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Package installed successfully!"
|
||||||
|
which nupst || echo "Binary location check skipped"
|
||||||
54
.npmignore
Normal file
54
.npmignore
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Source code (not needed for binary distribution)
|
||||||
|
/ts/
|
||||||
|
/test/
|
||||||
|
mod.ts
|
||||||
|
*.ts
|
||||||
|
|
||||||
|
# Development files
|
||||||
|
.git/
|
||||||
|
.gitea/
|
||||||
|
.claude/
|
||||||
|
.serena/
|
||||||
|
.nogit/
|
||||||
|
.github/
|
||||||
|
deno.json
|
||||||
|
deno.lock
|
||||||
|
tsconfig.json
|
||||||
|
|
||||||
|
# Scripts not needed for npm
|
||||||
|
/scripts/compile-all.sh
|
||||||
|
install.sh
|
||||||
|
uninstall.sh
|
||||||
|
example-action.sh
|
||||||
|
|
||||||
|
# Documentation files not needed for npm package
|
||||||
|
readme.plan.md
|
||||||
|
readme.hints.md
|
||||||
|
npm-publish-instructions.md
|
||||||
|
docs/
|
||||||
|
|
||||||
|
# IDE and editor files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Keep only the install-binary.js in scripts/
|
||||||
|
/scripts/*
|
||||||
|
!/scripts/install-binary.js
|
||||||
|
|
||||||
|
# Exclude all dist directory (binaries will be downloaded during install)
|
||||||
|
/dist/
|
||||||
|
|
||||||
|
# Logs and temporary files
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Other
|
||||||
|
node_modules/
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
108
bin/nupst-wrapper.js
Normal file
108
bin/nupst-wrapper.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NUPST npm wrapper
|
||||||
|
* This script executes the appropriate pre-compiled binary based on the current platform
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { dirname, join } from 'path';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
|
import { platform, arch } from 'os';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the binary name for the current platform
|
||||||
|
*/
|
||||||
|
function getBinaryName() {
|
||||||
|
const plat = platform();
|
||||||
|
const architecture = arch();
|
||||||
|
|
||||||
|
// Map Node's platform/arch to our binary naming
|
||||||
|
const platformMap = {
|
||||||
|
'darwin': 'macos',
|
||||||
|
'linux': 'linux',
|
||||||
|
'win32': 'windows'
|
||||||
|
};
|
||||||
|
|
||||||
|
const archMap = {
|
||||||
|
'x64': 'x64',
|
||||||
|
'arm64': 'arm64'
|
||||||
|
};
|
||||||
|
|
||||||
|
const mappedPlatform = platformMap[plat];
|
||||||
|
const mappedArch = archMap[architecture];
|
||||||
|
|
||||||
|
if (!mappedPlatform || !mappedArch) {
|
||||||
|
console.error(`Error: Unsupported platform/architecture: ${plat}/${architecture}`);
|
||||||
|
console.error('Supported platforms: Linux, macOS, Windows');
|
||||||
|
console.error('Supported architectures: x64, arm64');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct binary name
|
||||||
|
let binaryName = `nupst-${mappedPlatform}-${mappedArch}`;
|
||||||
|
if (plat === 'win32') {
|
||||||
|
binaryName += '.exe';
|
||||||
|
}
|
||||||
|
|
||||||
|
return binaryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the binary
|
||||||
|
*/
|
||||||
|
function executeBinary() {
|
||||||
|
const binaryName = getBinaryName();
|
||||||
|
const binaryPath = join(__dirname, '..', 'dist', 'binaries', binaryName);
|
||||||
|
|
||||||
|
// Check if binary exists
|
||||||
|
if (!existsSync(binaryPath)) {
|
||||||
|
console.error(`Error: Binary not found at ${binaryPath}`);
|
||||||
|
console.error('This might happen if:');
|
||||||
|
console.error('1. The postinstall script failed to run');
|
||||||
|
console.error('2. The platform is not supported');
|
||||||
|
console.error('3. The package was not installed correctly');
|
||||||
|
console.error('');
|
||||||
|
console.error('Try reinstalling the package:');
|
||||||
|
console.error(' npm uninstall -g @serve.zone/nupst');
|
||||||
|
console.error(' npm install -g @serve.zone/nupst');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn the binary with all arguments passed through
|
||||||
|
const child = spawn(binaryPath, process.argv.slice(2), {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle child process events
|
||||||
|
child.on('error', (err) => {
|
||||||
|
console.error(`Error executing nupst: ${err.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('exit', (code, signal) => {
|
||||||
|
if (signal) {
|
||||||
|
process.kill(process.pid, signal);
|
||||||
|
} else {
|
||||||
|
process.exit(code || 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forward signals to child process
|
||||||
|
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
||||||
|
signals.forEach(signal => {
|
||||||
|
process.on(signal, () => {
|
||||||
|
if (!child.killed) {
|
||||||
|
child.kill(signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
executeBinary();
|
||||||
11
changelog.md
11
changelog.md
@@ -1,5 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-10-22 - 5.1.0 - feat(packaging)
|
||||||
|
Add npm packaging and installer: wrapper, postinstall downloader, publish workflow, and packaging files
|
||||||
|
|
||||||
|
- Add package.json (v5.0.5) and npm packaging metadata to publish @serve.zone/nupst
|
||||||
|
- Include a small Node.js wrapper (bin/nupst-wrapper.js) to execute platform-specific precompiled binaries
|
||||||
|
- Add postinstall script (scripts/install-binary.js) that downloads the correct binary for the current platform and sets executable permissions
|
||||||
|
- Add GitHub Actions workflow (.github/workflows/npm-publish.yml) to build binaries, pack and publish to npm, and create releases
|
||||||
|
- Add .npmignore to keep source, tests and dev files out of npm package; keep only runtime installer and wrapper
|
||||||
|
- Move example action script into docs (docs/example-action.sh) and remove the top-level example-action.sh
|
||||||
|
- Include generated npm package artifact (serve.zone-nupst-5.0.5.tgz) and npmextra.json
|
||||||
|
|
||||||
## 2025-10-18 - 4.0.0 - BREAKING CHANGE(core): Complete migration to Deno runtime
|
## 2025-10-18 - 4.0.0 - BREAKING CHANGE(core): Complete migration to Deno runtime
|
||||||
|
|
||||||
**MAJOR RELEASE: NUPST v4.0 is a complete rewrite powered by Deno**
|
**MAJOR RELEASE: NUPST v4.0 is a complete rewrite powered by Deno**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@serve.zone/nupst",
|
"name": "@serve.zone/nupst",
|
||||||
"version": "5.0.4",
|
"version": "5.0.5",
|
||||||
"exports": "./mod.ts",
|
"exports": "./mod.ts",
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"dev": "deno run --allow-all mod.ts",
|
"dev": "deno run --allow-all mod.ts",
|
||||||
|
|||||||
11
install.sh
11
install.sh
@@ -216,9 +216,20 @@ fi
|
|||||||
BINARY_PATH="$INSTALL_DIR/nupst"
|
BINARY_PATH="$INSTALL_DIR/nupst"
|
||||||
mv "$TEMP_FILE" "$BINARY_PATH"
|
mv "$TEMP_FILE" "$BINARY_PATH"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] || [ ! -f "$BINARY_PATH" ]; then
|
||||||
|
echo "Error: Failed to move binary to $BINARY_PATH"
|
||||||
|
rm -f "$TEMP_FILE" 2>/dev/null
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Make executable
|
# Make executable
|
||||||
chmod +x "$BINARY_PATH"
|
chmod +x "$BINARY_PATH"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to make binary executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Binary installed successfully to: $BINARY_PATH"
|
echo "Binary installed successfully to: $BINARY_PATH"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|||||||
1
npmextra.json
Normal file
1
npmextra.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
62
package.json
Normal file
62
package.json
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"name": "@serve.zone/nupst",
|
||||||
|
"version": "5.1.0",
|
||||||
|
"description": "Network UPS Shutdown Tool - Monitor SNMP-enabled UPS devices and orchestrate graceful system shutdowns during power emergencies",
|
||||||
|
"keywords": [
|
||||||
|
"ups",
|
||||||
|
"snmp",
|
||||||
|
"power",
|
||||||
|
"shutdown",
|
||||||
|
"monitoring",
|
||||||
|
"cyberpower",
|
||||||
|
"apc",
|
||||||
|
"eaton",
|
||||||
|
"tripplite",
|
||||||
|
"liebert",
|
||||||
|
"vertiv",
|
||||||
|
"battery",
|
||||||
|
"backup"
|
||||||
|
],
|
||||||
|
"homepage": "https://code.foss.global/serve.zone/nupst",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://code.foss.global/serve.zone/nupst/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://code.foss.global/serve.zone/nupst.git"
|
||||||
|
},
|
||||||
|
"author": "Serve Zone",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"nupst": "./bin/nupst-wrapper.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "node scripts/install-binary.js",
|
||||||
|
"prepublishOnly": "echo 'Publishing NUPST binaries to npm...'",
|
||||||
|
"test": "echo 'Tests are run with Deno: deno task test'"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bin/",
|
||||||
|
"scripts/install-binary.js",
|
||||||
|
"readme.md",
|
||||||
|
"license",
|
||||||
|
"changelog.md"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"x64",
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"registry": "https://registry.npmjs.org/"
|
||||||
|
}
|
||||||
|
}
|
||||||
19
readme.md
19
readme.md
@@ -52,7 +52,24 @@ nupst service status
|
|||||||
|
|
||||||
## 📥 Installation
|
## 📥 Installation
|
||||||
|
|
||||||
### Automated Installer (Recommended)
|
### Via npm (NEW! - Recommended)
|
||||||
|
|
||||||
|
Install NUPST globally using npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g @serve.zone/nupst
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- Automatic platform detection and binary download
|
||||||
|
- Downloads only the binary for your platform (~400-500MB)
|
||||||
|
- Easy updates via `npm update -g @serve.zone/nupst`
|
||||||
|
- Version management with npm
|
||||||
|
- Works with Node.js >=14
|
||||||
|
|
||||||
|
**Note:** The installation will download the appropriate binary from GitHub releases during the postinstall step.
|
||||||
|
|
||||||
|
### Automated Installer Script
|
||||||
|
|
||||||
The installer script handles everything automatically:
|
The installer script handles everything automatically:
|
||||||
|
|
||||||
|
|||||||
231
scripts/install-binary.js
Normal file
231
scripts/install-binary.js
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NUPST npm postinstall script
|
||||||
|
* Downloads the appropriate binary for the current platform from GitHub releases
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { platform, arch } from 'os';
|
||||||
|
import { existsSync, mkdirSync, writeFileSync, chmodSync, unlinkSync } from 'fs';
|
||||||
|
import { join, dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import https from 'https';
|
||||||
|
import { pipeline } from 'stream';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
import { createWriteStream } from 'fs';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
const streamPipeline = promisify(pipeline);
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const REPO_BASE = 'https://code.foss.global/serve.zone/nupst';
|
||||||
|
const VERSION = process.env.npm_package_version || '5.0.5';
|
||||||
|
|
||||||
|
function getBinaryInfo() {
|
||||||
|
const plat = platform();
|
||||||
|
const architecture = arch();
|
||||||
|
|
||||||
|
const platformMap = {
|
||||||
|
'darwin': 'macos',
|
||||||
|
'linux': 'linux',
|
||||||
|
'win32': 'windows'
|
||||||
|
};
|
||||||
|
|
||||||
|
const archMap = {
|
||||||
|
'x64': 'x64',
|
||||||
|
'arm64': 'arm64'
|
||||||
|
};
|
||||||
|
|
||||||
|
const mappedPlatform = platformMap[plat];
|
||||||
|
const mappedArch = archMap[architecture];
|
||||||
|
|
||||||
|
if (!mappedPlatform || !mappedArch) {
|
||||||
|
return { supported: false, platform: plat, arch: architecture };
|
||||||
|
}
|
||||||
|
|
||||||
|
let binaryName = `nupst-${mappedPlatform}-${mappedArch}`;
|
||||||
|
if (plat === 'win32') {
|
||||||
|
binaryName += '.exe';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
supported: true,
|
||||||
|
platform: mappedPlatform,
|
||||||
|
arch: mappedArch,
|
||||||
|
binaryName,
|
||||||
|
originalPlatform: plat
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadFile(url, destination) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`Downloading from: ${url}`);
|
||||||
|
|
||||||
|
// Follow redirects
|
||||||
|
const download = (url, redirectCount = 0) => {
|
||||||
|
if (redirectCount > 5) {
|
||||||
|
reject(new Error('Too many redirects'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
https.get(url, (response) => {
|
||||||
|
if (response.statusCode === 301 || response.statusCode === 302) {
|
||||||
|
console.log(`Following redirect to: ${response.headers.location}`);
|
||||||
|
download(response.headers.location, redirectCount + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalSize = parseInt(response.headers['content-length'], 10);
|
||||||
|
let downloadedSize = 0;
|
||||||
|
let lastProgress = 0;
|
||||||
|
|
||||||
|
response.on('data', (chunk) => {
|
||||||
|
downloadedSize += chunk.length;
|
||||||
|
const progress = Math.round((downloadedSize / totalSize) * 100);
|
||||||
|
|
||||||
|
// Only log every 10% to reduce noise
|
||||||
|
if (progress >= lastProgress + 10) {
|
||||||
|
console.log(`Download progress: ${progress}%`);
|
||||||
|
lastProgress = progress;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const file = createWriteStream(destination);
|
||||||
|
|
||||||
|
pipeline(response, file, (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
console.log('Download complete!');
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).on('error', reject);
|
||||||
|
};
|
||||||
|
|
||||||
|
download(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('===========================================');
|
||||||
|
console.log(' NUPST - Binary Installation');
|
||||||
|
console.log('===========================================');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
const binaryInfo = getBinaryInfo();
|
||||||
|
|
||||||
|
if (!binaryInfo.supported) {
|
||||||
|
console.error(`❌ Error: Unsupported platform/architecture: ${binaryInfo.platform}/${binaryInfo.arch}`);
|
||||||
|
console.error('');
|
||||||
|
console.error('Supported platforms:');
|
||||||
|
console.error(' • Linux (x64, arm64)');
|
||||||
|
console.error(' • macOS (x64, arm64)');
|
||||||
|
console.error(' • Windows (x64)');
|
||||||
|
console.error('');
|
||||||
|
console.error('If you believe your platform should be supported, please file an issue:');
|
||||||
|
console.error(' https://code.foss.global/serve.zone/nupst/issues');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Platform: ${binaryInfo.platform} (${binaryInfo.originalPlatform})`);
|
||||||
|
console.log(`Architecture: ${binaryInfo.arch}`);
|
||||||
|
console.log(`Binary: ${binaryInfo.binaryName}`);
|
||||||
|
console.log(`Version: ${VERSION}`);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// Create dist/binaries directory if it doesn't exist
|
||||||
|
const binariesDir = join(__dirname, '..', 'dist', 'binaries');
|
||||||
|
if (!existsSync(binariesDir)) {
|
||||||
|
console.log('Creating binaries directory...');
|
||||||
|
mkdirSync(binariesDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const binaryPath = join(binariesDir, binaryInfo.binaryName);
|
||||||
|
|
||||||
|
// Check if binary already exists and skip download
|
||||||
|
if (existsSync(binaryPath)) {
|
||||||
|
console.log('✓ Binary already exists, skipping download');
|
||||||
|
} else {
|
||||||
|
// Construct download URL
|
||||||
|
// Try release URL first, fall back to raw branch if needed
|
||||||
|
const releaseUrl = `${REPO_BASE}/releases/download/v${VERSION}/${binaryInfo.binaryName}`;
|
||||||
|
const fallbackUrl = `${REPO_BASE}/raw/branch/main/dist/binaries/${binaryInfo.binaryName}`;
|
||||||
|
|
||||||
|
console.log('Downloading platform-specific binary...');
|
||||||
|
console.log('This may take a moment depending on your connection speed.');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try downloading from release
|
||||||
|
await downloadFile(releaseUrl, binaryPath);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Release download failed: ${err.message}`);
|
||||||
|
console.log('Trying fallback URL...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try fallback URL
|
||||||
|
await downloadFile(fallbackUrl, binaryPath);
|
||||||
|
} catch (fallbackErr) {
|
||||||
|
console.error(`❌ Error: Failed to download binary`);
|
||||||
|
console.error(` Primary URL: ${releaseUrl}`);
|
||||||
|
console.error(` Fallback URL: ${fallbackUrl}`);
|
||||||
|
console.error('');
|
||||||
|
console.error('This might be because:');
|
||||||
|
console.error('1. The release has not been created yet');
|
||||||
|
console.error('2. Network connectivity issues');
|
||||||
|
console.error('3. The version specified does not exist');
|
||||||
|
console.error('');
|
||||||
|
console.error('You can try:');
|
||||||
|
console.error('1. Installing from source: https://code.foss.global/serve.zone/nupst');
|
||||||
|
console.error('2. Downloading the binary manually from the releases page');
|
||||||
|
console.error('3. Using the install script: curl -sSL https://code.foss.global/serve.zone/nupst/raw/branch/main/install.sh | sudo bash');
|
||||||
|
|
||||||
|
// Clean up partial download
|
||||||
|
if (existsSync(binaryPath)) {
|
||||||
|
unlinkSync(binaryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✓ Binary downloaded successfully`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Unix-like systems, ensure the binary is executable
|
||||||
|
if (binaryInfo.originalPlatform !== 'win32') {
|
||||||
|
try {
|
||||||
|
console.log('Setting executable permissions...');
|
||||||
|
chmodSync(binaryPath, 0o755);
|
||||||
|
console.log('✓ Binary permissions updated');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`⚠️ Warning: Could not set executable permissions: ${err.message}`);
|
||||||
|
console.error(' You may need to manually run:');
|
||||||
|
console.error(` chmod +x ${binaryPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
console.log('✅ NUPST installation completed successfully!');
|
||||||
|
console.log('');
|
||||||
|
console.log('You can now use NUPST by running:');
|
||||||
|
console.log(' nupst --help');
|
||||||
|
console.log('');
|
||||||
|
console.log('For initial setup, run:');
|
||||||
|
console.log(' sudo nupst ups add');
|
||||||
|
console.log('');
|
||||||
|
console.log('===========================================');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the installation
|
||||||
|
main().catch(err => {
|
||||||
|
console.error(`❌ Installation failed: ${err.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
BIN
serve.zone-nupst-5.0.5.tgz
Normal file
BIN
serve.zone-nupst-5.0.5.tgz
Normal file
Binary file not shown.
@@ -1,10 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* commitinfo - reads version from deno.json
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
*/
|
*/
|
||||||
import denoConfig from '../deno.json' with { type: 'json' };
|
|
||||||
|
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: denoConfig.name,
|
name: '@serve.zone/nupst',
|
||||||
version: denoConfig.version,
|
version: '5.1.0',
|
||||||
description: 'Network UPS Shutdown Tool (https://nupst.serve.zone)',
|
description: 'Network UPS Shutdown Tool - Monitor SNMP-enabled UPS devices and orchestrate graceful system shutdowns during power emergencies'
|
||||||
};
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user