in platformio/src/com/jetbrains/cidr/cpp/embedded/platformio/project/PlatformioProjectResolver.kt [84:245]
override fun resolveProjectInfo(id: ExternalSystemTaskId,
projectPath: String,
isPreviewMode: Boolean,
settings: PlatformioExecutionSettings?,
resolverPolicy: ProjectResolverPolicy?,
listener: ExternalSystemTaskNotificationListener): DataNode<ProjectData>? {
cancelled = false
val project = id.findProject()!!
val platformioService = project.service<PlatformioService>()
if (!TrustedProjects.isProjectTrusted(project)) {
// To prevent a deadlock
assert(!EDT.isCurrentThreadEdt())
runBlockingCancellable {
if (!showUntrustedProjectLoadDialog(project)) {
platformioService.projectStatus = NOT_TRUSTED
throw ExternalSystemException(ClionEmbeddedPlatformioBundle.message("project.not.trusted"))
}
}
}
platformioService.projectStatus = PARSING
try {
val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(projectPath) ?: throw ExternalSystemException(FileNotFoundException(ClionEmbeddedPlatformioBundle.message("project.not.found", projectPath)))
val projectDir = if (projectFile.isDirectory) projectFile else projectFile.parent
val boardInfo = project.getUserData(PROJECT_INIT_KEY)
if (boardInfo != null) {
cliGenerateProject(project, listener, id, projectDir, boardInfo)
}
checkCancelled()
val pioResolvePolicy = resolverPolicy.asSafely<PlatformioProjectResolvePolicy>()
if (pioResolvePolicy?.cleanCache != false) {
platformioService.cleanCache()
}
checkCancelled()
var configJson = platformioService.configJson
if (configJson == null) {
configJson = gatherConfigJson(id, "pio-run:${UUID.randomUUID()}", project, listener)
platformioService.configJson = configJson
}
val envs: Map<String, PlatformioExecutionTarget>
val defaultEnv: PlatformioExecutionTarget?
checkCancelled()
val configMap: Map<String, List<Any>> =
@Suppress("UNCHECKED_CAST")
(Gson().fromJson(configJson, List::class.java) as List<List<Any>>)
.associate { it[0] as String to it[1] as List<Any> }
val platformioSection: Map<String, Any> =
@Suppress("UNCHECKED_CAST")
(configMap["platformio"] as List<List<Any>>?)?.associate { it[0] as String to it[1] } ?: emptyMap()
envs = configMap.keys
.filter { it.startsWith("env:") }
.associate {
val envName = it.removePrefix("env:")
envName to PlatformioExecutionTarget(envName)
}
when (val defaultEnvs = platformioSection["default_envs"]) {
is List<*> -> defaultEnv = envs[defaultEnvs[0].asSafely<String>() ?: ""]
is String -> defaultEnv = envs[defaultEnvs]
else -> defaultEnv = envs.values.firstOrNull()
}
val scanner = PlatformioFileScanner(projectDir, listener, id, this::checkCancelled)
platformioService.iniFiles = scanner.findConfigs(platformioSection)
val projectName = platformioSection["name"]?.asSafely<String>() ?: project.name
val ideProjectPath = ExternalSystemApiUtil.toCanonicalPath(project.basePath ?: projectDir.path)
val projectData = ProjectData(ID, projectName, ideProjectPath,
ExternalSystemApiUtil.toCanonicalPath(projectDir.path))
var projectNode: DataNode<ProjectData>
do {
val activeExecutionTarget = ExecutionTargetManager.getActiveTarget(project)
var activeEnv = activeExecutionTarget as? PlatformioExecutionTarget
platformioService.envs = envs.values.toList()
createRunConfigurationIfRequired(project)
if (activeEnv == null || !envs.containsKey(activeEnv.id)) {
activeEnv = defaultEnv
ApplicationManager.getApplication().invokeAndWait {
ExecutionTargetManager.setActiveTarget(project, activeEnv ?: DefaultExecutionTarget.INSTANCE)
}
}
val activeEnvName = ExecutionTargetManager.getActiveTarget(project).asSafely<PlatformioExecutionTarget>()?.id ?: defaultEnv?.id
if (activeEnvName == null) throw ExternalSystemException("No active platformio environment")
var pioActiveMetadataText = platformioService.metadataJson[activeEnvName]
if (pioActiveMetadataText == null) {
pioActiveMetadataText = gatherEnvMetadata(id, "pio-run:${UUID.randomUUID()}", project, activeEnvName, listener)
platformioService.setMetadataJson(activeEnvName, pioActiveMetadataText)
}
val pioActiveMetadata = Gson()
.fromJson<Map<String, Any>>(pioActiveMetadataText, Map::class.java)
?.get(activeEnvName)
?.asSafely<Map<String, Any>>()
?: throw ExternalSystemException("Project metadata does not contain expected '${activeEnv}' section")
platformioService.targetExecutablePath = pioActiveMetadata["prog_path"] as? String
platformioService.svdPath = pioActiveMetadata["svd_path"] as? String
val targets = (pioActiveMetadata["targets"]?.asSafely<List<Map<String, String?>>>())?.map {
val name = it["name"] ?: throw ExternalSystemException("Malformed metadata targets section")
PlatformioTargetData(name, it["title"], it["description"], it["group"])
}
platformioService.setTargets(addUploadIfMissing(targets.orEmpty()))
val buildDirectory: Path = calcBuildDir(projectDir, platformioSection)
platformioService.buildDirectory = buildDirectory
val name = pioActiveMetadata["env_name"] as String
val confBuilder = ExternalResolveConfigurationBuilder(id = name, configName = "PlatformIO", buildWorkingDir = projectDir.toNioPath().toFile())
.withVariants(name)
checkCancelled()
val languageConfigurations = configureLanguages(pioActiveMetadata, confBuilder)
checkCancelled()
val compDbJson = getCompDbJson(pioResolvePolicy, platformioService, id, project, activeEnvName, listener, projectPath)
checkCancelled()
scanner.scanSources(compDbJson, project.service<PlatformioWorkspace>(), languageConfigurations, confBuilder)
checkCancelled()
platformioService.librariesPaths = scanner.scanLibraries(pioActiveMetadata)
checkCancelled()
val module = ExternalModuleImpl(mutableSetOf(confBuilder.invoke()))
val cppModuleNode = DataNode(ExternalModule.OC_MODULE_KEY, module, null)
projectNode = DataNode(ProjectKeys.PROJECT, projectData, null)
attachExternalModule(project, ID, projectDir.toNioPath(), projectNode, cppModuleNode)
val needsToBeReparsed = with(ExecutionTargetManager.getActiveTarget(project)) {
this is PlatformioExecutionTarget && this.id != activeEnvName
}
}
while (needsToBeReparsed)
platformioService.projectStatus = PARSED
project.messageBus.syncPublisher(PLATFORMIO_UPDATES_TOPIC).projectStateChanged()
return projectNode
}
catch (e: ProcessCanceledException) {
platformioService.projectStatus = PARSE_FAILED
throw e
}
catch (e: RunPlatformioException) {
platformioService.projectStatus = when(e) {
is RunPlatformioExitcodeException -> PARSE_FAILED
is RunPlatformioExecutionException -> UTILITY_FAILED
else -> PARSE_FAILED
}
LOG.info(e)
return null
}
catch (e: ExternalSystemException) {
platformioService.projectStatus = PARSE_FAILED
throw e
}
catch (e: Throwable) {
platformioService.projectStatus = PARSE_FAILED
LOG.error(e)
throw ExternalSystemException(e)
}
}