|
1 | 1 | import process from "process"; |
2 | 2 | import fs from "fs"; |
| 3 | +import path from "path"; |
3 | 4 | import concurrently from "concurrently"; |
4 | 5 | import { config } from "./lib.js"; |
5 | 6 |
|
@@ -71,8 +72,120 @@ function hr() { |
71 | 72 | return "─".repeat(process.stdout.columns ?? 40); |
72 | 73 | } |
73 | 74 |
|
| 75 | +function listDatabases() { |
| 76 | + const meteorLocalDir = path.join('meteor', '.meteor', 'local'); |
| 77 | + const dbLink = path.join(meteorLocalDir, 'db'); |
| 78 | + |
| 79 | + if (!fs.existsSync(meteorLocalDir)) { |
| 80 | + console.log('No databases found (meteor/.meteor/local does not exist yet)'); |
| 81 | + return; |
| 82 | + } |
| 83 | + |
| 84 | + // Get current database |
| 85 | + let currentDb = null; |
| 86 | + if (fs.existsSync(dbLink)) { |
| 87 | + const stats = fs.lstatSync(dbLink); |
| 88 | + if (stats.isSymbolicLink()) { |
| 89 | + const target = fs.readlinkSync(dbLink); |
| 90 | + const match = target.match(/^db\.(.+)$/); |
| 91 | + if (match) { |
| 92 | + currentDb = match[1]; |
| 93 | + } |
| 94 | + } else { |
| 95 | + currentDb = '(unnamed - real directory)'; |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + // List all db.* directories |
| 100 | + const files = fs.readdirSync(meteorLocalDir); |
| 101 | + const dbDirs = files |
| 102 | + .filter(file => file.startsWith('db.') && fs.lstatSync(path.join(meteorLocalDir, file)).isDirectory()) |
| 103 | + .map(file => file.substring(3)); |
| 104 | + |
| 105 | + console.log('\nAvailable databases:'); |
| 106 | + if (dbDirs.length === 0) { |
| 107 | + console.log(' (none found)'); |
| 108 | + } else { |
| 109 | + dbDirs.sort().forEach(db => { |
| 110 | + const marker = db === currentDb ? ' ← current' : ''; |
| 111 | + console.log(` ${db}${marker}`); |
| 112 | + }); |
| 113 | + } |
| 114 | + |
| 115 | + if (currentDb && !dbDirs.includes(currentDb)) { |
| 116 | + console.log(`\nCurrent: ${currentDb}`); |
| 117 | + } |
| 118 | + console.log(''); |
| 119 | +} |
| 120 | + |
| 121 | +function switchDatabase(dbName) { |
| 122 | + const meteorLocalDir = path.join('meteor', '.meteor', 'local'); |
| 123 | + const dbLink = path.join(meteorLocalDir, 'db'); |
| 124 | + const dbTarget = path.join(meteorLocalDir, `db.${dbName}`); |
| 125 | + |
| 126 | + // Check if we're already using this database |
| 127 | + if (fs.existsSync(dbLink)) { |
| 128 | + const stats = fs.lstatSync(dbLink); |
| 129 | + if (stats.isSymbolicLink()) { |
| 130 | + const currentTarget = fs.readlinkSync(dbLink); |
| 131 | + if (currentTarget === `db.${dbName}`) { |
| 132 | + console.log(`✓ Already using database: ${dbName}`); |
| 133 | + return; |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + // Create target directory if it doesn't exist |
| 139 | + if (!fs.existsSync(dbTarget)) { |
| 140 | + console.log(`Creating new database directory: ${dbName}`); |
| 141 | + fs.mkdirSync(dbTarget, { recursive: true }); |
| 142 | + } |
| 143 | + |
| 144 | + // Remove existing db link/directory |
| 145 | + if (fs.existsSync(dbLink)) { |
| 146 | + const stats = fs.lstatSync(dbLink); |
| 147 | + if (stats.isSymbolicLink()) { |
| 148 | + fs.unlinkSync(dbLink); |
| 149 | + } else { |
| 150 | + // It's a real directory - back it up with timestamp |
| 151 | + const defaultDb = path.join(meteorLocalDir, 'db.default'); |
| 152 | + if (!fs.existsSync(defaultDb)) { |
| 153 | + console.log(`Backing up existing database to: default`); |
| 154 | + fs.renameSync(dbLink, defaultDb); |
| 155 | + } else { |
| 156 | + // Default already exists, create timestamped backup instead of deleting |
| 157 | + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19); |
| 158 | + let backupName = path.join(meteorLocalDir, `db.backup.${timestamp}`); |
| 159 | + // Ensure unique backup name |
| 160 | + let suffix = 0; |
| 161 | + while (fs.existsSync(backupName)) { |
| 162 | + suffix++; |
| 163 | + backupName = path.join(meteorLocalDir, `db.backup.${timestamp}.${suffix}`); |
| 164 | + } |
| 165 | + console.log(`Backing up existing database to: ${path.basename(backupName)}`); |
| 166 | + fs.renameSync(dbLink, backupName); |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + |
| 171 | + // Create symlink to target database |
| 172 | + fs.symlinkSync(`db.${dbName}`, dbLink); |
| 173 | + console.log(`✓ Switched to database: ${dbName}`); |
| 174 | +} |
| 175 | + |
74 | 176 | try { |
75 | | - // Note: This scricpt assumes that install-and-build.mjs has been run before |
| 177 | + // Note: This script assumes that install-and-build.mjs has been run before |
| 178 | + |
| 179 | + // List databases if requested |
| 180 | + if (config.dbList) { |
| 181 | + listDatabases(); |
| 182 | + process.exit(0); |
| 183 | + } |
| 184 | + |
| 185 | + // Switch database if requested |
| 186 | + if (config.dbName) { |
| 187 | + switchDatabase(config.dbName); |
| 188 | + } |
76 | 189 |
|
77 | 190 | // The main watching execution |
78 | 191 | console.log(hr()); |
|
0 commit comments