@@ -10,14 +10,14 @@ import com.intellij.openapi.vfs.VirtualFile
10
10
import com.intellij.openapi.vfs.VirtualFileVisitor
11
11
import com.intellij.openapi.vfs.isFile
12
12
import com.intellij.platform.ide.progress.withBackgroundProgress
13
- import kotlinx.coroutines.async
14
13
import kotlinx.coroutines.flow.channelFlow
15
14
import kotlinx.coroutines.launch
16
15
import kotlinx.coroutines.runBlocking
17
16
import kotlinx.coroutines.withContext
18
17
import org.apache.commons.codec.digest.DigestUtils
19
18
import org.apache.commons.io.FileUtils
20
19
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
20
+ import software.aws.toolkits.jetbrains.services.amazonq.QConstants.MAX_FILE_SIZE_BYTES
21
21
import software.aws.toolkits.jetbrains.services.telemetry.ALLOWED_CODE_EXTENSIONS
22
22
import software.aws.toolkits.jetbrains.utils.isDevFile
23
23
import software.aws.toolkits.resources.AwsCoreBundle
@@ -33,7 +33,6 @@ import java.nio.file.Paths
33
33
import java.nio.file.StandardCopyOption
34
34
import java.util.Base64
35
35
import java.util.UUID
36
- import kotlin.coroutines.coroutineContext
37
36
import kotlin.io.path.Path
38
37
import kotlin.io.path.createParentDirectories
39
38
import kotlin.io.path.getPosixFilePermissions
@@ -47,8 +46,7 @@ class RepoSizeLimitError(override val message: String) : RuntimeException(), Rep
47
46
class FeatureDevSessionContext (val project : Project , val maxProjectSizeBytes : Long? = null ) {
48
47
// TODO: Need to correct this class location in the modules going further to support both amazonq and codescan.
49
48
50
- private val requiredFilesForExecution = setOf (" gradle/wrapper/gradle-wrapper.jar" )
51
- private val additionalGitIgnoreRules = setOf (
49
+ private val additionalGitIgnoreFolderRules = setOf (
52
50
" .aws-sam" ,
53
51
" .gem" ,
54
52
" .git" ,
@@ -58,6 +56,12 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
58
56
" .project" ,
59
57
" .rvm" ,
60
58
" .svn" ,
59
+ " node_modules" ,
60
+ " build" ,
61
+ " dist" ,
62
+ )
63
+
64
+ private val additionalGitIgnoreBinaryFilesRules = setOf (
61
65
" *.zip" ,
62
66
" *.bin" ,
63
67
" *.png" ,
@@ -70,9 +74,6 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
70
74
" license.md" ,
71
75
" License.md" ,
72
76
" LICENSE.md" ,
73
- " node_modules" ,
74
- " build" ,
75
- " dist"
76
77
)
77
78
78
79
// well known source files that do not have extensions
@@ -90,12 +91,17 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
90
91
// selectedSourceFolder: is the directory selected in replacement of the root, this happens when the project is too big to bundle for uploading.
91
92
private var _selectedSourceFolder = projectRoot
92
93
private var ignorePatternsWithGitIgnore = emptyList<Regex >()
94
+ private var ignorePatternsForBinaryFiles = additionalGitIgnoreBinaryFilesRules
95
+ .map { convertGitIgnorePatternToRegex(it) }
96
+ .mapNotNull { pattern ->
97
+ runCatching { Regex (pattern) }.getOrNull()
98
+ }
93
99
private val gitIgnoreFile = File (selectedSourceFolder.path, " .gitignore" )
94
100
95
101
init {
96
102
ignorePatternsWithGitIgnore = try {
97
103
buildList {
98
- addAll(additionalGitIgnoreRules .map { convertGitIgnorePatternToRegex(it) })
104
+ addAll(additionalGitIgnoreFolderRules .map { convertGitIgnorePatternToRegex(it) })
99
105
addAll(parseGitIgnore())
100
106
}.mapNotNull { pattern ->
101
107
runCatching { Regex (pattern) }.getOrNull()
@@ -130,35 +136,49 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
130
136
return ALLOWED_CODE_EXTENSIONS .contains(extension)
131
137
}
132
138
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
+ }
135
154
136
- suspend fun ignoreFile (file : VirtualFile ): Boolean = ignoreFile (file.presentableUrl )
155
+ private fun wellKnown (file : VirtualFile ): Boolean = wellKnownSourceFiles.contains (file.name )
137
156
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 ) {
140
160
return false
141
161
}
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
153
167
}
154
168
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
+ }
160
178
161
- fun wellKnown (file : VirtualFile ): Boolean = wellKnownSourceFiles.contains(file.name)
179
+ // Any other files should not be included
180
+ return false
181
+ }
162
182
163
183
suspend fun zipFiles (projectRoot : VirtualFile , isAutoBuildFeatureEnabled : Boolean? ): File = withContext(getCoroutineBgContext()) {
164
184
val files = mutableListOf<VirtualFile >()
@@ -169,26 +189,13 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
169
189
projectRoot,
170
190
object : VirtualFileVisitor <Unit >() {
171
191
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) {
178
194
val extension = file.extension.orEmpty()
179
195
ignoredExtensionMap[extension] = (ignoredExtensionMap[extension] ? : 0 ) + 1
180
196
return false
181
197
}
182
198
183
- if (isFilterDevFile) {
184
- return false
185
- }
186
-
187
- val isFileIgnoredByPattern = runBlocking { ignoreFile(file.name) }
188
- if (isFileIgnoredByPattern) {
189
- return false
190
- }
191
-
192
199
if (file.isFile) {
193
200
totalSize + = file.length
194
201
files.add(file)
0 commit comments