Skip to content

Commit

Permalink
Support Settings (#33)
Browse files Browse the repository at this point in the history
* add settings
* changed pluginVerifierOptions
* update change-notes
  • Loading branch information
jxnu-liguobin authored Sep 12, 2023
1 parent d2fd2c4 commit 5cf6eeb
Show file tree
Hide file tree
Showing 14 changed files with 459 additions and 27 deletions.
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ But if statement **already exists** in `*.sbt` files, `sdap.sbt` will not be cre

Just click on the icon and wait for the analysis:

![](./docs/gotoAnalyze1.jpg)
<img src="./docs/gotoAnalyze1.jpg" width = "400" height = "280" alt="settings" align="center" />

When the analysis is complete:

![](./docs/dependencyTreeConflicts.jpg)
<img src="./docs/dependencyTreeConflicts.jpg" width = "500" height = "200" alt="settings" align="center" />

## For more details

Expand All @@ -44,6 +44,28 @@ When the analysis is complete:
4. `reload` reload project on-demand.
5. `update` update dependencies on-demand.

## Advanced Setup

> If you are not sure, you do not need to use these configurations!
Using configurations, analysis wait times can be dramatically reduced:

<img src="./docs/settings.png" width = "400" height = "280" alt="settings" align="right" />

**File Cache Timeout**

If the file hasn't been changed for more than `3600` seconds, plugin will execute the `dependencyDot` task, otherwise use the one that already exists, unless using `Refresh`.

**Organization**

If you set this value, the `organization` task will not be used to get your project's organization.

**Disable Scope**

If you don't need to analyze all scopes, just disable it.

Configurations are persistent and associated with each intellij project.

## Troubleshooting issues

### "Caused by: java.io.IOException: Could not create lock for ..."
Expand All @@ -54,8 +76,7 @@ Caused by: java.io.IOException: Could not create lock for \\.\pipe\sbt-load59647
```
Using sbt shell to reload or build the project avoids this issue:

![](docs/sbtShellUseForReload.jpg)

<img src="./docs/sbtShellUseForReload.jpg" width = "500" height = "230" alt="settings" align="center" />

### Can't analyze dependencies between modules?

Expand Down
7 changes: 4 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ lazy val `sbt-dependency-analyzer` = (project in file("."))
// Some("xxx") // or None if password is not set(or via PLUGIN_SIGN_KEY_PWD env var)
),
pluginVerifierOptions := pluginVerifierOptions.value.copy(
version = "1.301", // use a specific verifier version
offline = true, // forbid the verifier from reaching the internet
failureLevels = Set(FailureLevel.DEPRECATED_API_USAGES) // only fail if deprecated APIs are used
version = "1.301", // use a specific verifier version
offline = true, // forbid the verifier from reaching the internet
failureLevels =
Set(FailureLevel.INTERNAL_API_USAGES, FailureLevel.COMPATIBILITY_PROBLEMS, FailureLevel.COMPATIBILITY_WARNINGS)
),
Global / intellijAttachSources := true,
intellijPlugins ++= Seq("com.intellij.java", "com.intellij.java-i18n", "org.intellij.scala").map(_.toPlugin),
Expand Down
Binary file added docs/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 12 additions & 3 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

<extensions defaultExtensionNs="com.intellij">
<!-- https://plugins.jetbrains.com/feature#name_dependencySupport -->
<dependencySupport kind="java" coordinate="org.scala-sbt:sbt" displayName="sbt" />
<dependencySupport kind="java" coordinate="sbt" displayName="sbt" />
<dependencySupport kind="java" coordinate="org.scala-sbt:sbt" displayName="sbt"/>
<dependencySupport kind="java" coordinate="sbt" displayName="sbt"/>
<externalSystemDependencyAnalyzer implementation="bitlap.sbt.analyzer.SbtDependencyAnalyzerExtension"/>
<notificationGroup id="Sbt.DependencyAnalyzer.Notification" displayType="BALLOON"/>

Expand All @@ -26,7 +26,10 @@
description="Force translation for notification"/>

<postStartupActivity implementation="bitlap.sbt.analyzer.activity.PluginUpdateActivity"/>

<projectService serviceImplementation="bitlap.sbt.analyzer.SettingsState"/>
<projectConfigurable groupId="tools"
displayName="Sbt Dependency Analyzer"
instance="bitlap.sbt.analyzer.SbtDependencyAnalyzerConfigurable"/>
</extensions>

<actions>
Expand Down Expand Up @@ -116,6 +119,12 @@
<change-notes>
<![CDATA[
<h1>0.2.0-RC3-231.9392.1</h1>
<ul>
<li>🎉Add Intellij Settings.</li>
</ul>
<!-- @@ -->
<h1>0.2.0-RC2-231.9392.1</h1>
<ul>
<li>Update description and action name.</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ analyzer.action.gotoAction.text=Goto Dependency
analyzer.notification.gotoSdap=Goto "{0}"
analyzer.notification.addSdap.title=Sbt Dependency Analyzer is ready
analyzer.notification.addSdap.text=The "{0}" has been added or updated, please wait a moment, go to see more.
analyzer.notification.setting.changed.title=Sbt Dependency Analyzer settings have been changed
analyzer.notification.updated.title={0} plugin updated to v{1}
analyzer.notification.updated.text=Thank you for downloading \
<b><a href="https://github.com/bitlap/intellij-sbt-dependency-analyzer">Sbt Dependency Analyzer</a></b>! \
Expand All @@ -17,6 +18,7 @@ analyzer.refresh.dependencies.text=Refresh Dependencies
analyzer.refresh.dependencies.description=Refresh dependencies using reimport
analyzer.refresh.snapshot.dependencies.text=Refresh Snapshot Dependencies
analyzer.refresh.snapshot.dependencies.description=Set the "COURSIER_TTL=0s" to refresh snapshot dependencies
analyzer.settings.page.name=Sbt Dependency Analyzer



Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ analyzer.action.gotoAction.text=查看依赖
analyzer.notification.gotoSdap=打开 “{0}”
analyzer.notification.addSdap.title=Sbt Dependency Analyzer 已就绪
analyzer.notification.addSdap.text=已添加或更新文件 “{0}”,请稍等片刻,前往查看更多
analyzer.notification.setting.changed.title=Sbt Dependency Analyzer 配置已被更改
analyzer.notification.updated.title={0} 插件已更新为 v{1}
analyzer.notification.updated.text=感谢下载 \
<b><a href="https://github.com/bitlap/intellij-sbt-dependency-analyzer">Sbt Dependency Analyzer</a></b>! \
Expand All @@ -16,4 +17,5 @@ analyzer.notification.updated.gotoBrowser=去看看
analyzer.refresh.dependencies.text=刷新依赖
analyzer.refresh.dependencies.description=重新导入以刷新依赖
analyzer.refresh.snapshot.dependencies.text=刷新快照依赖
analyzer.refresh.snapshot.dependencies.description=设置 “COURSIER_TTL=0s” 以刷新快照依赖
analyzer.refresh.snapshot.dependencies.description=设置 “COURSIER_TTL=0s” 以刷新快照依赖
analyzer.settings.page.name=Sbt 依赖分析
2 changes: 0 additions & 2 deletions src/main/scala/bitlap/sbt/analyzer/Constants.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ object Constants:

final val IntervalTimeout = 1010.milliseconds

final val FileLifespan = 1000 * 60 * 60L

final val ChangeNotesSeparator = "<!-- @@ -->"

end Constants
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package bitlap.sbt.analyzer

import javax.swing.JComponent

import com.intellij.openapi.options.*
import com.intellij.openapi.options.Configurable.Composite
import com.intellij.openapi.project.Project

/** @author
* 梦境迷离
* @version 1.0,2023/9/7
*/
final class SbtDependencyAnalyzerConfigurable(project: Project) extends SearchableConfigurable {

// create a ui form
private val panel: SbtDependencyAnalyzerPanel = new SbtDependencyAnalyzerPanel(project)

override def getId(): String = SbtDependencyAnalyzerPlugin.PLUGIN_ID

override def getDisplayName(): String = SbtDependencyAnalyzerBundle.message("analyzer.settings.page.name")

override def getHelpTopic(): String = "default"

override def createComponent(): JComponent = panel.$$$getRootComponent$$$()

override def isModified(): Boolean = panel.isModified

override def apply(): Unit = panel.apply()

override def reset(): Unit = panel.from()

override def disposeUIResources(): Unit = {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.jetbrains.sbt.project.data.ModuleNode

import com.intellij.buildsystem.model.unified.UnifiedCoordinates
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.externalSystem.dependency.analyzer.{ DependencyAnalyzerDependency as Dependency, * }
import com.intellij.openapi.externalSystem.dependency.analyzer.DependencyAnalyzerDependency.Data
import com.intellij.openapi.externalSystem.model.ProjectKeys
Expand Down Expand Up @@ -138,7 +139,7 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc
)
}

private def deleteExistAnalysisFiles(modulePath: String)(using ParserTypeEnum): Unit = {
private def deleteExistAnalysisFiles(modulePath: String): Unit = {
DependencyScopeEnum.values
.map(scope => Path.of(modulePath + analysisFilePath(scope, summon[ParserTypeEnum])))
.foreach(p => Files.deleteIfExists(p))
Expand Down Expand Up @@ -206,7 +207,12 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc

private def getOrganization(project: Project): String =
// When force refresh, we will not re-read the settings, such organization,moduleName, because refreshing makes efficiency lower.
// Usually, Uses do not change frequently, so it's better to keep caching until the view is reopene.
// Usually, Uses do not change frequently, so it's better to keep caching until the view is reopen.
val org = SettingsState.getSettings(project).organization
if (org != null && org != Constants.EmptyString) {
return org
}

if (organization != null) return organization
organization = SbtShellOutputAnalysisTask.organizationTask.executeCommand(project)
organization
Expand Down Expand Up @@ -242,16 +248,25 @@ final class SbtDependencyAnalyzerContributor(project: Project) extends Dependenc
}
}

object SbtDependencyAnalyzerContributor:
object SbtDependencyAnalyzerContributor extends SettingsState.SettingsChangeListener:

final val isAvailable = new AtomicBoolean(true)

// if data change
override def onAnalyzerConfigurationChanged(project: Project, settingsState: SettingsState): Unit = {
// TODO
isAvailable.set(false)
SbtUtils.refreshProject(project)
}

ApplicationManager.getApplication.getMessageBus.connect().subscribe(SettingsState._Topic, this)

private final val isNotifying = new AtomicBoolean(false)

private def isValidFile(file: String): Boolean = {
private def isValidFile(project: Project, file: String): Boolean = {
if (isAvailable.get()) {
val lastModified = Path.of(file).toFile.lastModified()
System.currentTimeMillis() <= lastModified + Constants.FileLifespan
System.currentTimeMillis() <= lastModified + SettingsState.getSettings(project).fileCacheTimeout * 1000
} else {
isAvailable.getAndSet(true)
}
Expand Down Expand Up @@ -326,8 +341,10 @@ object SbtDependencyAnalyzerContributor:
ideaModuleNamePaths: Map[String, String],
ideaModuleIdSbtModules: Map[String, String],
declared: List[UnifiedCoordinates]
)(using ParserTypeEnum): JList[DependencyScopeNode] =
val module = findModule(project, moduleData)
): JList[DependencyScopeNode] =
val module = findModule(project, moduleData)
val moduleId = moduleData.getId.split(" ")(0)

if (DependencyUtils.canIgnoreModule(module)) return Collections.emptyList()

if (isNotifying.get() && SbtUtils.untilProjectReady(project)) {
Expand All @@ -340,9 +357,8 @@ object SbtDependencyAnalyzerContributor:
def executeCommandOrReadExistsFile(
scope: DependencyScopeEnum
): DependencyScopeNode =
val moduleId = moduleData.getId.split(" ")(0)
val file = moduleData.getLinkedExternalProjectPath + analysisFilePath(scope, summon[ParserTypeEnum])
val useCache = !isNotifying.get() && Files.exists(Path.of(file)) && isValidFile(file)
val useCache = !isNotifying.get() && Files.exists(Path.of(file)) && isValidFile(project, file)
// File cache for one hour
if (useCache) {
DependencyParserFactory
Expand Down Expand Up @@ -378,12 +394,20 @@ object SbtDependencyAnalyzerContributor:
val result = ListBuffer[DependencyScopeNode]()
import scala.util.control.Breaks.*
// break, no more commands will be executed
breakable(
breakable {
val settings = SettingsState.getSettings(project)
for (scope <- DependencyScopeEnum.values) {
var node: DependencyScopeNode = null
try {
node = executeCommandOrReadExistsFile(scope)
result.append(node)

if (settings.disableAnalyzeProvided && scope == DependencyScopeEnum.Provided) {} else if (
settings.disableAnalyzeTest && scope == DependencyScopeEnum.Test
) {} else if (settings.disableAnalyzeCompile && scope == DependencyScopeEnum.Compile) {} else {
node = executeCommandOrReadExistsFile(scope)
}
if (node != null) {
result.append(node)
}
} catch {
case _: AnalyzerCommandNotFoundException =>
if (isNotifying.compareAndSet(false, true)) {
Expand All @@ -397,7 +421,7 @@ object SbtDependencyAnalyzerContributor:
throw e
}
}
)
}

result.toList.asJava
end loadDependencies
Expand Down
103 changes: 103 additions & 0 deletions src/main/scala/bitlap/sbt/analyzer/SbtDependencyAnalyzerPanel.form
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="bitlap.sbt.analyzer.SbtDependencyAnalyzerPanel">
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="4" column-count="4" same-size-horizontally="true" same-size-vertically="false" hgap="0" vgap="0">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="9" y="9" width="600" height="120"/>
</constraints>
<properties>
<alignmentX value="0.0"/>
<alignmentY value="0.0"/>
<autoscrolls value="false"/>
<maximumSize width="-1" height="-1"/>
<minimumSize width="-1" height="-1"/>
<preferredSize width="600" height="120"/>
</properties>
<border type="none">
<font/>
</border>
<children>
<component id="e47fd" class="javax.swing.JLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Disable Scope:"/>
</properties>
</component>
<component id="d76eb" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Organization:"/>
</properties>
</component>
<component id="9adf2" class="javax.swing.JCheckBox" binding="testCheckBox" default-binding="true">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Test"/>
</properties>
</component>
<component id="1a5d3" class="javax.swing.JCheckBox" binding="compileCheckBox" default-binding="true">
<constraints>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Compile"/>
</properties>
</component>
<component id="e26b2" class="javax.swing.JCheckBox" binding="providedCheckBox" default-binding="true">
<constraints>
<grid row="2" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Provided"/>
</properties>
</component>
<component id="e19b" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="File Cache Timeout:"/>
</properties>
</component>
<component id="9f522" class="javax.swing.JTextField" binding="fileCache">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<columns value="4"/>
<horizontalAlignment value="2"/>
<text value="3600"/>
</properties>
</component>
<component id="7b57c" class="javax.swing.JTextField" binding="organization">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<columns value="12"/>
<horizontalAlignment value="2"/>
<text value=""/>
</properties>
</component>
<component id="7e6b6" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="seconds"/>
</properties>
</component>
<vspacer id="77ee8">
<constraints>
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
</children>
</grid>
</form>
Loading

0 comments on commit 5cf6eeb

Please sign in to comment.