olly-molly 0.1.5 ā 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +103 -99
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -6,143 +6,147 @@ const fs = require('fs');
|
|
|
6
6
|
const os = require('os');
|
|
7
7
|
const https = require('https');
|
|
8
8
|
|
|
9
|
-
const APP_NAME = 'olly-molly';
|
|
10
9
|
const REPO = 'ruucm/olly-molly';
|
|
11
10
|
const APP_DIR = path.join(os.homedir(), '.olly-molly');
|
|
11
|
+
const DB_DIR = path.join(APP_DIR, 'db');
|
|
12
12
|
const TARBALL_URL = `https://github.com/${REPO}/archive/refs/heads/main.tar.gz`;
|
|
13
13
|
const VERSION_URL = `https://raw.githubusercontent.com/${REPO}/main/package.json`;
|
|
14
14
|
|
|
15
|
-
console.log('\nš Olly Molly
|
|
15
|
+
console.log('\nš Olly Molly\n');
|
|
16
16
|
|
|
17
17
|
function fetchJSON(url) {
|
|
18
18
|
return new Promise((resolve, reject) => {
|
|
19
|
-
const get = (
|
|
20
|
-
https.get(
|
|
21
|
-
if (res.statusCode === 302 || res.statusCode === 301)
|
|
22
|
-
get(res.headers.location);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
19
|
+
const get = (u) => {
|
|
20
|
+
https.get(u, (res) => {
|
|
21
|
+
if (res.statusCode === 302 || res.statusCode === 301) return get(res.headers.location);
|
|
25
22
|
let data = '';
|
|
26
|
-
res.on('data',
|
|
27
|
-
res.on('end', () => {
|
|
28
|
-
try {
|
|
29
|
-
resolve(JSON.parse(data));
|
|
30
|
-
} catch {
|
|
31
|
-
reject(new Error('Invalid JSON'));
|
|
32
|
-
}
|
|
33
|
-
});
|
|
23
|
+
res.on('data', c => data += c);
|
|
24
|
+
res.on('end', () => { try { resolve(JSON.parse(data)); } catch { reject(); } });
|
|
34
25
|
}).on('error', reject);
|
|
35
26
|
};
|
|
36
27
|
get(url);
|
|
37
28
|
});
|
|
38
29
|
}
|
|
39
30
|
|
|
40
|
-
function
|
|
31
|
+
function download(url, destDir) {
|
|
41
32
|
return new Promise((resolve, reject) => {
|
|
42
|
-
const
|
|
43
|
-
const file = fs.createWriteStream(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
50
|
-
download(response.headers.location);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (response.statusCode !== 200) {
|
|
54
|
-
reject(new Error(`Download failed: ${response.statusCode}`));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
response.pipe(file);
|
|
33
|
+
const tmp = path.join(os.tmpdir(), 'olly-molly.tar.gz');
|
|
34
|
+
const file = fs.createWriteStream(tmp);
|
|
35
|
+
const get = (u) => {
|
|
36
|
+
https.get(u, (res) => {
|
|
37
|
+
if (res.statusCode === 302 || res.statusCode === 301) return get(res.headers.location);
|
|
38
|
+
if (res.statusCode !== 200) return reject(new Error('Download failed'));
|
|
39
|
+
res.pipe(file);
|
|
58
40
|
file.on('finish', () => {
|
|
59
41
|
file.close();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
execSync(`tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`, { stdio: 'pipe' });
|
|
66
|
-
fs.unlinkSync(tempFile);
|
|
67
|
-
resolve();
|
|
68
|
-
} catch (err) {
|
|
69
|
-
reject(err);
|
|
70
|
-
}
|
|
42
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
43
|
+
execSync(`tar -xzf "${tmp}" -C "${destDir}" --strip-components=1`, { stdio: 'pipe' });
|
|
44
|
+
fs.unlinkSync(tmp);
|
|
45
|
+
resolve();
|
|
71
46
|
});
|
|
72
47
|
}).on('error', reject);
|
|
73
48
|
};
|
|
74
|
-
|
|
49
|
+
get(url);
|
|
75
50
|
});
|
|
76
51
|
}
|
|
77
52
|
|
|
78
|
-
|
|
79
|
-
const pkgPath = path.join(APP_DIR, 'package.json');
|
|
80
|
-
if (!fs.existsSync(pkgPath)) return null;
|
|
53
|
+
function getLocalVersion() {
|
|
81
54
|
try {
|
|
82
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
55
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(APP_DIR, 'package.json'), 'utf8'));
|
|
83
56
|
return pkg.version;
|
|
84
|
-
} catch {
|
|
85
|
-
|
|
57
|
+
} catch { return null; }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Backup and restore user's database
|
|
61
|
+
function backupDB() {
|
|
62
|
+
const backupDir = path.join(os.tmpdir(), 'olly-molly-db-backup');
|
|
63
|
+
if (fs.existsSync(DB_DIR)) {
|
|
64
|
+
fs.cpSync(DB_DIR, backupDir, { recursive: true });
|
|
65
|
+
return backupDir;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function restoreDB(backupDir) {
|
|
71
|
+
if (backupDir && fs.existsSync(backupDir)) {
|
|
72
|
+
fs.mkdirSync(DB_DIR, { recursive: true });
|
|
73
|
+
// Only restore sqlite files, not schema files
|
|
74
|
+
const files = fs.readdirSync(backupDir);
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
if (file.endsWith('.sqlite') || file.endsWith('.sqlite-shm') || file.endsWith('.sqlite-wal')) {
|
|
77
|
+
fs.copyFileSync(path.join(backupDir, file), path.join(DB_DIR, file));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
fs.rmSync(backupDir, { recursive: true, force: true });
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
83
|
|
|
89
84
|
async function main() {
|
|
85
|
+
let needsInstall = false;
|
|
86
|
+
let needsBuild = false;
|
|
87
|
+
|
|
88
|
+
// Check for updates
|
|
89
|
+
const localVersion = getLocalVersion();
|
|
90
|
+
let remoteVersion = null;
|
|
91
|
+
|
|
90
92
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
remoteVersion = remotePkg.version;
|
|
96
|
-
} catch {
|
|
97
|
-
// Offline or error - continue with local
|
|
98
|
-
}
|
|
93
|
+
remoteVersion = (await fetchJSON(VERSION_URL)).version;
|
|
94
|
+
} catch {
|
|
95
|
+
// Offline - continue with local
|
|
96
|
+
}
|
|
99
97
|
|
|
100
|
-
|
|
98
|
+
// Update if version changed (preserve DB!)
|
|
99
|
+
if (localVersion && remoteVersion && localVersion !== remoteVersion) {
|
|
100
|
+
console.log(`š Updating ${localVersion} ā ${remoteVersion}\n`);
|
|
101
101
|
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
// Backup DB before update
|
|
103
|
+
const dbBackup = backupDB();
|
|
104
|
+
|
|
105
|
+
// Remove app (but DB is backed up)
|
|
106
|
+
fs.rmSync(APP_DIR, { recursive: true, force: true });
|
|
107
|
+
|
|
108
|
+
// Download new version
|
|
109
|
+
console.log('š„ Downloading...');
|
|
110
|
+
await download(TARBALL_URL, APP_DIR);
|
|
111
|
+
console.log('ā
Done\n');
|
|
112
|
+
|
|
113
|
+
// Restore DB
|
|
114
|
+
restoreDB(dbBackup);
|
|
115
|
+
|
|
116
|
+
needsInstall = true;
|
|
117
|
+
needsBuild = true;
|
|
118
|
+
}
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
// First time download
|
|
121
|
+
if (!fs.existsSync(APP_DIR)) {
|
|
122
|
+
console.log('š„ Downloading...');
|
|
123
|
+
await download(TARBALL_URL, APP_DIR);
|
|
124
|
+
console.log('ā
Done\n');
|
|
125
|
+
needsInstall = true;
|
|
126
|
+
needsBuild = true;
|
|
127
|
+
}
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
+
// Install if needed
|
|
130
|
+
if (needsInstall || !fs.existsSync(path.join(APP_DIR, 'node_modules'))) {
|
|
131
|
+
console.log('š¦ Installing dependencies...\n');
|
|
132
|
+
execSync('npm install --omit=dev', { cwd: APP_DIR, stdio: 'inherit' });
|
|
133
|
+
}
|
|
129
134
|
|
|
130
|
-
|
|
135
|
+
// Build if needed
|
|
136
|
+
if (needsBuild || !fs.existsSync(path.join(APP_DIR, '.next'))) {
|
|
137
|
+
console.log('\nšØ Building...\n');
|
|
138
|
+
execSync('npm run build', { cwd: APP_DIR, stdio: 'inherit' });
|
|
139
|
+
}
|
|
131
140
|
|
|
132
|
-
|
|
133
|
-
const server = spawn('npx', ['next', 'start', '--port', '1234'], {
|
|
134
|
-
cwd: APP_DIR,
|
|
135
|
-
stdio: 'inherit'
|
|
136
|
-
});
|
|
141
|
+
console.log('\nš http://localhost:1234\n');
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
const server = spawn('npx', ['next', 'start', '--port', '1234'], {
|
|
144
|
+
cwd: APP_DIR, stdio: 'inherit'
|
|
145
|
+
});
|
|
141
146
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
147
|
+
server.on('close', (code) => process.exit(code || 0));
|
|
148
|
+
process.on('SIGINT', () => server.kill('SIGINT'));
|
|
149
|
+
process.on('SIGTERM', () => server.kill('SIGTERM'));
|
|
146
150
|
}
|
|
147
151
|
|
|
148
|
-
main();
|
|
152
|
+
main().catch(e => { console.error('ā', e.message); process.exit(1); });
|