launch-unity 0.8.0 → 0.10.0
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.ja.md +7 -0
- package/README.md +7 -0
- package/dist/launch.js +206 -5
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -19,6 +19,7 @@ npx launch-unity
|
|
|
19
19
|
```bash
|
|
20
20
|
# 構文
|
|
21
21
|
launch-unity [OPTIONS] [PROJECT_PATH] [PLATFORM] [-- UNITY_ARGS...]
|
|
22
|
+
launch-unity update
|
|
22
23
|
|
|
23
24
|
# 引数
|
|
24
25
|
# PROJECT_PATH Unityプロジェクトのディレクトリ(省略時は3階層下まで探索)
|
|
@@ -40,6 +41,12 @@ npx launch-unity -a # Unity Hub に登録のみ(Unityは起動
|
|
|
40
41
|
npx launch-unity -f # Unity Hub にお気に入り登録(Unityは起動しない)
|
|
41
42
|
npx launch-unity . -- -batchmode -quit -nographics -logFile - # Unity引数を渡す
|
|
42
43
|
npx launch-unity /path Android -- -executeMethod My.Build.Entry
|
|
44
|
+
|
|
45
|
+
# 自己更新(npmグローバルインストール向け)
|
|
46
|
+
launch-unity update
|
|
47
|
+
|
|
48
|
+
# `update` という名前のディレクトリを開きたい場合は明示する
|
|
49
|
+
launch-unity ./update
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
指定した Unity プロジェクトの `ProjectSettings/ProjectVersion.txt` から必要な Unity Editor のバージョンを読み取り、
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ npx launch-unity
|
|
|
19
19
|
```bash
|
|
20
20
|
# Syntax
|
|
21
21
|
launch-unity [OPTIONS] [PROJECT_PATH] [PLATFORM] [-- UNITY_ARGS...]
|
|
22
|
+
launch-unity update
|
|
22
23
|
|
|
23
24
|
# Arguments
|
|
24
25
|
# PROJECT_PATH Unity project directory (searches up to 3 levels deep if omitted)
|
|
@@ -40,6 +41,12 @@ npx launch-unity -a # Register to Unity Hub only (does not launch
|
|
|
40
41
|
npx launch-unity -f # Register as favorite (does not launch Unity)
|
|
41
42
|
npx launch-unity . -- -batchmode -quit -nographics -logFile - # Pass Unity args
|
|
42
43
|
npx launch-unity /path Android -- -executeMethod My.Build.Entry
|
|
44
|
+
|
|
45
|
+
# Self update (for npm global install)
|
|
46
|
+
launch-unity update
|
|
47
|
+
|
|
48
|
+
# If you have a project directory named "update", specify it explicitly
|
|
49
|
+
launch-unity ./update
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
A TypeScript CLI for macOS and Windows that reads the required Unity Editor version from
|
package/dist/launch.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import { execFile, spawn } from "node:child_process";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, lstatSync, realpathSync } from "node:fs";
|
|
8
8
|
import { rm } from "node:fs/promises";
|
|
9
|
-
import { join, resolve } from "node:path";
|
|
9
|
+
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
10
11
|
import { promisify } from "node:util";
|
|
11
12
|
import { ensureProjectEntryAndUpdate, updateLastModifiedIfExists } from "./unityHub.js";
|
|
12
13
|
const execFileAsync = promisify(execFile);
|
|
@@ -18,11 +19,128 @@ const PROCESS_LIST_ARGS_MAC = ["-axo", "pid=,command=", "-ww"];
|
|
|
18
19
|
const WINDOWS_POWERSHELL = "powershell";
|
|
19
20
|
const UNITY_LOCKFILE_NAME = "UnityLockfile";
|
|
20
21
|
const TEMP_DIRECTORY_NAME = "Temp";
|
|
22
|
+
const npmExecutableName = () => {
|
|
23
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
24
|
+
};
|
|
25
|
+
const runCommand = async (command, args) => {
|
|
26
|
+
return await new Promise((resolve) => {
|
|
27
|
+
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
28
|
+
let stdout = "";
|
|
29
|
+
let stderr = "";
|
|
30
|
+
child.stdout?.on("data", (chunk) => {
|
|
31
|
+
stdout += chunk.toString("utf8");
|
|
32
|
+
});
|
|
33
|
+
child.stderr?.on("data", (chunk) => {
|
|
34
|
+
stderr += chunk.toString("utf8");
|
|
35
|
+
});
|
|
36
|
+
child.on("error", (error) => {
|
|
37
|
+
resolve({ exitCode: 127, stdout, stderr: `${stderr}${error.message}\n` });
|
|
38
|
+
});
|
|
39
|
+
child.on("close", (code) => {
|
|
40
|
+
resolve({ exitCode: code ?? 1, stdout, stderr });
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const parseSemverTriplet = (value) => {
|
|
45
|
+
const normalized = value.trim();
|
|
46
|
+
const withoutBuild = normalized.split("+")[0] ?? normalized;
|
|
47
|
+
const match = withoutBuild.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
|
|
48
|
+
if (!match) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const major = Number.parseInt(match[1] ?? "", 10);
|
|
52
|
+
const minor = Number.parseInt(match[2] ?? "", 10);
|
|
53
|
+
const patch = Number.parseInt(match[3] ?? "", 10);
|
|
54
|
+
if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const prereleaseRaw = match[4] ?? undefined;
|
|
58
|
+
if (!prereleaseRaw) {
|
|
59
|
+
return { major, minor, patch };
|
|
60
|
+
}
|
|
61
|
+
const prereleaseIdentifiers = prereleaseRaw
|
|
62
|
+
.split(".")
|
|
63
|
+
.map((part) => part.trim())
|
|
64
|
+
.filter((part) => part.length > 0)
|
|
65
|
+
.map((part) => {
|
|
66
|
+
const numeric = part.match(/^\d+$/);
|
|
67
|
+
if (numeric) {
|
|
68
|
+
const value = Number.parseInt(part, 10);
|
|
69
|
+
if (Number.isFinite(value)) {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return part;
|
|
74
|
+
});
|
|
75
|
+
if (prereleaseIdentifiers.length === 0) {
|
|
76
|
+
return { major, minor, patch };
|
|
77
|
+
}
|
|
78
|
+
return { major, minor, patch, prereleaseIdentifiers };
|
|
79
|
+
};
|
|
80
|
+
const compareSemverTriplet = (left, right) => {
|
|
81
|
+
if (left.major !== right.major) {
|
|
82
|
+
return left.major < right.major ? -1 : 1;
|
|
83
|
+
}
|
|
84
|
+
if (left.minor !== right.minor) {
|
|
85
|
+
return left.minor < right.minor ? -1 : 1;
|
|
86
|
+
}
|
|
87
|
+
if (left.patch !== right.patch) {
|
|
88
|
+
return left.patch < right.patch ? -1 : 1;
|
|
89
|
+
}
|
|
90
|
+
const leftPre = left.prereleaseIdentifiers;
|
|
91
|
+
const rightPre = right.prereleaseIdentifiers;
|
|
92
|
+
if (!leftPre && !rightPre) {
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
if (!leftPre && rightPre) {
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
if (leftPre && !rightPre) {
|
|
99
|
+
return -1;
|
|
100
|
+
}
|
|
101
|
+
const leftIdentifiers = leftPre ?? [];
|
|
102
|
+
const rightIdentifiers = rightPre ?? [];
|
|
103
|
+
const length = Math.max(leftIdentifiers.length, rightIdentifiers.length);
|
|
104
|
+
for (let i = 0; i < length; i++) {
|
|
105
|
+
const leftId = leftIdentifiers[i];
|
|
106
|
+
const rightId = rightIdentifiers[i];
|
|
107
|
+
if (leftId === undefined && rightId === undefined) {
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
if (leftId === undefined) {
|
|
111
|
+
return -1;
|
|
112
|
+
}
|
|
113
|
+
if (rightId === undefined) {
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
116
|
+
if (leftId === rightId) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const leftIsNumber = typeof leftId === "number";
|
|
120
|
+
const rightIsNumber = typeof rightId === "number";
|
|
121
|
+
if (leftIsNumber && rightIsNumber) {
|
|
122
|
+
return leftId < rightId ? -1 : 1;
|
|
123
|
+
}
|
|
124
|
+
if (leftIsNumber !== rightIsNumber) {
|
|
125
|
+
return leftIsNumber ? -1 : 1;
|
|
126
|
+
}
|
|
127
|
+
const leftText = String(leftId);
|
|
128
|
+
const rightText = String(rightId);
|
|
129
|
+
return leftText < rightText ? -1 : 1;
|
|
130
|
+
}
|
|
131
|
+
return 0;
|
|
132
|
+
};
|
|
21
133
|
function parseArgs(argv) {
|
|
22
134
|
const args = argv.slice(2);
|
|
23
135
|
const doubleDashIndex = args.indexOf("--");
|
|
24
|
-
|
|
136
|
+
let cliArgs = doubleDashIndex >= 0 ? args.slice(0, doubleDashIndex) : args;
|
|
25
137
|
const unityArgs = doubleDashIndex >= 0 ? args.slice(doubleDashIndex + 1) : [];
|
|
138
|
+
let subcommand;
|
|
139
|
+
const firstToken = cliArgs[0];
|
|
140
|
+
if (firstToken === "update") {
|
|
141
|
+
subcommand = "update";
|
|
142
|
+
cliArgs = cliArgs.slice(1);
|
|
143
|
+
}
|
|
26
144
|
const positionals = [];
|
|
27
145
|
let maxDepth = 3; // default 3; -1 means unlimited
|
|
28
146
|
let restart = false;
|
|
@@ -34,6 +152,10 @@ function parseArgs(argv) {
|
|
|
34
152
|
printHelp();
|
|
35
153
|
process.exit(0);
|
|
36
154
|
}
|
|
155
|
+
if (arg === "--version" || arg === "-v") {
|
|
156
|
+
console.log(getVersion());
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
37
159
|
if (arg === "-r" || arg === "--restart") {
|
|
38
160
|
restart = true;
|
|
39
161
|
continue;
|
|
@@ -97,7 +219,16 @@ function parseArgs(argv) {
|
|
|
97
219
|
projectPath = resolve(positionals[0] ?? "");
|
|
98
220
|
platform = String(positionals[1] ?? "");
|
|
99
221
|
}
|
|
100
|
-
const options = {
|
|
222
|
+
const options = {
|
|
223
|
+
unityArgs,
|
|
224
|
+
searchMaxDepth: maxDepth,
|
|
225
|
+
restart,
|
|
226
|
+
addUnityHub,
|
|
227
|
+
favoriteUnityHub,
|
|
228
|
+
};
|
|
229
|
+
if (subcommand) {
|
|
230
|
+
options.subcommand = subcommand;
|
|
231
|
+
}
|
|
101
232
|
if (projectPath !== undefined) {
|
|
102
233
|
options.projectPath = projectPath;
|
|
103
234
|
}
|
|
@@ -106,14 +237,23 @@ function parseArgs(argv) {
|
|
|
106
237
|
}
|
|
107
238
|
return options;
|
|
108
239
|
}
|
|
240
|
+
function getVersion() {
|
|
241
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
242
|
+
const currentDir = dirname(currentFilePath);
|
|
243
|
+
const packageJsonPath = join(currentDir, "..", "package.json");
|
|
244
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
245
|
+
return packageJson.version;
|
|
246
|
+
}
|
|
109
247
|
function printHelp() {
|
|
110
248
|
const help = `
|
|
111
|
-
Usage:
|
|
249
|
+
Usage:
|
|
250
|
+
launch-unity [PROJECT_PATH] [PLATFORM] -- [UNITY_ARGS...]
|
|
251
|
+
launch-unity update
|
|
112
252
|
|
|
113
253
|
Open a Unity project with the matching Unity Editor version installed by Unity Hub.
|
|
114
254
|
|
|
115
255
|
Arguments:
|
|
116
|
-
PROJECT_PATH Optional.
|
|
256
|
+
PROJECT_PATH Optional. If omitted, searches under the current directory (see --max-depth)
|
|
117
257
|
PLATFORM Optional. Passed to Unity as -buildTarget (e.g., StandaloneOSX, Android, iOS)
|
|
118
258
|
|
|
119
259
|
Forwarding:
|
|
@@ -122,11 +262,15 @@ Forwarding:
|
|
|
122
262
|
|
|
123
263
|
Flags:
|
|
124
264
|
-h, --help Show this help message
|
|
265
|
+
-v, --version Show version number
|
|
125
266
|
-r, --restart Kill running Unity and restart
|
|
126
267
|
--max-depth <N> Search depth when PROJECT_PATH is omitted (default 3, -1 unlimited)
|
|
127
268
|
-u, -a, --unity-hub-entry, --add-unity-hub
|
|
128
269
|
Add to Unity Hub if missing and update lastModified (does not launch Unity)
|
|
129
270
|
-f, --favorite Add to Unity Hub as favorite (does not launch Unity)
|
|
271
|
+
|
|
272
|
+
Commands:
|
|
273
|
+
update Update launch-unity to the latest version (npm global install)
|
|
130
274
|
`;
|
|
131
275
|
process.stdout.write(help);
|
|
132
276
|
}
|
|
@@ -577,6 +721,10 @@ function launch(opts) {
|
|
|
577
721
|
}
|
|
578
722
|
async function main() {
|
|
579
723
|
const options = parseArgs(process.argv);
|
|
724
|
+
if (options.subcommand === "update") {
|
|
725
|
+
await runSelfUpdate();
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
580
728
|
let resolvedProjectPath = options.projectPath;
|
|
581
729
|
if (!resolvedProjectPath) {
|
|
582
730
|
const searchRoot = process.cwd();
|
|
@@ -639,6 +787,59 @@ async function main() {
|
|
|
639
787
|
console.warn(`Failed to update Unity Hub lastModified: ${message}`);
|
|
640
788
|
}
|
|
641
789
|
}
|
|
790
|
+
async function runSelfUpdate() {
|
|
791
|
+
const currentVersion = getVersion();
|
|
792
|
+
const npmCmd = npmExecutableName();
|
|
793
|
+
const latestResult = await runCommand(npmCmd, ["view", "launch-unity", "version"]);
|
|
794
|
+
if (latestResult.exitCode !== 0) {
|
|
795
|
+
console.error("Error: Failed to retrieve latest version from npm.");
|
|
796
|
+
if (latestResult.stderr.trim().length > 0) {
|
|
797
|
+
process.stderr.write(latestResult.stderr);
|
|
798
|
+
}
|
|
799
|
+
process.exit(1);
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const latestVersion = latestResult.stdout.trim();
|
|
803
|
+
if (latestVersion.length === 0) {
|
|
804
|
+
console.error("Error: npm returned an empty version.");
|
|
805
|
+
process.exit(1);
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
console.log(`Current: ${currentVersion}`);
|
|
809
|
+
console.log(`Latest: ${latestVersion}`);
|
|
810
|
+
const currentSemver = parseSemverTriplet(currentVersion);
|
|
811
|
+
const latestSemver = parseSemverTriplet(latestVersion);
|
|
812
|
+
if (currentSemver && latestSemver) {
|
|
813
|
+
const cmp = compareSemverTriplet(currentSemver, latestSemver);
|
|
814
|
+
if (cmp >= 0) {
|
|
815
|
+
console.log("Already up to date.");
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
if (currentVersion === latestVersion) {
|
|
821
|
+
console.log("Already up to date.");
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const installArgs = ["install", "-g", `launch-unity@${latestVersion}`, "--ignore-scripts"];
|
|
826
|
+
console.log(`Running: ${npmCmd} ${installArgs.join(" ")}`);
|
|
827
|
+
const installResult = await runCommand(npmCmd, installArgs);
|
|
828
|
+
if (installResult.exitCode === 0) {
|
|
829
|
+
console.log("Update complete.");
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
console.error(`Error: Update failed (exit code ${installResult.exitCode}).`);
|
|
833
|
+
if (installResult.stderr.trim().length > 0) {
|
|
834
|
+
process.stderr.write(installResult.stderr);
|
|
835
|
+
}
|
|
836
|
+
if (process.platform === "darwin") {
|
|
837
|
+
const sudoSuggestion = `sudo ${npmCmd} ${installArgs.join(" ")}`;
|
|
838
|
+
console.error("If this is a permissions issue, try:");
|
|
839
|
+
console.error(` ${sudoSuggestion}`);
|
|
840
|
+
}
|
|
841
|
+
process.exit(1);
|
|
842
|
+
}
|
|
642
843
|
main().catch((error) => {
|
|
643
844
|
console.error(error);
|
|
644
845
|
process.exit(1);
|