launch-unity 0.9.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 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
@@ -19,11 +19,128 @@ const PROCESS_LIST_ARGS_MAC = ["-axo", "pid=,command=", "-ww"];
19
19
  const WINDOWS_POWERSHELL = "powershell";
20
20
  const UNITY_LOCKFILE_NAME = "UnityLockfile";
21
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
+ };
22
133
  function parseArgs(argv) {
23
134
  const args = argv.slice(2);
24
135
  const doubleDashIndex = args.indexOf("--");
25
- const cliArgs = doubleDashIndex >= 0 ? args.slice(0, doubleDashIndex) : args;
136
+ let cliArgs = doubleDashIndex >= 0 ? args.slice(0, doubleDashIndex) : args;
26
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
+ }
27
144
  const positionals = [];
28
145
  let maxDepth = 3; // default 3; -1 means unlimited
29
146
  let restart = false;
@@ -102,7 +219,16 @@ function parseArgs(argv) {
102
219
  projectPath = resolve(positionals[0] ?? "");
103
220
  platform = String(positionals[1] ?? "");
104
221
  }
105
- const options = { unityArgs, searchMaxDepth: maxDepth, restart, addUnityHub, favoriteUnityHub };
222
+ const options = {
223
+ unityArgs,
224
+ searchMaxDepth: maxDepth,
225
+ restart,
226
+ addUnityHub,
227
+ favoriteUnityHub,
228
+ };
229
+ if (subcommand) {
230
+ options.subcommand = subcommand;
231
+ }
106
232
  if (projectPath !== undefined) {
107
233
  options.projectPath = projectPath;
108
234
  }
@@ -120,12 +246,14 @@ function getVersion() {
120
246
  }
121
247
  function printHelp() {
122
248
  const help = `
123
- Usage: launch-unity [PROJECT_PATH] [PLATFORM] -- [UNITY_ARGS...]
249
+ Usage:
250
+ launch-unity [PROJECT_PATH] [PLATFORM] -- [UNITY_ARGS...]
251
+ launch-unity update
124
252
 
125
253
  Open a Unity project with the matching Unity Editor version installed by Unity Hub.
126
254
 
127
255
  Arguments:
128
- PROJECT_PATH Optional. Defaults to current directory
256
+ PROJECT_PATH Optional. If omitted, searches under the current directory (see --max-depth)
129
257
  PLATFORM Optional. Passed to Unity as -buildTarget (e.g., StandaloneOSX, Android, iOS)
130
258
 
131
259
  Forwarding:
@@ -140,6 +268,9 @@ Flags:
140
268
  -u, -a, --unity-hub-entry, --add-unity-hub
141
269
  Add to Unity Hub if missing and update lastModified (does not launch Unity)
142
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)
143
274
  `;
144
275
  process.stdout.write(help);
145
276
  }
@@ -590,6 +721,10 @@ function launch(opts) {
590
721
  }
591
722
  async function main() {
592
723
  const options = parseArgs(process.argv);
724
+ if (options.subcommand === "update") {
725
+ await runSelfUpdate();
726
+ return;
727
+ }
593
728
  let resolvedProjectPath = options.projectPath;
594
729
  if (!resolvedProjectPath) {
595
730
  const searchRoot = process.cwd();
@@ -652,6 +787,59 @@ async function main() {
652
787
  console.warn(`Failed to update Unity Hub lastModified: ${message}`);
653
788
  }
654
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
+ }
655
843
  main().catch((error) => {
656
844
  console.error(error);
657
845
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "launch-unity",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Open a Unity project with the matching Editor version (macOS/Windows)",
5
5
  "type": "module",
6
6
  "main": "dist/launch.js",