Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remap plugin problems when resolving plugin dependencies #1124

Merged
merged 13 commits into from
Aug 5, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class ProductInfoBasedIdeManager : IdeManager() {
): PluginWithArtifactPathResult {
return IdePluginManager
.createManager(pathResolver)
.createBundledModule(pluginArtifactPath, ideVersion, descriptorName)
.createBundledModule(pluginArtifactPath, ideVersion, descriptorName, bundledPluginCreationResultResolver)
.withPath(pluginArtifactPath)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,11 @@ internal class PluginCreator private constructor(
return false
}
val invalidPlugin = newInvalidPlugin(bean, document)
return problemResolver.classify(invalidPlugin, problems).any {
it.level == ERROR
}
return problemResolver
.classify(invalidPlugin, problems)
.filter {
it.level == ERROR
}.notEmpty(context = bean)
}

private fun validateId(plugin: PluginBean) {
Expand Down Expand Up @@ -948,6 +950,19 @@ internal class PluginCreator private constructor(

private val PluginCreationSuccess<IdePlugin>.problems: List<PluginProblem>
get() = warnings + unacceptableWarnings

private fun List<PluginProblem>.notEmpty(context: PluginBean): Boolean {
return if (isEmpty()) {
false
} else {
if (LOG.isDebugEnabled) {
val errorMsg = joinToString()
LOG.debug("Plugin '${context.id}' has $size error(s): $errorMsg")
}
true
}
}

}

private fun PluginCreationResult<IdePlugin>.add(telemetry: PluginTelemetry): PluginCreationResult<IdePlugin> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ package com.jetbrains.pluginverifier.dependencies.resolution
import com.jetbrains.pluginverifier.misc.retry
import com.jetbrains.pluginverifier.plugin.PluginDetailsCache
import com.jetbrains.pluginverifier.repository.PluginRepository
import com.jetbrains.pluginverifier.repository.repositories.dependency.DependencyPluginRepository

/**
* [DependencyFinder] that searches for the dependency in the [PluginRepository].
* The [pluginVersionSelector] is used to select a specific version of the plugin
* if multiple versions are available.
*/
class RepositoryDependencyFinder(
private val pluginRepository: PluginRepository,
pluginRepository: PluginRepository,
private val pluginVersionSelector: PluginVersionSelector,
private val pluginDetailsCache: PluginDetailsCache
) : DependencyFinder {

private val pluginRepository = DependencyPluginRepository(pluginRepository)

override val presentableName
get() = pluginRepository.toString()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import java.nio.file.Path
* uses the [extractDirectory] for extracting `.zip`-ped plugins.
*/
abstract class AbstractPluginDetailsProvider(private val extractDirectory: Path) : PluginDetailsProvider {
private val idePluginManager = IdePluginManager.createManager(extractDirectory)
protected val idePluginManager = IdePluginManager.createManager(extractDirectory)

private val IdePlugin.problems: List<PluginProblem>
get() = if (this is StructurallyValidated) this.problems else emptyList()
Expand All @@ -33,7 +33,7 @@ abstract class AbstractPluginDetailsProvider(private val extractDirectory: Path)

override fun providePluginDetails(pluginInfo: PluginInfo, pluginFileLock: FileLock) =
pluginFileLock.closeOnException {
with(idePluginManager.createPlugin(pluginFileLock.file)) {
with(createPlugin(pluginInfo, pluginFileLock)) {
when (this) {
is PluginCreationSuccess<IdePlugin> -> {
readPluginClasses(
Expand Down Expand Up @@ -84,4 +84,7 @@ abstract class AbstractPluginDetailsProvider(private val extractDirectory: Path)
PluginDetailsProvider.Result.InvalidPlugin(pluginInfo, listOf(UnableToReadPluginFile(message)))
}
}

protected open fun createPlugin(pluginInfo: PluginInfo, pluginFileLock: FileLock) =
idePluginManager.createPlugin(pluginFileLock.file)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package com.jetbrains.pluginverifier.plugin

import com.jetbrains.plugin.structure.base.plugin.PluginCreationResult
import com.jetbrains.plugin.structure.intellij.classes.locator.CompileServerExtensionKey
import com.jetbrains.plugin.structure.intellij.classes.plugin.BundledPluginClassesFinder
import com.jetbrains.plugin.structure.intellij.classes.plugin.IdePluginClassesLocations
import com.jetbrains.plugin.structure.intellij.plugin.IdePlugin
import com.jetbrains.plugin.structure.intellij.problems.IntelliJPluginCreationResultResolver
import com.jetbrains.plugin.structure.intellij.problems.JetBrainsPluginCreationResultResolver
import com.jetbrains.plugin.structure.intellij.problems.PluginCreationResultResolver
import com.jetbrains.pluginverifier.repository.PluginInfo
import com.jetbrains.pluginverifier.repository.files.FileLock
import com.jetbrains.pluginverifier.repository.repositories.bundled.BundledPluginInfo
import com.jetbrains.pluginverifier.repository.repositories.dependency.DependencyPluginInfo
import java.nio.file.Path

/**
Expand All @@ -16,11 +22,22 @@ import java.nio.file.Path
class DefaultPluginDetailsProvider(extractDirectory: Path) : AbstractPluginDetailsProvider(extractDirectory) {
private val nonBundledPluginDetailsProvider: PluginDetailsProviderImpl = PluginDetailsProviderImpl(extractDirectory)

private val dependencyProblemResolver: PluginCreationResultResolver =
JetBrainsPluginCreationResultResolver.fromClassPathJson(IntelliJPluginCreationResultResolver())

override fun readPluginClasses(pluginInfo: PluginInfo, idePlugin: IdePlugin): IdePluginClassesLocations {
return if (pluginInfo is BundledPluginInfo) {
BundledPluginClassesFinder.findPluginClasses(idePlugin, additionalKeys = listOf(CompileServerExtensionKey))
} else {
nonBundledPluginDetailsProvider.readPluginClasses(pluginInfo, idePlugin)
}
}

override fun createPlugin(pluginInfo: PluginInfo, pluginFileLock: FileLock): PluginCreationResult<IdePlugin> {
return if (pluginInfo is DependencyPluginInfo) {
idePluginManager.createPlugin(pluginFileLock.file, validateDescriptor = false, problemResolver = dependencyProblemResolver)
} else {
super.createPlugin(pluginInfo, pluginFileLock)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
package com.jetbrains.pluginverifier.plugin

import com.jetbrains.pluginverifier.repository.PluginInfo
import com.jetbrains.pluginverifier.repository.WithIdePlugin
import com.jetbrains.pluginverifier.repository.cache.ResourceCacheEntry
import com.jetbrains.pluginverifier.repository.cache.ResourceCacheEntryResult
import com.jetbrains.pluginverifier.repository.cache.createSizeLimitedResourceCache
import com.jetbrains.pluginverifier.repository.cleanup.SizeWeight
import com.jetbrains.pluginverifier.repository.provider.ProvideResult
import com.jetbrains.pluginverifier.repository.provider.ResourceProvider
import com.jetbrains.pluginverifier.repository.repositories.bundled.BundledPluginInfo
import com.jetbrains.pluginverifier.repository.repositories.dependency.DependencyPluginInfo
import com.jetbrains.pluginverifier.repository.repositories.local.LocalPluginInfo

/**
Expand All @@ -23,8 +25,8 @@ import com.jetbrains.pluginverifier.repository.repositories.local.LocalPluginInf
*/
class SizeLimitedPluginDetailsCache(
cacheSize: Int,
val pluginFileProvider: PluginFileProvider,
val pluginDetailsProvider: PluginDetailsProvider
pluginFileProvider: PluginFileProvider,
pluginDetailsProvider: PluginDetailsProvider
) : PluginDetailsCache {

private val internalCache = createSizeLimitedResourceCache(
Expand Down Expand Up @@ -75,19 +77,42 @@ private class PluginDetailsResourceProvider(
override fun provide(key: PluginInfo) = when (key) {
is LocalPluginInfo -> ProvideResult.Provided(pluginDetailsProvider.providePluginDetails(key, key.idePlugin))
is BundledPluginInfo -> ProvideResult.Provided(pluginDetailsProvider.providePluginDetails(key, key.idePlugin))
is DependencyPluginInfo -> provideDependencyDetails(key)
else -> provideFileAndDetails(key)
}

private fun provideFileAndDetails(pluginInfo: PluginInfo): ProvideResult<PluginDetailsProvider.Result> {
return with(pluginFileProvider.getPluginFile(pluginInfo)) {
when (this) {
is PluginFileProvider.Result.Found -> {
val pluginDetailsResult = pluginDetailsProvider.providePluginDetails(pluginInfo, pluginFileLock)
ProvideResult.Provided(pluginDetailsResult)
}
is PluginFileProvider.Result.NotFound -> ProvideResult.NotFound(reason)
is PluginFileProvider.Result.Failed -> ProvideResult.Failed(reason, error)
return pluginFileProvider
.getPluginFile(pluginInfo)
.provideDetails(pluginInfo)
}

private fun provideDependencyDetails(dependency: DependencyPluginInfo): ProvideResult<PluginDetailsProvider.Result> {
val unwrappedPluginInfo = dependency.pluginInfo
val unwrappedPlugin = (unwrappedPluginInfo as? WithIdePlugin)?.idePlugin
return if (unwrappedPlugin != null) {
pluginDetailsProvider.providePluginDetails(unwrappedPluginInfo, unwrappedPlugin).provided
} else {
pluginFileProvider
.getPluginFile(unwrappedPluginInfo)
.provideDetails(dependency)
}
}

private fun PluginFileProvider.Result.provideDetails(pluginInfo: PluginInfo): ProvideResult<PluginDetailsProvider.Result> {
return when (this) {
is PluginFileProvider.Result.Found -> {
pluginDetailsProvider
.providePluginDetails(pluginInfo, pluginFileLock)
.provided
}

is PluginFileProvider.Result.NotFound -> ProvideResult.NotFound(reason)
is PluginFileProvider.Result.Failed -> ProvideResult.Failed(reason, error)
}
}
}

private val PluginDetailsProvider.Result.provided
get() = ProvideResult.Provided(this)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2000-2024 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/

package com.jetbrains.pluginverifier.repository

import com.jetbrains.plugin.structure.intellij.plugin.IdePlugin

/**
* Indicates a [plugin info][PluginInfo] that contains a resolved [IDE Plugin][IdePlugin].
*/
interface WithIdePlugin {
val idePlugin: IdePlugin
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package com.jetbrains.pluginverifier.repository.repositories.bundled
import com.jetbrains.plugin.structure.intellij.plugin.IdePlugin
import com.jetbrains.plugin.structure.intellij.version.IdeVersion
import com.jetbrains.pluginverifier.repository.PluginInfo
import com.jetbrains.pluginverifier.repository.WithIdePlugin
import java.io.ObjectInputStream
import java.util.*

Expand All @@ -15,15 +16,15 @@ import java.util.*
*/
class BundledPluginInfo(
val ideVersion: IdeVersion,
val idePlugin: IdePlugin
override val idePlugin: IdePlugin
) : PluginInfo(
idePlugin.pluginId!!,
idePlugin.pluginName ?: idePlugin.pluginId!!,
idePlugin.pluginVersion ?: ideVersion.asString(),
idePlugin.sinceBuild,
idePlugin.untilBuild,
idePlugin.vendor
) {
), WithIdePlugin {

private fun writeReplace(): Any = throw UnsupportedOperationException("Bundled plugins cannot be serialized")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2000-2024 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.jetbrains.pluginverifier.repository.repositories.dependency

import com.jetbrains.pluginverifier.repository.PluginInfo

/**
* Plugin information that is resolved as a plugin dependency.
*/
class DependencyPluginInfo(val pluginInfo: PluginInfo) : PluginInfo(
pluginInfo.pluginId,
pluginInfo.pluginName,
pluginInfo.version,
pluginInfo.sinceBuild,
pluginInfo.untilBuild,
pluginInfo.vendor
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2024 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/

package com.jetbrains.pluginverifier.repository.repositories.dependency

import com.jetbrains.plugin.structure.intellij.version.IdeVersion
import com.jetbrains.pluginverifier.repository.PluginInfo
import com.jetbrains.pluginverifier.repository.PluginRepository

/**
* Repository wrapping another repository while mapping plugins into [dependencies][DependencyPluginInfo].
*/
class DependencyPluginRepository(private val delegateRepository: PluginRepository) : PluginRepository {
override val presentableName: String = "${delegateRepository.presentableName} (used for plugin dependencies)"

override fun getLastCompatiblePlugins(ideVersion: IdeVersion): List<PluginInfo> =
delegateRepository.getLastCompatiblePlugins(ideVersion).asDependencies()

override fun getLastCompatibleVersionOfPlugin(ideVersion: IdeVersion, pluginId: String): PluginInfo? =
delegateRepository.getLastCompatibleVersionOfPlugin(ideVersion, pluginId).asDependency()

override fun getAllVersionsOfPlugin(pluginId: String): List<PluginInfo> =
delegateRepository.getAllVersionsOfPlugin(pluginId).asDependencies()

override fun getPluginsDeclaringModule(moduleId: String, ideVersion: IdeVersion?): List<PluginInfo> =
delegateRepository.getPluginsDeclaringModule(moduleId, ideVersion).asDependencies()

private fun List<PluginInfo>.asDependencies(): List<DependencyPluginInfo> = map { DependencyPluginInfo(it) }

private fun PluginInfo?.asDependency(): PluginInfo? = this?.let { DependencyPluginInfo(it) }

}


Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package com.jetbrains.pluginverifier.repository.repositories.local

import com.jetbrains.plugin.structure.intellij.plugin.IdePlugin
import com.jetbrains.pluginverifier.repository.PluginInfo
import com.jetbrains.pluginverifier.repository.WithIdePlugin
import java.io.ObjectInputStream

/**
Expand All @@ -14,15 +15,15 @@ import java.io.ObjectInputStream
* @see [LocalPluginRepository]
*/
class LocalPluginInfo(
val idePlugin: IdePlugin
override val idePlugin: IdePlugin
) : PluginInfo(
idePlugin.pluginId!!,
idePlugin.pluginName ?: idePlugin.pluginId!!,
idePlugin.pluginVersion!!,
idePlugin.sinceBuild,
idePlugin.untilBuild,
idePlugin.vendor
) {
), WithIdePlugin {

val definedModules: Set<String>
get() = idePlugin.definedModules
Expand Down
Loading
Loading