Skip to content

Commit

Permalink
fix cross-build and optimize notification (#23)
Browse files Browse the repository at this point in the history
* fix cross-build, Root node judgment ignores Scala version suffix
* optimize: break if plugin find exception
  • Loading branch information
jxnu-liguobin authored Aug 31, 2023
1 parent dbab085 commit 9d4d27a
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 74 deletions.
74 changes: 29 additions & 45 deletions src/main/scala/bitlap/sbt/analyzer/DependencyUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ object DependencyUtils {
private final val artifactId = new AtomicLong(0)

private val ArtifactRegex = "(.*):(.*):(.*)".r
private val ScalaVerRegex = "(.*)\\.(.*)\\.(.*)".r
private val `ModuleWithScalaRegex` = "(.*)(_)(.*)".r
private val `ModuleWithScalaJs0.6Regex` = "(.*)(_sjs0\\.6_)(.*)".r
private val `ModuleWithScalaJs1Regex` = "(.*)(_sjs1_)(.*)".r
Expand All @@ -59,25 +58,13 @@ object DependencyUtils {
declaredDependencies(module).asScala.toList
}

def getUnifiedCoordinates(module: Module): List[UnifiedCoordinates] = {
getDeclaredDependency(module).map(_.getCoordinates)
}

def scalaMajorVersion(module: Module): String = {
val scalaVer = SbtDependencyUtils.getScalaVerFromModule(module)
scalaVer match
case ScalaVerRegex(major, minor, fix) if major == "2" => s"$major.$minor"
case _ => "3"
}

/** filter current module
*
* self is a ProjectDependencyNodeImpl, because we first convert it to DependencyNode and then filter it.
/** self is a ProjectDependencyNodeImpl, because we first convert it to DependencyNode and then filter it. This is
* important, for dependency graphs/trees, this is the root node.
*/
def isCurrentProjectModule(dn: DependencyNode, context: ModuleContext): Boolean = {
def isSelfModule(dn: DependencyNode, context: ModuleContext): Boolean = {
dn.getDisplayName match
case ArtifactRegex(group, artifact, version) =>
context.organization == group && isCurrentModule(artifact, context)
context.organization == group && isSelfArtifact(artifact, context)
case _ => false
}

Expand All @@ -92,13 +79,13 @@ object DependencyUtils {

/** do not analyze this module
*/
def ignoreModuleAnalysis(module: Module): Boolean = {
def canIgnoreModule(module: Module): Boolean = {
// if module is itself a build module, skip build module
val isBuildModule = module.isBuildModule
isBuildModule || module.isSharedSourceModule
}

def scopedKey(project: String, scope: DependencyScopeEnum, cmd: String): String = {
def getScopedCommandKey(project: String, scope: DependencyScopeEnum, cmd: String): String = {
if (project == null || project.isEmpty) s"$scope / $cmd"
else s"$project / $scope / $cmd"
}
Expand Down Expand Up @@ -149,40 +136,42 @@ object DependencyUtils {
}
}

private def isCurrentModule(artifact: String, context: ModuleContext): Boolean = {
private def isSelfArtifact(artifact: String, context: ModuleContext): Boolean = {
// Processing cross platform, module name is not artifact!
val currentModuleName =
context.ideaModuleIdSbtModuleNames.getOrElse(
context.currentModuleId,
context.ideaModuleIdSbtModuleNames.getOrElse(
Constants.RootSbtModule,
context.ideaModuleIdSbtModuleNames.getOrElse(Constants.SingleSbtModule, context.currentModuleId)
Constants.SingleSbtModule,
context.ideaModuleIdSbtModuleNames.getOrElse(Constants.RootSbtModule, context.currentModuleId)
)
)

// NOTE: we don't determine the Scala version number.
if (context.isScalaNative) {
artifact match
case `ModuleWithScalaNative0.4Regex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case `ModuleWithScalaNative0.3Regex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case `ModuleWithScalaNative0.2Regex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case `ModuleWithScalaNative0.4Regex`(module, _, _) =>
currentModuleName == module
case `ModuleWithScalaNative0.3Regex`(module, _, _) =>
currentModuleName == module
case `ModuleWithScalaNative0.2Regex`(module, _, _) =>
currentModuleName == module
case _ => false

} else if (context.isScalaJs) {
artifact match
case `ModuleWithScalaJs0.6Regex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case `ModuleWithScalaJs1Regex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case `ModuleWithScalaJs0.6Regex`(module, _, _) =>
currentModuleName == module
case `ModuleWithScalaJs1Regex`(module, _, _) =>
currentModuleName == module
case _ => false

} else {
artifact match
case `ModuleWithScalaRegex`(module, _, scalaVer) =>
currentModuleName == module && scalaVer == context.scalaMajor
case _ => false
case `ModuleWithScalaRegex`(module, _, _) =>
currentModuleName == module
// it is a java project
case _ => artifact == currentModuleName
}
}

Expand Down Expand Up @@ -222,7 +211,7 @@ object DependencyUtils {
}
p.getDependencies.addAll(
dn.getDependencies.asScala
.filterNot(d => isCurrentProjectModule(d, context.copy(currentModuleId = sbtModuleName)))
.filterNot(d => isSelfModule(d, context.copy(currentModuleId = sbtModuleName)))
.asJava
)
Some(p)
Expand All @@ -244,19 +233,14 @@ object DependencyUtils {
/** copy from DependencyModifierService, and fix
*/
def declaredDependencies(module: OpenapiModule.Module): java.util.List[DeclaredDependency] = try {

// Check whether the IDE is in Dumb Mode. If it is, return empty list instead proceeding
// if (DumbService.getInstance(module.getProject).isDumb) return Collections.emptyList()

val libDeps = SbtDependencyUtils
.getLibraryDependenciesOrPlaces(getSbtFileOpt(module), module.getProject, module, GetDep)
.map(_.asInstanceOf[(ScInfixExpr, String, ScInfixExpr)])

implicit val project: Project = module.getProject

// if (DumbService.getInstance(module.getProject).isDumb) return Collections.emptyList()
val scalaVer = SbtDependencyUtils.getScalaVerFromModule(module)

inReadAction({
val libDeps = SbtDependencyUtils
.getLibraryDependenciesOrPlaces(getSbtFileOpt(module), module.getProject, module, GetDep)
.map(_.asInstanceOf[(ScInfixExpr, String, ScInfixExpr)])
libDeps
.map(libDepInfixAndString => {
val libDepArr = SbtDependencyUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc
val module = findModule(project, moduleData)
if (module != null) {
val externalProject = DAProject(module, moduleData.getModuleName)
if (!DependencyUtils.ignoreModuleAnalysis(module)) {
if (!DependencyUtils.canIgnoreModule(module)) {
projects.put(externalProject, new ModuleNode(moduleData))
}
}
Expand Down Expand Up @@ -216,7 +216,7 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc
private def getDeclaredDependencies(project: Project, moduleData: ModuleData): List[UnifiedCoordinates] =
if (declaredDependencies.nonEmpty && SbtDependencyAnalyzerContributor.isValid.get()) return declaredDependencies
val module = findModule(project, moduleData)
declaredDependencies = DependencyUtils.getUnifiedCoordinates(module)
declaredDependencies = DependencyUtils.getDeclaredDependency(module).map(_.getCoordinates)
declaredDependencies

private def getOrRefreshData(moduleData: ModuleData)(using ParserTypeEnum): JList[DependencyScopeNode] = {
Expand Down Expand Up @@ -324,7 +324,7 @@ object SbtDependencyAnalyzerContributor:
declared: List[UnifiedCoordinates]
)(using ParserTypeEnum): JList[DependencyScopeNode] =
val module = findModule(project, moduleData)
if (DependencyUtils.ignoreModuleAnalysis(module)) return Collections.emptyList()
if (DependencyUtils.canIgnoreModule(module)) return Collections.emptyList()

// if the analysis files already exist (.dot), use it directly.
def executeCommandOrReadExistsFile(
Expand All @@ -341,7 +341,6 @@ object SbtDependencyAnalyzerContributor:
file,
moduleId,
scope,
scalaMajorVersion(module),
organization,
ideaModuleNamePaths,
module.isScalaJs,
Expand All @@ -365,31 +364,37 @@ object SbtDependencyAnalyzerContributor:
}
end executeCommandOrReadExistsFile

try {

if (isNotifying.get()) {
// must reload project to enable it
SbtShellOutputAnalysisTask.reloadTask.executeCommand(project)
}

val result =
DependencyScopeEnum.values.toList.map(executeCommandOrReadExistsFile)

isNotifying.set(false)
result.asJava
if (isNotifying.get()) {
// must reload project to enable it
SbtShellOutputAnalysisTask.reloadTask.executeCommand(project)
isNotifying.compareAndSet(true, false)
}

} catch {
case e: Throwable =>
e match
val result = ListBuffer[DependencyScopeNode]()
import scala.util.control.Breaks.*
// break, no more commands will be executed
breakable(
for (scope <- DependencyScopeEnum.values) {
var node: DependencyScopeNode = null
try {
node = executeCommandOrReadExistsFile(scope)
result.append(node)
} catch {
case _: AnalyzerCommandNotFoundException =>
if (isNotifying.compareAndSet(false, true)) {
SbtDependencyAnalyzerNotifier.notifyAndAddDependencyTreePlugin(project)
}
break()
case ue: AnalyzerCommandUnknownException =>
SbtDependencyAnalyzerNotifier.notifyUnknownError(project, ue.command, ue.moduleId, ue.scope)
case _ =>
null
}
break()
case e =>
throw e
}
}
)

result.toList.asJava
end loadDependencies
end extension

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ final case class ModuleContext(
analysisFile: String,
currentModuleId: String,
scope: DependencyScopeEnum,
scalaMajor: String,
organization: String,
ideaModuleNamePaths: Map[String, String] = Map.empty,
isScalaJs: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ final class DOTDependencyParser extends DependencyParser:
// if no relations for dependency object
if (dependencies == null || dependencies.relations.isEmpty) return {
val dep = data.map(_.dependencies.map(d => toDependencyNode(context, d)).toList).toList.flatten
val excludeSelfNode = dep.filterNot(d => isCurrentProjectModule(d, context))
val excludeSelfNode = dep.filterNot(d => isSelfModule(d, context))
appendChildrenAndFixProjectNodes(root, excludeSelfNode, context)
root
}
Expand All @@ -86,7 +86,7 @@ final class DOTDependencyParser extends DependencyParser:
}

// get self
val selfNode = depMap.values.toSet.toSeq.filter(d => isCurrentProjectModule(d, context))
val selfNode = depMap.values.toSet.toSeq.filter(d => isSelfModule(d, context))
// append children for self
selfNode.foreach { node =>
toNodes(node, parentChildrenMap, depMap, relationLabelsMap, context, dependencies.relations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ final class DependencyDotTask extends SbtShellDependencyAnalysisTask:
file,
moduleId,
scope,
scalaMajorVersion(module),
organization,
moduleNamePaths,
module.isScalaJs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ trait SbtShellDependencyAnalysisTask:
val file = moduleData.getLinkedExternalProjectPath + analysisFilePath(scope, parserTypeEnum)
val result = comms
.command(
scopedKey(moduleId, scope, parserTypeEnum.cmd),
getScopedCommandKey(moduleId, scope, parserTypeEnum.cmd),
new StringBuilder(),
SbtShellCommunication.listenerAggregator {
case SbtShellCommunication.TaskComplete =>
Expand Down
1 change: 0 additions & 1 deletion src/test/scala/bitlap/sbt/analyzer/DOTUtilSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class DOTUtilSpec extends AnyFlatSpec {
file,
"star-authority-protocol",
DependencyScopeEnum.Compile,
"3",
"fc.xuanwu.star",
ideaModuleNamePaths = Map.empty,
isScalaJs = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class DependencyGraphBuilderSpec extends AnyFlatSpec {
getClass.getClassLoader.getResource("test.dot").getFile,
"star-authority-protocol",
DependencyScopeEnum.Compile,
"3",
"fc.xuanwu.star",
ideaModuleNamePaths = Map.empty,
isScalaJs = false,
Expand Down

0 comments on commit 9d4d27a

Please sign in to comment.