UNPKG

@oletizi/sampler-backup

Version:

Akai sampler backup utilities for hardware samplers via PiSCSI

183 lines (175 loc) 5.59 kB
#!/usr/bin/env node import { existsSync, readdirSync, renameSync } from "node:fs"; import { join } from "node:path"; import { DEFAULT_PATH_CONVENTIONS, getActualSubdirectory } from "@oletizi/sampler-lib"; function findMigrationCandidates(conventions) { const candidates = []; if (!existsSync(conventions.backupRoot)) { return candidates; } try { const samplers = readdirSync(conventions.backupRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name); for (const sampler of samplers) { const actualSubdir = getActualSubdirectory(sampler, conventions); if (actualSubdir && conventions.legacySubdirectories.includes(actualSubdir)) { const currentPath = join(conventions.backupRoot, sampler, actualSubdir); const targetPath = join( conventions.backupRoot, sampler, conventions.defaultSubdirectory ); const diskImages = findDiskImages(currentPath); candidates.push({ sampler, currentSubdirectory: actualSubdir, currentPath, targetPath, diskImages }); } } } catch (err) { console.error(`Error scanning backup root: ${err.message}`); } return candidates; } function findDiskImages(directory) { if (!existsSync(directory)) { return []; } try { const entries = readdirSync(directory, { withFileTypes: true }); const images = []; for (const entry of entries) { if (entry.isFile()) { const lowerName = entry.name.toLowerCase(); if (lowerName.endsWith(".hds") || lowerName.endsWith(".img") || lowerName.endsWith(".iso")) { images.push(join(directory, entry.name)); } } } return images; } catch { return []; } } function migrateSampler(candidate, dryRun) { try { if (existsSync(candidate.targetPath)) { console.error( ` ✗ Target directory already exists: ${candidate.targetPath}` ); return false; } if (dryRun) ; else { renameSync(candidate.currentPath, candidate.targetPath); console.log(` ✓ Migrated: ${candidate.currentPath}`); console.log(` to: ${candidate.targetPath}`); return true; } } catch (err) { console.error(` ✗ Migration failed: ${err.message}`); return false; } } function displaySummary(candidates, dryRun) { console.log("\n=== Backup Directory Migration ===\n"); if (candidates.length === 0) { console.log("✓ No migration needed - all backups use current convention\n"); return; } console.log(`Found ${candidates.length} sampler(s) using legacy directory structure: `); for (const candidate of candidates) { console.log(`${candidate.sampler}/`); console.log(` Current: ${candidate.currentSubdirectory}/`); console.log(` New: images/`); console.log(` Disk images: ${candidate.diskImages.length}`); console.log(""); } if (dryRun) { console.log("DRY RUN MODE - No changes will be made"); console.log("Run with --execute to perform migration\n"); } } function parseArgs(args) { const options = { dryRun: true // Default to dry run for safety }; for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg === "--execute") { options.dryRun = false; } else if (arg === "--backup-root" && i + 1 < args.length) { options.backupRoot = args[i + 1]; i++; } else if (arg === "--help" || arg === "-h") { console.log(` Backup Directory Migration Tool Migrates legacy backup directory structures to the new path convention. Usage: sampler-migrate # Dry-run: show what would be migrated sampler-migrate --execute # Actually perform migration sampler-migrate --backup-root PATH # Use custom backup root Options: --execute Perform migration (default is dry-run) --backup-root PATH Use custom backup root directory -h, --help Show this help message Legacy convention: {sampler}/scsi0/, {sampler}/scsi1/, etc. New convention: {sampler}/images/ Examples: # Preview migration sampler-migrate # Perform migration sampler-migrate --execute # Migrate custom backup location sampler-migrate --backup-root /custom/path --execute `); process.exit(0); } } return options; } async function main() { const options = parseArgs(process.argv.slice(2)); const conventions = { ...DEFAULT_PATH_CONVENTIONS, ...options.backupRoot && { backupRoot: options.backupRoot } }; console.log(`Scanning backup root: ${conventions.backupRoot}`); const candidates = findMigrationCandidates(conventions); displaySummary(candidates, options.dryRun); if (candidates.length === 0) { process.exit(0); } if (options.dryRun) { process.exit(0); } console.log("=== Starting Migration ===\n"); let successCount = 0; let failureCount = 0; for (const candidate of candidates) { console.log(`Migrating ${candidate.sampler}...`); const success = migrateSampler(candidate, false); if (success) { successCount++; } else { failureCount++; } console.log(""); } console.log("=== Migration Complete ==="); console.log(`✓ Successful: ${successCount}`); if (failureCount > 0) { console.log(`✗ Failed: ${failureCount}`); } console.log(""); process.exit(failureCount > 0 ? 1 : 0); } main().catch((err) => { console.error(`Fatal error: ${err.message}`); process.exit(1); }); //# sourceMappingURL=migrate.js.map