Guest User

Untitled

a guest
Feb 17th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.61 KB | None | 0 0
  1. from pathlib import Path
  2. import plistlib
  3. import subprocess
  4. import re
  5. import csv
  6.  
  7. def app_uses_swift(path):
  8. libswiftPath = path / 'Frameworks' / 'libswiftCore.dylib'
  9. return libswiftPath.exists()
  10.  
  11. def is_executable(file_path):
  12. file_info = subprocess.run(["file", file_path], capture_output=True)
  13. return 'Mach-O' in str(file_info.stdout)
  14.  
  15. def find_executable_in(path):
  16. executables = [file for file in path.iterdir()
  17. if is_executable(file)]
  18. return None if len(executables) == 0 else executables[0]
  19.  
  20. def class_dump(executable_path):
  21. header = str(subprocess.run(["class-dump", executable_path], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout)
  22. return re.findall("@interface ([\w_]+)\s?:\s?(\w+)", header)
  23.  
  24. def is_apple_class(class_tuple):
  25. prefixes = ["NS", "UI", "CA", "SCN", "SK", "CI", "AB", "ML", "GK", "AV"]
  26. for prefix in prefixes:
  27. pattern = re.compile(f'{prefix}[A-Z][a-z]+')
  28. if pattern.match(class_tuple[0]):
  29. return True
  30. return False
  31.  
  32. def percentage_classes_in_swift(classes):
  33. classes = [item for item in classes if not is_apple_class(item)]
  34. if len(classes) == 0: return 0.0
  35. swift_classes = [item for item in classes if item[0].startswith("_T")]
  36. return float(len(swift_classes)) / float(len(classes))
  37.  
  38. def analyze_app(path):
  39. results = {}
  40. infoPlistPath = path / 'Info.plist'
  41. with open(str(infoPlistPath.resolve()), 'rb') as infoPlistFile:
  42. infoPlist = plistlib.load(infoPlistFile)
  43.  
  44. bundle_id = infoPlist['CFBundleIdentifier']
  45. app_name = infoPlist.get('CFBundleDisplayName', infoPlist.get('CFBundleName', infoPlist['CFBundleIdentifier']))
  46. print(f'analyzing {app_name} at {path.name}')
  47. results['app_name'] = app_name
  48. results['bundle_id'] = bundle_id
  49. results['sdk'] = infoPlist.get('DTSDKName')
  50. results['deployment_target'] = infoPlist.get('MinimumOSVersion')
  51. results['uses_swift'] = app_uses_swift(path)
  52. executable = find_executable_in(path)
  53. results['executable'] = executable.name
  54. classes = class_dump(executable)
  55. results['percentage_swift'] = percentage_classes_in_swift(classes)
  56. results['main_binary_uses_swift'] = results['percentage_swift'] > 0
  57. return results
  58.  
  59. apps = [path for path in Path.cwd().iterdir() if path.suffix == '.app']
  60.  
  61. with open('results.csv', mode='w', newline='') as csv_file:
  62. fieldnames = ['app_name', 'bundle_id', 'sdk', 'deployment_target', 'uses_swift', 'percentage_swift', 'main_binary_uses_swift', 'executable']
  63. writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
  64. writer.writeheader()
  65. writer.writerows(map(analyze_app, apps))
Add Comment
Please, Sign In to add comment