PageRenderTime 52ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/media/webrtc/trunk/build/android/pylib/apk_info.py

https://bitbucket.org/hsoft/mozilla-central
Python | 142 lines | 116 code | 16 blank | 10 comment | 27 complexity | c0bc107b18fa8acc758e5205429c111a MD5 | raw file
Possible License(s): JSON, LGPL-2.1, LGPL-3.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, Apache-2.0, GPL-2.0, BSD-2-Clause, MPL-2.0, BSD-3-Clause, 0BSD
  1. # Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Gathers information about APKs."""
  5. import collections
  6. import os
  7. import re
  8. import cmd_helper
  9. class ApkInfo(object):
  10. """Helper class for inspecting APKs."""
  11. _PROGUARD_PATH = os.path.join(os.environ['ANDROID_SDK_ROOT'],
  12. 'tools/proguard/bin/proguard.sh')
  13. if not os.path.exists(_PROGUARD_PATH):
  14. _PROGUARD_PATH = os.path.join(os.environ['ANDROID_BUILD_TOP'],
  15. 'external/proguard/bin/proguard.sh')
  16. _PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$')
  17. _PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$')
  18. _PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$')
  19. _PROGUARD_ANNOTATION_CONST_RE = re.compile(r'\s*?- Constant element value.*$')
  20. _PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$')
  21. _AAPT_PACKAGE_NAME_RE = re.compile(r'package: .*name=\'(\S*)\'')
  22. def __init__(self, apk_path, jar_path):
  23. if not os.path.exists(apk_path):
  24. raise Exception('%s not found, please build it' % apk_path)
  25. self._apk_path = apk_path
  26. if not os.path.exists(jar_path):
  27. raise Exception('%s not found, please build it' % jar_path)
  28. self._jar_path = jar_path
  29. self._annotation_map = collections.defaultdict(list)
  30. self._test_methods = []
  31. self._Initialize()
  32. def _Initialize(self):
  33. proguard_output = cmd_helper.GetCmdOutput([self._PROGUARD_PATH,
  34. '-injars', self._jar_path,
  35. '-dontshrink',
  36. '-dontoptimize',
  37. '-dontobfuscate',
  38. '-dontpreverify',
  39. '-dump',
  40. ]).split('\n')
  41. clazz = None
  42. method = None
  43. annotation = None
  44. has_value = False
  45. qualified_method = None
  46. for line in proguard_output:
  47. m = self._PROGUARD_CLASS_RE.match(line)
  48. if m:
  49. clazz = m.group(1).replace('/', '.') # Change package delim.
  50. annotation = None
  51. continue
  52. m = self._PROGUARD_METHOD_RE.match(line)
  53. if m:
  54. method = m.group(1)
  55. annotation = None
  56. qualified_method = clazz + '#' + method
  57. if method.startswith('test') and clazz.endswith('Test'):
  58. self._test_methods += [qualified_method]
  59. continue
  60. m = self._PROGUARD_ANNOTATION_RE.match(line)
  61. if m:
  62. assert qualified_method
  63. annotation = m.group(1).split('/')[-1] # Ignore the annotation package.
  64. self._annotation_map[qualified_method].append(annotation)
  65. has_value = False
  66. continue
  67. if annotation:
  68. assert qualified_method
  69. if not has_value:
  70. m = self._PROGUARD_ANNOTATION_CONST_RE.match(line)
  71. if m:
  72. has_value = True
  73. else:
  74. m = self._PROGUARD_ANNOTATION_VALUE_RE.match(line)
  75. if m:
  76. value = m.group(1)
  77. self._annotation_map[qualified_method].append(
  78. annotation + ':' + value)
  79. has_value = False
  80. def _GetAnnotationMap(self):
  81. return self._annotation_map
  82. def _IsTestMethod(self, test):
  83. class_name, method = test.split('#')
  84. return class_name.endswith('Test') and method.startswith('test')
  85. def GetApkPath(self):
  86. return self._apk_path
  87. def GetPackageName(self):
  88. """Returns the package name of this APK."""
  89. aapt_output = cmd_helper.GetCmdOutput(
  90. ['aapt', 'dump', 'badging', self._apk_path]).split('\n')
  91. for line in aapt_output:
  92. m = self._AAPT_PACKAGE_NAME_RE.match(line)
  93. if m:
  94. return m.group(1)
  95. raise Exception('Failed to determine package name of %s' % self._apk_path)
  96. def GetTestAnnotations(self, test):
  97. """Returns a list of all annotations for the given |test|. May be empty."""
  98. if not self._IsTestMethod(test):
  99. return []
  100. return self._GetAnnotationMap()[test]
  101. def _AnnotationsMatchFilters(self, annotation_filter_list, annotations):
  102. """Checks if annotations match any of the filters."""
  103. if not annotation_filter_list:
  104. return True
  105. for annotation_filter in annotation_filter_list:
  106. filters = annotation_filter.split('=')
  107. if len(filters) == 2:
  108. key = filters[0]
  109. value_list = filters[1].split(',')
  110. for value in value_list:
  111. if key + ':' + value in annotations:
  112. return True
  113. elif annotation_filter in annotations:
  114. return True
  115. return False
  116. def GetAnnotatedTests(self, annotation_filter_list):
  117. """Returns a list of all tests that match the given annotation filters."""
  118. return [test for test, annotations in self._GetAnnotationMap().iteritems()
  119. if self._IsTestMethod(test) and self._AnnotationsMatchFilters(
  120. annotation_filter_list, annotations)]
  121. def GetTestMethods(self):
  122. """Returns a list of all test methods in this apk as Class#testMethod."""
  123. return self._test_methods
  124. @staticmethod
  125. def IsPythonDrivenTest(test):
  126. return 'pythonDrivenTests' in test