def list_others(self): cmd = '%s --verbose --list --include_obsolete' % self._get_sdk_manager_path() return_code, stdout, stderr = PlatformHelper.execute_cmd(cmd) if return_code != 0: print_error_and_exit('Failed to list packages') print('Installed Packages:') lines = stdout.split('\n') for (i, line) in enumerate(lines): line = line.strip() previous_line = None if i > 0: previous_line = lines[i - 1].strip() is_package_name = not previous_line or previous_line.startswith('---') if not is_package_name: continue print_verbose('Line is \"%s\" and previous line is \"%s\"' % (line, previous_line)) if not line: continue elif line.startswith('system-images;') or line.startswith('platforms;') or line.startswith('sources;'): continue elif line.startswith('platform-tools'): continue elif line.startswith('build-tools;'): continue elif line.find('Info:') != -1: continue if line.endswith(':'): print('') print(line)
def _get_binary(binary_name, binary_paths_relative_to_android_sdk) -> str: sdk_location = AndroidSdkHelper._get_location_of_android_sdk() if not sdk_location: print_verbose('ANDROID_SDK_ROOT not defined') else: for relative_path in binary_paths_relative_to_android_sdk: binary_path = os.path.join(sdk_location, relative_path) if os.path.exists(binary_path): print_error('\"%s\" found at \"%s\"' % (binary_name, binary_path)) return binary_path else: print_error('\"%s\" not found at \"%s\"' % (binary_name, binary_path)) # Only works on Mac and GNU/Linux if PlatformHelper.on_linux() or PlatformHelper.on_mac(): return_code, stdout, stderr = PlatformHelper.execute_cmd( 'command -v %s' % binary_name) if return_code == 0: return stdout.strip() else: print_error('\"%s\" not in path' % binary_name) print_error_and_exit( 'Set ANDROID_SDK_ROOT environment variable to point to Android SDK root' )
def _get_emulator_path(self): """ :return: Path to Android emulator binary, caches the result for the future use. """ if not self._emulator: self._emulator = AndroidSdkHelper.get_emulator_path_uncached() print_verbose('Emulator is located at %s' % self._emulator) # Return the cached value return self._emulator
def _get_sdk_manager_path(self) -> Optional[str]: """ :return: path to sdkmanager binary, caches the result for the future use. """ if not self._sdk_manager: self._sdk_manager = AndroidSdkHelper.get_sdk_manager_path_uncached() print_verbose('sdkmanager is located at %s' % self._sdk_manager) # Return the cached value return self._sdk_manager
def _get_build_tools(self) -> [str]: """ :return: List of build tools packages, sorted by version number, latest package comes last """ cmd = '%s --verbose --list --include_obsolete' % self._get_sdk_manager_path() return_code, stdout, stderr = PlatformHelper.execute_cmd(cmd) if return_code != 0: print_error_and_exit('Failed to list build tools, stdout: %s, stderr: %s' % (stdout, stderr)) build_tools = re.findall(_BUILD_TOOLS_REGEX, stdout) build_tools = sorted(set(build_tools)) print_verbose('Build tools are %s' % build_tools) return build_tools
def _get_default_java_version() -> Optional[str]: return_code, stdout, stderr = PlatformHelper.execute_cmd('java -version') if return_code != 0: print_error('Failed to get java version') return None # TODO(ashishb): Do I need two different regex for Mac and Linux like _get_all_java_versions here? java_version_regex = r'"([0-9]+\.[0-9]+)\..*"' version = re.search(java_version_regex, stderr) if version is None: return None print_verbose('version object is %s' % version) return version.group(1)
def list_packages(self, arch=None, api_type=None) -> None: print_verbose('List packages(arch: %s, api_type: %s)' % (arch, api_type)) if api_type is None: google_api_type = '.*?' else: google_api_type = api_type if arch is None: arch_pattern = '.*?' else: arch_pattern = arch + '.*?' regex_pattern = 'system-images;android-([0-9]+);(%s);(%s)\n' % ( google_api_type, arch_pattern) print_verbose('Package pattern: %s' % regex_pattern) return_code, stdout, stderr = PlatformHelper.execute_cmd( '%s --verbose --list --include_obsolete' % self._get_sdk_manager_path()) if return_code != 0: print_error_and_exit('Failed to list packages (return code: %d)' % return_code) system_images = re.findall(regex_pattern, stdout) arch_to_android_version_map = {} for system_image in system_images: android_api_version = system_image[0] google_api_type = system_image[1] arch = system_image[2] if google_api_type not in arch_to_android_version_map: arch_to_android_version_map[google_api_type] = {} if arch not in arch_to_android_version_map[google_api_type]: arch_to_android_version_map[google_api_type][arch] = [] arch_to_android_version_map[google_api_type][arch].append( android_api_version) for (google_api_type, architectures) in arch_to_android_version_map.items(): if google_api_type == 'default': print( 'Google API type: default (Standard Android image; no Google API)' ) else: print('Google API type: %s' % google_api_type) for architecture in architectures: android_api_versions = arch_to_android_version_map[ google_api_type][architecture] print('%s -> %s' % (architecture, ', '.join(android_api_versions))) print()
def _get_system_images_package(version, arch, api_type) -> Optional[str]: try: version = int(version) if version < 10: print_verbose('System images are bundled in the platform below API 10') return None # API 24 onwards, for x86, prefer to install google_apis_playstore image # then google_apis image. It seems it is a better image. if version >= 24 and api_type == 'google_apis' and arch == 'x86': api_type = 'google_apis_playstore' return 'system-images;android-%s;%s;%s' % (version, api_type, arch) # API 28 onwards, for x86_64, prefer to install google_apis_playstore image # then google_apis image. It seems it is a better image. if version >= 28 and api_type == 'google_apis' and arch == 'x86_64': api_type = 'google_apis_playstore' return 'system-images;android-%s;%s;%s' % (version, api_type, arch) except ValueError: pass return 'system-images;android-%s;%s;%s' % (version, api_type, arch)
def _get_basic_packages(self) -> [str]: build_tools = self._get_build_tools() if not build_tools: print_error_and_exit('Build tools list is empty, this is unexpected') latest_build_package = build_tools[-1] print_verbose('Latest build package is \"%s\"' % latest_build_package) packages_to_install = [ latest_build_package, 'emulator', 'tools', 'platform-tools', 'extras;android;m2repository', 'extras;google;m2repository', 'patcher;v4', ] # HAXM is not required on Linux. It is required on Windows and OSX. # I am assuming that this tool will never run on anything except Windows and OSX. # I don't know whether HAXM is required on BSD or not. if not PlatformHelper.on_linux(): packages_to_install.append('extras;intel;Hardware_Accelerated_Execution_Manager') return packages_to_install
def _get_all_java_versions() -> [str]: if PlatformHelper.on_linux(): return_code, stdout, stderr = PlatformHelper.execute_cmd(_GET_ALL_JAVA_VERSIONS_ON_LINUX) java_version_regex = 'java-([0-9]+.*?)/' elif PlatformHelper.on_mac(): java_version_regex = r'"([0-9]+\.[0-9]+)\..*"' return_code, stdout, stderr = PlatformHelper.execute_cmd(_GET_ALL_JAVA_VERSIONS_ON_MAC) else: print_error('Unsupported operating system') return [] if return_code != 0: print_error('Failed to list java versions') return [] output = '' output += stdout output += stderr versions = re.findall(java_version_regex, output) versions = set(versions) print_verbose('Versions are %s' % versions) return versions
def create_avd(self, avd_name, api_version, arch, api_type): if api_type is None: api_type = 'google_apis' # Preferred if arch is None: if PlatformHelper.is_64bit_architecture(): arch = 'x86_64' else: arch = 'x86' package_name = AndroidEnhanced._get_system_images_package(api_version, arch, api_type) print_verbose('Package is %s' % package_name) self.install_api_version(api_version, arch=arch, api_type=api_type) # Say no to custom hardware profile. print_message('Creating AVD "%s" of type "%s" ' % (avd_name, package_name)) create_cmd = 'echo no | %s --verbose create avd --name %s --package "%s"' % ( self._get_avd_manager_path(), avd_name, package_name) return_code, stdout, stderr = PlatformHelper.execute_cmd(create_cmd) if return_code != 0: print_error('Failed to create AVD') print_error('stdout: %s' % stdout) print_error_and_exit('stderr: %s' % stderr) print_message('AVD \"%s\" created successfully' % avd_name)
def _ensure_basic_packages_are_installed(self) -> bool: success = True installed_packages = self._get_installed_packages() print_verbose('Installed packages are %s' % installed_packages) basic_packages = self._get_basic_packages() num_packages = len(basic_packages) for i in range(0, num_packages): basic_package = basic_packages[i] if basic_package == 'tools': print_message('Skipping over obsolete package \"%s\"' % basic_package) continue if basic_package not in installed_packages: print_error('Basic packages \"%s\" is not installed' % basic_package) success = False else: print_message('Package %d/%d: \"%s\" is installed' % (i + 1, num_packages, basic_package)) return success
def execute_cmd(cmd, cwd=None) -> (int, str, str): """ :param cmd: Command to be executed :param cwd: working directory for the command :return: (returncode, stdout, stderr) """ if cwd: print_verbose( 'Executing command: \"%s\" using working directory: \"%s\"' % (cmd, cwd)) else: print_verbose('Executing command: \"%s\"' % cmd) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ.copy(), cwd=cwd) stdout = '' stderr = '' # Disabled for now, since we lose stdout data due to this indeterministically. # while process.poll() is None: # line1 = process.stdout.readline() # line1 = line1.decode('utf-8').strip() # if line1: # stdout += (line1 + '\n') # print_verbose(line1) leftover_stdout, leftover_stderr = process.communicate() leftover_stdout = leftover_stdout.decode('utf-8').strip() leftover_stderr = leftover_stderr.decode('utf-8').strip() for line in leftover_stdout.split('\n'): line = line.strip() if line: print_verbose(line) stdout += (line + '\n') for line in leftover_stderr.split('\n'): line = line.strip() if line: print_verbose(line) stderr += (line + '\n') return process.returncode, stdout, stderr