From 6194799731b921407e0a2b29f1f3d038659236da Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Fri, 17 Oct 2025 20:04:01 -0400 Subject: [PATCH 1/4] unity-cli@v1.3.3 - throw an error if android sdk installation is not ran in elevated terminal - remove inherited env from android sdk processes --- package-lock.json | 4 ++-- package.json | 2 +- src/android-sdk.ts | 20 ++++++++++++++++---- src/utilities.ts | 16 +++++++++++++++- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2517aa7..0f39c7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.3.2", + "version": "1.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.3.2", + "version": "1.3.3", "license": "MIT", "dependencies": { "@electron/asar": "^4.0.1", diff --git a/package.json b/package.json index 69509e1..a92d061 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rage-against-the-pixel/unity-cli", - "version": "1.3.2", + "version": "1.3.3", "description": "A command line utility for the Unity Game Engine.", "author": "RageAgainstThePixel", "license": "MIT", diff --git a/src/android-sdk.ts b/src/android-sdk.ts index 8c5c62b..97fa77e 100644 --- a/src/android-sdk.ts +++ b/src/android-sdk.ts @@ -5,6 +5,7 @@ import { spawn } from 'child_process'; import { Logger } from './logging'; import { UnityEditor } from './unity-editor'; import { + isProcessElevated, ReadFileContents, ResolveGlobToPath } from './utilities'; @@ -124,11 +125,22 @@ async function execSdkManager(sdkManagerPath: string, javaPath: string, args: st try { exitCode = await new Promise((resolve, reject) => { - const child = spawn(sdkManagerPath, args, { + let cmd = sdkManagerPath; + let cmdArgs = args; + + if (process.platform === 'win32') { + if (!isProcessElevated()) { + throw new Error('Android SDK installation requires elevated (administrator) privileges. Please rerun as Administrator.'); + } + + cmd = 'cmd.exe'; + cmdArgs = ['/c', sdkManagerPath, ...args]; + } + + const child = spawn(cmd, cmdArgs, { stdio: ['pipe', 'pipe', 'pipe'], env: { - ...process.env, - JAVA_HOME: process.platform === 'win32' ? `"${javaPath}"` : javaPath + JAVA_HOME: javaPath } }); const sigintHandler = () => child.kill('SIGINT'); @@ -147,7 +159,7 @@ async function execSdkManager(sdkManagerPath: string, javaPath: string, args: st function handleDataStream(data: Buffer) { const chunk = data.toString(); output += chunk; - process.stderr.write(chunk); + process.stdout.write(chunk); } const acceptBuffer = Buffer.from(Array(10).fill('y').join(os.EOL), 'utf8'); child.stdin.write(acceptBuffer); diff --git a/src/utilities.ts b/src/utilities.ts index f707be1..182eed4 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as https from 'https'; import * as readline from 'readline'; import { glob } from 'glob'; -import { spawn } from 'child_process'; +import { spawn, spawnSync } from 'child_process'; import { Logger, LogLevel } from './logging'; const logger = Logger.instance; @@ -572,4 +572,18 @@ export async function KillChildProcesses(procInfo: ProcInfo): Promise { } catch (error) { logger.error(`Failed to kill child processes of pid ${procInfo.pid}:\n${JSON.stringify(error)}`); } +} + +/** + * Checks if the current process is running with elevated (administrator) privileges. + * @returns True if the process is elevated, false otherwise. + */ +export function isProcessElevated(): boolean { + if (process.platform !== 'win32') { return true; } + const probe = spawnSync('powershell.exe', [ + '-NoLogo', '-NoProfile', '-Command', + "[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()" + + ".IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" + ], { encoding: 'utf8' }); + return probe.status === 0 && probe.stdout.trim().toLowerCase() === 'true'; } \ No newline at end of file From da4f7b22d08cbf18cfb8bba9cb43a58edf33dbba Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Fri, 17 Oct 2025 20:06:05 -0400 Subject: [PATCH 2/4] don't get stuck installing forever --- .github/workflows/unity-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/unity-build.yml b/.github/workflows/unity-build.yml index e0ff576..23fc12a 100644 --- a/.github/workflows/unity-build.yml +++ b/.github/workflows/unity-build.yml @@ -38,6 +38,7 @@ jobs: unity-cli --version - name: Setup Unity shell: bash + timeout-minutes: 30 run: | unity-cli hub-install --auto-update unity-cli setup-unity --unity-version "${{ matrix.unity-version }}" --build-targets "${{ matrix.build-target }}" --json From 17fe135c61c736b239226343fb1651b2113b4a6c Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Fri, 17 Oct 2025 20:08:53 -0400 Subject: [PATCH 3/4] PR review feedback --- src/android-sdk.ts | 2 +- src/utilities.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/android-sdk.ts b/src/android-sdk.ts index 97fa77e..4b9f48b 100644 --- a/src/android-sdk.ts +++ b/src/android-sdk.ts @@ -140,7 +140,7 @@ async function execSdkManager(sdkManagerPath: string, javaPath: string, args: st const child = spawn(cmd, cmdArgs, { stdio: ['pipe', 'pipe', 'pipe'], env: { - JAVA_HOME: javaPath + JAVA_HOME: process.platform === 'win32' ? `"${javaPath}"` : javaPath } }); const sigintHandler = () => child.kill('SIGINT'); diff --git a/src/utilities.ts b/src/utilities.ts index 182eed4..3b17c0e 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -582,8 +582,7 @@ export function isProcessElevated(): boolean { if (process.platform !== 'win32') { return true; } const probe = spawnSync('powershell.exe', [ '-NoLogo', '-NoProfile', '-Command', - "[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()" - + ".IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" + "[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent().IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" ], { encoding: 'utf8' }); return probe.status === 0 && probe.stdout.trim().toLowerCase() === 'true'; } \ No newline at end of file From f395ca90bb8a9f7e221886bc0cbe3131bff70f88 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Fri, 17 Oct 2025 20:11:00 -0400 Subject: [PATCH 4/4] add comment --- src/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities.ts b/src/utilities.ts index 3b17c0e..647837d 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -579,7 +579,7 @@ export async function KillChildProcesses(procInfo: ProcInfo): Promise { * @returns True if the process is elevated, false otherwise. */ export function isProcessElevated(): boolean { - if (process.platform !== 'win32') { return true; } + if (process.platform !== 'win32') { return true; } // We can sudo easily on non-windows platforms const probe = spawnSync('powershell.exe', [ '-NoLogo', '-NoProfile', '-Command', "[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent().IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"