<commit_before>import { ChildProcess } from "./wrappers/child-process";
import { FileSystem } from "./wrappers/file-system";
import { HostInfo } from "./host-info";
import { ExecOptions } from "child_process";
import { WinReg } from "./winreg";
import { Helpers } from "./helpers";
import { platform } from "os";
import * as path from "path";
import * as osenv from "osenv";
import * as temp from "temp";
import * as semver from "semver";

export class SysInfo implements NativeScriptDoctor.ISysInfo {
	// Different java has different format for `java -version` command.
	private static JAVA_VERSION_REGEXP = /(?:openjdk|java) version \"((?:\d+\.)+(?:\d+))/i;

	private static JAVA_COMPILER_VERSION_REGEXP = /^javac (.*)/im;
	private static XCODE_VERSION_REGEXP = /Xcode (.*)/;
	private static VERSION_REGEXP = /(\d{1,})\.(\d{1,})\.*([\w-]{0,})/m;
	private static GIT_VERSION_REGEXP = /^git version (.*)/;
	private static GRADLE_VERSION_REGEXP = /Gradle (.*)/i;

	private monoVerRegExp = /version (\d+[.]\d+[.]\d+) /gm;

	private javaVerCache: string;
	private javaCompilerVerCache: string;
	private xCodeVerCache: string;
	private npmVerCache: string;
	private nodeGypVerCache: string;
	private xCodeprojGemLocationCache: string;
	private iTunesInstalledCache: boolean;
	private cocoaPodsVerCache: string;
	private osCache: string;
	private adbVerCache: string;
	private androidInstalledCache: boolean;
	private monoVerCache: string;
	private gitVerCache: string;
	private gradleVerCache: string;
	private sysInfoCache: NativeScriptDoctor.ISysInfoData;
	private isCocoaPodsWorkingCorrectlyCache: boolean;
	private nativeScriptCliVersionCache: string;
	private xcprojInfoCache: NativeScriptDoctor.IXcprojInfo;
	private isCocoaPodsUpdateRequiredCache: boolean;
	private shouldCache: boolean = true;
	private isAndroidSdkConfiguredCorrectlyCache: boolean;

	constructor(private childProcess: ChildProcess,
		private fileSystem: FileSystem,
		private helpers: Helpers,
		private hostInfo: HostInfo,
		private winReg: WinReg,
		private androidToolsInfo: NativeScriptDoctor.IAndroidToolsInfo) { }

	public getJavaVersion(): Promise<string> {
		return this.getValueForProperty(() => this.javaVerCache, async (): Promise<string> => {
			try {
				const spawnResult = await this.childProcess.spawnFromEvent("java", ["-version"], "exit");
				const matches = spawnResult && SysInfo.JAVA_VERSION_REGEXP.exec(spawnResult.stderr);
				return matches && matches[1];
			} catch (err) {
				return null;
			}
		});
	}

	public getJavaCompilerVersion(): Promise<string> {
		return this.getValueForProperty(() => this.javaCompilerVerCache, async (): Promise<string> => {
			const javaCompileExecutableName = "javac";
			const javaHome = process.env.JAVA_HOME;
			const pathToJavaCompilerExecutable = javaHome ? path.join(javaHome, "bin", javaCompileExecutableName) : javaCompileExecutableName;
			try {
				const output = await this.childProcess.exec(`"${pathToJavaCompilerExecutable}" -version`);
				return SysInfo.JAVA_COMPILER_VERSION_REGEXP.exec(output.stderr)[1];
			} catch (err) {
				return null;
			}
		});
	}

	public getXcodeVersion(): Promise<string> {
		return this.getValueForProperty(() => this.xCodeVerCache, async (): Promise<string> => {
			if (this.hostInfo.isDarwin) {
				const output = await this.execCommand("xcodebuild -version");
				const xcodeVersionMatch = output && output.match(SysInfo.XCODE_VERSION_REGEXP);

				if (xcodeVersionMatch) {
					return this.getVersionFromString(output);
				}
			}
		});
	}

	public async getNodeVersion(): Promise<string> {
		return this.getVersionFromString(process.version);
	}

	public getNpmVersion(): Promise<string> {
		return this.getValueForProperty(() => this.npmVerCache, async (): Promise<string> => {
			const output = await this.execCommand("npm -v");
			return output ? output.split("\n")[0] : null;
		});
	}

	public getNodeGypVersion(): Promise<string> {
		return this.getValueForProperty(() => this.nodeGypVerCache, async (): Promise<string> => {
			const output = await this.execCommand("node-gyp -v");
			return output ? this.getVersionFromString(output) : null;
		});
	}

	public getXcodeprojGemLocation(): Promise<string> {
		return this.getValueForProperty(() => this.xCodeprojGemLocationCache, async (): Promise<string> => {
			const output = await this.execCommand("gem which xcodeproj");
			return output ? output.trim() : null;
		});
	}

	public isITunesInstalled(): Promise<boolean> {
		return this.getValueForProperty(() => this.iTunesInstalledCache, async (): Promise<boolean> => {
			if (this.hostInfo.isLinux) {
				return false;
			}

			let coreFoundationDir: string;
			let mobileDeviceDir: string;

			if (this.hostInfo.isWindows) {
				const commonProgramFiles = this.hostInfo.isWindows64 ? process.env["CommonProgramFiles(x86)"] : process.env.CommonProgramFiles;
				coreFoundationDir = path.join(commonProgramFiles, "Apple", "Apple Application Support");
				mobileDeviceDir = path.join(commonProgramFiles, "Apple", "Mobile Device Support");
			} else if (this.hostInfo.isDarwin) {
				coreFoundationDir = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
				mobileDeviceDir = "/System/Library/PrivateFrameworks/MobileDevice.framework/MobileDevice";
			}

			return await this.fileSystem.exists(coreFoundationDir) && await this.fileSystem.exists(mobileDeviceDir);
		});
	}

	public getCocoaPodsVersion(): Promise<string> {
		return this.getValueForProperty(() => this.cocoaPodsVerCache, async (): Promise<string> => {
			if (this.hostInfo.isDarwin) {
				if (this.hostInfo.isDarwin) {
					const output = await this.execCommand("pod --version");
					// Output of pod --version could contain some warnings. Find the version in it.
					const cocoaPodsVersionMatch = output && output.match(SysInfo.VERSION_REGEXP);
					if (cocoaPodsVersionMatch && cocoaPodsVersionMatch[0]) {
						return cocoaPodsVersionMatch[0].trim();
					}
				}
			}
		});
	}

	public getOs(): Promise<string> {
		return this.getValueForProperty(() => this.osCache, async (): Promise<string> => {
			return await (this.hostInfo.isWindows ? this.winVer() : this.unixVer());
		});
	}

	public getAdbVersion(): Promise<string> {
		return this.getValueForProperty(() => this.adbVerCache, async (): Promise<string> => {
			const output = await this.childProcess.spawnFromEvent(await this.androidToolsInfo.getPathToAdbFromAndroidHome(), ["version"], "close", { ignoreError: true });
			return output && output.stdout ? this.getVersionFromString(output.stdout) : null;
		});
	}

	public isAndroidInstalled(): Promise<boolean> {
		return this.getValueForProperty(() => this.androidInstalledCache, async (): Promise<boolean> => {<commit_msg>Fix getting adb version when ANDROID_HOME is not set<commit_after>import { ChildProcess } from "./wrappers/child-process";
import { FileSystem } from "./wrappers/file-system";
import { HostInfo } from "./host-info";
import { ExecOptions } from "child_process";
import { WinReg } from "./winreg";
import { Helpers } from "./helpers";
import { platform } from "os";
import * as path from "path";
import * as osenv from "osenv";
import * as temp from "temp";
import * as semver from "semver";

export class SysInfo implements NativeScriptDoctor.ISysInfo {
	// Different java has different format for `java -version` command.
	private static JAVA_VERSION_REGEXP = /(?:openjdk|java) version \"((?:\d+\.)+(?:\d+))/i;

	private static JAVA_COMPILER_VERSION_REGEXP = /^javac (.*)/im;
	private static XCODE_VERSION_REGEXP = /Xcode (.*)/;
	private static VERSION_REGEXP = /(\d{1,})\.(\d{1,})\.*([\w-]{0,})/m;
	private static GIT_VERSION_REGEXP = /^git version (.*)/;
	private static GRADLE_VERSION_REGEXP = /Gradle (.*)/i;

	private monoVerRegExp = /version (\d+[.]\d+[.]\d+) /gm;

	private javaVerCache: string;
	private javaCompilerVerCache: string;
	private xCodeVerCache: string;
	private npmVerCache: string;
	private nodeGypVerCache: string;
	private xCodeprojGemLocationCache: string;
	private iTunesInstalledCache: boolean;
	private cocoaPodsVerCache: string;
	private osCache: string;
	private adbVerCache: string;
	private androidInstalledCache: boolean;
	private monoVerCache: string;
	private gitVerCache: string;
	private gradleVerCache: string;
	private sysInfoCache: NativeScriptDoctor.ISysInfoData;
	private isCocoaPodsWorkingCorrectlyCache: boolean;
	private nativeScriptCliVersionCache: string;
	private xcprojInfoCache: NativeScriptDoctor.IXcprojInfo;
	private isCocoaPodsUpdateRequiredCache: boolean;
	private shouldCache: boolean = true;
	private isAndroidSdkConfiguredCorrectlyCache: boolean;

	constructor(private childProcess: ChildProcess,
		private fileSystem: FileSystem,
		private helpers: Helpers,
		private hostInfo: HostInfo,
		private winReg: WinReg,
		private androidToolsInfo: NativeScriptDoctor.IAndroidToolsInfo) { }

	public getJavaVersion(): Promise<string> {
		return this.getValueForProperty(() => this.javaVerCache, async (): Promise<string> => {
			try {
				const spawnResult = await this.childProcess.spawnFromEvent("java", ["-version"], "exit");
				const matches = spawnResult && SysInfo.JAVA_VERSION_REGEXP.exec(spawnResult.stderr);
				return matches && matches[1];
			} catch (err) {
				return null;
			}
		});
	}

	public getJavaCompilerVersion(): Promise<string> {
		return this.getValueForProperty(() => this.javaCompilerVerCache, async (): Promise<string> => {
			const javaCompileExecutableName = "javac";
			const javaHome = process.env.JAVA_HOME;
			const pathToJavaCompilerExecutable = javaHome ? path.join(javaHome, "bin", javaCompileExecutableName) : javaCompileExecutableName;
			try {
				const output = await this.childProcess.exec(`"${pathToJavaCompilerExecutable}" -version`);
				return SysInfo.JAVA_COMPILER_VERSION_REGEXP.exec(output.stderr)[1];
			} catch (err) {
				return null;
			}
		});
	}

	public getXcodeVersion(): Promise<string> {
		return this.getValueForProperty(() => this.xCodeVerCache, async (): Promise<string> => {
			if (this.hostInfo.isDarwin) {
				const output = await this.execCommand("xcodebuild -version");
				const xcodeVersionMatch = output && output.match(SysInfo.XCODE_VERSION_REGEXP);

				if (xcodeVersionMatch) {
					return this.getVersionFromString(output);
				}
			}
		});
	}

	public async getNodeVersion(): Promise<string> {
		return this.getVersionFromString(process.version);
	}

	public getNpmVersion(): Promise<string> {
		return this.getValueForProperty(() => this.npmVerCache, async (): Promise<string> => {
			const output = await this.execCommand("npm -v");
			return output ? output.split("\n")[0] : null;
		});
	}

	public getNodeGypVersion(): Promise<string> {
		return this.getValueForProperty(() => this.nodeGypVerCache, async (): Promise<string> => {
			const output = await this.execCommand("node-gyp -v");
			return output ? this.getVersionFromString(output) : null;
		});
	}

	public getXcodeprojGemLocation(): Promise<string> {
		return this.getValueForProperty(() => this.xCodeprojGemLocationCache, async (): Promise<string> => {
			const output = await this.execCommand("gem which xcodeproj");
			return output ? output.trim() : null;
		});
	}

	public isITunesInstalled(): Promise<boolean> {
		return this.getValueForProperty(() => this.iTunesInstalledCache, async (): Promise<boolean> => {
			if (this.hostInfo.isLinux) {
				return false;
			}

			let coreFoundationDir: string;
			let mobileDeviceDir: string;

			if (this.hostInfo.isWindows) {
				const commonProgramFiles = this.hostInfo.isWindows64 ? process.env["CommonProgramFiles(x86)"] : process.env.CommonProgramFiles;
				coreFoundationDir = path.join(commonProgramFiles, "Apple", "Apple Application Support");
				mobileDeviceDir = path.join(commonProgramFiles, "Apple", "Mobile Device Support");
			} else if (this.hostInfo.isDarwin) {
				coreFoundationDir = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
				mobileDeviceDir = "/System/Library/PrivateFrameworks/MobileDevice.framework/MobileDevice";
			}

			return await this.fileSystem.exists(coreFoundationDir) && await this.fileSystem.exists(mobileDeviceDir);
		});
	}

	public getCocoaPodsVersion(): Promise<string> {
		return this.getValueForProperty(() => this.cocoaPodsVerCache, async (): Promise<string> => {
			if (this.hostInfo.isDarwin) {
				if (this.hostInfo.isDarwin) {
					const output = await this.execCommand("pod --version");
					// Output of pod --version could contain some warnings. Find the version in it.
					const cocoaPodsVersionMatch = output && output.match(SysInfo.VERSION_REGEXP);
					if (cocoaPodsVersionMatch && cocoaPodsVersionMatch[0]) {
						return cocoaPodsVersionMatch[0].trim();
					}
				}
			}
		});
	}

	public getOs(): Promise<string> {
		return this.getValueForProperty(() => this.osCache, async (): Promise<string> => {
			return await (this.hostInfo.isWindows ? this.winVer() : this.unixVer());
		});
	}

	public getAdbVersion(): Promise<string> {
		return this.getValueForProperty(() => this.adbVerCache, async (): Promise<string> => {
			let output: IProcessInfo = null;
			const pathToAdbFromAndroidHome = await this.androidToolsInfo.getPathToAdbFromAndroidHome();
			if (pathToAdbFromAndroidHome) {
				output = await this.childProcess.spawnFromEvent(pathToAdbFromAndroidHome, ["version"], "close", { ignoreError: true });
			}

			return output && output.stdout ? this.getVersionFromString(output.stdout) : null;
		});
	}

	public isAndroidInstalled(): Promise<boolean> {
		return this.getValueForProperty(() => this.androidInstalledCache, async (): Promise<boolean> => {
{'fraction_non_alphanumeric': 0.13159249724163297, 'fraction_numerical': 0.0017653549098933432, 'mean_word_length': 4.950109409190372, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '755530', 'n_tokens_mistral': 4613, 'n_tokens_neox': 4115, 'n_words': 914}