@glash/cli 0.2.48 → 0.2.49
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/glash.mjs +1 -1
- package/commands/update.mjs +81 -20
- package/package.json +1 -1
package/bin/glash.mjs
CHANGED
|
@@ -91,7 +91,7 @@ ${color.bold('PULL')}
|
|
|
91
91
|
pull [<slug>] [--out dir] [--no-env] Unpack a project (asks which, if no slug)
|
|
92
92
|
|
|
93
93
|
${color.bold('SYSTEM')}
|
|
94
|
-
update
|
|
94
|
+
update [--sudo] Update the glash CLI to the latest version
|
|
95
95
|
|
|
96
96
|
${color.bold('FLAGS')}
|
|
97
97
|
--project <slug|id> Override the linked project for this command
|
package/commands/update.mjs
CHANGED
|
@@ -1,46 +1,107 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { accessSync, constants } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { stdout } from 'node:process';
|
|
2
5
|
import { ok, fail, info, warn, color } from '../lib/ui.mjs';
|
|
3
6
|
import { VERSION } from '../lib/version.mjs';
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
// Both package names install the same CLI: @glash/cli is the primary, glashdb
|
|
9
|
+
// the alias. Update whichever one this machine actually has.
|
|
10
|
+
const PRIMARY = '@glash/cli';
|
|
11
|
+
const ALIAS = 'glashdb';
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
export async function update(parsed) {
|
|
14
|
+
const useSudo = Boolean(parsed?.flags?.sudo);
|
|
15
|
+
const pkg = installedPackage() ?? PRIMARY;
|
|
16
|
+
|
|
17
|
+
info(color.dim(`→ updating ${pkg} to the latest version...`));
|
|
18
|
+
|
|
19
|
+
const args = ['install', '-g', `${pkg}@latest`, '--no-fund', '--no-audit', '--loglevel=error'];
|
|
20
|
+
const child = useSudo
|
|
21
|
+
// Inherit stdio so sudo can prompt for the password.
|
|
22
|
+
? spawnSync('sudo', ['npm', ...args], { stdio: 'inherit', encoding: 'utf8' })
|
|
23
|
+
: spawnSync('npm', args, { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' });
|
|
24
|
+
|
|
25
|
+
if (child.error) {
|
|
26
|
+
return fail(`Could not run npm: ${child.error.message}`);
|
|
27
|
+
}
|
|
15
28
|
|
|
16
29
|
if (child.status !== 0) {
|
|
17
30
|
const stderr = (child.stderr || '').trim();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
// Show what npm actually said before any advice: guessing at the cause and
|
|
32
|
+
// hiding the error is how this command used to send people to sudo for
|
|
33
|
+
// problems sudo could not fix.
|
|
34
|
+
if (stderr) stdout.write(color.dim(`\n${stderr}\n\n`));
|
|
35
|
+
|
|
36
|
+
const target = globalLibDir();
|
|
37
|
+
const writable = target ? isWritable(target) : null;
|
|
38
|
+
|
|
39
|
+
if (writable === false) {
|
|
40
|
+
warn(`The global package directory is not writable: ${target}`);
|
|
41
|
+
return fail(
|
|
42
|
+
`Either re-run as \`glash update --sudo\`, or move npm's prefix somewhere you own:\n` +
|
|
43
|
+
` npm config set prefix ~/.npm-global\n` +
|
|
44
|
+
` export PATH="$HOME/.npm-global/bin:$PATH" # add to ~/.zshrc`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (/EACCES|EPERM|permission denied/i.test(stderr)) {
|
|
49
|
+
// Writable prefix but a permission error: almost always a cache left
|
|
50
|
+
// root-owned by an earlier `sudo npm install`.
|
|
51
|
+
warn(`${target ?? 'The global package directory'} is writable, so this is probably npm's cache, not the install location.`);
|
|
52
|
+
return fail(
|
|
53
|
+
`Check the cache owner and fix it if root owns it:\n` +
|
|
54
|
+
` ls -ld ~/.npm\n` +
|
|
55
|
+
` sudo chown -R "$(whoami)" ~/.npm\n` +
|
|
56
|
+
`Then run \`glash update\` again.`,
|
|
57
|
+
);
|
|
21
58
|
}
|
|
22
|
-
|
|
23
|
-
return fail(`Update failed with exit code ${child.status ?? 'unknown'}. Run \`npm install -g @
|
|
59
|
+
|
|
60
|
+
return fail(`Update failed with exit code ${child.status ?? 'unknown'}. Run \`npm install -g ${pkg}@latest\` to see the full output.`);
|
|
24
61
|
}
|
|
25
62
|
|
|
26
|
-
const installed = resolveInstalledVersion();
|
|
63
|
+
const installed = resolveInstalledVersion(pkg);
|
|
27
64
|
if (installed && installed === VERSION) {
|
|
28
65
|
ok(`Already on the latest version (${color.bold(`v${installed}`)}).`);
|
|
29
66
|
} else if (installed) {
|
|
30
|
-
ok(`Updated
|
|
67
|
+
ok(`Updated ${pkg} → ${color.bold(`v${installed}`)}.`);
|
|
31
68
|
} else {
|
|
32
|
-
ok(
|
|
69
|
+
ok(`Updated ${pkg} to the latest version.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Which of the two package names is installed globally, if either. */
|
|
74
|
+
function installedPackage() {
|
|
75
|
+
for (const name of [PRIMARY, ALIAS]) {
|
|
76
|
+
if (resolveInstalledVersion(name)) return name;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function globalLibDir() {
|
|
82
|
+
const res = spawnSync('npm', ['prefix', '-g'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' });
|
|
83
|
+
const prefix = (res.stdout || '').trim();
|
|
84
|
+
if (!prefix) return null;
|
|
85
|
+
return process.platform === 'win32' ? join(prefix, 'node_modules') : join(prefix, 'lib', 'node_modules');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isWritable(dir) {
|
|
89
|
+
try {
|
|
90
|
+
accessSync(dir, constants.W_OK);
|
|
91
|
+
return true;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
33
94
|
}
|
|
34
95
|
}
|
|
35
96
|
|
|
36
|
-
function resolveInstalledVersion() {
|
|
97
|
+
function resolveInstalledVersion(pkg = PRIMARY) {
|
|
37
98
|
try {
|
|
38
|
-
const res = spawnSync('npm', ['ls', '-g',
|
|
99
|
+
const res = spawnSync('npm', ['ls', '-g', pkg, '--depth=0', '--json'], {
|
|
39
100
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
40
101
|
encoding: 'utf8',
|
|
41
102
|
});
|
|
42
103
|
const parsed = JSON.parse(res.stdout || '{}');
|
|
43
|
-
return parsed?.dependencies?.[
|
|
104
|
+
return parsed?.dependencies?.[pkg]?.version || null;
|
|
44
105
|
} catch {
|
|
45
106
|
return null;
|
|
46
107
|
}
|
package/package.json
CHANGED