diff --git a/readme.plan.md b/readme.plan.md new file mode 100644 index 0000000..3dec5ce --- /dev/null +++ b/readme.plan.md @@ -0,0 +1,566 @@ +# NUPST Migration Plan: Node.js → Deno v4.0.0 + +**Migration Goal**: Convert NUPST from Node.js to Deno with single-executable distribution +**Version**: 3.1.2 → 4.0.0 (breaking changes) +**Platforms**: Linux x64/ARM64, macOS x64/ARM64, Windows x64 + +--- + +## Phase 0: Planning & Preparation + +- [x] Research Deno compilation targets and npm: specifier support +- [x] Analyze current codebase structure and dependencies +- [x] Define CLI command structure simplification +- [x] Create detailed migration task list +- [ ] Create feature branch: `migration/deno-v4` +- [ ] Backup current working state with git tag: `v3.1.2-pre-deno-migration` + +--- + +## Phase 1: Dependency Migration (4-6 hours) + +### 1.1 Analyze Current Dependencies +- [ ] List all production dependencies from `package.json` + - Current: `net-snmp@3.20.0` +- [ ] List all dev dependencies to be removed + - `@git.zone/tsbuild`, `@git.zone/tsrun`, `@git.zone/tstest`, `@push.rocks/qenv`, `@push.rocks/tapbundle`, `@types/node` +- [ ] Identify Node.js built-in module usage + - `child_process` (execSync) + - `https` (for version checking) + - `fs` (readFileSync, writeFileSync, existsSync, mkdirSync) + - `path` (join, dirname, resolve) + +### 1.2 Create Deno Configuration +- [ ] Create `deno.json` with project configuration + ```json + { + "name": "@serve.zone/nupst", + "version": "4.0.0", + "exports": "./mod.ts", + "tasks": { + "dev": "deno run --allow-all mod.ts", + "compile": "deno task compile:all", + "compile:all": "bash scripts/compile-all.sh", + "test": "deno test --allow-all tests/", + "check": "deno check mod.ts" + }, + "lint": { + "rules": { + "tags": ["recommended"] + } + }, + "fmt": { + "useTabs": false, + "lineWidth": 100, + "indentWidth": 2, + "semiColons": true + }, + "compilerOptions": { + "lib": ["deno.window"], + "strict": true + }, + "imports": { + "@std/cli": "jsr:@std/cli@^1.0.0", + "@std/fmt": "jsr:@std/fmt@^1.0.0", + "@std/path": "jsr:@std/path@^1.0.0" + } + } + ``` + +### 1.3 Update Import Statements +- [ ] `ts/snmp/manager.ts`: Change `import * as snmp from 'net-snmp'` to `import * as snmp from "npm:net-snmp@3.20.0"` +- [ ] `ts/cli.ts`: Change `import { execSync } from 'child_process'` to `import { execSync } from "node:child_process"` +- [ ] `ts/nupst.ts`: Change `import * as https from 'https'` to `import * as https from "node:https"` +- [ ] Search for all `fs` imports and update to `node:fs` +- [ ] Search for all `path` imports and update to `node:path` +- [ ] Update all relative imports to use `.ts` extension instead of `.js` + - Example: `'./nupst.js'` → `'./nupst.ts'` + +### 1.4 Test npm: Specifier Compatibility +- [ ] Create test file: `tests/snmp_compatibility_test.ts` +- [ ] Test SNMP v1 connection with npm:net-snmp +- [ ] Test SNMP v2c connection with npm:net-snmp +- [ ] Test SNMP v3 connection with npm:net-snmp +- [ ] Verify native addon loading works in compiled binary + +--- + +## Phase 2: Code Structure Refactoring (3-4 hours) + +### 2.1 Create Main Entry Point +- [ ] Create `mod.ts` as main Deno entry point: + ```typescript + #!/usr/bin/env -S deno run --allow-all + + /** + * NUPST - UPS Shutdown Tool for Deno + * + * Required Permissions: + * --allow-net: SNMP communication with UPS devices + * --allow-read: Configuration file access (/etc/nupst/config.json) + * --allow-write: Configuration file updates + * --allow-run: System commands (systemctl, shutdown) + * --allow-sys: System information (hostname, OS info) + * --allow-env: Environment variables + */ + + import { NupstCli } from './ts/cli.ts'; + + const cli = new NupstCli(); + await cli.parseAndExecute(Deno.args); + ``` + +### 2.2 Update All Import Extensions +Files to update (change .js → .ts in imports): +- [ ] `ts/index.ts` +- [ ] `ts/cli.ts` (imports from ./nupst.js, ./logger.js) +- [ ] `ts/nupst.ts` (imports from ./snmp/manager.js, ./daemon.js, etc.) +- [ ] `ts/daemon.ts` (imports from ./snmp/manager.js, ./logger.js, ./helpers/) +- [ ] `ts/systemd.ts` (imports from ./daemon.js, ./logger.js) +- [ ] `ts/cli/service-handler.ts` +- [ ] `ts/cli/group-handler.ts` +- [ ] `ts/cli/ups-handler.ts` +- [ ] `ts/snmp/index.ts` +- [ ] `ts/snmp/manager.ts` (imports from ./types.js, ./oid-sets.js) +- [ ] `ts/snmp/oid-sets.ts` (imports from ./types.js) +- [ ] `ts/helpers/index.ts` +- [ ] `ts/logger.ts` + +### 2.3 Update process.argv References +- [ ] `ts/cli.ts`: Replace `process.argv` with `Deno.args` (adjust indexing: process.argv[2] → Deno.args[0]) +- [ ] Update parseAndExecute method to work with Deno.args (0-indexed vs 2-indexed) + +### 2.4 Update File System Operations +- [ ] Search for `fs.readFileSync()` → Consider using `Deno.readTextFile()` or keep node:fs +- [ ] Search for `fs.writeFileSync()` → Consider using `Deno.writeTextFile()` or keep node:fs +- [ ] Search for `fs.existsSync()` → Keep node:fs or use Deno.stat +- [ ] Search for `fs.mkdirSync()` → Keep node:fs or use Deno.mkdir +- [ ] Decision: Keep node:fs for consistency or migrate to Deno APIs? + +### 2.5 Update Path Operations +- [ ] Verify all `path.join()`, `path.resolve()`, `path.dirname()` work with node:path +- [ ] Consider using `@std/path` from JSR for better Deno integration + +### 2.6 Handle __dirname and __filename +- [ ] Find all `__dirname` usage +- [ ] Replace with `import.meta.dirname` (Deno) or `dirname(fromFileUrl(import.meta.url))` +- [ ] Find all `__filename` usage +- [ ] Replace with `import.meta.filename` or `fromFileUrl(import.meta.url)` + +--- + +## Phase 3: CLI Command Simplification (3-4 hours) + +### 3.1 Design New Command Structure +Current → New mapping: +``` +OLD NEW +=== === +nupst enable → nupst service enable +nupst disable → nupst service disable +nupst daemon-start → nupst service start-daemon +nupst logs → nupst service logs +nupst stop → nupst service stop +nupst start → nupst service start +nupst status → nupst service status + +nupst add → nupst ups add +nupst edit [id] → nupst ups edit [id] +nupst delete → nupst ups remove +nupst list → nupst ups list +nupst setup → nupst ups edit (removed alias) +nupst test → nupst ups test + +nupst group list → nupst group list +nupst group add → nupst group add +nupst group edit → nupst group edit +nupst group delete → nupst group remove + +nupst config → nupst config show +nupst update → nupst update +nupst uninstall → nupst uninstall +nupst help → nupst help / nupst --help +(new) → nupst --version +``` + +### 3.2 Update CLI Parser (ts/cli.ts) +- [ ] Refactor `parseAndExecute()` to handle new command structure +- [ ] Add `service` subcommand handler +- [ ] Add `ups` subcommand handler +- [ ] Keep `group` subcommand handler (already exists, just update delete→remove) +- [ ] Add `config` subcommand handler with `show` default +- [ ] Add `--version` flag handler +- [ ] Update `help` command to show new structure +- [ ] Add command aliases: `rm` → `remove`, `ls` → `list` +- [ ] Add `--json` flag for machine-readable output (future enhancement) + +### 3.3 Update Command Handlers +- [ ] `ts/cli/service-handler.ts`: Update method names if needed +- [ ] `ts/cli/ups-handler.ts`: Rename `delete()` → `remove()`, remove `setup` method +- [ ] `ts/cli/group-handler.ts`: Rename `delete()` → `remove()` + +### 3.4 Improve Help Messages +- [ ] Update `showHelp()` in ts/cli.ts with new command structure +- [ ] Update `showGroupHelp()` in ts/cli.ts +- [ ] Add `showServiceHelp()` method +- [ ] Add `showUpsHelp()` method +- [ ] Add `showConfigHelp()` method +- [ ] Include usage examples in help text + +### 3.5 Add Version Command +- [ ] Read version from deno.json +- [ ] Create `--version` handler in CLI +- [ ] Display version with build info + +--- + +## Phase 4: Compilation & Distribution (2-3 hours) + +### 4.1 Create Compilation Script +- [ ] Create directory: `scripts/` +- [ ] Create `scripts/compile-all.sh`: + ```bash + #!/bin/bash + set -e + + VERSION=$(cat deno.json | jq -r '.version') + BINARY_DIR="dist/binaries" + + echo "Compiling NUPST v${VERSION} for all platforms..." + mkdir -p "$BINARY_DIR" + + # Linux x86_64 + echo "→ Linux x86_64..." + deno compile --allow-all --output "$BINARY_DIR/nupst-linux-x64" \ + --target x86_64-unknown-linux-gnu mod.ts + + # Linux ARM64 + echo "→ Linux ARM64..." + deno compile --allow-all --output "$BINARY_DIR/nupst-linux-arm64" \ + --target aarch64-unknown-linux-gnu mod.ts + + # macOS x86_64 + echo "→ macOS x86_64..." + deno compile --allow-all --output "$BINARY_DIR/nupst-macos-x64" \ + --target x86_64-apple-darwin mod.ts + + # macOS ARM64 + echo "→ macOS ARM64..." + deno compile --allow-all --output "$BINARY_DIR/nupst-macos-arm64" \ + --target aarch64-apple-darwin mod.ts + + # Windows x86_64 + echo "→ Windows x86_64..." + deno compile --allow-all --output "$BINARY_DIR/nupst-windows-x64.exe" \ + --target x86_64-pc-windows-msvc mod.ts + + echo "" + echo "✓ Compilation complete!" + ls -lh "$BINARY_DIR/" + ``` +- [ ] Make script executable: `chmod +x scripts/compile-all.sh` + +### 4.2 Test Local Compilation +- [ ] Run `deno task compile` to compile for all platforms +- [ ] Verify all 5 binaries are created +- [ ] Check binary sizes (should be reasonable, < 100MB each) +- [ ] Test local binary on current platform: `./dist/binaries/nupst-linux-x64 --version` + +### 4.3 Update Installation Scripts +- [ ] Update `install.sh`: + - Remove Node.js download logic (lines dealing with vendor/node-*) + - Add detection for binary download from GitHub releases + - Simplify to download appropriate binary based on OS/arch + - Place binary in `/opt/nupst/bin/nupst` + - Create symlink: `/usr/local/bin/nupst → /opt/nupst/bin/nupst` + - Update to v4.0.0 in script +- [ ] Simplify or remove `setup.sh` (no longer needed without Node.js) +- [ ] Update `bin/nupst` launcher: + - Option A: Keep as simple wrapper + - Option B: Remove and symlink directly to binary +- [ ] Update `uninstall.sh`: + - Remove vendor directory cleanup + - Update paths to new binary location + +### 4.4 Update Systemd Service +- [ ] Update systemd service file path in `ts/systemd.ts` +- [ ] Verify ExecStart points to correct binary location: `/opt/nupst/bin/nupst daemon-start` +- [ ] Remove Node.js environment variables if any +- [ ] Test service installation and startup + +--- + +## Phase 5: Testing & Validation (4-6 hours) + +### 5.1 Create Deno Test Suite +- [ ] Create `tests/` directory (or migrate from existing `test/`) +- [ ] Create `tests/snmp_test.ts`: Test SNMP manager functionality +- [ ] Create `tests/config_test.ts`: Test configuration loading/saving +- [ ] Create `tests/cli_test.ts`: Test CLI parsing and command routing +- [ ] Create `tests/daemon_test.ts`: Test daemon logic +- [ ] Remove dependency on @git.zone/tstest and @push.rocks/tapbundle +- [ ] Use Deno's built-in test runner (`Deno.test()`) + +### 5.2 Unit Tests +- [ ] Test SNMP connection with mock responses +- [ ] Test configuration validation +- [ ] Test UPS status parsing for different models +- [ ] Test group logic (redundant/non-redundant modes) +- [ ] Test threshold checking +- [ ] Test version comparison logic + +### 5.3 Integration Tests +- [ ] Test CLI command parsing for all commands +- [ ] Test config file creation and updates +- [ ] Test UPS add/edit/remove operations +- [ ] Test group add/edit/remove operations +- [ ] Mock systemd operations for testing + +### 5.4 Binary Testing +- [ ] Test compiled binary on Linux x64 +- [ ] Test compiled binary on Linux ARM64 (if available) +- [ ] Test compiled binary on macOS x64 (if available) +- [ ] Test compiled binary on macOS ARM64 (if available) +- [ ] Test compiled binary on Windows x64 (if available) +- [ ] Verify SNMP functionality works in compiled binary +- [ ] Verify config file operations work in compiled binary +- [ ] Test systemd integration with compiled binary + +### 5.5 Performance Testing +- [ ] Measure binary size for each platform +- [ ] Measure startup time: `time ./nupst-linux-x64 --version` +- [ ] Measure memory footprint during daemon operation +- [ ] Compare with Node.js version performance +- [ ] Document performance metrics + +### 5.6 Upgrade Path Testing +- [ ] Create test with v3.x config +- [ ] Verify v4.x can read existing config +- [ ] Test migration from old commands to new commands +- [ ] Verify systemd service upgrade path + +--- + +## Phase 6: Distribution Strategy (2-3 hours) + +### 6.1 GitHub Actions Workflow +- [ ] Create `.github/workflows/release.yml`: + ```yaml + name: Release + on: + push: + tags: + - 'v*' + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - name: Compile binaries + run: deno task compile + - name: Generate checksums + run: | + cd dist/binaries + sha256sum * > SHA256SUMS + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + files: dist/binaries/* + generate_release_notes: true + ``` + +### 6.2 Update package.json for npm +- [ ] Update version to 4.0.0 +- [ ] Update description to mention Deno +- [ ] Add postinstall script to symlink appropriate binary: + ```json + { + "name": "@serve.zone/nupst", + "version": "4.0.0", + "description": "UPS Shutdown Tool - Deno-based single executable", + "bin": { + "nupst": "bin/nupst-npm-wrapper.js" + }, + "type": "module", + "scripts": { + "postinstall": "node bin/setup-npm-binary.js" + }, + "files": [ + "dist/binaries/*", + "bin/*" + ] + } + ``` +- [ ] Create `bin/setup-npm-binary.js` to symlink correct binary +- [ ] Create `bin/nupst-npm-wrapper.js` as entry point + +### 6.3 Verify Distribution Methods +- [ ] Test GitHub release download and installation +- [ ] Test npm install from tarball +- [ ] Test direct install.sh script +- [ ] Verify all methods create working installation + +--- + +## Phase 7: Documentation Updates (2-3 hours) + +### 7.1 Update README.md +- [ ] Remove Node.js requirements section +- [ ] Update features list (mention Deno, single executable) +- [ ] Update installation methods: + - Method 1: Quick install script (updated) + - Method 2: GitHub releases (new) + - Method 3: npm (updated with notes) +- [ ] Update usage section with new command structure +- [ ] Add command mapping table (v3 → v4) +- [ ] Update platform support matrix (note: no Windows ARM) +- [ ] Update "System Changes" section (no vendor directory) +- [ ] Update security section (remove Node.js mentions) +- [ ] Update uninstallation instructions + +### 7.2 Create MIGRATION.md +- [ ] Create detailed migration guide from v3.x to v4.x +- [ ] List all breaking changes: + 1. CLI command structure reorganization + 2. No Node.js requirement + 3. Windows ARM not supported + 4. Installation path changes +- [ ] Provide command mapping table +- [ ] Explain config compatibility +- [ ] Document upgrade procedure +- [ ] Add rollback instructions + +### 7.3 Update CHANGELOG.md +- [ ] Add v4.0.0 section with all breaking changes +- [ ] List new features (Deno, single executable) +- [ ] List improvements (startup time, binary size) +- [ ] List removed features (Windows ARM, setup command alias) +- [ ] Migration guide reference + +### 7.4 Update Help Text +- [ ] Ensure all help commands show new structure +- [ ] Add examples for common operations +- [ ] Include migration notes in help output + +--- + +## Phase 8: Cleanup & Finalization (1 hour) + +### 8.1 Remove Obsolete Files +- [ ] Delete `vendor/` directory (Node.js binaries) +- [ ] Delete `dist/` directory (old compiled JS) +- [ ] Delete `dist_ts/` directory (old compiled TS) +- [ ] Delete `node_modules/` directory +- [ ] Remove or update `tsconfig.json` (decide if needed for npm compatibility) +- [ ] Remove `setup.sh` if no longer needed +- [ ] Remove old test files in `test/` if migrated to `tests/` +- [ ] Delete `pnpm-lock.yaml` + +### 8.2 Update Git Configuration +- [ ] Update `.gitignore`: + ``` + # Deno + .deno/ + deno.lock + + # Compiled binaries + dist/binaries/ + + # Old Node.js artifacts (to be removed) + node_modules/ + vendor/ + dist/ + dist_ts/ + pnpm-lock.yaml + ``` +- [ ] Add `deno.lock` to version control +- [ ] Create `.denoignore` if needed + +### 8.3 Final Validation +- [ ] Run `deno check mod.ts` - verify no type errors +- [ ] Run `deno lint` - verify code quality +- [ ] Run `deno fmt --check` - verify formatting +- [ ] Run `deno task test` - verify all tests pass +- [ ] Run `deno task compile` - verify all binaries compile +- [ ] Test each binary manually + +### 8.4 Prepare for Release +- [ ] Create git tag: `v4.0.0` +- [ ] Push to main branch +- [ ] Push tags to trigger release workflow +- [ ] Verify GitHub Actions workflow succeeds +- [ ] Verify binaries are attached to release +- [ ] Test installation from GitHub release +- [ ] Publish to npm: `npm publish` +- [ ] Test npm installation + +--- + +## Rollback Strategy + +If critical issues are discovered: +- [ ] Keep `v3.1.2` tag available for rollback +- [ ] Create `v3-stable` branch for continued v3 maintenance +- [ ] Update install.sh to offer v3/v4 choice +- [ ] Document known issues in GitHub Issues +- [ ] Provide downgrade instructions in docs + +--- + +## Success Criteria Checklist + +- [ ] ✅ All 5 platform binaries compile successfully +- [ ] ✅ Binary sizes are reasonable (< 100MB per platform) +- [ ] ✅ Startup time < 2 seconds +- [ ] ✅ SNMP v1/v2c/v3 functionality verified on real UPS device +- [ ] ✅ All CLI commands work with new structure +- [ ] ✅ Config file compatibility maintained +- [ ] ✅ Systemd integration works on Linux +- [ ] ✅ Installation scripts work on fresh systems +- [ ] ✅ npm package still installable and functional +- [ ] ✅ All tests pass +- [ ] ✅ Documentation is complete and accurate +- [ ] ✅ GitHub release created with binaries +- [ ] ✅ Migration guide tested by following it step-by-step + +--- + +## Timeline + +- **Phase 0**: 1 hour ✓ (in progress) +- **Phase 1**: 4-6 hours +- **Phase 2**: 3-4 hours +- **Phase 3**: 3-4 hours +- **Phase 4**: 2-3 hours +- **Phase 5**: 4-6 hours +- **Phase 6**: 2-3 hours +- **Phase 7**: 2-3 hours +- **Phase 8**: 1 hour + +**Total Estimate**: 22-31 hours + +--- + +## Notes & Decisions + +### Key Decisions Made: +1. ✅ Use npm:net-snmp (no pure Deno SNMP library available) +2. ✅ Major version bump to 4.0.0 (breaking changes) +3. ✅ CLI reorganization with subcommands +4. ✅ Keep npm publishing alongside binary distribution +5. ✅ 5 platform targets (Windows ARM not supported by Deno yet) + +### Open Questions: +- [ ] Should we keep tsconfig.json for npm package compatibility? +- [ ] Should we fully migrate to Deno APIs (Deno.readFile) or keep node:fs? +- [ ] Should we remove the `bin/nupst` wrapper or keep it? +- [ ] Should setup.sh be completely removed or kept for dependencies? + +### Risk Areas: +- ⚠️ SNMP native addon compatibility in compiled binaries (HIGH PRIORITY TO TEST) +- ⚠️ Systemd integration with new binary structure +- ⚠️ Config migration from v3 to v4 +- ⚠️ npm package installation with embedded binaries