def scan_device_port(self): port = 0 apktime_path = self._get_apktime_path() self.debug("apktime path: " + apktime_path) sync_value = get_sync_value(apktime_path, self._cache_dir) self.debug('your local sync value is: {}'.format(sync_value)) uuid = get_apk_created_ticket(apktime_path) self.debug('your local uuid value is: {}'.format(uuid)) for i in range(0, 10): cexec([self._adb, 'forward', 'tcp:{}'.format(41128 + i), 'tcp:{}'.format(41128 + i)], callback=None) url = 'http://127.0.0.1:{}/checkSync?sync={}&uuid={}'.format(41128 + i, sync_value, uuid) result, err, code = curl(url) if code == 0 and result is not None: result = int(result) self.debug('server result is {}'.format(result)) if result == 0: self.debug('check sync value failed, maybe you need a clean build.') from exceptions import CheckSyncStateException raise CheckSyncStateException('check sync value failed, maybe you need a clean build.', 'NO CAUSE') elif result == -1: continue else: port = 41128 + i break for i in range(0, 10): if (41128 + i) != port: cexec([self._adb, 'forward', '--remove', 'tcp:{}'.format(41128 + i)], callback=None) return port
def scan_device_port(self, sync_value, uuid): port = 0 for i in range(0, 10): cexec([self._adb, 'forward', 'tcp:{}'.format(PORT_START + i), 'tcp:{}'.format(PORT_START + i)], callback=None) url = 'http://127.0.0.1:{}/checkSync?sync={}&uuid={}'.format(PORT_START + i, sync_value, uuid) result, err, code = curl(url) if code == 0 and result is not None: result = int(result) self.debug('server result is {}'.format(result)) if result == 0: self.debug('check sync value failed, maybe you need a clean build.') from exceptions import CheckSyncStateException raise CheckSyncStateException('check sync value failed, maybe you need a clean build.', 'NO CAUSE') elif result == -1: continue else: port = PORT_START + i break for i in range(0, 10): if (PORT_START + i) != port: cexec([self._adb, 'forward', '--remove', 'tcp:{}'.format(PORT_START + i)], callback=None) return port
def wake_up(self, need_protection=False): package = self._config['package'] if 'debug_package' in self._config: package = self._config['debug_package'] wake_up_args = [self._adb, 'shell', 'am', 'startservice', '-n', '{}/{}'.format(package, 'com.antfortune.freeline.FreelineService')] if not need_protection: wake_up_args.extend(['-e', 'wakeup', 'marker']) self.debug('wake up Service: {}'.format(' '.join(wake_up_args))) cexec(wake_up_args, callback=None)
def connect_device(self): self.debug('start to connect device...') if not self.check_installation(): return sync_value, uuid = self._get_check_values() self.scan_to_get_port(sync_value, uuid) if self._port == 0: self.check_device_connection() commands = [self._adb, 'uninstall', self._config['debug_package']] cexec(commands, callback=None) self.debug('find device port: {}'.format(self._port))
def _install_apk(self): if self._adb: if not os.path.exists(self._apk_path): raise FreelineException('apk not found.', 'apk path: {}, not exists.'.format(self._apk_path)) install_args = [self._adb, 'install', '-r', self._apk_path] self.debug('start to install apk to device: {}'.format(' '.join(install_args))) output, err, code = cexec(install_args, callback=None) if 'Failure' in output: self.debug('install apk failed, start to retry.') output, err, code = cexec(install_args, callback=None) if 'Failure' in output: raise FreelineException('install apk to device failed.', '{}\n{}'.format(output, err))
def run_apt_only(self): if self._is_databinding_enabled and self._should_run_databinding_apt(): apt_args = self._generate_java_compile_args(extra_javac_args_enabled=True) self.debug('apt exec: ' + ' '.join(apt_args)) output, err, code = cexec(apt_args, callback=None) if code != 0: raise FreelineException('apt compile failed.', '{}\n{}'.format(output, err)) if self._apt_output_dir and os.path.exists(self._apt_output_dir): apt_cache_path = os.path.join(self._config['build_cache_dir'], 'apt_files_stat_cache.json') if os.path.exists(apt_cache_path): apt_cache = load_json_cache(apt_cache_path) for dirpath, dirnames, files in os.walk(self._apt_output_dir): for fn in files: fpath = os.path.join(dirpath, fn) if apt_cache and self._name in apt_cache: if fpath in apt_cache[self._name]: new_md5 = get_md5(fpath) if new_md5 != apt_cache[self._name][fpath]['md5']: self.debug('detect new md5 value, add apt file to change list: {}'.format(fpath)) self._changed_files['src'].append(fpath) else: self.debug('find new apt file, add to change list: {}'.format(fpath)) self._changed_files['src'].append(fpath) else: self.debug('apt cache not found, add to change list: {}'.format(fpath)) self._changed_files['src'].append(fpath)
def _check_connection(self): self.debug('check device\' connection...') commands = [self._adb, 'devices'] output, err, code = cexec(commands, callback=None) if code == 0: devices = output.strip().split('\n') length = len(devices) from exceptions import UsbConnectionException if length < 2: raise UsbConnectionException('No device\'s connection found', '\tUse `adb devices` to check your device connection') if length > 2: raise UsbConnectionException('More than 1 device connect', '\tOnly 1 device allowed, ' 'use `adb devices` to check your devices\' connection') for content in devices: if content.find('offline') <> -1: raise UsbConnectionException('Device is connected but offline', '\tPlease replug in device') if content.find('unauthorized') <> -1: raise UsbConnectionException('Device is connected but unauthorized', '\tReplug in device and accept authorization as usual') if not (content.find('device') > -1): raise UsbConnectionException('Device is connected but unknown status', '\tPlease replug in device')
def execute(self): command = '{} -q checkBeforeCleanBuild'.format(get_gradle_executable(self._config)) output, err, code = cexec(command.split(' '), callback=None) if code != 0: from exceptions import FreelineException raise FreelineException('freeline failed when read project info with script: {}'.format(command), '{}\n{}'.format(output, err))
def run_retrolambda(self): if self._is_retrolambda_enabled: lambda_config = self._config['retrolambda'][self._name] target_dir = self._finder.get_patch_classes_cache_dir() jar_args = [Builder.get_java(self._config), '-Dretrolambda.inputDir={}'.format(target_dir), '-Dretrolambda.outputDir={}'.format(target_dir)] if lambda_config['supportIncludeFiles']: include_files = [] classes = [] for dirpath, dirnames, files in os.walk(target_dir): for fn in files: if fn.endswith('.class'): classes.append(os.path.relpath(os.path.join(dirpath, fn), target_dir)) src_dirs = self._config['project_source_sets'][self._name]['main_src_directory'] for fpath in self._changed_files['src']: short_path = fpath.replace('.java', '.class') for src_dir in src_dirs: if src_dir in short_path: short_path = os.path.relpath(fpath, src_dir).replace('.java', '') break for clazz in classes: if short_path + '.class' in clazz or short_path + '$' in clazz or 'R.class' in clazz \ or 'R$' in clazz or short_path + '_' in clazz: include_file = os.path.join(target_dir, clazz) if os.path.exists(include_file): self.debug('incremental build lambda file: {}'.format(include_file)) include_files.append(include_file) include_files_param = os.pathsep.join(include_files) if len(include_files_param) > 3496: include_files_path = os.path.join(self._cache_dir, self._name, 'retrolambda_inc.list') self.__save_parms_to_file(include_files_path, include_files) jar_args.append('-Dretrolambda.includedFile={}'.format(include_files_path)) else: jar_args.append('-Dretrolambda.includedFiles={}'.format(include_files_param)) lambda_classpaths = [target_dir, lambda_config['rtJar']] lambda_classpaths.extend(self._classpaths) param = os.pathsep.join(lambda_classpaths) if lambda_config['supportIncludeFiles'] and len(param) > 3496: classpath_file = os.path.join(self._cache_dir, self._name, 'retrolambda_classpaths.path') self.__save_parms_to_file(classpath_file, lambda_classpaths) jar_args.append('-Dretrolambda.classpathFile={}'.format(classpath_file)) else: jar_args.append('-Dretrolambda.classpath={}'.format(param)) jar_args.append('-cp') jar_args.append(lambda_config['targetJar']) jar_args.append(lambda_config['mainClass']) self.debug('retrolambda exec: ' + ' '.join(jar_args)) output, err, code = cexec(jar_args, callback=None) if code != 0: raise FreelineException('retrolambda compile failed.', '{}\n{}'.format(output, err))
def run_javac_task(self): javacargs = [self._javac, '-encoding', 'UTF-8', '-g'] if not self._is_retrolambda_enabled: javacargs.extend(['-target', '1.7', '-source', '1.7']) javacargs.append('-cp') javacargs.append(os.pathsep.join(self._classpaths)) for fpath in self._changed_files['src']: javacargs.append(fpath) javacargs.extend(self._extra_javac_args) javacargs.append('-d') javacargs.append(self._finder.get_patch_classes_cache_dir()) self.debug('javac exec: ' + ' '.join(javacargs)) output, err, code = cexec(javacargs, callback=None) if code != 0: raise FreelineException('incremental javac compile failed.', '{}\n{}'.format(output, err)) else: if self._is_r_file_changed: old_r_file = self._finder.get_dst_r_path(config=self._config) new_r_file = android_tools.DirectoryFinder.get_r_file_path(self._finder.get_backup_dir()) shutil.copyfile(new_r_file, old_r_file) self.debug('copy {} to {}'.format(new_r_file, old_r_file))
def run_desugar_task(self): self.debug('========= desugar task ========') javaargs = [Builder.get_java(self._config)] arguments = ['-jar', Builder.get_desugar()] patch_classes_cache_dir = self._finder.get_patch_classes_cache_dir() arguments.append('--input') arguments.append(patch_classes_cache_dir) arguments.append('--output') arguments.append(patch_classes_cache_dir) # bootclasspath arguments.append('--bootclasspath_entry') arguments.append(os.path.join(self._config['compile_sdk_directory'], 'android.jar')) # classpath for path in self._classpaths: arguments.append('--classpath_entry') arguments.append(path) javaargs.extend(arguments) self.debug('java exec: ' + ' '.join(javaargs)) output, err, code = cexec(javaargs, callback=None) if code != 0: raise FreelineException('desugar failed.', '{}\n{}'.format(output, err))
def init(): project_dir = os.getcwd() symlink('freeline', project_dir, 'freeline.py') if is_windows: symlink('freeline', project_dir, 'freeline_core') from gradle_tools import get_all_modules modules = get_all_modules(project_dir) for m in modules: if is_main_project(m['path']): main_module = m break if not main_module: raise FreelineException('main module not found', 'set main module first') print('find main module: ' + main_module['name']) args = [] if is_windows: args.append('gradlew.bat') else: args.append('./gradlew') args.append(':{}:checkBeforeCleanBuild'.format(main_module['name'])) print('freeline is reading project info, please wait a moment...') output, err, code = cexec(args, cwd=project_dir) if code != 0: raise FreelineException('freeline failed when read project info with script: {}'.format(args), '{}\n{}'.format(output, err)) print('freeline init success')
def check_installation(self): commands = [self._adb, 'shell', 'pm', 'list', 'packages', self._config['debug_package']] self.debug(commands) output, err, code = cexec(commands, callback=None) result = re.findall(self._config['debug_package'].replace('.', '\.') + '\s', output) if len(result) == 1: return True return False
def check_installation(self): commands = [self._adb, 'shell', 'pm', 'list', 'packages', self._config['package']] output, err, code = cexec(commands, callback=None) result = re.findall(self._config['package'].replace('.', '\.') + '\s+\Z', output) if len(result) != 1: self.debug('No package named {} been installed to your device'.format(self._config['package'])) from exceptions import NoInstallationException raise NoInstallationException( 'No package named {} been installed to your device'.format(self._config['package']), '\tUse `adb shell pm list packages {}` to check app installation.'.format(self._config['package']))
def execute(self): command = './gradlew -q checkBeforeCleanBuild' if is_windows_system(): command = 'gradlew.bat -q checkBeforeCleanBuild' output, err, code = cexec(command.split(' '), callback=None) if code != 0: from exceptions import FreelineException raise FreelineException('freeline failed when read project info with script: {}'.format(command), '{}\n{}'.format(output, err))
def get_device_sdk_version_by_adb(adb): dev_version = 0 try: output = cexec([adb, 'shell', 'getprop ro.build.version.sdk'], callback=None) if output and len(output) > 0: if isinstance(output, str): dev_version = int(output.strip()) elif isinstance(output, tuple): dev_version = int(output[0]) except: pass return dev_version
def scan_device_port(self, sync_value, uuid): port = 0 for i in range(0, 10): cexec([self._adb, 'forward', 'tcp:{}'.format(PORT_START + i), 'tcp:{}'.format(PORT_START + i)], callback=None) url = 'http://127.0.0.1:{}/getSyncTicket'.format(PORT_START + i) self.debug('url===='+url) result, err, code = curl(url) if code == 0 and result is not None: try: result = json.loads(result.replace("'", '"')) self.debug(result) if result["apkBuildFlag"] == uuid: port = PORT_START + i break elif result["apkBuildFlag"] is not None: self.debug('apkBuildFlag: {} does not match uuid: {}'.format(result["apkBuildFlag"], uuid)) port = -1 break except Exception, e: pass
def _check_connection(self): self.debug('check device\' connection...') commands = [self._adb, 'devices'] output, err, code = cexec(commands, callback=None) if code == 0: length = len(output.strip().split('\n')) from exceptions import UsbConnectionException if length < 2: raise UsbConnectionException('No device\'s connection found', '\tUse `adb devices` to check your device connection') if length > 2: raise UsbConnectionException('More than 1 device connect', '\tOnly 1 device allowed, ' 'use `adb devices` to check your devices\' connection')
def execute(self): if is_src_changed(self._cache_dir): pending_merge_dexes = self._get_dexes() dex_path = get_incremental_dex_path(self._cache_dir) if len(pending_merge_dexes) == 1: self.debug('just 1 dex need to sync, copy {} to {}'.format(pending_merge_dexes[0], dex_path)) shutil.copy(pending_merge_dexes[0], dex_path) elif len(pending_merge_dexes) > 1: dex_path = get_incremental_dex_path(self._cache_dir) dex_merge_args = ['java', '-jar', os.path.join('freeline', 'release-tools', 'DexMerge.jar'), dex_path] dex_merge_args.extend(pending_merge_dexes) self.debug('merge dex exec: ' + ' '.join(dex_merge_args)) output, err, code = cexec(dex_merge_args, callback=None) if code != 0: raise FreelineException('merge dex failed: {}'.format(' '.join(dex_merge_args)), output + '\n' + err)
def execute(self): # reload config from dispatcher import read_freeline_config self._config = read_freeline_config() cwd = self._config['build_script_work_directory'].strip() if not cwd or not os.path.isdir(cwd): cwd = None output, err, code = cexec(self._config['build_script'].split(' '), callback=None, cwd=cwd) self.debug(self._config['build_script']) self.debug("Gradle build task is running, please wait a minute...") if code != 0: from exceptions import FreelineException raise FreelineException('build failed with script: {}'.format(self._config['build_script']), '{}\n{}'.format(output, err))
def run_dex_task(self): patch_classes_cache_dir = self._finder.get_patch_classes_cache_dir() # dex_path = self._finder.get_dst_dex_path() dex_path = self._finder.get_patch_dex_dir() add_path = None if is_windows_system(): add_path = str(os.path.abspath(os.path.join(self._javac, os.pardir))) dex_args = [self._dx, '--dex', '--multi-dex', '--output=' + dex_path, patch_classes_cache_dir] else: dex_args = [self._dx, '--dex', '--no-optimize', '--force-jumbo', '--multi-dex', '--output=' + dex_path, patch_classes_cache_dir] self.debug('dex exec: ' + ' '.join(dex_args)) output, err, code = cexec(dex_args, add_path=add_path) if code != 0: raise FreelineException('incremental dex compile failed.', '{}\n{}'.format(output, err)) else: mark_restart_flag(self._cache_dir)
def execute(self): # reload config from dispatcher import read_freeline_config self._config = read_freeline_config() cwd = self._config['build_script_work_directory'].strip() if not cwd or not os.path.isdir(cwd): cwd = None command = self._config['build_script'] command += ' -P freelineBuild=true' if 'auto_dependency' in self._config and not self._config['auto_dependency']: command += ' -PdisableAutoDependency=true' if Logger.debuggable: command += ' --stacktrace' self.debug(command) self.debug("Gradle build task is running, please wait a minute...") output, err, code = cexec(command.split(' '), callback=None, cwd=cwd) if code != 0: from exceptions import FreelineException raise FreelineException('build failed with script: {}'.format(command), '{}\n{}'.format(output, err))
def run_aapt_task(self): self._changed_files['res'].append(self._public_xml_path) self._changed_files['res'].append(self._ids_xml_path) aapt_args, final_changed_list = self._get_aapt_args() self.debug('aapt exec: ' + ' '.join(aapt_args)) st = time.time() output, err, code = cexec(aapt_args, callback=None) if code == 0: self.debug('aapt use time: {}ms'.format((time.time() - st) * 1000)) self.debug('merged_changed_list:') self.debug(final_changed_list) self._backup_res_changed_list(final_changed_list) self._handle_with_backup_files(True) mark_res_sync_status(self._finder.get_sync_file_path()) else: clean_res_build_job_flag(self._finder.get_res_build_job_path()) self._handle_with_backup_files(False) rollback_backup_files(self._origin_res_list, self._new_res_list) raise FreelineException('incremental res build failed.', '{}\n{}'.format(output, err))
def run_javac_task(self): javacargs = [self._javac, '-target', '1.7', '-source', '1.7', '-encoding', 'UTF-8', '-g', '-cp', os.pathsep.join(self._classpaths)] for fpath in self._changed_files['src']: javacargs.append(fpath) javacargs.extend(self._extra_javac_args) javacargs.append('-d') javacargs.append(self._finder.get_patch_classes_cache_dir()) self.debug('javac exec: ' + ' '.join(javacargs)) output, err, code = cexec(javacargs, callback=None) if code != 0: raise FreelineException('incremental javac compile failed.', '{}\n{}'.format(output, err)) else: if self._is_r_file_changed: old_r_file = self._finder.get_dst_r_path(config=self._config) new_r_file = DirectoryFinder.get_r_file_path(self._finder.get_backup_dir()) shutil.copyfile(new_r_file, old_r_file) self.debug('copy {} to {}'.format(new_r_file, old_r_file))
def run_javac_task(self): if self._is_only_r_changed() and not self._is_other_modules_has_src_changed: self._is_need_javac = False android_tools.clean_src_changed_flag(self._cache_dir) self.debug('apt process do not generate new files, ignore javac task.') return extra_javac_args_enabled = not (self._is_databinding_enabled and self._should_run_databinding_apt()) javacargs = self._generate_java_compile_args(extra_javac_args_enabled=extra_javac_args_enabled) self.debug('javac exec: ' + ' '.join(javacargs)) output, err, code = cexec(javacargs, callback=None) if code != 0: raise FreelineException('incremental javac compile failed.', '{}\n{}'.format(output, err)) else: if self._is_r_file_changed: old_r_file = self._finder.get_dst_r_path(config=self._config) new_r_file = android_tools.DirectoryFinder.get_r_file_path(self._finder.get_backup_dir()) if old_r_file and new_r_file: shutil.copyfile(new_r_file, old_r_file) self.debug('copy {} to {}'.format(new_r_file, old_r_file))
def execute(self): if is_src_changed(self._cache_dir): pending_merge_dexes = self._get_dexes() dex_path = get_incremental_dex_path(self._cache_dir) if len(pending_merge_dexes) == 1: self.debug('just 1 dex need to sync, copy {} to {}'.format( pending_merge_dexes[0], dex_path)) shutil.copy(pending_merge_dexes[0], dex_path) elif len(pending_merge_dexes) > 1: dex_path = get_incremental_dex_path(self._cache_dir) dex_merge_args = [ 'java', '-jar', os.path.join('freeline', 'release-tools', 'DexMerge.jar'), dex_path ] dex_merge_args.extend(pending_merge_dexes) self.debug('merge dex exec: ' + ' '.join(dex_merge_args)) output, err, code = cexec(dex_merge_args, callback=None) if code != 0: raise FreelineException( 'merge dex failed: {}'.format(dex_merge_args), output + '\n' + err)
def run_kotlinc_task(self): # todo 检查R的变化 if self._is_only_r_changed() and not self._is_other_modules_has_src_changed: self._is_need_javac = False # self._is_need_kotlinc = False android_tools.clean_src_changed_flag(self._cache_dir) self.debug('apt process do not generate new files, ignore javac task.') return kotlincargs = self._generate_kotlin_compile_args() self.debug('kotlinc exec: ' + ' '.join(kotlincargs)) output, err, code = cexec(kotlincargs, callback=None) if code != 0: raise FreelineException('incremental kotlinc compile failed.', '{}\n{}'.format(output, err)) else: # todo 这个应该是和kotlin没有关系 拷贝R类用的 if self._is_r_file_changed: old_r_file = self._finder.get_dst_r_path(config=self._config) new_r_file = android_tools.DirectoryFinder.get_r_file_path(self._finder.get_backup_dir()) if old_r_file and new_r_file: shutil.copyfile(new_r_file, old_r_file) self.debug('copy {} to {}'.format(new_r_file, old_r_file))
def run_apt_only(self): if self._is_databinding_enabled and self._should_run_databinding_apt(): apt_args = self._generate_java_compile_args( extra_javac_args_enabled=True) self.debug('apt exec: ' + ' '.join(apt_args)) output, err, code = cexec(apt_args, callback=None) if code != 0: raise FreelineException('apt compile failed.', '{}\n{}'.format(output, err)) if self._apt_output_dir and os.path.exists(self._apt_output_dir): apt_cache_path = os.path.join(self._config['build_cache_dir'], 'apt_files_stat_cache.json') if os.path.exists(apt_cache_path): apt_cache = load_json_cache(apt_cache_path) for dirpath, dirnames, files in os.walk(self._apt_output_dir): for fn in files: fpath = os.path.join(dirpath, fn) if apt_cache and self._name in apt_cache: if fpath in apt_cache[self._name]: new_md5 = get_md5(fpath) if new_md5 != apt_cache[ self._name][fpath]['md5']: self.debug( 'detect new md5 value, add apt file to change list: {}' .format(fpath)) self._changed_files['src'].append(fpath) else: self.debug( 'find new apt file, add to change list: {}' .format(fpath)) self._changed_files['src'].append(fpath) else: self.debug( 'apt cache not found, add to change list: {}'. format(fpath)) self._changed_files['src'].append(fpath)
def run_dex_task(self): patch_classes_cache_dir = self._finder.get_patch_classes_cache_dir() dex_path = self._finder.get_dst_dex_path() add_path = None if is_windows_system(): add_path = os.path.abspath(os.path.join(self._javac, os.pardir)) dex_args = [ self._dx, '--dex', '--output=' + dex_path, patch_classes_cache_dir ] else: dex_args = [ self._dx, '--dex', '--no-optimize', '--force-jumbo', '--output=' + dex_path, patch_classes_cache_dir ] self.debug('dex exec: ' + ' '.join(dex_args)) output, err, code = cexec(dex_args, add_path=add_path) if code != 0: raise FreelineException('incremental dex compile failed.', '{}\n{}'.format(output, err)) else: mark_restart_flag(self._cache_dir)
def run_retrolambda(self): if self._is_need_javac and self._is_retrolambda_enabled: lambda_config = self._config['retrolambda'][self._name] target_dir = self._finder.get_patch_classes_cache_dir() jar_args = [ Builder.get_java(self._config), '-Dretrolambda.inputDir={}'.format(target_dir), '-Dretrolambda.outputDir={}'.format(target_dir) ] if lambda_config['supportIncludeFiles']: include_files = [] classes = [] for dirpath, dirnames, files in os.walk(target_dir): for fn in files: if fn.endswith('.class'): classes.append( os.path.relpath(os.path.join(dirpath, fn), target_dir)) src_dirs = self._config['project_source_sets'][ self._name]['main_src_directory'] for fpath in self._changed_files['src']: short_path = fpath.replace('.java', '.class') for src_dir in src_dirs: if src_dir in short_path: short_path = os.path.relpath(fpath, src_dir).replace( '.java', '') break for clazz in classes: if short_path + '.class' in clazz or short_path + '$' in clazz or 'R.class' in clazz \ or 'R$' in clazz or short_path + '_' in clazz: include_file = os.path.join(target_dir, clazz) if os.path.exists(include_file): self.debug( 'incremental build lambda file: {}'.format( include_file)) include_files.append(include_file) include_files_param = os.pathsep.join(include_files) if len(include_files_param) > 3496: include_files_path = os.path.join(self._cache_dir, self._name, 'retrolambda_inc.list') self.__save_parms_to_file(include_files_path, include_files) jar_args.append('-Dretrolambda.includedFile={}'.format( include_files_path)) else: jar_args.append('-Dretrolambda.includedFiles={}'.format( include_files_param)) lambda_classpaths = [target_dir, lambda_config['rtJar']] lambda_classpaths.extend(self._classpaths) param = os.pathsep.join(lambda_classpaths) if lambda_config['supportIncludeFiles'] and len(param) > 3496: classpath_file = os.path.join(self._cache_dir, self._name, 'retrolambda_classpaths.path') self.__save_parms_to_file(classpath_file, lambda_classpaths) jar_args.append( '-Dretrolambda.classpathFile={}'.format(classpath_file)) else: jar_args.append('-Dretrolambda.classpath={}'.format(param)) jar_args.append('-cp') jar_args.append(lambda_config['targetJar']) jar_args.append(lambda_config['mainClass']) self.debug('retrolambda exec: ' + ' '.join(jar_args)) output, err, code = cexec(jar_args, callback=None) if code != 0: raise FreelineException('retrolambda compile failed.', '{}\n{}'.format(output, err))
def _launch_application(self): if self._package and self._launcher: adb_args = [self._adb, 'shell', 'am', 'start', '-n', self._package + '/' + self._launcher] self.debug('start to launch application {}/{}'.format(self._package, self._launcher)) self.debug(' '.join(adb_args)) cexec(adb_args, callback=None)
def _debug_app(self): if self._wait_for_debugger: adb_args = [Builder.get_adb(self._config), 'shell', 'am', 'set-debug-app', '-w', self._package] self.debug('make application wait for debugger: {}'.format(' '.join(adb_args))) cexec(adb_args, callback=None)
def _check_screen_status(self): commands = [self._adb, 'shell', 'dumpsys', 'input_method'] check_str = 'mInteractive=true' if self._is_art else 'mScreenOn=true' output, err, code = cexec(commands, callback=None) return re.search(check_str, output)
def close_connection(self): if self._port != 0: cexec([self._adb, 'forward', '--remove', 'tcp:{}'.format(self._port)], callback=None)
def run_aapt(self): aapt_args = [Builder.get_aapt(), 'package', '-f', '-I', os.path.join(self._config['compile_sdk_directory'], 'android.jar'), '-M', self._finder.get_dst_manifest_path()] for rdir in self._config['project_source_sets'][self._main_module_name]['main_res_directory']: if os.path.exists(rdir): aapt_args.append('-S') aapt_args.append(rdir) for rdir in self._module_info['local_dep_res_path']: if os.path.exists(rdir): aapt_args.append('-S') aapt_args.append(rdir) if 'extra_dep_res_paths' in self._config and self._config['extra_dep_res_paths'] is not None: arr = self._config['extra_dep_res_paths'] for path in arr: path = path.strip() if os.path.isdir(path): aapt_args.append('-S') aapt_args.append(path) for resdir in self._module_info['dep_res_path']: if os.path.exists(resdir): aapt_args.append('-S') aapt_args.append(resdir) aapt_args.extend(['-S', self._finder.get_backup_res_dir()]) freeline_assets_dir = os.path.join(self._config['build_cache_dir'], 'freeline-assets') aapt_args.append('-A') aapt_args.append(freeline_assets_dir) for adir in self._config['project_source_sets'][self._main_module_name]['main_assets_directory']: if os.path.exists(adir): aapt_args.append('-A') aapt_args.append(adir) for m in self._module_info['local_module_dep']: if m in self._config['project_source_sets']: for adir in self._config['project_source_sets'][m]['main_assets_directory']: if os.path.exists(adir): aapt_args.append('-A') aapt_args.append(adir) base_resource_path = get_base_resource_path(self._config['build_cache_dir']) aapt_args.append('-m') aapt_args.append('-J') aapt_args.append(self._finder.get_backup_dir()) aapt_args.append('--auto-add-overlay') aapt_args.append('-F') aapt_args.append(base_resource_path) aapt_args.append('--debug-mode') aapt_args.append('--resoucres-md5-cache-path') aapt_args.append(os.path.join(self._config['build_cache_dir'], "arsc_cache.dat")) aapt_args.append('--ignore-assets') aapt_args.append('public_id.xml:public.xml:*.bak:.*') self.debug('aapt exec: ' + ' '.join(aapt_args)) output, err, code = cexec(aapt_args, callback=None) if code != 0: raise FreelineException('build base resources failed with: {}'.format(' '.join(aapt_args)), '{}\n{}'.format(output, err)) self.debug('generate base resource success: {}'.format(base_resource_path))
def run_retrolambda(self): if self._is_need_javac and self._is_retrolambda_enabled: lambda_config = self._config['retrolambda'][self._name] target_dir = self._finder.get_patch_classes_cache_dir() jar_args = [Builder.get_java(self._config), '-Dretrolambda.inputDir={}'.format(target_dir), '-Dretrolambda.outputDir={}'.format(target_dir)] if lambda_config['supportIncludeFiles']: files_stat_path = os.path.join(self._cache_dir, self._name, 'lambda_files_stat.json') include_files = [] if os.path.exists(files_stat_path): files_stat = load_json_cache(files_stat_path) else: files_stat = {} for dirpath, dirnames, files in os.walk(target_dir): for fn in files: fpath = os.path.join(dirpath, fn) if fpath not in files_stat: include_files.append(fpath) self.debug('incremental build new lambda file: {}'.format(fpath)) else: if os.path.getmtime(fpath) > files_stat[fpath]['mtime']: include_files.append(fpath) self.debug('incremental build lambda file: {}'.format(fpath)) include_files_param = os.pathsep.join(include_files) if len(include_files_param) > 3496: include_files_path = os.path.join(self._cache_dir, self._name, 'retrolambda_inc.list') self.__save_parms_to_file(include_files_path, include_files) jar_args.append('-Dretrolambda.includedFile={}'.format(include_files_path)) else: jar_args.append('-Dretrolambda.includedFiles={}'.format(include_files_param)) lambda_classpaths = [target_dir, lambda_config['rtJar']] lambda_classpaths.extend(self._classpaths) param = os.pathsep.join(lambda_classpaths) if lambda_config['supportIncludeFiles'] and len(param) > 3496: classpath_file = os.path.join(self._cache_dir, self._name, 'retrolambda_classpaths.path') self.__save_parms_to_file(classpath_file, lambda_classpaths) jar_args.append('-Dretrolambda.classpathFile={}'.format(classpath_file)) else: jar_args.append('-Dretrolambda.classpath={}'.format(param)) jar_args.append('-cp') jar_args.append(lambda_config['targetJar']) jar_args.append(lambda_config['mainClass']) self.debug('retrolambda exec: ' + ' '.join(jar_args)) output, err, code = cexec(jar_args, callback=None) if code != 0: raise FreelineException('retrolambda compile failed.', '{}\n{}'.format(output, err)) if lambda_config['supportIncludeFiles']: for fpath in include_files: if fpath not in files_stat: files_stat[fpath] = {} files_stat[fpath]['mtime'] = os.path.getmtime(fpath) write_json_cache(files_stat_path, files_stat) self.debug('save lambda files stat to {}'.format(files_stat_path))
def _turn_on_screen(self): commands = [self._adb, 'shell', 'input', 'keyevent', '26'] cexec(commands, callback=None)
def wake_up(self): cexec([ self._adb, 'shell', 'am', 'start', '-n', '{}/{}'.format( self._config['package'], self._config['launcher']) ], callback=None)
def __update_class_related(self): # update class related changed_java_files = [] for module, file_dict in self._changed_files['projects'].iteritems(): if len(file_dict['src']) > 0: changed_java_files.extend(file_dict['src']) # process changed java files if len(changed_java_files) > 0: # update stat_cache.json cache_path = os.path.join(self._config['build_cache_dir'], 'stat_cache.json') changefiles = ';'.join(changed_java_files) class_related_args = ['java', '-jar', os.path.join('freeline', 'release-tools', 'classrelated.jar'), cache_path, changefiles] self.debug('update class related: ' + ' '.join(class_related_args)) #show_gradle_log = False #if ArgsConfig.args is not None and ('gradlelog' in ArgsConfig.args and ArgsConfig.args.gradlelog): show_gradle_log = True output, err, code = cexec(class_related_args, callback=None) # read from stat_cache.json stat_cache = load_json_cache(cache_path) # ignore files ignore_java_files = ['UCR.java', 'UCContentProvider.java'] related_files = [] package_map = {} # read all package java files for module, file_dict in stat_cache.items(): for file in file_dict.keys(): package_name = self.__get_package(file) if package_name == '': continue if not package_map.has_key(package_name): same_package_files = [] package_map[package_name] = same_package_files else: same_package_files = package_map.get(package_name); same_package_files.append(file) # read all related java files for file in changed_java_files: for module, file_dict in stat_cache.items(): if file_dict.has_key(file): file_stat = file_dict[file] if file_stat.has_key('related'): related_files.extend(file_stat['related']) # read all same package files package_name = self.__get_package(file) if package_name != '' and package_map.has_key(package_name): same_package_files = package_map[package_name] related_files.extend(same_package_files) related_files = list(set(related_files)) if len(related_files) > 0: # update self._changed_files['projects'] module's file_dict['src'] for module, file_dict in stat_cache.items(): for file in related_files: if file_dict.has_key(file): self._changed_files['projects'][module]['src'].append(file) self.debug('updated file changed list:') self.debug(self._changed_files)
def close_connection(self): if self._port != 0: cexec([ self._adb, 'forward', '--remove', 'tcp:{}'.format(self._port) ], callback=None)
def debug_app(config): adb_args = [Builder.get_adb(config), 'shell', 'am', 'set-debug-app', '-w', config['debug_package']] cexec(adb_args, callback=None)
class SyncClient(object): def __init__(self, is_art, config): self._is_art = is_art self._config = config self._adb = Builder.get_adb(self._config) self._cache_dir = self._config['build_cache_dir'] self._port = 0 def debug(self, message): Logger.debug('[sync_client] {}'.format(message)) def check_device_connection(self): commands = [self._adb, 'devices'] output, err, code = cexec(commands, callback=None) if code == 0: devices = output.strip().split('\n') length = len(devices) from exceptions import UsbConnectionException if length < 2: self.debug('No device\'s connection found') raise UsbConnectionException('No device\'s connection found', '\tUse `adb devices` to check your device connection') if length > 2: self.debug('More than 1 devices connect:') self.debug(devices) raise UsbConnectionException('More than 1 devices connect', '\tOnly 1 device allowed, ' 'use `adb devices` to check your devices\' connection') def check_installation(self): commands = [self._adb, 'shell', 'pm', 'list', 'packages', self._config['debug_package']] self.debug(commands) output, err, code = cexec(commands, callback=None) result = re.findall(self._config['debug_package'].replace('.', '\.') + '\s', output) if len(result) == 1: return True return False def ensure_device_status(self): if not self._check_screen_status(): self.debug('try to turn on your device\'s screen...') self._turn_on_screen() def connect_device(self): self.debug('start to connect device...') if not self.check_installation(): return sync_value, uuid = self._get_check_values() self.scan_to_get_port(sync_value, uuid) if self._port == 0: self.check_device_connection() commands = [self._adb, 'uninstall', self._config['debug_package']] cexec(commands, callback=None) self.debug('find device port: {}'.format(self._port)) def scan_to_get_port(self, sync_value, uuid): self._port = self.scan_device_port(sync_value, uuid) if self._port == 0: for i in range(1, 11): need_protection = i <= 1 self.wake_up(need_protection=need_protection) self._port = self.scan_device_port(sync_value, uuid) if self._port != 0: break time.sleep(0.2) self.debug('try to connect device {} times...'.format(i)) def close_connection(self): if self._port != 0: cexec([self._adb, 'forward', '--remove', 'tcp:{}'.format(self._port)], callback=None) def scan_device_port(self, sync_value, uuid): port = 0 for i in range(0, 10): cexec([self._adb, 'forward', 'tcp:{}'.format(PORT_START + i), 'tcp:{}'.format(PORT_START + i)], callback=None) url = 'http://127.0.0.1:{}/getSyncTicket'.format(PORT_START + i) result, err, code = curl(url) if code == 0 and result is not None: try: result = json.loads(result.replace("'", '"')) self.debug(result) self.debug("uuid={}".format(uuid)) if result["apkBuildFlag"] == uuid: port = PORT_START + i break except Exception, e: pass for i in range(0, 10): if (PORT_START + i) != port: cexec([self._adb, 'forward', '--remove', 'tcp:{}'.format(PORT_START + i)], callback=None) return port