-
Notifications
You must be signed in to change notification settings - Fork 1
/
siminfo.py
152 lines (135 loc) · 5.54 KB
/
siminfo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/python
# encoding: utf-8
#from workflow import Workflow
from os.path import expanduser, join, dirname, basename, isfile, realpath
import glob
from subprocess import check_output, CalledProcessError, STDOUT
import re
import cPickle
HOME = expanduser("~")
SIM_DIR = join(HOME, "Library/Application\ Support/iPhone\ Simulator/7.1/Applications/*/*.app")
SIM_DIR6 = join(HOME, "Library/Developer/CoreSimulator/Devices/*/data/Containers")
SIM_DIRAPP_SEARCH = join(SIM_DIR6, 'Bundle/Application/*/*.app')
class DeviceInfo(object):
def __init__(self, cachePath):
self.cacheFilePath = join(cachePath, 'devices.cache')
self.devices = {}
self.cacheIsDirty = False
if isfile(self.cacheFilePath):
cacheFile = file(self.cacheFilePath)
cache = cPickle.load(cacheFile)
if cache:
self.devices = cache
def infoForDevice(self, deviceID):
if deviceID in self.devices:
return self.devices[deviceID]
else:
# no cache yet, read it in
plist = join(HOME, "Library/Developer/CoreSimulator/Devices/", deviceID, "device.plist")
if isfile(plist):
deviceName = get_plist_key(plist, 'name')
deviceRuntime = get_plist_key(plist, 'runtime')
deviceRuntime = deviceRuntime.split('.')[-1].split('-')
deviceRuntime = '%s %s.%s' % (deviceRuntime[0], deviceRuntime[1], deviceRuntime[2])
result = {'name': deviceName, 'id': deviceID, 'runtime': deviceRuntime}
self.devices[deviceID] = result
self.cacheIsDirty = True
return result
#else:
# print "Device %s missing device.plist: %s" % (deviceID, plist)
return None
def updateCache(self):
if self.cacheIsDirty:
cacheFile = file(self.cacheFilePath, "w+")
cPickle.dump(self.devices, cacheFile)
def get_plist_key(path, key):
try:
result = check_output(['/usr/libexec/PlistBuddy', '-c', ("Print :%s" % (key)), path], stderr=STDOUT)
result = result.strip()
return unicode( result, "utf-8" )
except CalledProcessError, e:
pass
return None
def get_device_id_for_app_path(path):
m = re.search('CoreSimulator/Devices/([\w\d\-]+)/data', path)
return m.group(1)
def get_device_infos():
deviceInfos = {}
devicePaths = glob.glob(join(HOME, "Library/Developer/CoreSimulator/Devices/*"))
for devicePath in devicePaths:
plist = join(devicePath, 'device.plist')
if not isfile(plist):
continue
deviceId = basename(devicePath)
deviceName = get_plist_key(plist, 'name')
deviceRuntime = get_plist_key(plist, 'runtime')
deviceRuntime = deviceRuntime.split('.')[-1].split('-')
deviceRuntime = '%s %s.%s' % (deviceRuntime[0], deviceRuntime[1], deviceRuntime[2])
deviceInfos[deviceId] = {'name': deviceName, 'id': deviceId, 'runtime': deviceRuntime}
return deviceInfos
def get_sim6_data_paths():
pathLookup = {}
for file in glob.glob(join(SIM_DIR6, 'Data/Application/*/.com.apple.mobile_container_manager.metadata.plist')):
appId = get_plist_key(file, 'MCMMetadataIdentifier')
if appId:
lookupKey = get_device_id_for_app_path(file) + '-' + appId
pathLookup[lookupKey] = dirname(file)
return pathLookup
def get_app_icon(appPath):
plistPath = join(appPath, 'Info.plist')
devices = ['', '~ipad', '~iphone']
for device in devices:
for x in [2,1,0]:
key = 'CFBundleIcons%s:CFBundlePrimaryIcon:CFBundleIconFiles:%i' % (device, x)
icon = get_plist_key(plistPath, key)
if icon:
iconPath = join(appPath, icon + '%s.png' % (device))
if not isfile(iconPath):
iconPath = join(appPath, icon + '@2x%s.png' % (device))
if not isfile(iconPath):
iconPath = None
return iconPath
return None
def get_sim6_items(data_paths, device_info, include_watch=True):
appPaths = []
for file in glob.glob(SIM_DIRAPP_SEARCH):
file = unicode( file, "utf-8" )
deviceId = get_device_id_for_app_path(file)
plistPath = join(file, 'Info.plist')
appId = get_plist_key(plistPath, 'CFBundleIdentifier')
isWatchApp = get_plist_key(plistPath, 'WKWatchKitApp')
lookupKey = deviceId + '-' + appId
if lookupKey in data_paths:
dataPath = data_paths[lookupKey]
else:
dataPath = ''
appName = get_plist_key(plistPath, 'CFBundleDisplayName')
if not appName:
appName = basename(file)
appInfo = {
'id': appId,
'path': file,
'short_path': basename(file),
'name': appName,
'data_path': dataPath,
'device': device_info.infoForDevice(deviceId),
'icon': get_app_icon(file)
}
if include_watch or not isWatchApp:
appPaths.append(appInfo)
return appPaths
def getSimAppResults(cachePath, include_watch=True):
data_paths = get_sim6_data_paths()
device_info = DeviceInfo(cachePath)
apps = get_sim6_items(data_paths, device_info, include_watch)
device_info.updateCache()
return apps
def main(wf):
data_paths = get_sim6_data_paths()
device_info = DeviceInfo(wf.cachedir)
apps = get_sim6_items(data_paths, device_info)
print "Done: "
print len(apps)
device_info.updateCache()
if __name__ == '__main__':
main(None)