All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbakery.simulators.SimulatorControl.groovy Maven / Gradle / Ivy

Go to download

XCode-Plugin is a plugin to allow custom XCode projects to build as generated by CMake

There is a newer version: 0.0.201
Show newest version
package org.openbakery.simulators

import org.openbakery.*
import org.openbakery.xcode.Destination
import org.openbakery.xcode.Type
import org.openbakery.xcode.Version
import org.openbakery.xcode.Xcode
import org.slf4j.Logger
import org.slf4j.LoggerFactory

class SimulatorControl {



	enum Section {
		DEVICE_TYPE("== Device Types =="),
		RUNTIMES("== Runtimes =="),
		DEVICES("== Devices =="),
		DEVICE_PAIRS("== Device Pairs ==")

		private final String identifier
		Section(String identifier) {
			this.identifier = identifier
		}


		public static Section isSection(String line) {
			for (Section section : Section.values()) {
				if (section.identifier.equals(line)) {
					return section;
				}
			}
			return null
		}

	}


	private static Logger logger = LoggerFactory.getLogger(SimulatorControl.class)

	CommandRunner commandRunner
	Xcode xcode

	ArrayList deviceTypes
	ArrayList runtimes
	HashMap> devices
	HashMap identifierToDevice
	ArrayList devicePairs





	public SimulatorControl(CommandRunner commandRunner, Xcode xcode) {
		this.commandRunner = commandRunner
		this.xcode = xcode
	}

	void parse() {
		runtimes = new ArrayList<>()
		devices = new HashMap<>()
		deviceTypes = new ArrayList<>()
    identifierToDevice = new HashMap<>()
		devicePairs = new ArrayList<>()


		Section section = null
		String simctlList = simctl("list")

		ArrayList simulatorDevices = null

		SimulatorDevicePair pair = null

		for (String line in simctlList.split("\n")) {

			Section isSection = Section.isSection(line)
			if (isSection != null) {
				section = isSection
				continue
			}

			switch (section) {
				case Section.DEVICE_TYPE:
					deviceTypes.add(new SimulatorDeviceType(line))
					break
				case Section.RUNTIMES:
					SimulatorRuntime runtime = new SimulatorRuntime(line)
					runtimes.add(runtime)
					break
				case Section.DEVICES:

					SimulatorRuntime isRuntime = parseDevicesRuntime(line)
					if (isRuntime != null) {
						simulatorDevices = new ArrayList<>()
						devices.put(isRuntime, simulatorDevices)
						continue
					}
					if (line.startsWith("--")) {
						// unknown runtime, so we are done
						simulatorDevices = null
					}

					if (simulatorDevices != null) {
						SimulatorDevice device = new SimulatorDevice(line)
						simulatorDevices.add(device)
            identifierToDevice[device.identifier]=device
					}

					break
				case Section.DEVICE_PAIRS:


					if (line ==~ /^\s+Watch.*/) {
						pair.watch = parseIdentifierFromDevicePairs(line)
					} else if (line ==~ /^\s+Phone.*/) {
						pair.phone = parseIdentifierFromDevicePairs(line)
					} else {
						// is new device pair
						pair = new SimulatorDevicePair(line)
						devicePairs.add(pair)
					}

					break


			}
		}
		Collections.sort(runtimes, new SimulatorRuntimeComparator())

	}

	SimulatorDevice parseIdentifierFromDevicePairs(String line) {
		def tokenizer = new StringTokenizer(line, "()");
		if (tokenizer.hasMoreTokens()) {
			// ignore first token
			tokenizer.nextToken()
		}
		if (tokenizer.hasMoreTokens()) {
			def identifier =  tokenizer.nextToken().trim()
			return getDeviceWithIdentifier(identifier)
		}
		return null

	}


	SimulatorRuntime parseDevicesRuntime(String line) {
		for (SimulatorRuntime runtime in runtimes) {
			if (line.equals("-- " + runtime.name + " --")) {
				return runtime
			}
		}
		return null
	}


	public void waitForDevice(SimulatorDevice device, int timeoutMS = 10000) {
		def start = System.currentTimeMillis()
		while ((System.currentTimeMillis() - start) < timeoutMS) {
			parse()
			def polledDevice = identifierToDevice[device.identifier]
			if (polledDevice != null && polledDevice.state == "Booted")
				return
			sleep(500)
		}
		throw new Exception("Timeout waiting for " + device)
	}

	List getRuntimes() {
		if (runtimes == null) {
			parse()
		}
		return runtimes;
	}


	List getRuntimes(String name) {
		List result = []
		for (SimulatorRuntime runtime in getRuntimes()) {
			if (runtime.available && runtime.getName().startsWith(name)) {
				result << runtime
			}
		}
		Collections.sort(result, new SimulatorRuntimeComparator())
		return result
	}


	List getRuntimes(Type type) {
		ArrayList result = new ArrayList<>()

		for (SimulatorRuntime runtime in getRuntimes()) {
			if (runtime.type == type) {
				result.add(runtime);
			}
		}
		Collections.sort(result, new SimulatorRuntimeComparator())
		return result;
	}

	SimulatorRuntime getMostRecentRuntime(Type type) {
		List runtimes = getRuntimes(type);
		if (runtimes.size() > 0) {
			return runtimes.get(0)
		}
		return null;
	}



	SimulatorDevice getDevice(SimulatorRuntime simulatorRuntime, String name) {
		for (SimulatorDevice device in getDevices(simulatorRuntime)) {
			if (device.name.equalsIgnoreCase(name)) {
				return device
			}
		}
		null
	}


	SimulatorRuntime getRuntime(Destination destination) {
		for (SimulatorRuntime runtime in getRuntimes()) {
			if (runtime.type == Type.iOS && runtime.version.equals(new Version(destination.os))) {
				return runtime;
			}
		}
		return null;
	}

	SimulatorDevice getDevice(Destination destination) {
		SimulatorRuntime runtime = getRuntime(destination);
		if (runtime != null) {

			for (SimulatorDevice device in getDevices(runtime)) {
				if (device.name.equalsIgnoreCase(destination.name)) {
					return device
				}
			}
		}
		return null
	}

	SimulatorDevice getDeviceWithIdentifier(String identifier) {
		for (Map.Entry> entry in devices.entrySet()) {
			for (SimulatorDevice device in entry.value) {
				if (device.identifier == identifier) {
					return device
				}
			}
		}
		return null
	}

	List  getDevices(SimulatorRuntime runtime) {
		return getDevices().get(runtime)
	}


	HashMap> getDevices() {
		if (devices == null) {
			parse()
		}
		return devices
	}

	List getDeviceTypes() {
		if (deviceTypes == null) {
			parse()
		}
		return deviceTypes
	}

	List getDevicePairs() {
		if (devicePairs == null) {
			parse()
		}
		return devicePairs

	}


	String simctl(String... commands) {
		ArrayListparameters = new ArrayList<>()
		parameters.add(xcode.getSimctl())
		parameters.addAll(commands)
		return commandRunner.runWithResult(parameters)
	}




	void deleteAll() {

		for (Map.Entry> entry : getDevices().entrySet()) {
			for (SimulatorDevice device in entry.getValue()) {
				if (device.available) {
					println "Delete simulator: '" + device.name + "' " + device.identifier
					simctl("delete", device.identifier)
				}
			}
		}
	}


	void createAll() {
		for (SimulatorRuntime runtime in getRuntimes()) {

			if (runtime.available) {

				for (SimulatorDeviceType deviceType in getDeviceTypes()) {

					if (deviceType.canCreateWithRuntime(runtime)) {
						logger.debug("create '" + deviceType.name + "' '" + deviceType.identifier + "' '" + runtime.identifier + "'")
						try {
							simctl("create", deviceType.name, deviceType.identifier, runtime.identifier)
							println "Create simulator: '" + deviceType.name + "' for " + runtime.version
						} catch (CommandRunnerException ex) {
							println "Unable to create simulator: '" + deviceType.name + "' for " + runtime.version
						}
					}
				}
			}
		}
		pair()
	}

	void pair() {
		parse() // read the created ids again

		List watchRuntimes = getRuntimes("watchOS")
		List iOS9Runtimes = getRuntimes("iOS 9")


		for (SimulatorRuntime iOS9Runtime in iOS9Runtimes) {
			for (SimulatorRuntime watchRuntime in watchRuntimes) {

				SimulatorDevice iPhone6 = getDevice(iOS9Runtime, "iPhone 6")
				SimulatorDevice watch38 = getDevice(watchRuntime, "Apple Watch - 38mm")
				simctl("pair", iPhone6.identifier, watch38.identifier)


				SimulatorDevice iPhone6Plus = getDevice(iOS9Runtime, "iPhone 6 Plus")
				SimulatorDevice watch42 = getDevice(watchRuntime, "Apple Watch - 42mm")
				simctl("pair", iPhone6Plus.identifier, watch42.identifier)


			}
		}

	}


	void eraseAll() {
		for (Map.Entry> entry : getDevices().entrySet()) {
			for (SimulatorDevice device in entry.getValue()) {
				if (device.available) {
					println "Erase simulator: '" + device.name + "' " + device.identifier
					simctl("erase", device.identifier)
				}
			}
		}
	}

	public void killAll() {
		// kill a running simulator
		logger.info("Killing old simulators")
		try {
			commandRunner.run("killall", "iOS Simulator")
		} catch (CommandRunnerException ex) {
			// ignore, this exception means that no simulator was running
		}
		try {
			commandRunner.run("killall", "Simulator") // for xcode 7
		} catch (CommandRunnerException ex) {
			// ignore, this exception means that no simulator was running
		}
	}

	public void runDevice(SimulatorDevice device) {
		SimulatorRuntime runtime = getRuntime(device)
		if (runtime == null) {
			throw new IllegalArgumentException("cannot find runtime for device: " + device)
		}

		try {
			commandRunner.run([xcode.getPath() + "/Contents/Developer/usr/bin/instruments", "-w", device.identifier])
		} catch (CommandRunnerException ex) {
			// ignore, because the result of this command is a failure, but the simulator should be launched
		}
	}

	SimulatorRuntime getRuntime(SimulatorDevice simulatorDevice) {

		for (Map.Entry> runtime : devices) {
			for (SimulatorDevice device : runtime.value) {
				if (device.equals(simulatorDevice)) {
					return runtime.key
				}
			}
		}

		return null
	}

	List getAllDestinations(Type type) {
		def allDestinations = []

		getRuntimes(type).each { runtime ->
			allDestinations.addAll(getAllDestinations(type, runtime))
		}

		return allDestinations
	}

	List getAllDestinations(Type type, SimulatorRuntime runtime) {
		def allDestinations = []

		getDevices(runtime).each { device ->
			Destination destination = new Destination()
			destination.platform = type.value + ' Simulator'
			destination.name = device.name
			destination.os = runtime.version.toString()
			destination.id = device.identifier
			allDestinations << destination
		}
		return allDestinations
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy