bin-home 0.1.0 → 0.1.1
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/README.md +35 -0
- package/bin/cli.js +53 -8
- package/lib/versionUpdate.js +126 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,41 @@ npm install -g bin-home
|
|
|
16
16
|
bin-home <command> [--open]
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
### Version & Update
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 显示自身版本与线上版本
|
|
23
|
+
bin-home --version
|
|
24
|
+
|
|
25
|
+
# 显示指定命令对应包的版本信息
|
|
26
|
+
bin-home codex --version
|
|
27
|
+
|
|
28
|
+
# 进入更新流程(默认 latest)
|
|
29
|
+
bin-home --update
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
示例输出:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
当前版本: 0.1.0
|
|
36
|
+
线上版本: 0.1.0
|
|
37
|
+
请输入要更新的版本 (默认 latest):
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
指定命令的更新示例:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bin-home codex --update
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
示例输出:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
当前版本: 0.72.0
|
|
50
|
+
线上版本: 0.92.0-alpha.9,0.92.0-alpha.8,0.92.0-alpha.7,0.92.0-alpha.5,0.92.0-alpha.4,0.92.0-alpha.3
|
|
51
|
+
请输入要更新的版本 (默认 latest):
|
|
52
|
+
```
|
|
53
|
+
|
|
19
54
|
### Examples
|
|
20
55
|
|
|
21
56
|
```bash
|
package/bin/cli.js
CHANGED
|
@@ -3,6 +3,12 @@ const path = require("path");
|
|
|
3
3
|
const validateCommand = require("../lib/commandValidator");
|
|
4
4
|
const findPackageForCommand = require("../lib/packageFinder");
|
|
5
5
|
const displayPackageInfo = require("../lib/packageInfoFormatter");
|
|
6
|
+
const {
|
|
7
|
+
fetchOnlineVersions,
|
|
8
|
+
formatVersionOutput,
|
|
9
|
+
promptForVersion,
|
|
10
|
+
runGlobalUpdate
|
|
11
|
+
} = require("../lib/versionUpdate");
|
|
6
12
|
|
|
7
13
|
const COMMAND_NOT_FOUND_EXIT_CODE = 1;
|
|
8
14
|
const PACKAGE_NOT_FOUND_EXIT_CODE = 2;
|
|
@@ -13,14 +19,10 @@ function printHelp() {
|
|
|
13
19
|
console.log("Options:");
|
|
14
20
|
console.log(" --help, -h Show help");
|
|
15
21
|
console.log(" --version, -v Show version");
|
|
22
|
+
console.log(" --update, -u Update to specified version");
|
|
16
23
|
console.log(" --open, -o Open npm package page in browser");
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
function printVersion() {
|
|
20
|
-
const packageJson = require(path.join(__dirname, "..", "package.json"));
|
|
21
|
-
console.log(packageJson.version);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
26
|
function parseArgs(argv) {
|
|
25
27
|
const flags = new Set();
|
|
26
28
|
let commandName = null;
|
|
@@ -37,15 +39,58 @@ function parseArgs(argv) {
|
|
|
37
39
|
commandName,
|
|
38
40
|
help: flags.has("--help") || flags.has("-h"),
|
|
39
41
|
version: flags.has("--version") || flags.has("-v"),
|
|
42
|
+
update: flags.has("--update") || flags.has("-u"),
|
|
40
43
|
open: flags.has("--open") || flags.has("-o")
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
async function resolvePackageInfo(commandName) {
|
|
48
|
+
if (!commandName) {
|
|
49
|
+
const packageJson = require(path.join(__dirname, "..", "package.json"));
|
|
50
|
+
return { packageName: packageJson.name, localVersion: packageJson.version };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const commandExists = await validateCommand(commandName);
|
|
54
|
+
if (!commandExists) {
|
|
55
|
+
const error = new Error(`Command '${commandName}' not found in system PATH`);
|
|
56
|
+
error.exitCode = COMMAND_NOT_FOUND_EXIT_CODE;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const packageInfo = await findPackageForCommand(commandName);
|
|
61
|
+
if (!packageInfo) {
|
|
62
|
+
const error = new Error(
|
|
63
|
+
`No npm package found for command '${commandName}'. It may not be installed via npm.`
|
|
64
|
+
);
|
|
65
|
+
error.exitCode = PACKAGE_NOT_FOUND_EXIT_CODE;
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const packageName = packageInfo.packageJson.name || packageInfo.packageName;
|
|
70
|
+
return {
|
|
71
|
+
packageName,
|
|
72
|
+
localVersion: packageInfo.packageJson.version
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function showVersionInfo(commandName) {
|
|
77
|
+
const { packageName, localVersion } = await resolvePackageInfo(commandName);
|
|
78
|
+
const onlineVersions = await fetchOnlineVersions(packageName, { limit: 6 });
|
|
79
|
+
console.log(formatVersionOutput(localVersion, onlineVersions));
|
|
80
|
+
return packageName;
|
|
81
|
+
}
|
|
82
|
+
|
|
44
83
|
async function run() {
|
|
45
|
-
const { commandName, help, version, open } = parseArgs(
|
|
84
|
+
const { commandName, help, version, update, open } = parseArgs(
|
|
85
|
+
process.argv.slice(2)
|
|
86
|
+
);
|
|
46
87
|
|
|
47
|
-
if (version) {
|
|
48
|
-
|
|
88
|
+
if (version || update) {
|
|
89
|
+
const packageName = await showVersionInfo(commandName);
|
|
90
|
+
if (update) {
|
|
91
|
+
const targetVersion = await promptForVersion();
|
|
92
|
+
await runGlobalUpdate(packageName, targetVersion);
|
|
93
|
+
}
|
|
49
94
|
return;
|
|
50
95
|
}
|
|
51
96
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const { exec } = require("child_process");
|
|
2
|
+
const readline = require("readline");
|
|
3
|
+
|
|
4
|
+
const NPM_VIEW_EXIT_CODE = 5;
|
|
5
|
+
const NPM_UPDATE_EXIT_CODE = 6;
|
|
6
|
+
|
|
7
|
+
function getNpmCommand() {
|
|
8
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function normalizeVersions(raw) {
|
|
12
|
+
if (!raw) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(raw)) {
|
|
17
|
+
return raw.filter(Boolean);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const text = String(raw).trim();
|
|
21
|
+
if (!text) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(text);
|
|
27
|
+
if (Array.isArray(parsed)) {
|
|
28
|
+
return parsed.filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
// Fall through for non-JSON outputs.
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return text
|
|
35
|
+
.replace(/[\[\]]/g, "")
|
|
36
|
+
.split(/[\s,]+/)
|
|
37
|
+
.filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function sortNewestFirst(versions) {
|
|
41
|
+
if (!versions.length) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const sorted = versions.slice();
|
|
46
|
+
sorted.reverse();
|
|
47
|
+
return sorted;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function execCommand(command, execFn, exitCode, errorMessage) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
execFn(
|
|
53
|
+
command,
|
|
54
|
+
{ maxBuffer: 10 * 1024 * 1024, windowsHide: true },
|
|
55
|
+
(error, stdout) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
const err = new Error(`${errorMessage}: ${error.message}`);
|
|
58
|
+
err.exitCode = exitCode;
|
|
59
|
+
return reject(err);
|
|
60
|
+
}
|
|
61
|
+
resolve(stdout);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function fetchOnlineVersions(packageName, options = {}) {
|
|
68
|
+
if (options.versionsOverride) {
|
|
69
|
+
const versions = normalizeVersions(options.versionsOverride);
|
|
70
|
+
return sortNewestFirst(versions).slice(0, options.limit || 6);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (process.env.BIN_HOME_TEST_VERSIONS) {
|
|
74
|
+
const versions = normalizeVersions(process.env.BIN_HOME_TEST_VERSIONS);
|
|
75
|
+
return sortNewestFirst(versions).slice(0, options.limit || 6);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const npmCommand = getNpmCommand();
|
|
79
|
+
const command = `${npmCommand} view ${packageName} versions --json`;
|
|
80
|
+
const stdout = await execCommand(
|
|
81
|
+
command,
|
|
82
|
+
options.execFn || exec,
|
|
83
|
+
NPM_VIEW_EXIT_CODE,
|
|
84
|
+
`Failed to fetch npm versions for ${packageName}`
|
|
85
|
+
);
|
|
86
|
+
const versions = normalizeVersions(stdout);
|
|
87
|
+
return sortNewestFirst(versions).slice(0, options.limit || 6);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function formatVersionOutput(localVersion, versions) {
|
|
91
|
+
const list = Array.isArray(versions) ? versions : [];
|
|
92
|
+
return `当前版本: ${localVersion}\n线上版本: ${list.join(",")}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function promptForVersion(options = {}) {
|
|
96
|
+
const input = options.input || process.stdin;
|
|
97
|
+
const output = options.output || process.stdout;
|
|
98
|
+
const defaultVersion = options.defaultVersion || "latest";
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve) => {
|
|
101
|
+
const rl = readline.createInterface({ input, output });
|
|
102
|
+
rl.question(`请输入要更新的版本 (默认 ${defaultVersion}): `, (answer) => {
|
|
103
|
+
rl.close();
|
|
104
|
+
const trimmed = answer.trim();
|
|
105
|
+
resolve(trimmed || defaultVersion);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function runGlobalUpdate(packageName, version, options = {}) {
|
|
111
|
+
const npmCommand = getNpmCommand();
|
|
112
|
+
const command = `${npmCommand} i -g ${packageName}@${version}`;
|
|
113
|
+
return execCommand(
|
|
114
|
+
command,
|
|
115
|
+
options.execFn || exec,
|
|
116
|
+
NPM_UPDATE_EXIT_CODE,
|
|
117
|
+
`Failed to update ${packageName}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
fetchOnlineVersions,
|
|
123
|
+
formatVersionOutput,
|
|
124
|
+
promptForVersion,
|
|
125
|
+
runGlobalUpdate
|
|
126
|
+
};
|