blob: 30d3e8adc34a4b71280ed5e9d07764122afda1e9 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""It is an AIDEGen sub task : launch IDE task!
Takes a project file path as input, after passing the needed check(file
existence, IDE type, etc.), launch the project in related IDE.
Typical usage example:
launch_ide(file_path)
launch_intellij(file_path)
"""
import glob
import logging
import os
import subprocess
# We use this type command to determine whether the user has installed intelliJ
# IDEA, and the reason is that, in linux, the launch script is created by IDEA
# with specific path naming rule when installed, i.e. /opt/intellij-*/bin/
# idea.sh.
_CHECK_INTELLIJ_PATH = '/opt/intellij-*/bin/idea.sh'
# In this version, if community edition(CE) exists, AIDEGen prefers IntelliJ
# community edition(CE) over ultimate edition(UE).
# TODO(albaltai): prompt user to select a preferred IDE version from all
# installed versions.
_LS_CE_PATH = '/opt/intellij-ce-*/bin/idea.sh'
_LS_UE_PATH = '/opt/intellij-ue-*/bin/idea.sh'
# TODO(albaltai): If needed, create a log file to replace /dev/null and to
# collect IDEA related usage metrics data.
_IGNORE_STD_OUT_ERR_CMD = '&>/dev/null'
# To confirm target is IDEA by project file extension.
_IML_EXTENSION = '.iml'
# To confirm target is IDEA by VERIFYING folder existence.
_IDEA_FOLDER = '.idea'
def launch_ide(file_path):
"""Launches the relative IDE by opening the passed project file.
Args:
file_path: The full path of the IDE project file.
"""
assert file_path, 'Empty file path is not allowed.'
logging.info('Project file path: %s.', file_path)
if (os.path.isfile(file_path) and _is_intellij_project(file_path)):
launch_intellij(file_path)
else:
logging.error('No IntelliJ IDEA file exists.')
def launch_intellij(file_path):
"""Launches IntelliJ IDE by opening the validated project file.
Args:
file_path: The target IDE project file.
"""
assert file_path, 'Empty file path is not allowed.'
logging.info('Project file path: %s.', file_path)
if (os.path.isfile(file_path) and _is_intellij_project(file_path)):
# TODO(albaltai@): Remove below IDEA check after main flow does the
# same check before calling launch_intellij
if check_intellij():
_run_intellij_sh(file_path)
def check_intellij():
"""Checks if the IntelliJ is already installed. No exception will be
raised if IntelliJ is not installed.
Returns:
True if IntelliJ is installed already, otherwise False.
"""
logging.debug('Check if IDEA exists by path: %s.', _CHECK_INTELLIJ_PATH)
return glob.glob(_CHECK_INTELLIJ_PATH) != []
def _is_intellij_project(file_path):
"""Checks if the path passed in is an IntelliJ project file.
Args:
file_path: The project file's full path.
Returns:
True if file_path is an IntelliJ project, False otherwise.
"""
_, ext = os.path.splitext(os.path.basename(file_path))
if ext and _IML_EXTENSION == ext.lower():
path = os.path.dirname(file_path)
logging.debug('Extracted path is: %s.', path)
check_folder = os.path.join(path, _IDEA_FOLDER)
return os.path.isdir(check_folder) # There must exist a .idea folder
return False
def _get_intellij_path():
"""Locates the IntelliJ IDEA launch script path by following rule.
1. If the community edition(CE) exists, use the newest CE version as
target.
2. If there's no CE version, launch the newest UE version if available.
Returns:
The sh full path, or None if neither IntelliJ version is installed.
"""
ls_output = glob.glob(_LS_CE_PATH)
if ls_output != []:
ls_output = sorted(ls_output, reverse=True)
logging.debug('Result for checking IntelliJ CE after sort: %s.',
ls_output)
return ls_output[0]
ls_output = glob.glob(_LS_UE_PATH)
if ls_output != []:
ls_output = sorted(ls_output, reverse=True)
logging.debug('Result for checking IntelliJ UE after sort: %s.',
ls_output)
return ls_output[0]
return None
def _get_run_intellij_cmd(sh_path, file_path):
"""Get the command to launch IntelliJ.
Args:
sh_path: The idea.sh path where IntelliJ is installed.
file_path: The path of IntelliJ IDEA project file.
Returns:
A string: The IntelliJ launching command.
"""
return ' '.join([sh_path, file_path, _IGNORE_STD_OUT_ERR_CMD, '&'])
def _run_intellij_sh(file_path):
"""Run launch script idea.sh with file_path as argument.
Args:
file_path: The path of IntelliJ IDEA project file.
"""
sh_path = _get_intellij_path()
if not sh_path:
logging.error('No suitable IntelliJ IDEA installed.')
return
logging.debug('Script path: %s, file path: %s.', sh_path, file_path)
# Compose launch IDEA command to run as a new process and redirect output.
run_sh_cmd = _get_run_intellij_cmd(sh_path, file_path)
logging.debug('Run commnad: %s to launch IDEA project file.', run_sh_cmd)
try:
subprocess.check_call(run_sh_cmd, shell=True)
except subprocess.CalledProcessError as err:
logging.error('Launch file, %s failed with error: %s.', file_path, err)