Skip to content

Commit bad2661

Browse files
committed
Added download progress indicator
1 parent bd4dd63 commit bad2661

File tree

4 files changed

+53
-32
lines changed

4 files changed

+53
-32
lines changed

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactHelper.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts
55

6+
import com.intellij.openapi.project.Project
7+
import com.intellij.platform.ide.progress.withBackgroundProgress
68
import com.intellij.util.io.createDirectories
79
import com.intellij.util.text.SemVer
810
import org.jetbrains.annotations.VisibleForTesting
@@ -99,7 +101,7 @@ class ArtifactHelper(private val lspArtifactsPath: Path = DEFAULT_ARTIFACT_PATH,
99101
return !hasInvalidFiles
100102
}
101103

102-
fun tryDownloadLspArtifacts(versions: List<ManifestManager.Version>, target: ManifestManager.VersionTarget?) {
104+
suspend fun tryDownloadLspArtifacts(project: Project, versions: List<ManifestManager.Version>, target: ManifestManager.VersionTarget?) {
103105
val temporaryDownloadPath = lspArtifactsPath.resolve("temp")
104106
val downloadPath = lspArtifactsPath.resolve(versions.first().serverVersion.toString())
105107

@@ -108,23 +110,23 @@ class ArtifactHelper(private val lspArtifactsPath: Path = DEFAULT_ARTIFACT_PATH,
108110
logger.info { "Attempt ${currentAttempt.get()} of $maxDownloadAttempts to download LSP artifacts" }
109111

110112
try {
111-
if (downloadLspArtifacts(temporaryDownloadPath, target) && target != null && !target.contents.isNullOrEmpty()) {
112-
moveFilesFromSourceToDestination(temporaryDownloadPath, downloadPath)
113-
target.contents
114-
.mapNotNull { it.filename }
115-
.forEach { filename -> extractZipFile(downloadPath.resolve(filename), downloadPath) }
116-
logger.info { "Successfully downloaded and moved LSP artifacts to $downloadPath" }
117-
return
113+
withBackgroundProgress(project, "Downloading & Extracting LSP artifacts...", cancellable = true) {
114+
if (downloadLspArtifacts(temporaryDownloadPath, target) && target != null && !target.contents.isNullOrEmpty()) {
115+
moveFilesFromSourceToDestination(temporaryDownloadPath, downloadPath)
116+
target.contents
117+
.mapNotNull { it.filename }
118+
.forEach { filename -> extractZipFile(downloadPath.resolve(filename), downloadPath) }
119+
logger.info { "Successfully downloaded and moved LSP artifacts to $downloadPath" }
120+
}
118121
}
122+
return
119123
} catch (e: Exception) {
120124
logger.error(e) { "Failed to download/move LSP artifacts on attempt ${currentAttempt.get()}" }
121125
temporaryDownloadPath.toFile().deleteRecursively()
122126
downloadPath.toFile().deleteRecursively()
123127
}
124128
}
125-
if (currentAttempt.get() >= maxDownloadAttempts) {
126-
throw LspException("Failed to download LSP artifacts after $maxDownloadAttempts attempts", LspException.ErrorCode.DOWNLOAD_FAILED)
127-
}
129+
throw LspException("Failed to download LSP artifacts after $maxDownloadAttempts attempts", LspException.ErrorCode.DOWNLOAD_FAILED)
128130
}
129131

130132
@VisibleForTesting

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactManager.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts
55

6+
import com.intellij.openapi.project.Project
67
import com.intellij.util.text.SemVer
78
import org.jetbrains.annotations.VisibleForTesting
89
import software.aws.toolkits.core.utils.error
@@ -11,6 +12,7 @@ import software.aws.toolkits.core.utils.info
1112
import software.aws.toolkits.jetbrains.services.amazonq.project.manifest.ManifestManager
1213

1314
class ArtifactManager(
15+
private val project: Project,
1416
private val manifestFetcher: ManifestFetcher = ManifestFetcher(),
1517
private val artifactHelper: ArtifactHelper = ArtifactHelper(),
1618
manifestRange: SupportedManifestVersionRange?,
@@ -27,9 +29,6 @@ class ArtifactManager(
2729

2830
private val manifestVersionRanges: SupportedManifestVersionRange = manifestRange ?: DEFAULT_VERSION_RANGE
2931

30-
// Secondary constructor with no parameters
31-
constructor() : this(ManifestFetcher(), ArtifactHelper(), null)
32-
3332
companion object {
3433
private val DEFAULT_VERSION_RANGE = SupportedManifestVersionRange(
3534
startVersion = SemVer("3.0.0", 3, 0, 0),
@@ -38,7 +37,7 @@ class ArtifactManager(
3837
private val logger = getLogger<ArtifactManager>()
3938
}
4039

41-
fun fetchArtifact() {
40+
suspend fun fetchArtifact() {
4241
val manifest = manifestFetcher.fetch() ?: throw LspException(
4342
"Language Support is not available, as manifest is missing.",
4443
LspException.ErrorCode.MANIFEST_FETCH_FAILED
@@ -61,7 +60,7 @@ class ArtifactManager(
6160

6261
// Get Local LSP files and check if we can re-use existing LSP Artifacts
6362
if (!this.artifactHelper.getExistingLspArtifacts(lspVersions.inRangeVersions, target)) {
64-
this.artifactHelper.tryDownloadLspArtifacts(lspVersions.inRangeVersions, target)
63+
this.artifactHelper.tryDownloadLspArtifacts(project, lspVersions.inRangeVersions, target)
6564
}
6665

6766
this.artifactHelper.deleteOlderLspArtifacts(manifestVersionRanges)

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactHelperTest.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts
55

6+
import com.intellij.openapi.project.Project
67
import com.intellij.util.io.createDirectories
78
import com.intellij.util.text.SemVer
89
import io.mockk.Runs
910
import io.mockk.every
1011
import io.mockk.just
12+
import io.mockk.mockk
1113
import io.mockk.mockkStatic
1214
import io.mockk.spyk
15+
import kotlinx.coroutines.runBlocking
1316
import org.assertj.core.api.Assertions.assertThat
1417
import org.assertj.core.api.Assertions.assertThatThrownBy
1518
import org.jetbrains.annotations.TestOnly
@@ -30,6 +33,7 @@ class ArtifactHelperTest {
3033
private lateinit var manifestVersionRanges: SupportedManifestVersionRange
3134
private lateinit var mockManifestManager: ManifestManager
3235
private lateinit var contents: List<ManifestManager.TargetContent>
36+
private lateinit var mockProject: Project
3337

3438
@BeforeEach
3539
fun setUp() {
@@ -41,6 +45,10 @@ class ArtifactHelperTest {
4145
hashes = listOf("sha384:1234")
4246
)
4347
)
48+
mockProject = mockk<Project>(relaxed = true) {
49+
every { basePath } returns tempDir.toString()
50+
every { name } returns "TestProject"
51+
}
4452
}
4553

4654
@Test
@@ -181,7 +189,7 @@ class ArtifactHelperTest {
181189
fun `tryDownloadLspArtifacts should not download artifacts if target does not have contents`() {
182190
val versions = listOf(ManifestManager.Version(serverVersion = "2.0.0"))
183191
assertThatThrownBy {
184-
artifactHelper.tryDownloadLspArtifacts(versions, null)
192+
runBlocking { artifactHelper.tryDownloadLspArtifacts(mockProject, versions, null) }
185193
}
186194
.isInstanceOf(LspException::class.java)
187195
.hasFieldOrPropertyWithValue("errorCode", LspException.ErrorCode.DOWNLOAD_FAILED)
@@ -196,14 +204,14 @@ class ArtifactHelperTest {
196204
every { spyArtifactHelper.downloadLspArtifacts(any(), any()) } returns false
197205

198206
assertThatThrownBy {
199-
spyArtifactHelper.tryDownloadLspArtifacts(versions, null)
207+
runBlocking { spyArtifactHelper.tryDownloadLspArtifacts(mockProject, versions, null) }
200208
}
201209
.isInstanceOf(LspException::class.java)
202210
.hasFieldOrPropertyWithValue("errorCode", LspException.ErrorCode.DOWNLOAD_FAILED)
203211
}
204212

205213
@Test
206-
fun `tryDownloadLspArtifacts should not throw error on successful download`() {
214+
fun `tryDownloadLspArtifacts should throw error after attempts are exhausted`() {
207215
val versions = listOf(ManifestManager.Version(serverVersion = "1.0.0"))
208216
val target = ManifestManager.VersionTarget(contents = contents)
209217
val spyArtifactHelper = spyk(artifactHelper)
@@ -213,7 +221,10 @@ class ArtifactHelperTest {
213221
every { moveFilesFromSourceToDestination(any(), any()) } just Runs
214222
every { extractZipFile(any(), any()) } just Runs
215223

216-
spyArtifactHelper.tryDownloadLspArtifacts(versions, target)
224+
assertThatThrownBy {
225+
runBlocking { spyArtifactHelper.tryDownloadLspArtifacts(mockProject, versions, target) }
226+
}
227+
.isInstanceOf(LspException::class.java)
217228
}
218229

219230
@Test

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactManagerTest.kt

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts
55

6+
import com.intellij.openapi.project.Project
67
import com.intellij.util.text.SemVer
78
import io.mockk.Runs
9+
import io.mockk.coEvery
810
import io.mockk.every
911
import io.mockk.just
12+
import io.mockk.mockk
1013
import io.mockk.mockkStatic
1114
import io.mockk.spyk
1215
import io.mockk.verify
16+
import kotlinx.coroutines.runBlocking
1317
import org.assertj.core.api.Assertions.assertThatThrownBy
1418
import org.jetbrains.annotations.TestOnly
1519
import org.junit.jupiter.api.BeforeEach
@@ -29,6 +33,7 @@ class ArtifactManagerTest {
2933
private lateinit var artifactManager: ArtifactManager
3034
private lateinit var manifestFetcher: ManifestFetcher
3135
private lateinit var manifestVersionRanges: SupportedManifestVersionRange
36+
private lateinit var mockProject: Project
3237

3338
@BeforeEach
3439
fun setUp() {
@@ -38,15 +43,19 @@ class ArtifactManagerTest {
3843
startVersion = SemVer("1.0.0", 1, 0, 0),
3944
endVersion = SemVer("2.0.0", 2, 0, 0)
4045
)
41-
artifactManager = ArtifactManager(manifestFetcher, artifactHelper, manifestVersionRanges)
46+
mockProject = mockk<Project>(relaxed = true) {
47+
every { basePath } returns tempDir.toString()
48+
every { name } returns "TestProject"
49+
}
50+
artifactManager = ArtifactManager(mockProject, manifestFetcher, artifactHelper, manifestVersionRanges)
4251
}
4352

4453
@Test
4554
fun `fetch artifact fetcher throws exception if manifest is null`() {
4655
every { manifestFetcher.fetch() }.returns(null)
4756

4857
assertThatThrownBy {
49-
artifactManager.fetchArtifact()
58+
runBlocking { artifactManager.fetchArtifact() }
5059
}
5160
.isInstanceOf(LspException::class.java)
5261
.hasFieldOrPropertyWithValue("errorCode", LspException.ErrorCode.MANIFEST_FETCH_FAILED)
@@ -55,14 +64,14 @@ class ArtifactManagerTest {
5564
@Test
5665
fun `fetch artifact does not have any valid lsp versions`() {
5766
every { manifestFetcher.fetch() }.returns(ManifestManager.Manifest())
58-
artifactManager = spyk(ArtifactManager(manifestFetcher, artifactHelper, manifestVersionRanges))
67+
artifactManager = spyk(ArtifactManager(mockProject, manifestFetcher, artifactHelper, manifestVersionRanges))
5968

6069
every { artifactManager.getLSPVersionsFromManifestWithSpecifiedRange(any()) }.returns(
6170
ArtifactManager.LSPVersions(deListedVersions = emptyList(), inRangeVersions = emptyList())
6271
)
6372

6473
assertThatThrownBy {
65-
artifactManager.fetchArtifact()
74+
runBlocking { artifactManager.fetchArtifact() }
6675
}
6776
.isInstanceOf(LspException::class.java)
6877
.hasFieldOrPropertyWithValue("errorCode", LspException.ErrorCode.NO_COMPATIBLE_LSP_VERSION)
@@ -75,7 +84,7 @@ class ArtifactManagerTest {
7584
every { manifestFetcher.fetch() }.returns(ManifestManager.Manifest())
7685
every { artifactHelper.getAllLocalLspArtifactsWithinManifestRange(any()) }.returns(expectedResult)
7786

78-
artifactManager.fetchArtifact()
87+
runBlocking { artifactManager.fetchArtifact() }
7988

8089
verify(exactly = 1) { manifestFetcher.fetch() }
8190
verify(exactly = 1) { artifactHelper.getAllLocalLspArtifactsWithinManifestRange(any()) }
@@ -86,7 +95,7 @@ class ArtifactManagerTest {
8695
val target = ManifestManager.VersionTarget(platform = "temp", arch = "temp")
8796
val versions = listOf(ManifestManager.Version("1.0.0", targets = listOf(target)))
8897

89-
artifactManager = spyk(ArtifactManager(manifestFetcher, artifactHelper, manifestVersionRanges))
98+
artifactManager = spyk(ArtifactManager(mockProject, manifestFetcher, artifactHelper, manifestVersionRanges))
9099

91100
every { artifactManager.getLSPVersionsFromManifestWithSpecifiedRange(any()) }.returns(
92101
ArtifactManager.LSPVersions(deListedVersions = emptyList(), inRangeVersions = versions)
@@ -98,12 +107,12 @@ class ArtifactManagerTest {
98107
every { getCurrentArchitecture() }.returns("temp")
99108

100109
every { artifactHelper.getExistingLspArtifacts(any(), any()) }.returns(false)
101-
every { artifactHelper.tryDownloadLspArtifacts(any(), any()) } just Runs
110+
coEvery { artifactHelper.tryDownloadLspArtifacts(any(), any(), any()) } just Runs
102111
every { artifactHelper.deleteOlderLspArtifacts(any()) } just Runs
103112

104-
artifactManager.fetchArtifact()
113+
runBlocking { artifactManager.fetchArtifact() }
105114

106-
verify(exactly = 1) { artifactHelper.tryDownloadLspArtifacts(any(), any()) }
115+
verify(exactly = 1) { runBlocking { artifactHelper.tryDownloadLspArtifacts(any(), any(), any()) } }
107116
verify(exactly = 1) { artifactHelper.deleteOlderLspArtifacts(any()) }
108117
}
109118

@@ -112,7 +121,7 @@ class ArtifactManagerTest {
112121
val target = ManifestManager.VersionTarget(platform = "temp", arch = "temp")
113122
val versions = listOf(ManifestManager.Version("1.0.0", targets = listOf(target)))
114123

115-
artifactManager = spyk(ArtifactManager(manifestFetcher, artifactHelper, manifestVersionRanges))
124+
artifactManager = spyk(ArtifactManager(mockProject, manifestFetcher, artifactHelper, manifestVersionRanges))
116125

117126
every { artifactManager.getLSPVersionsFromManifestWithSpecifiedRange(any()) }.returns(
118127
ArtifactManager.LSPVersions(deListedVersions = emptyList(), inRangeVersions = versions)
@@ -126,9 +135,9 @@ class ArtifactManagerTest {
126135
every { artifactHelper.getExistingLspArtifacts(any(), any()) }.returns(true)
127136
every { artifactHelper.deleteOlderLspArtifacts(any()) } just Runs
128137

129-
artifactManager.fetchArtifact()
138+
runBlocking { artifactManager.fetchArtifact() }
130139

131-
verify(exactly = 0) { artifactHelper.tryDownloadLspArtifacts(any(), any()) }
140+
verify(exactly = 0) { runBlocking { artifactHelper.tryDownloadLspArtifacts(any(), any(), any()) } }
132141
verify(exactly = 1) { artifactHelper.deleteOlderLspArtifacts(any()) }
133142
}
134143
}

0 commit comments

Comments
 (0)