@rage-against-the-pixel/unity-cli 1.0.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/android-sdk.d.ts +7 -0
- package/dist/android-sdk.js +144 -0
- package/dist/android-sdk.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +298 -0
- package/dist/index.js.map +1 -0
- package/dist/license-client.d.ts +25 -0
- package/dist/license-client.js +411 -0
- package/dist/license-client.js.map +1 -0
- package/dist/logging.d.ts +44 -0
- package/dist/logging.js +147 -0
- package/dist/logging.js.map +1 -0
- package/dist/unity-editor.d.ts +26 -0
- package/dist/unity-editor.js +333 -0
- package/dist/unity-editor.js.map +1 -0
- package/dist/unity-hub.d.ts +73 -0
- package/dist/unity-hub.js +902 -0
- package/dist/unity-hub.js.map +1 -0
- package/dist/unity-project.d.ts +13 -0
- package/dist/unity-project.js +87 -0
- package/dist/unity-project.js.map +1 -0
- package/dist/unity-version.d.ts +14 -0
- package/dist/unity-version.js +186 -0
- package/dist/unity-version.js.map +1 -0
- package/dist/utilities.d.ts +44 -0
- package/dist/utilities.js +291 -0
- package/dist/utilities.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.UnityHub = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const yaml = __importStar(require("yaml"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const logging_1 = require("./logging");
|
|
43
|
+
const semver_1 = require("semver");
|
|
44
|
+
const utilities_1 = require("./utilities");
|
|
45
|
+
const unity_version_1 = require("./unity-version");
|
|
46
|
+
const client_1 = require("@rage-against-the-pixel/unity-releases-api/dist/client");
|
|
47
|
+
const unity_editor_1 = require("./unity-editor");
|
|
48
|
+
class UnityHub {
|
|
49
|
+
executable;
|
|
50
|
+
rootDirectory;
|
|
51
|
+
editorInstallationDirectory;
|
|
52
|
+
editorFileExtension;
|
|
53
|
+
logger = logging_1.Logger.instance;
|
|
54
|
+
constructor() {
|
|
55
|
+
switch (process.platform) {
|
|
56
|
+
case 'win32':
|
|
57
|
+
this.executable = process.env.UNITY_HUB_PATH || 'C:\\Program Files\\Unity Hub\\Unity Hub.exe';
|
|
58
|
+
this.rootDirectory = path.join(this.executable, '../');
|
|
59
|
+
this.editorInstallationDirectory = 'C:\\Program Files\\Unity\\Hub\\Editor\\';
|
|
60
|
+
this.editorFileExtension = '\\Editor\\Unity.exe';
|
|
61
|
+
break;
|
|
62
|
+
case 'darwin':
|
|
63
|
+
this.executable = process.env.UNITY_HUB_PATH || '/Applications/Unity Hub.app/Contents/MacOS/Unity Hub';
|
|
64
|
+
this.rootDirectory = path.join(this.executable, '../../../');
|
|
65
|
+
this.editorInstallationDirectory = '/Applications/Unity/Hub/Editor/';
|
|
66
|
+
this.editorFileExtension = '/Unity.app/Contents/MacOS/Unity';
|
|
67
|
+
break;
|
|
68
|
+
case 'linux':
|
|
69
|
+
this.executable = process.env.UNITY_HUB_PATH || '/opt/unityhub/unityhub';
|
|
70
|
+
this.rootDirectory = path.join(this.executable, '../');
|
|
71
|
+
this.editorInstallationDirectory = `${process.env.HOME}/Unity/Hub/Editor/`;
|
|
72
|
+
this.editorFileExtension = '/Editor/Unity';
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Executes the Unity Hub command with the specified arguments.
|
|
80
|
+
* @param args Arguments to pass to the Unity Hub executable.
|
|
81
|
+
* @param silent If true, suppresses output logging.
|
|
82
|
+
* @returns The output from the command.
|
|
83
|
+
*/
|
|
84
|
+
async Exec(args, options = { silent: this.logger.logLevel > logging_1.LogLevel.CI, showCommand: this.logger.logLevel <= logging_1.LogLevel.CI }) {
|
|
85
|
+
let output = '';
|
|
86
|
+
let exitCode = 0;
|
|
87
|
+
function processOutput(data) {
|
|
88
|
+
const chunk = data.toString();
|
|
89
|
+
output += chunk;
|
|
90
|
+
if (!options.silent) {
|
|
91
|
+
process.stdout.write(chunk);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const filteredArgs = args.filter(arg => arg !== '--headless' && arg !== '--');
|
|
95
|
+
const executable = process.platform === 'linux' ? 'unity-hub' : this.executable;
|
|
96
|
+
const execArgs = process.platform === 'linux' ? ['--headless', ...filteredArgs] : ['--', '--headless', ...filteredArgs];
|
|
97
|
+
if (options.showCommand) {
|
|
98
|
+
this.logger.startGroup(`\x1b[34m${executable} ${execArgs.join(' ')}\x1b[0m`);
|
|
99
|
+
}
|
|
100
|
+
if (this.executable.includes(path.sep)) {
|
|
101
|
+
fs.accessSync(this.executable, fs.constants.R_OK | fs.constants.X_OK);
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
exitCode = await new Promise((resolve, reject) => {
|
|
105
|
+
const child = (0, child_process_1.spawn)(executable, execArgs, {
|
|
106
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
107
|
+
});
|
|
108
|
+
process.once('SIGINT', () => child.kill('SIGINT'));
|
|
109
|
+
process.once('SIGTERM', () => child.kill('SIGTERM'));
|
|
110
|
+
child.stdout.on('data', processOutput);
|
|
111
|
+
child.stderr.on('data', processOutput);
|
|
112
|
+
child.on('error', (error) => reject(error));
|
|
113
|
+
child.on('close', (code) => {
|
|
114
|
+
process.stdout.write('\n');
|
|
115
|
+
resolve(code === null ? 0 : code);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
this.logger.endGroup();
|
|
121
|
+
const match = output.match(/Assertion (?<assert>.+) failed/g);
|
|
122
|
+
if (match ||
|
|
123
|
+
output.includes('async hook stack has become corrupted')) {
|
|
124
|
+
this.logger.warn(`Install failed, retrying...`);
|
|
125
|
+
return await this.Exec(args);
|
|
126
|
+
}
|
|
127
|
+
if (exitCode > 0 || output.includes('Error:')) {
|
|
128
|
+
const error = output.match(/Error: (.+)/);
|
|
129
|
+
const errorMessage = error && error[1] ? error[1] : 'Unknown Error';
|
|
130
|
+
switch (errorMessage) {
|
|
131
|
+
case 'No modules found to install.':
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
throw new Error(`Failed to execute Unity Hub: [${exitCode}] ${errorMessage}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const ignoredLines = [
|
|
138
|
+
`This error originated either by throwing inside of an async function without a catch block`,
|
|
139
|
+
`Unexpected error attempting to determine if executable file exists`,
|
|
140
|
+
`dri3 extension not supported`,
|
|
141
|
+
`Failed to connect to the bus:`,
|
|
142
|
+
`Checking for beta autoupdate feature for deb/rpm distributions`,
|
|
143
|
+
`Found package-type: deb`,
|
|
144
|
+
`XPC error for connection com.apple.backupd.sandbox.xpc: Connection invalid`
|
|
145
|
+
];
|
|
146
|
+
output = output.split('\n')
|
|
147
|
+
.filter(line => line.trim().length > 0)
|
|
148
|
+
.filter(line => !ignoredLines.some(ignored => line.includes(ignored)))
|
|
149
|
+
.join('\n');
|
|
150
|
+
}
|
|
151
|
+
return output;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Prints the installed Unity Hub version.
|
|
155
|
+
*/
|
|
156
|
+
async Version() {
|
|
157
|
+
const version = await this.getInstalledHubVersion();
|
|
158
|
+
return version.version;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Installs or updates the Unity Hub.
|
|
162
|
+
* If the Unity Hub is already installed, it will be updated to the latest version.
|
|
163
|
+
*/
|
|
164
|
+
async Install() {
|
|
165
|
+
let isInstalled = false;
|
|
166
|
+
try {
|
|
167
|
+
await fs.promises.access(this.executable, fs.constants.X_OK);
|
|
168
|
+
isInstalled = true;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
await this.installHub();
|
|
172
|
+
}
|
|
173
|
+
if (isInstalled) {
|
|
174
|
+
const installedVersion = await this.getInstalledHubVersion();
|
|
175
|
+
this.logger.ci(`Installed Unity Hub version: ${installedVersion.version}`);
|
|
176
|
+
let latestVersion = undefined;
|
|
177
|
+
try {
|
|
178
|
+
latestVersion = await this.getLatestHubVersion();
|
|
179
|
+
this.logger.ci(`Latest Unity Hub version: ${latestVersion.version}`);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
this.logger.warn(`Failed to get latest Unity Hub version: ${error}`);
|
|
183
|
+
}
|
|
184
|
+
if (latestVersion && (0, semver_1.compare)(installedVersion, latestVersion) < 0) {
|
|
185
|
+
this.logger.info(`Updating Unity Hub from ${installedVersion.version} to ${latestVersion.version}...`);
|
|
186
|
+
if (process.platform !== 'linux') {
|
|
187
|
+
await (0, utilities_1.DeleteDirectory)(this.rootDirectory);
|
|
188
|
+
await this.installHub();
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
await (0, utilities_1.Exec)('sudo', ['sh', '-c', `#!/bin/bash
|
|
192
|
+
set -e
|
|
193
|
+
wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor | sudo tee /usr/share/keyrings/Unity_Technologies_ApS.gpg >/dev/null
|
|
194
|
+
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/Unity_Technologies_ApS.gpg] https://hub.unity3d.com/linux/repos/deb stable main" > /etc/apt/sources.list.d/unityhub.list'
|
|
195
|
+
sudo apt-get update --allow-releaseinfo-change
|
|
196
|
+
sudo apt-get install -y --no-install-recommends --only-upgrade unityhub`]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this.logger.info(`Unity Hub is already installed and up to date.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return this.executable;
|
|
204
|
+
}
|
|
205
|
+
async installHub() {
|
|
206
|
+
switch (process.platform) {
|
|
207
|
+
case 'win32': {
|
|
208
|
+
const url = 'https://public-cdn.cloud.unity3d.com/hub/prod/UnityHubSetup.exe';
|
|
209
|
+
const downloadPath = path.join((0, utilities_1.GetTempDir)(), 'UnityHubSetup.exe');
|
|
210
|
+
await (0, utilities_1.DownloadFile)(url, downloadPath);
|
|
211
|
+
this.logger.info(`Running Unity Hub installer...`);
|
|
212
|
+
try {
|
|
213
|
+
await (0, utilities_1.Exec)(downloadPath, ['/S'], { silent: true });
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
if (fs.statSync(downloadPath).isFile()) {
|
|
217
|
+
await fs.promises.unlink(downloadPath);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case 'darwin': {
|
|
223
|
+
const baseUrl = 'https://public-cdn.cloud.unity3d.com/hub/prod';
|
|
224
|
+
const url = `${baseUrl}/UnityHubSetup-${process.arch}.dmg`;
|
|
225
|
+
const downloadPath = path.join((0, utilities_1.GetTempDir)(), `UnityHubSetup-${process.arch}.dmg`);
|
|
226
|
+
this.logger.info(`Downloading Unity Hub from ${url} to ${downloadPath}`);
|
|
227
|
+
await (0, utilities_1.DownloadFile)(url, downloadPath);
|
|
228
|
+
await fs.promises.chmod(downloadPath, 0o777);
|
|
229
|
+
let mountPoint = '';
|
|
230
|
+
this.logger.debug(`Mounting DMG...`);
|
|
231
|
+
try {
|
|
232
|
+
const output = await (0, utilities_1.Exec)('hdiutil', ['attach', downloadPath, '-nobrowse'], { silent: true });
|
|
233
|
+
// can be "/Volumes/Unity Hub 3.13.1-arm64" or "/Volumes/Unity Hub 3.13.1"
|
|
234
|
+
const mountPointMatch = output.match(/\/Volumes\/Unity Hub.*$/m);
|
|
235
|
+
if (!mountPointMatch || mountPointMatch.length === 0) {
|
|
236
|
+
throw new Error(`Failed to find mount point in hdiutil output: ${output}`);
|
|
237
|
+
}
|
|
238
|
+
mountPoint = mountPointMatch[0];
|
|
239
|
+
this.logger.debug(`Mounted Unity Hub at ${mountPoint}`);
|
|
240
|
+
const appPath = path.join(mountPoint, 'Unity Hub.app');
|
|
241
|
+
this.logger.debug(`Copying ${appPath} to /Applications...`);
|
|
242
|
+
await fs.promises.access(appPath, fs.constants.R_OK | fs.constants.X_OK);
|
|
243
|
+
if (fs.existsSync('/Applications/Unity Hub.app')) {
|
|
244
|
+
await (0, utilities_1.Exec)('sudo', ['rm', '-rf', '/Applications/Unity Hub.app'], { silent: true });
|
|
245
|
+
}
|
|
246
|
+
await (0, utilities_1.Exec)('sudo', ['cp', '-R', appPath, '/Applications/Unity Hub.app'], { silent: true });
|
|
247
|
+
await (0, utilities_1.Exec)('sudo', ['chmod', '777', '/Applications/Unity Hub.app/Contents/MacOS/Unity Hub'], { silent: true });
|
|
248
|
+
await (0, utilities_1.Exec)('sudo', ['mkdir', '-p', '/Library/Application Support/Unity'], { silent: true });
|
|
249
|
+
await (0, utilities_1.Exec)('sudo', ['chmod', '777', '/Library/Application Support/Unity'], { silent: true });
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
try {
|
|
253
|
+
if (mountPoint && mountPoint.length > 0) {
|
|
254
|
+
await (0, utilities_1.Exec)('hdiutil', ['detach', mountPoint, '-quiet'], { silent: true });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
if (fs.statSync(downloadPath).isFile()) {
|
|
259
|
+
await fs.promises.unlink(downloadPath);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case 'linux': {
|
|
266
|
+
await (0, utilities_1.Exec)('sudo', ['sh', '-c', `#!/bin/bash
|
|
267
|
+
set -e
|
|
268
|
+
dbus-uuidgen >/etc/machine-id && mkdir -p /var/lib/dbus/ && ln -sf /etc/machine-id /var/lib/dbus/machine-id
|
|
269
|
+
wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor | tee /usr/share/keyrings/Unity_Technologies_ApS.gpg >/dev/null
|
|
270
|
+
echo "deb [signed-by=/usr/share/keyrings/Unity_Technologies_ApS.gpg] https://hub.unity3d.com/linux/repos/deb stable main" > /etc/apt/sources.list.d/unityhub.list
|
|
271
|
+
echo "deb https://archive.ubuntu.com/ubuntu jammy main universe" | tee /etc/apt/sources.list.d/jammy.list
|
|
272
|
+
apt-get update
|
|
273
|
+
apt-get install -y --no-install-recommends unityhub ffmpeg libgtk2.0-0 libglu1-mesa libgconf-2-4 libncurses5
|
|
274
|
+
apt-get clean
|
|
275
|
+
sed -i 's/^\\(.*DISPLAY=:.*XAUTHORITY=.*\\)\\( "\\$@" \\)2>&1$/\\1\\2/' /usr/bin/xvfb-run
|
|
276
|
+
printf '#!/bin/bash\nxvfb-run --auto-servernum /opt/unityhub/unityhub "$@" 2>/dev/null' | tee /usr/bin/unity-hub >/dev/null
|
|
277
|
+
chmod 777 /usr/bin/unity-hub
|
|
278
|
+
hubPath=$(which unityhub)
|
|
279
|
+
|
|
280
|
+
if [ -z "$hubPath" ]; then
|
|
281
|
+
echo "Failed to install Unity Hub"
|
|
282
|
+
exit 1
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
chmod -R 777 "$hubPath"`]);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
default:
|
|
289
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
290
|
+
}
|
|
291
|
+
await fs.promises.access(this.executable, fs.constants.X_OK);
|
|
292
|
+
this.logger.info(`Unity Hub installed successfully.`);
|
|
293
|
+
}
|
|
294
|
+
async getInstalledHubVersion() {
|
|
295
|
+
let asarPath = undefined;
|
|
296
|
+
switch (process.platform) {
|
|
297
|
+
case 'darwin': {
|
|
298
|
+
asarPath = path.join(this.rootDirectory, 'Contents', 'Resources', 'app.asar');
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
default: {
|
|
302
|
+
asarPath = path.join(this.rootDirectory, 'resources', 'app.asar');
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
await fs.promises.access(asarPath, fs.constants.R_OK);
|
|
307
|
+
const asar = await Promise.resolve().then(() => __importStar(require('@electron/asar')));
|
|
308
|
+
const fileBuffer = asar.extractFile(asarPath, 'package.json');
|
|
309
|
+
const packageJson = JSON.parse(fileBuffer.toString());
|
|
310
|
+
const version = (0, semver_1.coerce)(packageJson.version);
|
|
311
|
+
if (!version || !(0, semver_1.valid)(version)) {
|
|
312
|
+
throw new Error(`Failed to parse Unity Hub version: ${packageJson.version}`);
|
|
313
|
+
}
|
|
314
|
+
return version;
|
|
315
|
+
}
|
|
316
|
+
async getLatestHubVersion() {
|
|
317
|
+
let url = undefined;
|
|
318
|
+
switch (process.platform) {
|
|
319
|
+
case 'win32':
|
|
320
|
+
url = 'https://public-cdn.cloud.unity3d.com/hub/prod/latest.yml';
|
|
321
|
+
break;
|
|
322
|
+
case 'darwin':
|
|
323
|
+
url = 'https://public-cdn.cloud.unity3d.com/hub/prod/latest-mac.yml';
|
|
324
|
+
break;
|
|
325
|
+
case 'linux':
|
|
326
|
+
url = 'https://public-cdn.cloud.unity3d.com/hub/prod/latest-linux.yml';
|
|
327
|
+
break;
|
|
328
|
+
default:
|
|
329
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
330
|
+
}
|
|
331
|
+
const response = await fetch(url);
|
|
332
|
+
const data = await response.text();
|
|
333
|
+
const parsed = yaml.parse(data);
|
|
334
|
+
const version = (0, semver_1.coerce)(parsed.version);
|
|
335
|
+
if (!version || !(0, semver_1.valid)(version)) {
|
|
336
|
+
throw new Error(`Failed to parse latest Unity Hub version: ${parsed.version}`);
|
|
337
|
+
}
|
|
338
|
+
return version;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Returns the path where the Unity editors will be installed.
|
|
342
|
+
* @returns {Promise<string>} The install path.
|
|
343
|
+
*/
|
|
344
|
+
async GetInstallPath() {
|
|
345
|
+
const result = (await this.Exec(['install-path', '--get'])).trim();
|
|
346
|
+
if (!result || result.length === 0) {
|
|
347
|
+
throw new Error('Failed to get Unity Hub install path.');
|
|
348
|
+
}
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Sets the path where Unity editors will be installed.
|
|
353
|
+
* @param installPath The path to set.
|
|
354
|
+
*/
|
|
355
|
+
async SetInstallPath(installPath) {
|
|
356
|
+
await fs.promises.mkdir(installPath, { recursive: true });
|
|
357
|
+
await this.Exec(['install-path', '--set', installPath]);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Locate and associate an installed editor from a stipulated path.
|
|
361
|
+
* @param editorPath
|
|
362
|
+
*/
|
|
363
|
+
async AddEditor(editorPath) {
|
|
364
|
+
await fs.promises.access(editorPath, fs.constants.R_OK | fs.constants.X_OK);
|
|
365
|
+
await this.Exec(['editors', '--add', editorPath]);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Attempts to find or install the specified Unity Editor version with the requested modules.
|
|
369
|
+
* @param unityVersion The Unity version to find or install.
|
|
370
|
+
* @param modules The modules to install alongside the editor.
|
|
371
|
+
* @returns The path to the Unity Editor executable.
|
|
372
|
+
*/
|
|
373
|
+
async GetEditor(unityVersion, modules) {
|
|
374
|
+
const retryErrorMessages = [
|
|
375
|
+
'Editor already installed in this location',
|
|
376
|
+
'failed to download. Error given: Request timeout'
|
|
377
|
+
];
|
|
378
|
+
this.logger.ci(`Getting release info for Unity ${unityVersion.toString()}...`);
|
|
379
|
+
let editorPath = await this.checkInstalledEditors(unityVersion, false);
|
|
380
|
+
// attempt to resolve the full version with the changeset if we don't have one already
|
|
381
|
+
if (!unityVersion.isLegacy() && !editorPath && !unityVersion.changeset) {
|
|
382
|
+
try {
|
|
383
|
+
const releases = await this.getLatestHubReleases();
|
|
384
|
+
unityVersion = unityVersion.findMatch(releases);
|
|
385
|
+
const unityReleaseInfo = await this.getEditorReleaseInfo(unityVersion);
|
|
386
|
+
unityVersion = new unity_version_1.UnityVersion(unityReleaseInfo.version, unityReleaseInfo.shortRevision, unityVersion.architecture);
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
this.logger.warn(`Failed to get Unity release info for ${unityVersion.toString()}! falling back to legacy search...\n${error}`);
|
|
390
|
+
try {
|
|
391
|
+
unityVersion = await this.fallbackVersionLookup(unityVersion);
|
|
392
|
+
}
|
|
393
|
+
catch (fallbackError) {
|
|
394
|
+
this.logger.warn(`Failed to lookup changeset for Unity ${unityVersion.toString()}!\n${fallbackError}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
let installPath = undefined;
|
|
399
|
+
if (!editorPath) {
|
|
400
|
+
try {
|
|
401
|
+
installPath = await this.installUnity(unityVersion, modules);
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
if (retryErrorMessages.some(msg => error.message.includes(msg))) {
|
|
405
|
+
if (editorPath) {
|
|
406
|
+
await (0, utilities_1.DeleteDirectory)(editorPath);
|
|
407
|
+
}
|
|
408
|
+
if (installPath) {
|
|
409
|
+
await (0, utilities_1.DeleteDirectory)(installPath);
|
|
410
|
+
}
|
|
411
|
+
installPath = await this.installUnity(unityVersion, modules);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
throw error;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
editorPath = await this.checkInstalledEditors(unityVersion, true, installPath);
|
|
418
|
+
}
|
|
419
|
+
if (!editorPath) {
|
|
420
|
+
throw new Error(`Failed to find or install Unity Editor: ${unityVersion.toString()}`);
|
|
421
|
+
}
|
|
422
|
+
await fs.promises.access(editorPath, fs.constants.X_OK);
|
|
423
|
+
await this.patchBeeBackend(editorPath);
|
|
424
|
+
if (unityVersion.isLegacy() || modules.length === 0) {
|
|
425
|
+
return editorPath;
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
this.logger.ci(`Checking installed modules for Unity ${unityVersion.toString()}...`);
|
|
429
|
+
const [installedModules, additionalModules] = await this.checkEditorModules(editorPath, unityVersion, modules);
|
|
430
|
+
if (installedModules && installedModules.length > 0) {
|
|
431
|
+
this.logger.ci(`Installed Modules:`);
|
|
432
|
+
for (const module of installedModules) {
|
|
433
|
+
this.logger.ci(` > ${module}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (additionalModules && additionalModules.length > 0) {
|
|
437
|
+
this.logger.ci(`Additional Modules:`);
|
|
438
|
+
for (const module of additionalModules) {
|
|
439
|
+
this.logger.ci(` > ${module}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
if (error.message.includes(`No modules found`)) {
|
|
445
|
+
await (0, utilities_1.DeleteDirectory)(editorPath);
|
|
446
|
+
await this.GetEditor(unityVersion, modules);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return path.normalize(editorPath);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Lists the installed Unity Editors.
|
|
453
|
+
* @returns A list of installed Unity Editor versions and their paths.
|
|
454
|
+
*/
|
|
455
|
+
async ListInstalledEditors() {
|
|
456
|
+
const output = await this.Exec(['editors', '-i']);
|
|
457
|
+
return output.split('\n')
|
|
458
|
+
.filter(line => line.trim().length > 0)
|
|
459
|
+
.map(line => line.trim());
|
|
460
|
+
}
|
|
461
|
+
async checkInstalledEditors(unityVersion, failOnEmpty, installPath = undefined) {
|
|
462
|
+
let editorPath = undefined;
|
|
463
|
+
if (!installPath) {
|
|
464
|
+
const paths = await this.ListInstalledEditors();
|
|
465
|
+
if (paths && paths.length > 0) {
|
|
466
|
+
const pattern = /(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\s*(?:\((?<arch>Apple silicon|Intel)\))?\s*,? installed at (?<editorPath>.*)/;
|
|
467
|
+
const matches = paths.map(path => path.match(pattern)).filter(match => match && match.groups);
|
|
468
|
+
if (paths.length !== matches.length) {
|
|
469
|
+
throw new Error(`Failed to parse all installed Unity Editors!\n > paths: ${JSON.stringify(paths)}\n > matches: ${JSON.stringify(matches)}`);
|
|
470
|
+
}
|
|
471
|
+
// Prefer exact version match first
|
|
472
|
+
const exactMatch = matches.find(match => match?.groups?.version === unityVersion.version);
|
|
473
|
+
if (exactMatch) {
|
|
474
|
+
editorPath = exactMatch.groups.editorPath;
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
// Fallback: semver satisfies
|
|
478
|
+
const versionMatches = matches.filter(match => match?.groups?.version && unityVersion.satisfies(match.groups.version));
|
|
479
|
+
if (versionMatches.length === 0) {
|
|
480
|
+
return undefined;
|
|
481
|
+
}
|
|
482
|
+
const archMap = {
|
|
483
|
+
'ARM64': 'Apple silicon',
|
|
484
|
+
'X86_64': 'Intel',
|
|
485
|
+
};
|
|
486
|
+
for (const match of versionMatches) {
|
|
487
|
+
if (!match || !match.groups || !match.groups.version || !match.groups.editorPath) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
// If no architecture is set, or no arch in match, accept the version match
|
|
491
|
+
if (!unityVersion.architecture || !match.groups.arch) {
|
|
492
|
+
editorPath = match.groups.editorPath;
|
|
493
|
+
}
|
|
494
|
+
// If architecture is set and present in match, check for match
|
|
495
|
+
else if (archMap[unityVersion.architecture] === match.groups.arch) {
|
|
496
|
+
editorPath = match.groups.editorPath;
|
|
497
|
+
}
|
|
498
|
+
// Fallback: check if editorPath includes architecture string (case-insensitive)
|
|
499
|
+
else if (unityVersion.architecture && match.groups.editorPath.toLowerCase().includes(`-${unityVersion.architecture.toLowerCase()}`)) {
|
|
500
|
+
editorPath = match.groups.editorPath;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
if (process.platform == 'win32') {
|
|
508
|
+
editorPath = path.join(installPath, 'Unity.exe');
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
editorPath = installPath;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (!editorPath) {
|
|
515
|
+
if (failOnEmpty) {
|
|
516
|
+
throw new Error(`Failed to find installed Unity Editor: ${unityVersion.toString()}`);
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (process.platform === 'darwin') {
|
|
523
|
+
editorPath = path.join(editorPath, '/Contents/MacOS/Unity');
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
await fs.promises.access(editorPath, fs.constants.R_OK | fs.constants.X_OK);
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
throw new Error(`Failed to find installed Unity Editor: ${unityVersion.toString()}\n > ${error}`);
|
|
530
|
+
}
|
|
531
|
+
this.logger.ci(`Found installed Unity Editor: ${editorPath}`);
|
|
532
|
+
return editorPath;
|
|
533
|
+
}
|
|
534
|
+
async getLatestHubReleases() {
|
|
535
|
+
// Normalize output to bare version strings (e.g., 2022.3.62f1)
|
|
536
|
+
// Unity Hub can return lines like:
|
|
537
|
+
// - "6000.0.56f1 (Apple silicon)"
|
|
538
|
+
// - "2022.3.62f1 installed at C:\\..."
|
|
539
|
+
// - "2022.3.62f1, installed at ..." (older format)
|
|
540
|
+
// We extract the first version token and discard the rest.
|
|
541
|
+
const versionRegex = /(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/;
|
|
542
|
+
return (await this.Exec([`editors`, `--releases`]))
|
|
543
|
+
.split('\n')
|
|
544
|
+
.map(line => line.trim())
|
|
545
|
+
.filter(line => line.length > 0)
|
|
546
|
+
.map(line => {
|
|
547
|
+
const match = line.match(versionRegex);
|
|
548
|
+
return match ? match[0] : '';
|
|
549
|
+
})
|
|
550
|
+
.filter(v => v.length > 0);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Patches the Bee Backend for Unity Linux Editor.
|
|
554
|
+
* https://discussions.unity.com/t/linux-editor-stuck-on-loading-because-of-bee-backend-w-workaround/854480
|
|
555
|
+
* @param editorPath The path to the Unity Editor executable.
|
|
556
|
+
*/
|
|
557
|
+
async patchBeeBackend(editorPath) {
|
|
558
|
+
if (process.platform === 'linux') {
|
|
559
|
+
const dataPath = path.join(path.dirname(editorPath), 'Data');
|
|
560
|
+
const beeBackend = path.join(dataPath, 'bee_backend');
|
|
561
|
+
const dotBeeBackend = path.join(dataPath, '.bee_backend');
|
|
562
|
+
if (fs.existsSync(beeBackend) && !fs.existsSync(dotBeeBackend)) {
|
|
563
|
+
this.logger.ci(`Patching Unity Linux Editor for Bee Backend...`);
|
|
564
|
+
await fs.promises.rename(beeBackend, dotBeeBackend);
|
|
565
|
+
const wrapperSource = `#!/bin/bash
|
|
566
|
+
# https://discussions.unity.com/t/linux-editor-stuck-on-loading-because-of-bee-backend-w-workaround/854480
|
|
567
|
+
set -e
|
|
568
|
+
args=("$@")
|
|
569
|
+
for ((i = 0; i < "\${#args[@]}"; ++i)); do
|
|
570
|
+
case \${args[i]} in
|
|
571
|
+
--stdin-canary)
|
|
572
|
+
unset "args[i]"
|
|
573
|
+
break
|
|
574
|
+
;;
|
|
575
|
+
esac
|
|
576
|
+
done
|
|
577
|
+
"$(dirname "$0")/.$(basename "$0")" "\${args[@]}"`;
|
|
578
|
+
await fs.promises.writeFile(beeBackend, wrapperSource, { encoding: 'utf-8', mode: 0o755 });
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async getEditorReleaseInfo(unityVersion) {
|
|
583
|
+
// Prefer querying the releases API with the exact fully-qualified Unity version (e.g., 2022.3.10f1).
|
|
584
|
+
// If we don't have a fully-qualified version, use the most specific prefix available:
|
|
585
|
+
// - "YYYY.M" when provided (e.g., 6000.1)
|
|
586
|
+
// - otherwise "YYYY"
|
|
587
|
+
const fullUnityVersionPattern = /^\d{1,4}\.\d+\.\d+[abcfpx]\d+$/;
|
|
588
|
+
let version;
|
|
589
|
+
if (fullUnityVersionPattern.test(unityVersion.version)) {
|
|
590
|
+
version = unityVersion.version;
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
const mm = unityVersion.version.match(/^(\d{1,4})(?:\.(\d+))?/);
|
|
594
|
+
if (mm) {
|
|
595
|
+
version = mm[2] ? `${mm[1]}.${mm[2]}` : mm[1];
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
version = unityVersion.version.split('.')[0];
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const releasesClient = new client_1.UnityReleasesClient();
|
|
602
|
+
function getPlatform() {
|
|
603
|
+
switch (process.platform) {
|
|
604
|
+
case 'darwin':
|
|
605
|
+
return ['MAC_OS'];
|
|
606
|
+
case 'linux':
|
|
607
|
+
return ['LINUX'];
|
|
608
|
+
case 'win32':
|
|
609
|
+
return ['WINDOWS'];
|
|
610
|
+
default:
|
|
611
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const request = {
|
|
615
|
+
query: {
|
|
616
|
+
version: version,
|
|
617
|
+
architecture: [unityVersion.architecture],
|
|
618
|
+
platform: getPlatform(),
|
|
619
|
+
limit: 1,
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
this.logger.debug(`Get Unity Release: ${JSON.stringify(request, null, 2)}`);
|
|
623
|
+
const { data, error } = await releasesClient.api.ReleaseService.getUnityReleases(request);
|
|
624
|
+
if (error) {
|
|
625
|
+
throw new Error(`Failed to get Unity releases: ${JSON.stringify(error, null, 2)}`);
|
|
626
|
+
}
|
|
627
|
+
if (!data || !data.results || data.results.length === 0) {
|
|
628
|
+
throw new Error(`No Unity releases found for version: ${version}`);
|
|
629
|
+
}
|
|
630
|
+
this.logger.debug(`Found Unity Release: ${JSON.stringify(data, null, 2)}`);
|
|
631
|
+
// Filter to stable 'f' releases only unless the user explicitly asked for a pre-release
|
|
632
|
+
const isExplicitPrerelease = /[abcpx]$/.test(unityVersion.version) || /[abcpx]/.test(unityVersion.version);
|
|
633
|
+
const results = (data.results || [])
|
|
634
|
+
.filter(r => isExplicitPrerelease ? true : /f\d+$/.test(r.version))
|
|
635
|
+
// Sort descending by minor, patch, f-number where possible; fallback to semver coercion
|
|
636
|
+
.sort((a, b) => {
|
|
637
|
+
const parse = (v) => {
|
|
638
|
+
const m = v.match(/(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/);
|
|
639
|
+
return m ? [parseInt(m[2]), parseInt(m[3]), m[4], parseInt(m[5])] : [0, 0, 'f', 0];
|
|
640
|
+
};
|
|
641
|
+
const [aMinor, aPatch, aTag, aNum] = parse(a.version);
|
|
642
|
+
const [bMinor, bPatch, bTag, bNum] = parse(b.version);
|
|
643
|
+
// Prefer higher minor
|
|
644
|
+
if (aMinor !== bMinor)
|
|
645
|
+
return bMinor - aMinor;
|
|
646
|
+
// Then higher patch
|
|
647
|
+
if (aPatch !== bPatch)
|
|
648
|
+
return bPatch - aPatch;
|
|
649
|
+
// Tag order: f > p > c > b > a > x
|
|
650
|
+
const order = { f: 5, p: 4, c: 3, b: 2, a: 1, x: 0 };
|
|
651
|
+
if (order[aTag] !== order[bTag])
|
|
652
|
+
return (order[bTag] || 0) - (order[aTag] || 0);
|
|
653
|
+
return bNum - aNum;
|
|
654
|
+
});
|
|
655
|
+
if (results.length === 0) {
|
|
656
|
+
throw new Error(`No suitable Unity releases (stable) found for version: ${version}`);
|
|
657
|
+
}
|
|
658
|
+
this.logger.debug(`Found Unity Release: ${JSON.stringify({ query: version, picked: results[0] }, null, 2)}`);
|
|
659
|
+
return results[0];
|
|
660
|
+
}
|
|
661
|
+
async fallbackVersionLookup(unityVersion) {
|
|
662
|
+
const url = `https://unity.com/releases/editor/whats-new/${unityVersion.version}`;
|
|
663
|
+
this.logger.debug(`Fetching release page: "${url}"`);
|
|
664
|
+
let response;
|
|
665
|
+
try {
|
|
666
|
+
response = await fetch(url);
|
|
667
|
+
}
|
|
668
|
+
catch (error) {
|
|
669
|
+
this.logger.warn(`Failed to fetch changeset for Unity ${unityVersion.toString()}: ${error}`);
|
|
670
|
+
return unityVersion;
|
|
671
|
+
}
|
|
672
|
+
const responseText = await response.text();
|
|
673
|
+
if (!response.ok) {
|
|
674
|
+
this.logger.info(responseText);
|
|
675
|
+
}
|
|
676
|
+
if (!response.ok) {
|
|
677
|
+
throw new Error(`Failed to fetch changeset for Unity ${unityVersion.toString()} [${response.status}] "${url}"`);
|
|
678
|
+
}
|
|
679
|
+
this.logger.debug(`Release page content: \n${responseText}`);
|
|
680
|
+
const match = responseText.match(/unityhub:\/\/(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\/(?<changeset>[a-zA-Z0-9]+)/);
|
|
681
|
+
if (match && match.groups && match.groups.version && match.groups.changeset) {
|
|
682
|
+
return new unity_version_1.UnityVersion(match.groups.version, match.groups.changeset, unityVersion.architecture);
|
|
683
|
+
}
|
|
684
|
+
this.logger.error(`Failed to find changeset for Unity ${unityVersion.toString()}`);
|
|
685
|
+
return unityVersion;
|
|
686
|
+
}
|
|
687
|
+
async checkEditorModules(editorPath, unityVersion, modules) {
|
|
688
|
+
let args = ['install-modules', '--version', unityVersion.version];
|
|
689
|
+
if (unityVersion.architecture) {
|
|
690
|
+
args.push('-a', unityVersion.architecture.toLowerCase());
|
|
691
|
+
}
|
|
692
|
+
for (const module of modules) {
|
|
693
|
+
args.push('-m', module);
|
|
694
|
+
}
|
|
695
|
+
const editorRootPath = unity_editor_1.UnityEditor.GetEditorRootPath(editorPath);
|
|
696
|
+
const modulesPath = path.join(editorRootPath, 'modules.json');
|
|
697
|
+
this.logger.debug(`Editor Modules Manifest:\n > "${modulesPath}"`);
|
|
698
|
+
const output = await this.Exec([...args, '--cm']);
|
|
699
|
+
const moduleMatches = output.matchAll(/Omitting module (?<module>.+) because it's already installed/g);
|
|
700
|
+
if (moduleMatches) {
|
|
701
|
+
const omittedModules = [...moduleMatches].map(match => match.groups?.module);
|
|
702
|
+
for (const module of omittedModules) {
|
|
703
|
+
if (module && !modules.includes(module)) {
|
|
704
|
+
modules.push(module);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const installedModules = [...modules];
|
|
709
|
+
const additionalModules = [];
|
|
710
|
+
const additionalModulesJson = await this.getModulesContent(modulesPath);
|
|
711
|
+
if (additionalModulesJson.length > 0) {
|
|
712
|
+
for (const module of additionalModulesJson) {
|
|
713
|
+
if (module.category === "Platforms" && module.visible === true) {
|
|
714
|
+
if (!installedModules.includes(module.id)) {
|
|
715
|
+
additionalModules.push(module.id);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return [installedModules, additionalModules];
|
|
721
|
+
}
|
|
722
|
+
async getModulesContent(modulesPath) {
|
|
723
|
+
const modulesContent = await (0, utilities_1.ReadFileContents)(modulesPath);
|
|
724
|
+
return JSON.parse(modulesContent);
|
|
725
|
+
}
|
|
726
|
+
async installUnity(unityVersion, modules) {
|
|
727
|
+
if (unityVersion.isLegacy()) {
|
|
728
|
+
return await this.installUnity4x(unityVersion);
|
|
729
|
+
}
|
|
730
|
+
if (process.platform === 'linux') {
|
|
731
|
+
const arch = process.arch === 'x64' ? 'amd64' : process.arch === 'arm64' ? 'arm64' : process.arch;
|
|
732
|
+
if (['2019.1', '2019.2'].some(v => unityVersion.version.startsWith(v))) {
|
|
733
|
+
const url = `https://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.0.0_1.0.2g-1ubuntu4.20_${arch}.deb`;
|
|
734
|
+
const downloadPath = path.join((0, utilities_1.GetTempDir)(), `libssl1.0.0_1.0.2g-1ubuntu4.20_${arch}.deb`);
|
|
735
|
+
await (0, utilities_1.DownloadFile)(url, downloadPath);
|
|
736
|
+
try {
|
|
737
|
+
await (0, utilities_1.Exec)('sudo', ['dpkg', '-i', downloadPath]);
|
|
738
|
+
}
|
|
739
|
+
finally {
|
|
740
|
+
fs.promises.unlink(downloadPath);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else if (['2019.3', '2019.4'].some(v => unityVersion.version.startsWith(v)) || unityVersion.version.startsWith('2020.')) {
|
|
744
|
+
const url = `https://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_${arch}.deb`;
|
|
745
|
+
const downloadPath = path.join((0, utilities_1.GetTempDir)(), `libssl1.1_1.1.0g-2ubuntu4_${arch}.deb`);
|
|
746
|
+
await (0, utilities_1.DownloadFile)(url, downloadPath);
|
|
747
|
+
try {
|
|
748
|
+
await (0, utilities_1.Exec)('sudo', ['dpkg', '-i', downloadPath]);
|
|
749
|
+
}
|
|
750
|
+
finally {
|
|
751
|
+
fs.promises.unlink(downloadPath);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const args = ['install', '--version', unityVersion.version];
|
|
756
|
+
if (unityVersion.changeset) {
|
|
757
|
+
args.push('--changeset', unityVersion.changeset);
|
|
758
|
+
}
|
|
759
|
+
if (unityVersion.architecture) {
|
|
760
|
+
args.push('-a', unityVersion.architecture.toLowerCase());
|
|
761
|
+
}
|
|
762
|
+
if (modules.length > 0) {
|
|
763
|
+
for (const module of modules) {
|
|
764
|
+
this.logger.ci(` > with module: ${module}`);
|
|
765
|
+
args.push('-m', module);
|
|
766
|
+
}
|
|
767
|
+
args.push('--cm');
|
|
768
|
+
}
|
|
769
|
+
this.logger.info(`Installing Unity ${unityVersion.toString()}...`);
|
|
770
|
+
const output = await this.Exec(args, { showCommand: true, silent: false });
|
|
771
|
+
if (output.includes(`Error while installing an editor or a module from changeset`)) {
|
|
772
|
+
throw new Error(`Failed to install Unity ${unityVersion.toString()}`);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async installUnity4x(unityVersion) {
|
|
776
|
+
const installDir = await this.GetInstallPath();
|
|
777
|
+
switch (process.platform) {
|
|
778
|
+
case 'win32': {
|
|
779
|
+
const installPath = path.join(installDir, `Unity ${unityVersion.version}`);
|
|
780
|
+
if (!fs.existsSync(installPath)) {
|
|
781
|
+
const url = `https://beta.unity3d.com/download/UnitySetup-${unityVersion.version}.exe`;
|
|
782
|
+
const installerPath = path.join((0, utilities_1.GetTempDir)(), `UnitySetup-${unityVersion.version}.exe`);
|
|
783
|
+
await (0, utilities_1.DownloadFile)(url, installerPath);
|
|
784
|
+
this.logger.info(`Running Unity ${unityVersion.toString()} installer...`);
|
|
785
|
+
try {
|
|
786
|
+
await (0, utilities_1.Exec)(installerPath, ['/S', `/D=${installPath}`, '-Wait', '-NoNewWindow'], { silent: true });
|
|
787
|
+
}
|
|
788
|
+
catch (error) {
|
|
789
|
+
this.logger.error(`Failed to install Unity ${unityVersion.toString()}: ${error}`);
|
|
790
|
+
}
|
|
791
|
+
finally {
|
|
792
|
+
fs.promises.unlink(installerPath);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
await fs.promises.access(installPath, fs.constants.R_OK);
|
|
796
|
+
return installPath;
|
|
797
|
+
}
|
|
798
|
+
case 'darwin': {
|
|
799
|
+
const installPath = path.join(installDir, `Unity ${unityVersion.version}`, 'Unity.app');
|
|
800
|
+
if (!fs.existsSync(installPath)) {
|
|
801
|
+
const url = `https://beta.unity3d.com/download/unity-${unityVersion.version}.dmg`;
|
|
802
|
+
const installerPath = path.join((0, utilities_1.GetTempDir)(), `UnitySetup-${unityVersion.version}.dmg`);
|
|
803
|
+
await (0, utilities_1.DownloadFile)(url, installerPath);
|
|
804
|
+
this.logger.info(`Running Unity ${unityVersion.toString()} installer...`);
|
|
805
|
+
let mountPoint = '';
|
|
806
|
+
try {
|
|
807
|
+
const output = await (0, utilities_1.Exec)('hdiutil', ['attach', installerPath, '-nobrowse'], { silent: true });
|
|
808
|
+
const mountPointMatch = output.match(/\/Volumes\/Unity Installer.*$/m);
|
|
809
|
+
if (!mountPointMatch || mountPointMatch.length === 0) {
|
|
810
|
+
throw new Error(`Failed to find mount point in hdiutil output: ${output}`);
|
|
811
|
+
}
|
|
812
|
+
mountPoint = mountPointMatch[0];
|
|
813
|
+
this.logger.debug(`Mounted Unity Installer at ${mountPoint}`);
|
|
814
|
+
const pkgPath = path.join(mountPoint, 'Unity.pkg');
|
|
815
|
+
await fs.promises.access(pkgPath, fs.constants.R_OK);
|
|
816
|
+
this.logger.debug(`Found .pkg installer: ${pkgPath}`);
|
|
817
|
+
await (0, utilities_1.Exec)('sudo', ['installer', '-pkg', pkgPath, '-target', '/', '-verboseR'], { silent: true });
|
|
818
|
+
const unityAppPath = path.join('/Applications', 'Unity');
|
|
819
|
+
const targetPath = path.join(installDir, `Unity ${unityVersion.version}`);
|
|
820
|
+
if (fs.existsSync(unityAppPath)) {
|
|
821
|
+
this.logger.debug(`Moving ${unityAppPath} to ${targetPath}...`);
|
|
822
|
+
await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });
|
|
823
|
+
const items = await fs.promises.readdir(unityAppPath);
|
|
824
|
+
for (const item of items) {
|
|
825
|
+
if (item !== 'Hub') {
|
|
826
|
+
const src = path.join(unityAppPath, item);
|
|
827
|
+
const dest = path.join(targetPath, item);
|
|
828
|
+
this.logger.debug(` > Moving ${src} to ${dest}`);
|
|
829
|
+
await fs.promises.cp(src, dest, { recursive: true });
|
|
830
|
+
await fs.promises.rm(src, { recursive: true, force: true });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
await fs.promises.chmod(targetPath, 0o777);
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
throw new Error(`Failed to find Unity.app after installation.`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
this.logger.error(`Failed to mount Unity ${unityVersion.toString()} installer: ${error}`);
|
|
841
|
+
}
|
|
842
|
+
finally {
|
|
843
|
+
try {
|
|
844
|
+
if (mountPoint && mountPoint.length > 0) {
|
|
845
|
+
await (0, utilities_1.Exec)('hdiutil', ['detach', mountPoint, '-quiet'], { silent: true });
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
finally {
|
|
849
|
+
await fs.promises.unlink(installerPath);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
await fs.promises.access(installPath, fs.constants.R_OK);
|
|
854
|
+
return installPath;
|
|
855
|
+
}
|
|
856
|
+
default:
|
|
857
|
+
throw new Error(`Unity ${unityVersion.toString()} is not supported on ${process.platform}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
static GetPlatformTargetModuleMap() {
|
|
861
|
+
const osType = os.type();
|
|
862
|
+
let moduleMap;
|
|
863
|
+
switch (osType) {
|
|
864
|
+
case 'Linux':
|
|
865
|
+
moduleMap = {
|
|
866
|
+
"StandaloneLinux64": "linux-il2cpp",
|
|
867
|
+
"Android": "android",
|
|
868
|
+
"WebGL": "webgl",
|
|
869
|
+
"iOS": "ios",
|
|
870
|
+
};
|
|
871
|
+
break;
|
|
872
|
+
case 'Darwin':
|
|
873
|
+
moduleMap = {
|
|
874
|
+
"StandaloneOSX": "mac-il2cpp",
|
|
875
|
+
"iOS": "ios",
|
|
876
|
+
"Android": "android",
|
|
877
|
+
"tvOS": "appletv",
|
|
878
|
+
"StandaloneLinux64": "linux-il2cpp",
|
|
879
|
+
"WebGL": "webgl",
|
|
880
|
+
"VisionOS": "visionos"
|
|
881
|
+
};
|
|
882
|
+
break;
|
|
883
|
+
case 'Windows_NT':
|
|
884
|
+
moduleMap = {
|
|
885
|
+
"StandaloneWindows64": "windows-il2cpp",
|
|
886
|
+
"WSAPlayer": "universal-windows-platform",
|
|
887
|
+
"Android": "android",
|
|
888
|
+
"iOS": "ios",
|
|
889
|
+
"tvOS": "appletv",
|
|
890
|
+
"StandaloneLinux64": "linux-il2cpp",
|
|
891
|
+
"Lumin": "lumin",
|
|
892
|
+
"WebGL": "webgl",
|
|
893
|
+
};
|
|
894
|
+
break;
|
|
895
|
+
default:
|
|
896
|
+
throw Error(`${osType} not supported`);
|
|
897
|
+
}
|
|
898
|
+
return moduleMap;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
exports.UnityHub = UnityHub;
|
|
902
|
+
//# sourceMappingURL=unity-hub.js.map
|