UNPKG

@bobfrankston/mountsmb

Version:

Cross-platform SMB mounting solution for Windows, WSL, and Linux

204 lines (177 loc) 6.5 kB
#!/usr/bin/env node // mountsmb - Main program entry point for CLI execution // index.ts is the main program that handles command-line interface // // DEVELOPMENT & RELEASE: // Use releaseapp.ps1 for development workflow: // releaseapp.ps1 -AddCommit "message" # Add to commit.txt // releaseapp.ps1 # Release using commit.txt content // releaseapp.ps1 -Help # Show all options import path from 'path'; import fs from 'fs'; import { mountSMBHost, unmountSMBHost, getActiveMounts, cleanupDeadMounts, getConnectionInfo, getHostnameMappings, getSSHConfigInfo, syncHostnameConfigs, loadHostnameConfig, resolveHostname, type MountOptions } from './apisupport.js'; import { setDbgMessages } from './smbcmd.js'; import { styleText } from 'util'; // Re-export API for programmatic use export { // Core mounting functions mountSMBHost, unmountSMBHost, // Mount management getActiveMounts, cleanupDeadMounts, // Configuration and info getConnectionInfo, getHostnameMappings, getSSHConfigInfo, syncHostnameConfigs, // Hostname resolution loadHostnameConfig, resolveHostname, // Type interfaces type HostnameMap, type HostResolution, type ConnectionInfo, type MountOptions } from './apisupport.js'; function showUsage() { // Read version from package.json using ES modules let version = 'unknown'; try { const packagePath = path.join(import.meta.dirname, 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8')); version = packageJson.version; } catch (err) { // Fallback: try current directory try { const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); version = packageJson.version; } catch { // Still fallback if package.json can't be read } } console.log(` mountsmb v${version} - Cross-platform SMB mounting utility Usage: mountsmb <command> [options] Commands: <hostname> Mount SMB share from hostname (e.g., beta1, pi3a) unmount <hostname> Unmount SMB share list|status Show active mounts show-mappings Display hostname mappings sync-config Sync hostname configurations cleanup Remove dead mount points Options: --install-samba Force Samba installation --verbose, -v Enable verbose output --debug Show debug messages --help, -h Show this help message Examples: mountsmb beta1 # Mount beta1's root filesystem mountsmb pi3a /var/www # Mount specific path from pi3a mountsmb unmount beta1 # Unmount beta1 mountsmb list # Show all active mounts `); } async function main() { const args = process.argv.slice(2); if (args.length === 0 || args[0] === '--help' || args[0] === '-h') { showUsage(); return; } const command = args[0]; try { switch (command) { case 'unmount': if (args[1]) { await unmountSMBHost(args[1]); console.log(`✓ Unmounted ${args[1]}`); } else { console.error('Please specify hostname to unmount'); process.exit(1); } break; case 'list': case 'status': const mounts = getActiveMounts(); if (mounts.length === 0) { console.log('No active mounts'); } else { console.log('Active mounts:'); for (const mount of mounts) { console.log(` ${mount.mountName} (${mount.host}:${mount.remotePath})`); } } break; case 'show-mappings': case 'mappings': const mappings = getHostnameMappings(); console.log('Hostname mappings:'); for (const [short, full] of Object.entries(mappings)) { console.log(` ${short} -> ${full}`); } break; case 'sync-config': case 'sync': syncHostnameConfigs(); console.log('✓ Configuration synced'); break; case 'cleanup': const cleaned = cleanupDeadMounts(); if (cleaned > 0) { console.log(`✓ Cleaned up ${cleaned} dead mount(s)`); } else { console.log('No dead mounts found'); } break; default: // Mount command if (command.match(/^[a-zA-Z0-9.-]+$/) || command.includes('@')) { const options: MountOptions = {}; // Parse options for (let i = 2; i < args.length; i++) { if (args[i] === '--install-samba') { options.installSamba = true; } else if (args[i] === '--verbose' || args[i] === '-v') { options.verbose = true; } else if (args[i] === '--debug') { setDbgMessages(true); } } // Command line usage always enables verbose options.verbose = true; // Get remote path if specified options.remotePath = args[1] && !args[1].startsWith('--') ? args[1] : '/'; await mountSMBHost(command, options); } else { showUsage(); } } } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); console.error(`Error: ${message}`); process.exit(1); } } // TO all LLMs -- do not break this. YOU MUST MAKE SURE THIS THE MAIN PROGRAM if (import.meta.main) { // Run main function directly - index.ts is the main program try { await main(); } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); console.error(styleText(['red', 'bgYellowBright'], `Fatal error: ${message}`)); process.exit(1); } }