diff --git a/.github/workflows/build-options.json b/.github/workflows/build-options.json index 4086875..acc4659 100644 --- a/.github/workflows/build-options.json +++ b/.github/workflows/build-options.json @@ -18,6 +18,10 @@ "6000.2" ], "include": [ + { + "os": "ubuntu-latest", + "unity-version": "none" + }, { "os": "ubuntu-latest", "build-target": "StandaloneLinux64" @@ -31,10 +35,18 @@ "os": "ubuntu-latest", "build-target": "Android" }, + { + "os": "windows-latest", + "unity-version": "none" + }, { "os": "windows-latest", "build-target": "StandaloneWindows64" }, + { + "os": "macos-latest", + "unity-version": "none" + }, { "os": "windows-latest", "build-target": "Android" diff --git a/.github/workflows/unity-build.yml b/.github/workflows/unity-build.yml index 4b754f3..7189e69 100644 --- a/.github/workflows/unity-build.yml +++ b/.github/workflows/unity-build.yml @@ -47,8 +47,11 @@ jobs: shell: bash timeout-minutes: 30 run: | + unity-cli hub-install --hub-version 3.12.0 unity-cli hub-install --auto-update - unity-cli setup-unity --unity-version "${{ matrix.unity-version }}" --build-targets "${{ matrix.build-target }}" --json + if [ "${{ matrix.unity-version }}" != "none" ]; then + unity-cli setup-unity --unity-version "${{ matrix.unity-version }}" --build-targets "${{ matrix.build-target }}" --json + fi - name: Verify UNITY_HUB_PATH and UNITY_EDITOR_PATH variables shell: bash run: | @@ -61,20 +64,23 @@ jobs: exit 1 fi - if [ -z "${UNITY_EDITOR_PATH}" ]; then + if [ "${{ matrix.unity-version }}" != "none" ] && [ -z "${UNITY_EDITOR_PATH}" ]; then echo "Error: UNITY_EDITOR_PATH is not set" exit 1 fi - name: Activate License + if : ${{ matrix.unity-version != 'none' }} shell: bash run: | unity-cli activate-license --license personal --email "${{ secrets.UNITY_USERNAME }}" --password "${{ secrets.UNITY_PASSWORD }}" - name: Create Unity Project + if : ${{ matrix.unity-version != 'none' }} shell: bash run: | unity-cli list-project-templates --unity-editor "${UNITY_EDITOR_PATH}" --json unity-cli create-project --name "Unity Project" --unity-editor "${UNITY_EDITOR_PATH}" --json - name: Verify UNITY_PROJECT_PATH variable + if : ${{ matrix.unity-version != 'none' }} shell: bash run: | if [ -z "${UNITY_PROJECT_PATH}" ]; then @@ -119,6 +125,7 @@ jobs: unity-cli run --log-name Validate -quit -executeMethod Utilities.Editor.BuildPipeline.UnityPlayerBuildTools.ValidateProject -importTMProEssentialsAsset unity-cli run --log-name Build -buildTarget ${{ matrix.build-target }} -quit -executeMethod Utilities.Editor.BuildPipeline.UnityPlayerBuildTools.StartCommandLineBuild -sceneList Assets/Scenes/SampleScene.unity ${{ matrix.build-args }} - name: Uninstall Editor + if: ${{ matrix.unity-version != 'none' }} shell: bash run: | if [ -z "${UNITY_EDITOR_PATH}" ]; then diff --git a/README.md b/README.md index 5d907ce..4fe308a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,31 @@ A powerful command line utility for the Unity Game Engine. Automate Unity project setup, editor installation, license management, building, and more—ideal for CI/CD pipelines and developer workflows. +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Usage](#usage) + - [Common Commands](#common-commands) + - [Auth](#auth) + - [License Version](#license-version) + - [Activate License](#activate-license) + - [Return License](#return-license) + - [Unity Hub](#unity-hub) + - [Hub Version](#hub-version) + - [Hub Path](#hub-path) + - [Unity Hub Install](#unity-hub-install) + - [Run Unity Hub Commands](#run-unity-hub-commands) + - [Unity Editor](#unity-editor) + - [Setup Unity Editor](#setup-unity-editor) + - [Uninstall Unity Editor](#uninstall-unity-editor) + - [List Project Templates](#list-project-templates) + - [Create Unity Project](#create-unity-project) + - [Open Unity Project](#open-unity-project) + - [Run Unity Editor Commands](#run-unity-editor-commands) + - [Unity Package Manager](#unity-package-manager) + - [Sign a Unity Package](#sign-a-unity-package) + ## Features - Install and manage Unity Hub and Unity Editors (multi-platform) @@ -32,59 +57,190 @@ With options always using double dashes (`--option`) and arguments passed direct ### Common Commands +- `unity-cli --help` for a full list of commands and options. +- `unity-cli [command] --help` for details on a specific command. +- `unity-cli [command] --json` to get the output in JSON format (if supported). +- `unity-cli [command] --verbose` to enable verbose logging for debugging. + +```bash +unity-cli --help +``` + #### Auth -- `unity-cli license-version`: Print the Unity License Client version. -- `unity-cli activate-license [options]`: Activate a Unity license. -- `unity-cli return-license [options]`: Return a Unity license. +##### License Version + +`license-version`: Print the Unity License Client version. + +```bash +unity-cli license-version +``` + +##### Activate License + +`activate-license [options]`: Activate a Unity license. + +- `-l`, `--license`: License type (personal, professional, floating). Required. +- `-e`, `--email`: Email associated with the Unity account. Required when activating a personal or professional license. +- `-p`, `--password`: Password for the Unity account. Required when activating a personal or professional license. +- `-s`, `--serial`: License serial number. Required when activating a professional license. +- `-c`, `--config`: Path to the configuration file, or base64 encoded JSON string. Required when activating a floating license. +- `--verbose`: Enable verbose output. + +```bash +unity-cli activate-license --license personal --email --password +``` + +##### Return License + +`return-license [options]`: Return a Unity license. + +- `-l`, `--license`: License type (personal, professional, floating) +- `--verbose`: Enable verbose output. + +```bash +unity-cli return-license --license personal +``` #### Unity Hub -- `unity-cli hub-version`: Print the Unity Hub version. -- `unity-cli hub-install [options]`: Install or update the Unity Hub. -- `unity-cli hub-path`: Print the Unity Hub executable path. -- `unity-cli hub [options] `: Run Unity Hub command line arguments (passes args directly to the hub executable). +##### Hub Version -#### Unity Editor +`hub-version`: Print the Unity Hub version. + +```bash +unity-cli hub-version +``` -- `unity-cli setup-unity [options]`: Find or install the Unity Editor for a project or specific version. -- `unity-cli uninstall-unity [options]`: Uninstall a Unity Editor version. -- `unity-cli list-project-templates [options]`: List available Unity project templates for an editor. -- `unity-cli create-project [options]`: Create a new Unity project from a template. -- `unity-cli open-project [options]`: Open a Unity project in the Unity Editor. -- `unity-cli run [options] `: Run Unity Editor command line arguments (passes args directly to the editor). +##### Hub Path -#### Unity Package Manager +`hub-path`: Print the Unity Hub executable path. -- `unity-cli sign-package [options]`: Sign a Unity package for distribution. +```bash +unity-cli hub-path +``` -Run `unity-cli --help` for a full list of commands and options. +##### Unity Hub Install -#### Install Unity Hub and Editor +`hub-install [options]`: Install or update the Unity Hub + +- `--auto-update`: Automatically updates the Unity Hub if it is already installed. Cannot be used with --hub-version. +- `--hub-version`: Specify to install a specific version of Unity Hub. Cannot be used with --auto-update. +- `--verbose`: Enable verbose output. +- `--json`: Output installation information in JSON format. ```bash unity-cli hub-install -unity-cli setup-unity --unity-version 2022.3.x --modules android,ios ``` -#### Activate a Unity License +##### Run Unity Hub Commands + +`hub [options] `: Run Unity Hub command line arguments (passes args directly to the hub executable). + +- ``: Arguments to pass directly to the Unity Hub executable. +- `--verbose`: Enable verbose output. -Supports personal, professional, and floating licenses (using a license server configuration). +Lists available Unity Hub commands: ```bash -unity-cli activate-license --license personal --email --password +unity-cli hub help ``` -#### Create a New Project from a Template +Gets a list of installed editors: + +```bash +unity-cli hub editors --installed +``` + +#### Unity Editor + +##### Setup Unity Editor + +`setup-unity [options]`: Find or install the Unity Editor for a project or specific version. + +- `-p`, `--unity-project ` The path to a Unity project or `none` to skip project detection. +- `-u`, `--unity-version ` The Unity version to get (e.g. `2020.3.1f1`, `2021.x`, `2022.1.*`, `6000`). If specified, it will override the version read from the project. +- `-c`, `--changeset ` The Unity changeset to get (e.g. `1234567890ab`). +- `-a`, `--arch ` The Unity architecture to get (e.g. `x86_64`, `arm64`). Defaults to the architecture of the current process. +- `-b`, `--build-targets ` The Unity build target to get (e.g. `iOS,Android`). +- `-m`, `--modules ` The Unity module to get (e.g. ios, android). +- `-i`, `--install-path ` The path to install the Unity Editor to. By default, it will be installed to the default Unity Hub location. +- `--verbose` Enable verbose logging. +- `--json` Prints the last line of output as JSON string. + +Installs the latest Unity 6 version with Android and iOS modules: + +```bash +unity-cli setup-unity --unity-version 6000 --modules android,ios +``` + +##### Uninstall Unity Editor + +`uninstall-unity [options]`: Uninstall a Unity Editor version. + +- `-e`, `--unity-editor ` The path to the Unity Editor executable. If unspecified, `-u`, `--unity-version` or the `UNITY_EDITOR_PATH` environment variable must be set. +- `-u`, `--unity-version ` The Unity version to get (e.g. `2020.3.1f1`, `2021.x`, `2022.1.*`, `6000`). If unspecified, then `--unity-editor` must be specified. +- `-c`, `--changeset ` The Unity changeset to get (e.g. `1234567890ab`). +- `-a`, `--arch ` The Unity architecture to get (e.g. `x86_64`, `arm64`). Defaults to the architecture of the current process. +- `--verbose` Enable verbose logging. + +```bash +unity-cli uninstall-unity --unity-version 6000 +``` + +##### List Project Templates > [!NOTE] > Regex patterns are supported for the `--template` option. For example, to create a 3D project with either the standard or cross-platform template, you can use `com.unity.template.3d(-cross-platform)?`. +`list-project-templates [options]`: List available Unity project templates for an editor. + +- `-e`, `--unity-editor ` The path to the Unity Editor executable. If unspecified, `-u`, `--unity-version` or the `UNITY_EDITOR_PATH` environment variable must be set. +- `-u`, `--unity-version ` The Unity version to get (e.g. `2020.3.1f1`, `2021.x`, `2022.1.*`, `6000`). If unspecified, then `--unity-editor` must be specified. +- `-c`, `--changeset ` The Unity changeset to get (e.g. `1234567890ab`). +- `-a`, `--arch ` The Unity architecture to get (e.g. `x86_64`, `arm64`). Defaults to the architecture of the current process. +- `--verbose` Enable verbose logging. +- `--json` Prints the last line of output as JSON string. + +Lists available project templates for Unity 6: + ```bash -unity-cli create-project --name "MyGame" --template com.unity.template.3d(-cross-platform)? --unity-editor +unity-cli list-project-templates --unity-version 6000 ``` -#### Open a project from the command line +##### Create Unity Project + +`create-project [options]`: Create a new Unity project from a template. + +- `-n`, `--name ` The name of the new Unity project. If unspecified, the project will be created in the specified path or the current working directory. +- `-p`, `--path ` The path to create the new Unity project. If unspecified, the current working directory will be used. +- `-t`, `--template ` The name of the template package to use for creating the unity project. Supports regex patterns. (default: + `com.unity.template.3d(-cross-platform)?`) +- `-u`, `--unity-version ` The Unity version to get (e.g. `2020.3.1f1`, `2021.x`, `2022.1.*`, `6000`). If unspecified, then `--unity-editor` must be specified. +- `-e`, `--unity-editor ` The path to the Unity Editor executable. If unspecified, `-u`, `--unity-version`, or the `UNITY_EDITOR_PATH` environment variable must be set. +- `--verbose` Enable verbose logging. +- `--json` Prints the last line of output as JSON string. + +Creates a new Unity project named "MyGame" using the latest version of Unity 6 and the 3D template: + +```bash +unity-cli create-project --name "MyGame" --template com.unity.template.3d(-cross-platform)? --unity-version 6000 +``` + +##### Open Unity Project + +`open-project [options]`: Open a Unity project in the Unity Editor. + +- `-p`, `--unity-project ` The path to a Unity project. If unspecified, the `UNITY_PROJECT_PATH` environment variable or the current working directory will be used. +- `-u`, `--unity-version ` The Unity version to get (e.g. `2020.3.1f1`, `2021.x`, `2022.1.*`, `6000`). If specified, it will override the version read from the project. +- `-t`, `--build-target ` The Unity build target to switch the project to (e.g. `StandaloneWindows64`, `StandaloneOSX`, `iOS`, `Android`, etc). +- `--verbose` Enable verbose logging. + +Opens a specific Unity project with the latest Unity 6 version: + +```bash +unity-cli open-project --unity-project --unity-version 6000 +``` > [!TIP] > If you run this command in the same directory as your Unity project, you can omit the `--unity-project`, `--unity-version`, and `--unity-editor` options. @@ -93,13 +249,35 @@ unity-cli create-project --name "MyGame" --template com.unity.template.3d(-cross unity-cli open-project ``` -#### Build a Project +##### Run Unity Editor Commands + +`run [options] `: Run Unity Editor command line arguments (passes args directly to the editor). + +- `--unity-editor ` The path to the Unity Editor executable. If unspecified, `--unity-project` or the `UNITY_EDITOR_PATH` environment variable must be set. +- `--unity-project ` The path to a Unity project. If unspecified, the `UNITY_PROJECT_PATH` environment variable will be used, otherwise no project will be specified. +- `--log-name ` The name of the log file. +- `` Arguments to pass directly to the Unity Editor executable. +- `--verbose` Enable verbose logging. ```bash unity-cli run --unity-project -quit -batchmode -executeMethod StartCommandLineBuild ``` -#### Sign a Unity Package +#### Unity Package Manager + +##### Sign a Unity Package + +> [!WARNING] +> This command feature is in beta and may change in future releases. + +`sign-package [options]`: Sign a Unity package for distribution. + +- `--package ` Required. The fully qualified path to the folder that contains the package.json file for the package you want to sign. Note: Don’t include package.json in this parameter value. +- `--output ` Optional. The output directory where you want to save the signed tarball file (.tgz). If unspecified, the package contents will be updated in place with the signed .attestation.p7m file. +- `--email ` Email associated with the Unity account. If unspecified, the `UNITY_USERNAME` environment variable will be used. +- `--password ` The password of the Unity account. If unspecified, the `UNITY_PASSWORD` environment variable will be used. +- `--organization ` The Organization ID you copied from the Unity Cloud Dashboard. If unspecified, the `UNITY_ORGANIZATION_ID` environment variable will be used. +- `--verbose` Enable verbose logging. > [!NOTE] > The `--output` option is optional. If not specified, the package contents will be updated in place with the signed `.attestation.p7m` file. Otherwise a signed `.tgz` file will be created in the specified output directory. diff --git a/package-lock.json b/package-lock.json index a67915f..c04a610 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.5.0", + "version": "1.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT", "dependencies": { "@electron/asar": "^4.0.1", diff --git a/package.json b/package.json index 741e4f7..2c1e340 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.5.0", + "version": "1.5.1", "description": "A command line utility for the Unity Game Engine.", "author": "RageAgainstThePixel", "license": "MIT", diff --git a/src/cli.ts b/src/cli.ts index fc613cc..ecea303 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -136,10 +136,28 @@ program.command('hub-version') } }); +program.command('hub-path') + .description('Print the path to the Unity Hub executable.') + .option('--json', 'Prints the last line of output as JSON string.') + .action(async (options) => { + const hub = new UnityHub(); + + Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hub.executable); + + if (options.json) { + process.stdout.write(`\n${JSON.stringify({ UNITY_HUB_PATH: hub.executable })}\n`); + } else { + process.stdout.write(`${hub.executable}\n`); + } + + process.exit(0); + }); + program.command('hub-install') .description('Install the Unity Hub.') .option('--verbose', 'Enable verbose logging.') - .option('--auto-update', 'Automatically updates the Unity Hub if it is already installed.') + .option('--auto-update', 'Automatically updates the Unity Hub if it is already installed. Cannot be used with --hub-version.') + .option('--hub-version ', 'Specify to install a specific version of Unity Hub. Cannot be used with --auto-update.') .option('--json', 'Prints the last line of output as JSON string.') .action(async (options) => { if (options.verbose) { @@ -148,8 +166,13 @@ program.command('hub-install') Logger.instance.debug(JSON.stringify(options)); + if (options.autoUpdate === true && options.hubVersion) { + Logger.instance.error('Cannot use --auto-update with --hub-version.'); + process.exit(1); + } + const unityHub = new UnityHub(); - const hubPath = await unityHub.Install(options.autoUpdate === true); + const hubPath = await unityHub.Install(options.autoUpdate === true, options.hubVersion); Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hubPath); @@ -162,23 +185,6 @@ program.command('hub-install') process.exit(0); }); -program.command('hub-path') - .description('Print the path to the Unity Hub executable.') - .option('--json', 'Prints the last line of output as JSON string.') - .action(async (options) => { - const hub = new UnityHub(); - - Logger.instance.CI_setEnvironmentVariable('UNITY_HUB_PATH', hub.executable); - - if (options.json) { - process.stdout.write(`\n${JSON.stringify({ UNITY_HUB_PATH: hub.executable })}\n`); - } else { - process.stdout.write(`${hub.executable}\n`); - } - - process.exit(0); - }); - program.command('hub') .description('Run commands directly to the Unity Hub. (You need not to pass --headless or -- to this command).') .allowUnknownOption(true) diff --git a/src/license-client.ts b/src/license-client.ts index 8c34daa..52c58b4 100644 --- a/src/license-client.ts +++ b/src/license-client.ts @@ -45,7 +45,7 @@ export class LicensingClient { await fs.promises.access(this.unityHub.executable, fs.constants.R_OK); await fs.promises.access(this.unityHub.rootDirectory, fs.constants.R_OK); } catch (error) { - await this.unityHub.Install(); + throw new Error('Unity Hub is not installed or not accessible. Please install Unity Hub before using the Licensing Client.'); } const licensingClientExecutable = process.platform === 'win32' ? 'Unity.Licensing.Client.exe' : 'Unity.Licensing.Client'; diff --git a/src/unity-editor.ts b/src/unity-editor.ts index e3e4f6f..cd13f96 100644 --- a/src/unity-editor.ts +++ b/src/unity-editor.ts @@ -69,6 +69,14 @@ export class UnityEditor { this.autoAddNoGraphics = this.version.isGreaterThan('2018.0.0'); + // check if we have permissions to write to this file + try { + fs.accessSync(this.editorRootPath, fs.constants.W_OK); + } catch (error) { + return; + } + + // ensure metadata.hub.json exists and has a productName entry const hubMetaDataPath = path.join(this.editorRootPath, 'metadata.hub.json'); if (!fs.existsSync(hubMetaDataPath)) { const metadata = { diff --git a/src/unity-hub.ts b/src/unity-hub.ts index 0912bd2..5c8510d 100644 --- a/src/unity-hub.ts +++ b/src/unity-hub.ts @@ -25,9 +25,7 @@ import { UnityReleasesClient, GetUnityReleasesData, UnityRelease, - Release } from '@rage-against-the-pixel/unity-releases-api'; -import { get } from 'http'; interface ReleaseInfo { unityRelease: UnityRelease; @@ -281,48 +279,67 @@ export class UnityHub { * @param autoUpdate If true, automatically updates the Unity Hub if it is already installed. Default is true. * @returns The path to the Unity Hub executable. */ - public async Install(autoUpdate: boolean = true): Promise { + public async Install(autoUpdate: boolean = true, version: string | undefined): Promise { + if (autoUpdate && version) { + throw new Error('Cannot use autoUpdate with version.'); + } + let isInstalled = false; try { await fs.promises.access(this.executable, fs.constants.X_OK); isInstalled = true; } catch { - await this.installHub(); + await this.installHub(version); } if (isInstalled && autoUpdate) { const installedVersion: SemVer = await this.getInstalledHubVersion(); this.logger.ci(`Installed Unity Hub version: ${installedVersion.version}`); - let latestVersion: SemVer | undefined = undefined; + let versionToInstall: SemVer | null = null; - try { - latestVersion = await this.getLatestHubVersion(); - this.logger.ci(`Latest Unity Hub version: ${latestVersion.version}`); - } catch (error) { - this.logger.warn(`Failed to get latest Unity Hub version: ${error}`); + if (!version) { + try { + versionToInstall = await this.getLatestHubVersion(); + this.logger.ci(`Latest Unity Hub version: ${versionToInstall.version}`); + } catch (error) { + this.logger.warn(`Failed to get latest Unity Hub version: ${error}`); + } + } else { + versionToInstall = coerce(version); } - if (latestVersion && compare(installedVersion, latestVersion) < 0) { - this.logger.info(`Updating Unity Hub from ${installedVersion.version} to ${latestVersion.version}...`); + if (versionToInstall === null || + !versionToInstall && + !valid(versionToInstall)) { + throw new Error(`Invalid Unity Hub version to install: ${versionToInstall}`); + } + + const mustInstall = version || (versionToInstall && compare(installedVersion, versionToInstall) < 0); + + if (mustInstall) { + this.logger.info(`Updating Unity Hub from ${installedVersion.version} to ${versionToInstall.version}...`); if (process.platform === 'darwin') { await Exec('sudo', ['rm', '-rf', this.rootDirectory], { silent: true, showCommand: true }); - await this.installHub(); + await this.installHub(version); } else if (process.platform === 'win32') { - const uninstaller = path.join(path.dirname(this.executable), 'Uninstall Unity Hub.exe'); + const uninstaller = path.join(this.rootDirectory, 'Uninstall Unity Hub.exe'); await Exec('powershell', [ '-NoProfile', '-Command', `Start-Process -FilePath '${uninstaller}' -ArgumentList '/S' -Verb RunAs -Wait` ], { silent: true, showCommand: true }); - await this.installHub(); + await DeleteDirectory(this.rootDirectory); + await this.installHub(version); } else if (process.platform === 'linux') { await Exec('sudo', ['sh', '-c', `#!/bin/bash set -e wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor | sudo tee /usr/share/keyrings/Unity_Technologies_ApS.gpg >/dev/null 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' sudo apt-get update --allow-releaseinfo-change -sudo apt-get install -y --no-install-recommends --only-upgrade unityhub`]); +sudo apt-get install -y --no-install-recommends --only-upgrade unityhub${version ? '=' + version : ''}`]); + } else { + throw new Error(`Unsupported platform: ${process.platform}`); } } else { this.logger.info(`Unity Hub is already installed and up to date.`); @@ -333,11 +350,21 @@ sudo apt-get install -y --no-install-recommends --only-upgrade unityhub`]); return this.executable; } - private async installHub(): Promise { - this.logger.ci(`Installing Unity Hub...`); + private async installHub(version: SemVer | string | undefined): Promise { + this.logger.ci(`Installing Unity Hub${version ? ' ' + version : ''}...`); + + if (!version) { + switch (process.platform) { + case 'win32': + case 'darwin': + version = 'prod'; + break; + } + } + switch (process.platform) { case 'win32': { - const url = 'https://public-cdn.cloud.unity3d.com/hub/prod/UnityHubSetup.exe'; + const url = `https://public-cdn.cloud.unity3d.com/hub/${version}/UnityHubSetup.exe`; const downloadPath = path.join(GetTempDir(), 'UnityHubSetup.exe'); await DownloadFile(url, downloadPath); @@ -358,7 +385,7 @@ sudo apt-get install -y --no-install-recommends --only-upgrade unityhub`]); break; } case 'darwin': { - const baseUrl = 'https://public-cdn.cloud.unity3d.com/hub/prod'; + const baseUrl = `https://public-cdn.cloud.unity3d.com/hub/${version}`; const url = `${baseUrl}/UnityHubSetup-${process.arch}.dmg`; const downloadPath = path.join(GetTempDir(), `UnityHubSetup-${process.arch}.dmg`); @@ -412,11 +439,12 @@ wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor | tee /usr/ 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 echo "deb https://archive.ubuntu.com/ubuntu jammy main universe" | tee /etc/apt/sources.list.d/jammy.list apt-get update -apt-get install -y --no-install-recommends unityhub ffmpeg libgtk2.0-0 libglu1-mesa libgconf-2-4 libncurses5 +apt-get install -y --no-install-recommends unityhub${version ? '=' + version : ''} ffmpeg libgtk2.0-0 libglu1-mesa libgconf-2-4 libncurses5 apt-get clean sed -i 's/^\\(.*DISPLAY=:.*XAUTHORITY=.*\\)\\( "\\$@" \\)2>&1$/\\1\\2/' /usr/bin/xvfb-run printf '#!/bin/bash\nxvfb-run --auto-servernum /opt/unityhub/unityhub "$@" 2>/dev/null' | tee /usr/bin/unity-hub >/dev/null chmod 777 /usr/bin/unity-hub +which unityhub || { echo "Unity Hub installation failed"; exit 1; } hubPath=$(which unityhub) if [ -z "$hubPath" ]; then @@ -432,7 +460,8 @@ chmod -R 777 "$hubPath"`]); } await fs.promises.access(this.executable, fs.constants.X_OK); - this.logger.debug(`Unity Hub install complete`); + const installedVersion = await this.getInstalledHubVersion(); + this.logger.info(`Unity Hub ${installedVersion} installed successfully.`); } private async getInstalledHubVersion(): Promise { @@ -455,8 +484,17 @@ chmod -R 777 "$hubPath"`]); throw new Error('Unity Hub is not installed.'); } - const fileBuffer = asar.extractFile(asarPath, 'package.json'); - const packageJson = JSON.parse(fileBuffer.toString()); + asar.uncacheAll(); + const fileBuffer = asar.extractFile(asarPath, 'package.json').toString('utf-8'); + let packageJson: any; + + try { + packageJson = JSON.parse(fileBuffer); + } catch (error) { + + throw new Error(`Failed to parse Unity Hub package.json: ${error}\n${fileBuffer}`); + } + const version = coerce(packageJson.version); if (!version || !valid(version)) { diff --git a/src/utilities.ts b/src/utilities.ts index ae12fb4..63c1c8e 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -174,7 +174,7 @@ export async function Exec(command: string, args: string[], options: ExecOptions } if (exitCode !== 0) { - throw new Error(`${command} failed with exit code ${exitCode}`); + throw new Error(`${command} failed with exit code ${exitCode}\n${output}`); } }