* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { execCommand } from './commandExecutor';
export interface PythonEnvInfo {
hasPython3: boolean;
pythonVersion?: string;
hasPyMobileDevice3: boolean;
pyMobileDevice3Version?: string;
}
* Utility methods for checking the Python environment
*/
export class PythonEnvUtils {
public static readonly PYTHON_VERSION_COMMAND = 'python3 --version';
public static readonly PY_MOBILE_DEVICE3_VERSION_COMMAND = 'python3 -m pymobiledevice3 version';
public static readonly INSTALL_PY_MOBILE_DEVICE3_COMMAND = 'python3 -m pip install --user --upgrade pymobiledevice3';
* Timeout for pip install, in milliseconds (default 120s).
* Installing pymobiledevice3 may take a while due to its many dependencies.
*/
private static readonly INSTALL_TIMEOUT = 120000;
* Checks whether `python3` is installed
*/
static async checkPython3(): Promise<{ exists: boolean, version?: string }> {
try {
let execResult = await execCommand(this.PYTHON_VERSION_COMMAND);
let match = execResult.output.match(/Python\s+([\d.]+)/);
return { exists: true, version: match ? match[1] : undefined };
} catch {
return { exists: false };
}
}
* Checks whether `pymobiledevice3` is installed
*
* @param autoInstall Install automatically if not exists. Default is `false`
*/
static async checkPyMobileDevice3(autoInstall: boolean = false): Promise<{ exists: boolean, version?: string }> {
let matcher = /([\d]+\.[\d]+\.[\d]+)/;
try {
let execResult = await execCommand(this.PY_MOBILE_DEVICE3_VERSION_COMMAND);
let match = execResult.output.match(matcher);
return { exists: true, version: match ? match[1] : undefined };
} catch {
if (!autoInstall) {
return { exists: false };
}
try {
await execCommand(this.INSTALL_PY_MOBILE_DEVICE3_COMMAND, this.INSTALL_TIMEOUT);
let execResult = await execCommand(this.PY_MOBILE_DEVICE3_VERSION_COMMAND);
let match = execResult.output.match(matcher);
return { exists: true, version: match ? match[1] : undefined };
} catch {
return { exists: false };
}
}
}
* Check all required Python environment dependencies
*
* @param autoInstallPyMobileDevice3 Install `pyMobileDevice3` automatically if not exists. Default is `false`
*/
static async checkEnvironment(autoInstallPyMobileDevice3: boolean = false): Promise<PythonEnvInfo> {
let python = await this.checkPython3();
if (!python.exists) {
return { hasPython3: false, hasPyMobileDevice3: false };
}
let pyMobileDevice3 = await this.checkPyMobileDevice3(autoInstallPyMobileDevice3);
return {
hasPython3: true,
pythonVersion: python.version,
hasPyMobileDevice3: pyMobileDevice3.exists,
pyMobileDevice3Version: pyMobileDevice3.version,
};
}
}