1*c2e18aaaSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*c2e18aaaSAndroid Build Coastguard Worker# 3*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2019 - The Android Open Source Project 4*c2e18aaaSAndroid Build Coastguard Worker# 5*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*c2e18aaaSAndroid Build Coastguard Worker# 9*c2e18aaaSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*c2e18aaaSAndroid Build Coastguard Worker# 11*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License. 16*c2e18aaaSAndroid Build Coastguard Worker 17*c2e18aaaSAndroid Build Coastguard Worker"""ide_common_util 18*c2e18aaaSAndroid Build Coastguard Worker 19*c2e18aaaSAndroid Build Coastguard WorkerThis module has a collection of helper functions of the ide_util module. 20*c2e18aaaSAndroid Build Coastguard Worker""" 21*c2e18aaaSAndroid Build Coastguard Worker 22*c2e18aaaSAndroid Build Coastguard Workerimport fnmatch 23*c2e18aaaSAndroid Build Coastguard Workerimport glob 24*c2e18aaaSAndroid Build Coastguard Workerimport logging 25*c2e18aaaSAndroid Build Coastguard Workerimport os 26*c2e18aaaSAndroid Build Coastguard Workerimport subprocess 27*c2e18aaaSAndroid Build Coastguard Worker 28*c2e18aaaSAndroid Build Coastguard Workerfrom aidegen import constant 29*c2e18aaaSAndroid Build Coastguard Worker 30*c2e18aaaSAndroid Build Coastguard Worker_IDEA_FOLDER = '.idea' 31*c2e18aaaSAndroid Build Coastguard Worker_IML_EXTENSION = '.iml' 32*c2e18aaaSAndroid Build Coastguard Worker 33*c2e18aaaSAndroid Build Coastguard Worker 34*c2e18aaaSAndroid Build Coastguard Workerdef get_script_from_internal_path(ide_paths, ide_name): 35*c2e18aaaSAndroid Build Coastguard Worker """Get the studio.sh script path from internal path. 36*c2e18aaaSAndroid Build Coastguard Worker 37*c2e18aaaSAndroid Build Coastguard Worker Args: 38*c2e18aaaSAndroid Build Coastguard Worker ide_paths: A list of IDE installed paths to be checked. 39*c2e18aaaSAndroid Build Coastguard Worker ide_name: The IDE name. 40*c2e18aaaSAndroid Build Coastguard Worker 41*c2e18aaaSAndroid Build Coastguard Worker Returns: 42*c2e18aaaSAndroid Build Coastguard Worker The list of the full path of IDE or None if the IDE doesn't exist. 43*c2e18aaaSAndroid Build Coastguard Worker """ 44*c2e18aaaSAndroid Build Coastguard Worker for ide_path in ide_paths: 45*c2e18aaaSAndroid Build Coastguard Worker ls_output = glob.glob(ide_path, recursive=True) 46*c2e18aaaSAndroid Build Coastguard Worker ls_output = sorted(ls_output) 47*c2e18aaaSAndroid Build Coastguard Worker if ls_output: 48*c2e18aaaSAndroid Build Coastguard Worker logging.debug('The script%s for %s %s found.', 49*c2e18aaaSAndroid Build Coastguard Worker 's' if len(ls_output) > 1 else '', ide_name, 50*c2e18aaaSAndroid Build Coastguard Worker 'are' if len(ls_output) > 1 else 'is') 51*c2e18aaaSAndroid Build Coastguard Worker return ls_output 52*c2e18aaaSAndroid Build Coastguard Worker logging.error('There is not any script of %s found.', ide_name) 53*c2e18aaaSAndroid Build Coastguard Worker return None 54*c2e18aaaSAndroid Build Coastguard Worker 55*c2e18aaaSAndroid Build Coastguard Worker 56*c2e18aaaSAndroid Build Coastguard Workerdef _run_ide_sh(run_sh_cmd, project_path): 57*c2e18aaaSAndroid Build Coastguard Worker """Run IDE launching script with an IntelliJ project path as argument. 58*c2e18aaaSAndroid Build Coastguard Worker 59*c2e18aaaSAndroid Build Coastguard Worker Args: 60*c2e18aaaSAndroid Build Coastguard Worker run_sh_cmd: The command to launch IDE. 61*c2e18aaaSAndroid Build Coastguard Worker project_path: The path of IntelliJ IDEA project content. 62*c2e18aaaSAndroid Build Coastguard Worker """ 63*c2e18aaaSAndroid Build Coastguard Worker assert run_sh_cmd, 'No suitable IDE installed.' 64*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Run command: "%s" to launch project.', run_sh_cmd) 65*c2e18aaaSAndroid Build Coastguard Worker try: 66*c2e18aaaSAndroid Build Coastguard Worker subprocess.check_call(run_sh_cmd, shell=True) 67*c2e18aaaSAndroid Build Coastguard Worker except subprocess.CalledProcessError as err: 68*c2e18aaaSAndroid Build Coastguard Worker logging.error('Launch project path %s failed with error: %s.', 69*c2e18aaaSAndroid Build Coastguard Worker project_path, err) 70*c2e18aaaSAndroid Build Coastguard Worker 71*c2e18aaaSAndroid Build Coastguard Worker 72*c2e18aaaSAndroid Build Coastguard Workerdef _walk_tree_find_ide_exe_file(top, ide_script_name): 73*c2e18aaaSAndroid Build Coastguard Worker """Recursively descend the directory tree rooted at top and filter out the 74*c2e18aaaSAndroid Build Coastguard Worker IDE executable script we need. 75*c2e18aaaSAndroid Build Coastguard Worker 76*c2e18aaaSAndroid Build Coastguard Worker Args: 77*c2e18aaaSAndroid Build Coastguard Worker top: the tree root to be checked. 78*c2e18aaaSAndroid Build Coastguard Worker ide_script_name: IDE file name such i.e. IdeIntelliJ._INTELLIJ_EXE_FILE. 79*c2e18aaaSAndroid Build Coastguard Worker 80*c2e18aaaSAndroid Build Coastguard Worker Returns: 81*c2e18aaaSAndroid Build Coastguard Worker the IDE executable script file(s) found. 82*c2e18aaaSAndroid Build Coastguard Worker """ 83*c2e18aaaSAndroid Build Coastguard Worker logging.info('Searching IDE script %s in path: %s.', ide_script_name, top) 84*c2e18aaaSAndroid Build Coastguard Worker for root, _, files in os.walk(top): 85*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Search all files under %s to get %s, %s.', top, root, 86*c2e18aaaSAndroid Build Coastguard Worker files) 87*c2e18aaaSAndroid Build Coastguard Worker for file_ in fnmatch.filter(files, ide_script_name): 88*c2e18aaaSAndroid Build Coastguard Worker exe_file = os.path.join(root, file_) 89*c2e18aaaSAndroid Build Coastguard Worker if os.access(exe_file, os.X_OK): 90*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Use file name filter to find %s in path %s.', 91*c2e18aaaSAndroid Build Coastguard Worker file_, exe_file) 92*c2e18aaaSAndroid Build Coastguard Worker yield exe_file 93*c2e18aaaSAndroid Build Coastguard Worker 94*c2e18aaaSAndroid Build Coastguard Worker 95*c2e18aaaSAndroid Build Coastguard Workerdef get_run_ide_cmd(sh_path, project_file, new_process=True): 96*c2e18aaaSAndroid Build Coastguard Worker """Get the command to launch IDE. 97*c2e18aaaSAndroid Build Coastguard Worker 98*c2e18aaaSAndroid Build Coastguard Worker Args: 99*c2e18aaaSAndroid Build Coastguard Worker sh_path: The idea.sh path where IDE is installed. 100*c2e18aaaSAndroid Build Coastguard Worker project_file: The path of IntelliJ IDEA project file. 101*c2e18aaaSAndroid Build Coastguard Worker new_process: Default is True, means to run command in a new process. 102*c2e18aaaSAndroid Build Coastguard Worker 103*c2e18aaaSAndroid Build Coastguard Worker Returns: 104*c2e18aaaSAndroid Build Coastguard Worker A string: The IDE launching command. 105*c2e18aaaSAndroid Build Coastguard Worker """ 106*c2e18aaaSAndroid Build Coastguard Worker process_flag = '&' if new_process else '' 107*c2e18aaaSAndroid Build Coastguard Worker # In command usage, the space ' ' should be '\ ' for correctness. 108*c2e18aaaSAndroid Build Coastguard Worker return ' '.join([ 109*c2e18aaaSAndroid Build Coastguard Worker constant.NOHUP, sh_path.replace(' ', r'\ '), project_file, 110*c2e18aaaSAndroid Build Coastguard Worker constant.IGNORE_STD_OUT_ERR_CMD, process_flag 111*c2e18aaaSAndroid Build Coastguard Worker ]) 112*c2e18aaaSAndroid Build Coastguard Worker 113*c2e18aaaSAndroid Build Coastguard Worker 114*c2e18aaaSAndroid Build Coastguard Workerdef _get_scripts_from_file_path(input_path, ide_file_name): 115*c2e18aaaSAndroid Build Coastguard Worker """Get IDE executable script file from input file path. 116*c2e18aaaSAndroid Build Coastguard Worker 117*c2e18aaaSAndroid Build Coastguard Worker Args: 118*c2e18aaaSAndroid Build Coastguard Worker input_path: the file path to be checked. 119*c2e18aaaSAndroid Build Coastguard Worker ide_file_name: the IDE executable script file name. 120*c2e18aaaSAndroid Build Coastguard Worker 121*c2e18aaaSAndroid Build Coastguard Worker Returns: 122*c2e18aaaSAndroid Build Coastguard Worker A list of the IDE executable script path if exists otherwise None. 123*c2e18aaaSAndroid Build Coastguard Worker """ 124*c2e18aaaSAndroid Build Coastguard Worker if os.path.basename(input_path).startswith(ide_file_name): 125*c2e18aaaSAndroid Build Coastguard Worker files_found = glob.glob(input_path) 126*c2e18aaaSAndroid Build Coastguard Worker if files_found: 127*c2e18aaaSAndroid Build Coastguard Worker return sorted(files_found) 128*c2e18aaaSAndroid Build Coastguard Worker return None 129*c2e18aaaSAndroid Build Coastguard Worker 130*c2e18aaaSAndroid Build Coastguard Worker 131*c2e18aaaSAndroid Build Coastguard Workerdef get_scripts_from_dir_path(input_path, ide_file_name): 132*c2e18aaaSAndroid Build Coastguard Worker """Get an IDE executable script file from input directory path. 133*c2e18aaaSAndroid Build Coastguard Worker 134*c2e18aaaSAndroid Build Coastguard Worker Args: 135*c2e18aaaSAndroid Build Coastguard Worker input_path: the directory to be searched. 136*c2e18aaaSAndroid Build Coastguard Worker ide_file_name: the IDE executable script file name. 137*c2e18aaaSAndroid Build Coastguard Worker 138*c2e18aaaSAndroid Build Coastguard Worker Returns: 139*c2e18aaaSAndroid Build Coastguard Worker A list of an IDE executable script paths if exist otherwise None. 140*c2e18aaaSAndroid Build Coastguard Worker """ 141*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Call get_scripts_from_dir_path with %s, and %s', input_path, 142*c2e18aaaSAndroid Build Coastguard Worker ide_file_name) 143*c2e18aaaSAndroid Build Coastguard Worker files_found = list(_walk_tree_find_ide_exe_file(input_path, 144*c2e18aaaSAndroid Build Coastguard Worker ide_file_name + '*')) 145*c2e18aaaSAndroid Build Coastguard Worker if files_found: 146*c2e18aaaSAndroid Build Coastguard Worker return sorted(files_found) 147*c2e18aaaSAndroid Build Coastguard Worker return None 148*c2e18aaaSAndroid Build Coastguard Worker 149*c2e18aaaSAndroid Build Coastguard Worker 150*c2e18aaaSAndroid Build Coastguard Workerdef launch_ide(project_path, run_ide_cmd, ide_name): 151*c2e18aaaSAndroid Build Coastguard Worker """Launches relative IDE by opening the passed project file. 152*c2e18aaaSAndroid Build Coastguard Worker 153*c2e18aaaSAndroid Build Coastguard Worker Args: 154*c2e18aaaSAndroid Build Coastguard Worker project_path: The full path of the IDE project content. 155*c2e18aaaSAndroid Build Coastguard Worker run_ide_cmd: The command to launch IDE. 156*c2e18aaaSAndroid Build Coastguard Worker ide_name: the IDE name is to be launched. 157*c2e18aaaSAndroid Build Coastguard Worker """ 158*c2e18aaaSAndroid Build Coastguard Worker assert project_path, 'Empty content path is not allowed.' 159*c2e18aaaSAndroid Build Coastguard Worker if ide_name == constant.IDE_ECLIPSE: 160*c2e18aaaSAndroid Build Coastguard Worker logging.info( 161*c2e18aaaSAndroid Build Coastguard Worker 'Launch %s with workspace: %s.', ide_name, constant.ECLIPSE_WS) 162*c2e18aaaSAndroid Build Coastguard Worker else: 163*c2e18aaaSAndroid Build Coastguard Worker logging.info('Launch %s for project content path: %s.', ide_name, 164*c2e18aaaSAndroid Build Coastguard Worker project_path) 165*c2e18aaaSAndroid Build Coastguard Worker _run_ide_sh(run_ide_cmd, project_path) 166*c2e18aaaSAndroid Build Coastguard Worker 167*c2e18aaaSAndroid Build Coastguard Worker 168*c2e18aaaSAndroid Build Coastguard Workerdef is_intellij_project(project_path): 169*c2e18aaaSAndroid Build Coastguard Worker """Checks if the path passed in is an IntelliJ project content. 170*c2e18aaaSAndroid Build Coastguard Worker 171*c2e18aaaSAndroid Build Coastguard Worker Args: 172*c2e18aaaSAndroid Build Coastguard Worker project_path: The full path of IDEA project content, which contains 173*c2e18aaaSAndroid Build Coastguard Worker .idea folder and .iml file(s). 174*c2e18aaaSAndroid Build Coastguard Worker 175*c2e18aaaSAndroid Build Coastguard Worker Returns: 176*c2e18aaaSAndroid Build Coastguard Worker True if project_path is an IntelliJ project, False otherwise. 177*c2e18aaaSAndroid Build Coastguard Worker """ 178*c2e18aaaSAndroid Build Coastguard Worker if not os.path.isfile(project_path): 179*c2e18aaaSAndroid Build Coastguard Worker return os.path.isdir(project_path) and os.path.isdir( 180*c2e18aaaSAndroid Build Coastguard Worker os.path.join(project_path, _IDEA_FOLDER)) 181*c2e18aaaSAndroid Build Coastguard Worker 182*c2e18aaaSAndroid Build Coastguard Worker _, ext = os.path.splitext(os.path.basename(project_path)) 183*c2e18aaaSAndroid Build Coastguard Worker if ext and _IML_EXTENSION == ext.lower(): 184*c2e18aaaSAndroid Build Coastguard Worker path = os.path.dirname(project_path) 185*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Extracted path is: %s.', path) 186*c2e18aaaSAndroid Build Coastguard Worker return os.path.isdir(os.path.join(path, _IDEA_FOLDER)) 187*c2e18aaaSAndroid Build Coastguard Worker return False 188*c2e18aaaSAndroid Build Coastguard Worker 189*c2e18aaaSAndroid Build Coastguard Worker 190*c2e18aaaSAndroid Build Coastguard Workerdef get_script_from_input_path(input_path, ide_file_name): 191*c2e18aaaSAndroid Build Coastguard Worker """Get correct IntelliJ executable script path from input path. 192*c2e18aaaSAndroid Build Coastguard Worker 193*c2e18aaaSAndroid Build Coastguard Worker 1. If input_path is a file, check if it is an IDE executable script file. 194*c2e18aaaSAndroid Build Coastguard Worker 2. It input_path is a directory, search if it contains IDE executable script 195*c2e18aaaSAndroid Build Coastguard Worker file(s). 196*c2e18aaaSAndroid Build Coastguard Worker 197*c2e18aaaSAndroid Build Coastguard Worker Args: 198*c2e18aaaSAndroid Build Coastguard Worker input_path: input path to be checked if it's an IDE executable 199*c2e18aaaSAndroid Build Coastguard Worker script. 200*c2e18aaaSAndroid Build Coastguard Worker ide_file_name: the IDE executable script file name. 201*c2e18aaaSAndroid Build Coastguard Worker 202*c2e18aaaSAndroid Build Coastguard Worker Returns: 203*c2e18aaaSAndroid Build Coastguard Worker IDE executable file(s) if exists otherwise None. 204*c2e18aaaSAndroid Build Coastguard Worker """ 205*c2e18aaaSAndroid Build Coastguard Worker if not input_path: 206*c2e18aaaSAndroid Build Coastguard Worker return None 207*c2e18aaaSAndroid Build Coastguard Worker ide_path = [] 208*c2e18aaaSAndroid Build Coastguard Worker if os.path.isfile(input_path): 209*c2e18aaaSAndroid Build Coastguard Worker ide_path = _get_scripts_from_file_path(input_path, ide_file_name) 210*c2e18aaaSAndroid Build Coastguard Worker if os.path.isdir(input_path): 211*c2e18aaaSAndroid Build Coastguard Worker ide_path = get_scripts_from_dir_path(input_path, ide_file_name) 212*c2e18aaaSAndroid Build Coastguard Worker if ide_path: 213*c2e18aaaSAndroid Build Coastguard Worker logging.debug('IDE installed path from user input: %s.', ide_path) 214*c2e18aaaSAndroid Build Coastguard Worker return ide_path 215*c2e18aaaSAndroid Build Coastguard Worker return None 216*c2e18aaaSAndroid Build Coastguard Worker 217*c2e18aaaSAndroid Build Coastguard Worker 218*c2e18aaaSAndroid Build Coastguard Workerdef get_intellij_version_path(version_path): 219*c2e18aaaSAndroid Build Coastguard Worker """Locates the IntelliJ IDEA launch script path by version. 220*c2e18aaaSAndroid Build Coastguard Worker 221*c2e18aaaSAndroid Build Coastguard Worker Args: 222*c2e18aaaSAndroid Build Coastguard Worker version_path: IntelliJ CE or UE version launch script path. 223*c2e18aaaSAndroid Build Coastguard Worker 224*c2e18aaaSAndroid Build Coastguard Worker Returns: 225*c2e18aaaSAndroid Build Coastguard Worker A list of the sh full paths, or None if no such IntelliJ version is 226*c2e18aaaSAndroid Build Coastguard Worker installed. 227*c2e18aaaSAndroid Build Coastguard Worker """ 228*c2e18aaaSAndroid Build Coastguard Worker ls_output = glob.glob(version_path, recursive=True) 229*c2e18aaaSAndroid Build Coastguard Worker if not ls_output: 230*c2e18aaaSAndroid Build Coastguard Worker return None 231*c2e18aaaSAndroid Build Coastguard Worker ls_output = sorted(ls_output, reverse=True) 232*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Result for checking IntelliJ path %s after sorting:%s.', 233*c2e18aaaSAndroid Build Coastguard Worker version_path, ls_output) 234*c2e18aaaSAndroid Build Coastguard Worker return ls_output 235*c2e18aaaSAndroid Build Coastguard Worker 236*c2e18aaaSAndroid Build Coastguard Worker 237*c2e18aaaSAndroid Build Coastguard Workerdef ask_preference(all_versions, ide_name): 238*c2e18aaaSAndroid Build Coastguard Worker """Ask users which version they prefer. 239*c2e18aaaSAndroid Build Coastguard Worker 240*c2e18aaaSAndroid Build Coastguard Worker Args: 241*c2e18aaaSAndroid Build Coastguard Worker all_versions: A list of all CE and UE version launch script paths. 242*c2e18aaaSAndroid Build Coastguard Worker ide_name: The IDE name is going to be launched. 243*c2e18aaaSAndroid Build Coastguard Worker 244*c2e18aaaSAndroid Build Coastguard Worker Returns: 245*c2e18aaaSAndroid Build Coastguard Worker An users selected version. 246*c2e18aaaSAndroid Build Coastguard Worker """ 247*c2e18aaaSAndroid Build Coastguard Worker options = [] 248*c2e18aaaSAndroid Build Coastguard Worker for i, sfile in enumerate(all_versions, 1): 249*c2e18aaaSAndroid Build Coastguard Worker options.append('\t{}. {}'.format(i, sfile)) 250*c2e18aaaSAndroid Build Coastguard Worker query = ('You installed {} versions of {}:\n{}\nPlease select ' 251*c2e18aaaSAndroid Build Coastguard Worker 'one.\t').format(len(all_versions), ide_name, '\n'.join(options)) 252*c2e18aaaSAndroid Build Coastguard Worker return _select_intellij_version(query, all_versions) 253*c2e18aaaSAndroid Build Coastguard Worker 254*c2e18aaaSAndroid Build Coastguard Worker 255*c2e18aaaSAndroid Build Coastguard Workerdef _select_intellij_version(query, all_versions): 256*c2e18aaaSAndroid Build Coastguard Worker """Select one from different IntelliJ versions users installed. 257*c2e18aaaSAndroid Build Coastguard Worker 258*c2e18aaaSAndroid Build Coastguard Worker Args: 259*c2e18aaaSAndroid Build Coastguard Worker query: The query message. 260*c2e18aaaSAndroid Build Coastguard Worker all_versions: A list of all CE and UE version launch script paths. 261*c2e18aaaSAndroid Build Coastguard Worker """ 262*c2e18aaaSAndroid Build Coastguard Worker all_numbers = [] 263*c2e18aaaSAndroid Build Coastguard Worker for i in range(len(all_versions)): 264*c2e18aaaSAndroid Build Coastguard Worker all_numbers.append(str(i + 1)) 265*c2e18aaaSAndroid Build Coastguard Worker input_data = input(query) 266*c2e18aaaSAndroid Build Coastguard Worker while input_data not in all_numbers: 267*c2e18aaaSAndroid Build Coastguard Worker input_data = input('Please select a number:\t') 268*c2e18aaaSAndroid Build Coastguard Worker return all_versions[int(input_data) - 1] 269