@@ -10,14 +10,14 @@ import com.intellij.openapi.vfs.VirtualFile
1010import com.intellij.openapi.vfs.VirtualFileVisitor
1111import com.intellij.openapi.vfs.isFile
1212import com.intellij.platform.ide.progress.withBackgroundProgress
13- import kotlinx.coroutines.async
1413import kotlinx.coroutines.flow.channelFlow
1514import kotlinx.coroutines.launch
1615import kotlinx.coroutines.runBlocking
1716import kotlinx.coroutines.withContext
1817import org.apache.commons.codec.digest.DigestUtils
1918import org.apache.commons.io.FileUtils
2019import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
20+ import software.aws.toolkits.jetbrains.services.amazonq.QConstants.MAX_FILE_SIZE_BYTES
2121import software.aws.toolkits.jetbrains.services.telemetry.ALLOWED_CODE_EXTENSIONS
2222import software.aws.toolkits.jetbrains.utils.isDevFile
2323import software.aws.toolkits.resources.AwsCoreBundle
@@ -33,7 +33,6 @@ import java.nio.file.Paths
3333import java.nio.file.StandardCopyOption
3434import java.util.Base64
3535import java.util.UUID
36- import kotlin.coroutines.coroutineContext
3736import kotlin.io.path.Path
3837import kotlin.io.path.createParentDirectories
3938import kotlin.io.path.getPosixFilePermissions
@@ -47,8 +46,7 @@ class RepoSizeLimitError(override val message: String) : RuntimeException(), Rep
4746class FeatureDevSessionContext (val project : Project , val maxProjectSizeBytes : Long? = null ) {
4847 // TODO: Need to correct this class location in the modules going further to support both amazonq and codescan.
4948
50- private val requiredFilesForExecution = setOf (" gradle/wrapper/gradle-wrapper.jar" )
51- private val additionalGitIgnoreRules = setOf (
49+ private val additionalGitIgnoreFolderRules = setOf (
5250 " .aws-sam" ,
5351 " .gem" ,
5452 " .git" ,
@@ -58,6 +56,12 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
5856 " .project" ,
5957 " .rvm" ,
6058 " .svn" ,
59+ " node_modules" ,
60+ " build" ,
61+ " dist" ,
62+ )
63+
64+ private val additionalGitIgnoreBinaryFilesRules = setOf (
6165 " *.zip" ,
6266 " *.bin" ,
6367 " *.png" ,
@@ -70,9 +74,6 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
7074 " license.md" ,
7175 " License.md" ,
7276 " LICENSE.md" ,
73- " node_modules" ,
74- " build" ,
75- " dist"
7677 )
7778
7879 // well known source files that do not have extensions
@@ -90,12 +91,17 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
9091 // selectedSourceFolder: is the directory selected in replacement of the root, this happens when the project is too big to bundle for uploading.
9192 private var _selectedSourceFolder = projectRoot
9293 private var ignorePatternsWithGitIgnore = emptyList<Regex >()
94+ private var ignorePatternsForBinaryFiles = additionalGitIgnoreBinaryFilesRules
95+ .map { convertGitIgnorePatternToRegex(it) }
96+ .mapNotNull { pattern ->
97+ runCatching { Regex (pattern) }.getOrNull()
98+ }
9399 private val gitIgnoreFile = File (selectedSourceFolder.path, " .gitignore" )
94100
95101 init {
96102 ignorePatternsWithGitIgnore = try {
97103 buildList {
98- addAll(additionalGitIgnoreRules .map { convertGitIgnorePatternToRegex(it) })
104+ addAll(additionalGitIgnoreFolderRules .map { convertGitIgnorePatternToRegex(it) })
99105 addAll(parseGitIgnore())
100106 }.mapNotNull { pattern ->
101107 runCatching { Regex (pattern) }.getOrNull()
@@ -130,35 +136,49 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
130136 return ALLOWED_CODE_EXTENSIONS .contains(extension)
131137 }
132138
133- private fun ignoreFileByExtension (file : VirtualFile ) =
134- ! isFileExtensionAllowed(file)
139+ fun ignoreFile (file : VirtualFile , applyExtraBinaryFilesRules : Boolean = true): Boolean = ignoreFile(file.presentableUrl, applyExtraBinaryFilesRules)
140+
141+ fun ignoreFile (path : String , applyExtraBinaryFilesRules : Boolean = true): Boolean {
142+ val allIgnoreRules = if (applyExtraBinaryFilesRules) ignorePatternsWithGitIgnore + ignorePatternsForBinaryFiles else ignorePatternsWithGitIgnore
143+ val matchedRules = allIgnoreRules.map { pattern ->
144+ // avoid partial match (pattern.containsMatchIn) since it causes us matching files
145+ // against folder patterns. (e.g. settings.gradle ignored by .gradle rule!)
146+ // we convert the glob rules to regex, add a trailing /* to all rules and then match
147+ // entries against them by adding a trailing /.
148+ // TODO: Add unit tests for gitignore matching
149+ val relative = if (path.startsWith(projectRootPath.toString())) Paths .get(path).relativeTo(projectRootPath) else path
150+ pattern.matches(" $relative /" )
151+ }
152+ return matchedRules.any { it }
153+ }
135154
136- suspend fun ignoreFile (file : VirtualFile ): Boolean = ignoreFile (file.presentableUrl )
155+ private fun wellKnown (file : VirtualFile ): Boolean = wellKnownSourceFiles.contains (file.name )
137156
138- suspend fun ignoreFile (path : String ): Boolean {
139- if (requiredFilesForExecution.any { path.endsWith(it) }) {
157+ private fun shouldIncludeInZipFile (file : VirtualFile , isAutoBuildFeatureEnabled : Boolean ): Boolean {
158+ // large files always ignored
159+ if (file.length > MAX_FILE_SIZE_BYTES ) {
140160 return false
141161 }
142- // this method reads like something a JS dev would write and doesn't do what the author thinks
143- val deferredResults = ignorePatternsWithGitIgnore.map { pattern ->
144- withContext(coroutineContext) {
145- // avoid partial match (pattern.containsMatchIn) since it causes us matching files
146- // against folder patterns. (e.g. settings.gradle ignored by .gradle rule!)
147- // we convert the glob rules to regex, add a trailing /* to all rules and then match
148- // entries against them by adding a trailing /.
149- // TODO: Add unit tests for gitignore matching
150- val relative = if (path.startsWith(projectRootPath.toString())) Paths .get(path).relativeTo(projectRootPath) else path
151- async { pattern.matches(" $relative /" ) }
152- }
162+
163+ // always respect gitignore rules and remove binary files if auto build is disabled
164+ val isFileIgnoredByPattern = ignoreFile(file, ! isAutoBuildFeatureEnabled)
165+ if (isFileIgnoredByPattern) {
166+ return false
153167 }
154168
155- // this will serially iterate over and block
156- // ideally we race the results https://github.com/Kotlin/kotlinx.coroutines/issues/2867
157- // i.e. Promise.any(...)
158- return deferredResults.any { it.await() }
159- }
169+ // all other files are included when auto build enabled
170+ if (isAutoBuildFeatureEnabled) {
171+ return true
172+ }
173+
174+ // when auto build is disabled, only include files with well known extensions and names except "devfile.yam"
175+ if (! isDevFile(file) && (wellKnown(file) || isFileExtensionAllowed(file))) {
176+ return true
177+ }
160178
161- fun wellKnown (file : VirtualFile ): Boolean = wellKnownSourceFiles.contains(file.name)
179+ // Any other files should not be included
180+ return false
181+ }
162182
163183 suspend fun zipFiles (projectRoot : VirtualFile , isAutoBuildFeatureEnabled : Boolean? ): File = withContext(getCoroutineBgContext()) {
164184 val files = mutableListOf<VirtualFile >()
@@ -169,26 +189,13 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
169189 projectRoot,
170190 object : VirtualFileVisitor <Unit >() {
171191 override fun visitFile (file : VirtualFile ): Boolean {
172- val isWellKnown = runBlocking { wellKnown(file) }
173- val isFileIgnoredByExtension = runBlocking { ignoreFileByExtension(file) }
174- // if `isAutoBuildFeatureEnabled` is false, then filter devfile
175- val isFilterDevFile = if (isAutoBuildFeatureEnabled == true ) false else isDevFile(file)
176-
177- if (! isWellKnown && isFileIgnoredByExtension) {
192+ val isIncluded = shouldIncludeInZipFile(file, isAutoBuildFeatureEnabled == true )
193+ if (! isIncluded) {
178194 val extension = file.extension.orEmpty()
179195 ignoredExtensionMap[extension] = (ignoredExtensionMap[extension] ? : 0 ) + 1
180196 return false
181197 }
182198
183- if (isFilterDevFile) {
184- return false
185- }
186-
187- val isFileIgnoredByPattern = runBlocking { ignoreFile(file.name) }
188- if (isFileIgnoredByPattern) {
189- return false
190- }
191-
192199 if (file.isFile) {
193200 totalSize + = file.length
194201 files.add(file)
0 commit comments