// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. import * as path from "path"; import { homedir } from "os"; import { ApplePlatformDebugModeManager } from "../applePlatformDebugModeManager"; import { PlistBuddy } from "../ios/plistBuddy"; import { FileSystem } from "../../common/node/fileSystem"; import { PlatformType } from "../launchArgs"; import { DefaultsHelper } from "./defaultsHelper"; export class MacOSDebugModeManager extends ApplePlatformDebugModeManager { protected static REMOTE_DEBUGGING_FLAG_NAME = "isDebuggingRemotely"; private scheme?: string; private nodeFileSystem: FileSystem; private plistBuddy: PlistBuddy; private defaultsHelper: DefaultsHelper; constructor( macosProjectRoot: string, projectRoot: string, scheme?: string, { nodeFileSystem = new FileSystem(), plistBuddy = undefined } = {}, ) { super(macosProjectRoot, projectRoot); this.scheme = scheme; this.nodeFileSystem = nodeFileSystem; this.plistBuddy = plistBuddy || new PlistBuddy(); this.defaultsHelper = new DefaultsHelper(); } public async setAppRemoteDebuggingSetting( enable: boolean, configuration?: string, productName?: string, ): Promise { // Find the plistFile with the configuration setting // There is a race here between us checking for the plist file, and the application starting up. const plistFile = await this.findPListFileWithRetry(configuration, productName); // Set the "isDebuggingRemotely" flag to "true", so on the next startup the application will default into debug mode // This is approximately equivalent to clicking the "Debug in Chrome" button return await this.defaultsHelper.setPlistBooleanProperty( plistFile, MacOSDebugModeManager.REMOTE_DEBUGGING_FLAG_NAME, enable, ); } public async getAppRemoteDebuggingSetting( configuration?: string, productName?: string, ): Promise { const plistFile = await this.findPListFileWithRetry(configuration, productName); try { // Attempt to read from the file, but if the property is not defined then return the empty string const remoteDebugEnabled = await this.plistBuddy.readPlistProperty( plistFile, MacOSDebugModeManager.REMOTE_DEBUGGING_SETTING_NAME, ); return remoteDebugEnabled === "true"; } catch (e) { return false; } } protected async tryOneAttemptToFindPListFile( configuration?: string, productName?: string, ): Promise { try { return await this.findPlistFile(configuration, productName); } catch (reason) { this.logger.debug(`Failed one attempt to find plist file: ${String(reason)}`); return ""; } } private async findPlistFile(configuration?: string, productName?: string): Promise { const bundleId = await this.plistBuddy.getBundleId( this.platformProjectRoot, this.projectRoot, PlatformType.macOS, false, configuration, productName, this.scheme, ); // Find the name of the application const plistFilePath = path.join(homedir(), "Library", "Preferences", `${bundleId}.plist`); const exist = await this.nodeFileSystem.exists(plistFilePath); if (!exist) { throw new Error(`Unable to find plist file for ${bundleId}`); } else { return plistFilePath; } } }