Skip to content

Commit 4d2ff28

Browse files
committed
Merge remote-tracking branch 'origin/main' into HEAD
Conflicts: plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererSettingsTest.kt
2 parents 9a4bfd6 + 32c2ef6 commit 4d2ff28

File tree

7 files changed

+109
-63
lines changed

7 files changed

+109
-63
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Fix integer overflow when local context index input is larger than 2GB"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Fix workspace index process quits when hitting a race condition"
4+
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererConfigurable.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class CodeWhispererConfigurable(private val project: Project) :
169169

170170
row(message("aws.settings.codewhisperer.project_context_index_thread")) {
171171
intTextField(
172-
range = IntRange(0, 50)
172+
range = CodeWhispererSettings.CONTEXT_INDEX_THREADS
173173
).bindIntText(codeWhispererSettings::getProjectContextIndexThreadCount, codeWhispererSettings::setProjectContextIndexThreadCount)
174174
.apply {
175175
connect.subscribe(
@@ -186,7 +186,7 @@ class CodeWhispererConfigurable(private val project: Project) :
186186

187187
row(message("aws.settings.codewhisperer.project_context_index_max_size")) {
188188
intTextField(
189-
range = IntRange(1, 4096)
189+
range = CodeWhispererSettings.CONTEXT_INDEX_SIZE
190190
).bindIntText(codeWhispererSettings::getProjectContextIndexMaxSize, codeWhispererSettings::setProjectContextIndexMaxSize)
191191
.apply {
192192
connect.subscribe(

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererSettingsTest.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,41 @@ class CodeWhispererSettingsTest : CodeWhispererTestBase() {
220220
assertThat(actual.autoBuildSetting["project1"]).isTrue()
221221
}
222222

223+
@Test
224+
fun `context thread count is returned in range`() {
225+
val sut = CodeWhispererSettings.getInstance()
226+
227+
mapOf(
228+
1 to 1,
229+
0 to 0,
230+
-1 to 0,
231+
123 to 50,
232+
50 to 50,
233+
51 to 50,
234+
).forEach { s, expected ->
235+
sut.setProjectContextIndexThreadCount(s)
236+
assertThat(sut.getProjectContextIndexThreadCount()).isEqualTo(expected)
237+
}
238+
}
239+
240+
@Test
241+
fun `context index size is returned in range`() {
242+
val sut = CodeWhispererSettings.getInstance()
243+
244+
mapOf(
245+
1 to 1,
246+
0 to 1,
247+
-1 to 1,
248+
123 to 123,
249+
2047 to 2047,
250+
4096 to 4096,
251+
4097 to 4096,
252+
).forEach { s, expected ->
253+
sut.setProjectContextIndexMaxSize(s)
254+
assertThat(sut.getProjectContextIndexMaxSize()).isEqualTo(expected)
255+
}
256+
}
257+
223258
@Test
224259
fun `toggleMetricOptIn should trigger LSP didChangeConfiguration`() {
225260
mockkObject(AmazonQLspService)

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/project/ProjectContextProvider.kt

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class ProjectContextProvider(val project: Project, private val encoderServer: En
7070

7171
data class FileCollectionResult(
7272
val files: List<String>,
73-
val fileSize: Int,
73+
val fileSize: Int, // in MB
7474
)
7575

7676
// TODO: move to LspMessage.kt
@@ -246,59 +246,7 @@ class ProjectContextProvider(val project: Project, private val encoderServer: En
246246
}
247247
}
248248

249-
private fun willExceedPayloadLimit(currentTotalFileSize: Long, currentFileSize: Long): Boolean {
250-
val maxSize = CodeWhispererSettings.getInstance().getProjectContextIndexMaxSize()
251-
return currentTotalFileSize.let { totalSize -> totalSize > (maxSize * 1024 * 1024 - currentFileSize) }
252-
}
253-
254-
private fun isBuildOrBin(fileName: String): Boolean {
255-
val regex = Regex("""bin|build|node_modules|venv|\.venv|env|\.idea|\.conda""", RegexOption.IGNORE_CASE)
256-
return regex.find(fileName) != null
257-
}
258-
259-
fun collectFiles(): FileCollectionResult {
260-
val collectedFiles = mutableListOf<String>()
261-
var currentTotalFileSize = 0L
262-
val allFiles = mutableListOf<VirtualFile>()
263-
264-
val projectBaseDirectories = project.getBaseDirectories()
265-
val changeListManager = ChangeListManager.getInstance(project)
266-
267-
projectBaseDirectories.forEach {
268-
VfsUtilCore.visitChildrenRecursively(
269-
it,
270-
object : VirtualFileVisitor<Unit>(NO_FOLLOW_SYMLINKS) {
271-
// TODO: refactor this along with /dev & codescan file traversing logic
272-
override fun visitFile(file: VirtualFile): Boolean {
273-
if ((file.isDirectory && isBuildOrBin(file.name)) ||
274-
!isWorkspaceSourceContent(file, projectBaseDirectories, changeListManager, additionalGlobalIgnoreRulesForStrictSources) ||
275-
(file.isFile && file.length > 10 * 1024 * 1024)
276-
) {
277-
return false
278-
}
279-
if (file.isFile) {
280-
allFiles.add(file)
281-
return false
282-
}
283-
return true
284-
}
285-
}
286-
)
287-
}
288-
289-
for (file in allFiles) {
290-
if (willExceedPayloadLimit(currentTotalFileSize, file.length)) {
291-
break
292-
}
293-
collectedFiles.add(file.path)
294-
currentTotalFileSize += file.length
295-
}
296-
297-
return FileCollectionResult(
298-
files = collectedFiles.toList(),
299-
fileSize = (currentTotalFileSize / 1024 / 1024).toInt()
300-
)
301-
}
249+
fun collectFiles(): FileCollectionResult = collectFiles(project.getBaseDirectories(), ChangeListManager.getInstance(project))
302250

303251
private fun queryResultToRelevantDocuments(queryResult: List<Chunk>): List<RelevantDocument> {
304252
val documents: MutableList<RelevantDocument> = mutableListOf()
@@ -358,5 +306,57 @@ class ProjectContextProvider(val project: Project, private val encoderServer: En
358306

359307
companion object {
360308
private val logger = getLogger<ProjectContextProvider>()
309+
private val regex = Regex("""bin|build|node_modules|venv|\.venv|env|\.idea|\.conda""", RegexOption.IGNORE_CASE)
310+
private val mega = (1024 * 1024).toULong()
311+
private val tenMb = 10 * mega.toInt()
312+
313+
private fun willExceedPayloadLimit(maxSize: ULong, currentTotalFileSize: ULong, currentFileSize: Long) =
314+
currentTotalFileSize.let { totalSize -> totalSize > (maxSize - currentFileSize.toUInt()) }
315+
316+
private fun isBuildOrBin(fileName: String): Boolean =
317+
regex.find(fileName) != null
318+
319+
fun collectFiles(projectBaseDirectories: Set<VirtualFile>, changeListManager: ChangeListManager): FileCollectionResult {
320+
val maxSize = CodeWhispererSettings.getInstance()
321+
.getProjectContextIndexMaxSize().toULong() * mega
322+
val collectedFiles = mutableListOf<String>()
323+
var currentTotalFileSize = 0UL
324+
val allFiles = mutableListOf<VirtualFile>()
325+
326+
projectBaseDirectories.forEach {
327+
VfsUtilCore.visitChildrenRecursively(
328+
it,
329+
object : VirtualFileVisitor<Unit>(NO_FOLLOW_SYMLINKS) {
330+
// TODO: refactor this along with /dev & codescan file traversing logic
331+
override fun visitFile(file: VirtualFile): Boolean {
332+
if ((file.isDirectory && isBuildOrBin(file.name)) ||
333+
!isWorkspaceSourceContent(file, projectBaseDirectories, changeListManager, additionalGlobalIgnoreRulesForStrictSources) ||
334+
(file.isFile && file.length > tenMb)
335+
) {
336+
return false
337+
}
338+
if (file.isFile) {
339+
allFiles.add(file)
340+
return false
341+
}
342+
return true
343+
}
344+
}
345+
)
346+
}
347+
348+
for (file in allFiles) {
349+
if (willExceedPayloadLimit(maxSize, currentTotalFileSize, file.length)) {
350+
break
351+
}
352+
collectedFiles.add(file.path)
353+
currentTotalFileSize += file.length.toUInt()
354+
}
355+
356+
return FileCollectionResult(
357+
files = collectedFiles.toList(),
358+
fileSize = (currentTotalFileSize / 1024u / 1024u).toInt()
359+
)
360+
}
361361
}
362362
}

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/project/manifest/ManifestManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import software.aws.toolkits.jetbrains.core.getTextFromUrl
1515

1616
class ManifestManager {
1717
private val cloudFrontUrl = "https://aws-toolkit-language-servers.amazonaws.com/q-context/manifest.json"
18-
val currentVersion = "0.1.46"
18+
val currentVersion = "0.1.49"
1919
val currentOs = getOs()
2020
private val arch = CpuArch.CURRENT
2121
private val mapper = jacksonObjectMapper().apply { configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) }

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/settings/CodeWhispererSettings.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class CodeWhispererSettings : PersistentStateComponent<CodeWhispererConfiguratio
119119
fun getProjectContextIndexThreadCount(): Int = state.intValue.getOrDefault(
120120
CodeWhispererIntConfigurationType.ProjectContextIndexThreadCount,
121121
0
122-
)
122+
).coerceIn(CONTEXT_INDEX_THREADS)
123123

124124
fun setProjectContextIndexThreadCount(value: Int) {
125125
state.intValue[CodeWhispererIntConfigurationType.ProjectContextIndexThreadCount] = value
@@ -128,7 +128,7 @@ class CodeWhispererSettings : PersistentStateComponent<CodeWhispererConfiguratio
128128
fun getProjectContextIndexMaxSize(): Int = state.intValue.getOrDefault(
129129
CodeWhispererIntConfigurationType.ProjectContextIndexMaxSize,
130130
250
131-
)
131+
).coerceIn(CONTEXT_INDEX_SIZE)
132132

133133
fun setProjectContextIndexMaxSize(value: Int) {
134134
state.intValue[CodeWhispererIntConfigurationType.ProjectContextIndexMaxSize] = value
@@ -161,10 +161,6 @@ class CodeWhispererSettings : PersistentStateComponent<CodeWhispererConfiguratio
161161
state.value[CodeWhispererConfigurationType.IsTabAcceptPriorityNotificationShownOnce] = value
162162
}
163163

164-
companion object {
165-
fun getInstance(): CodeWhispererSettings = service()
166-
}
167-
168164
override fun getState(): CodeWhispererConfiguration = CodeWhispererConfiguration().apply {
169165
value.putAll(state.value)
170166
intValue.putAll(state.intValue)
@@ -182,6 +178,13 @@ class CodeWhispererSettings : PersistentStateComponent<CodeWhispererConfiguratio
182178
this.state.stringValue.putAll(state.stringValue)
183179
this.state.autoBuildSetting.putAll(state.autoBuildSetting)
184180
}
181+
182+
companion object {
183+
fun getInstance(): CodeWhispererSettings = service()
184+
185+
val CONTEXT_INDEX_SIZE = IntRange(1, 4096)
186+
val CONTEXT_INDEX_THREADS = IntRange(0, 50)
187+
}
185188
}
186189

187190
class CodeWhispererConfiguration : BaseState() {

0 commit comments

Comments
 (0)