4
4
package software.aws.toolkits.jetbrains.services.ecs.execution
5
5
6
6
import com.intellij.docker.dockerFile.DockerFileType
7
- import com.intellij.docker.dockerFile.parser.psi.DockerPsiCommand
8
7
import com.intellij.openapi.fileChooser.FileChooser
9
8
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
10
9
import com.intellij.openapi.project.Project
11
10
import com.intellij.openapi.project.guessProjectDir
12
11
import com.intellij.openapi.ui.Messages
13
- import com.intellij.openapi.vfs.VirtualFile
14
- import com.intellij.plugins.docker.dockerFile.parser.psi.DockerFileAddOrCopyCommand
15
- import com.intellij.plugins.docker.dockerFile.parser.psi.DockerFileCmdCommand
16
- import com.intellij.plugins.docker.dockerFile.parser.psi.DockerFileExposeCommand
17
- import com.intellij.plugins.docker.dockerFile.parser.psi.DockerFileFromCommand
18
- import com.intellij.plugins.docker.dockerFile.parser.psi.DockerFileWorkdirCommand
19
- import com.intellij.psi.PsiElement
20
- import com.intellij.psi.PsiManager
21
- import com.intellij.psi.impl.source.tree.LeafPsiElement
22
12
import software.aws.toolkits.core.utils.tryOrNull
23
13
import software.aws.toolkits.jetbrains.core.plugins.pluginIsInstalledAndEnabled
14
+ import software.aws.toolkits.jetbrains.services.ecs.execution.docker.DockerfileParser
24
15
import software.aws.toolkits.resources.message
25
16
import java.awt.event.ActionEvent
26
17
import java.awt.event.ActionListener
27
- import java.io.File
28
18
29
19
object DockerUtil {
30
20
@JvmStatic
31
21
fun dockerPluginAvailable () = pluginIsInstalledAndEnabled(" Docker" )
32
22
}
33
23
34
- class ImportFromDockerfile @JvmOverloads constructor (
24
+ class ImportFromDockerfile (
35
25
private val project : Project ,
36
26
private val view : PerContainerSettings ,
37
- private val dockerfileParser : DockerfileParser = DockerfileParser (project)
38
27
) : ActionListener {
39
28
override fun actionPerformed (e : ActionEvent ? ) {
40
29
val file = FileChooser .chooseFile(
41
30
FileChooserDescriptorFactory .createSingleFileDescriptor(DockerFileType .DOCKER_FILE_TYPE ),
42
31
project,
43
32
project.guessProjectDir()
44
33
) ? : return
45
- val details = tryOrNull { dockerfileParser .parse(file) }
34
+ val details = tryOrNull { DockerfileParser (project) .parse(file) }
46
35
if (details == null ) {
47
36
Messages .showWarningDialog(
48
37
view.component,
@@ -57,83 +46,3 @@ class ImportFromDockerfile @JvmOverloads constructor(
57
46
details.copyDirectives.map { ArtifactMapping (it.from, it.to) }.takeIf { it.isNotEmpty() }?.let { view.artifactMappingsTable.setValues(it) }
58
47
}
59
48
}
60
-
61
- class DockerfileParser (private val project : Project ) {
62
- fun parse (virtualFile : VirtualFile ): DockerfileDetails ? {
63
- val psiFile = PsiManager .getInstance(project).findFile(virtualFile)!!
64
- val contextDirectory = virtualFile.parent.path
65
-
66
- val lastFromCommand = psiFile.children.filterIsInstance<DockerFileFromCommand >().lastOrNull() ? : return null
67
- val commandsAfterLastFrom = psiFile.children.dropWhile { it != lastFromCommand }
68
- if (commandsAfterLastFrom.isEmpty()) {
69
- return null
70
- }
71
-
72
- val command = commandsAfterLastFrom.filterIsInstance<DockerFileCmdCommand >().lastOrNull()?.text?.substringAfter(" CMD " )
73
- val portMappings = commandsAfterLastFrom.filterIsInstance<DockerFileExposeCommand >().mapNotNull {
74
- it.listChildren().find { child -> (child as ? LeafPsiElement )?.elementType?.toString() == " INTEGER_LITERAL" }?.text?.toIntOrNull()
75
- }
76
-
77
- val copyDirectives = groupByWorkDir(commandsAfterLastFrom).flatMap { (workDir, commands) ->
78
- commands.filterIsInstance<DockerFileAddOrCopyCommand >()
79
- .filter { it.copyKeyword != null }
80
- .mapNotNull { cmd -> cmd.fileOrUrlList.takeIf { it.size == 2 }?.let { it.first().text to it.last().text } }
81
- .map { (rawLocal, rawRemote) ->
82
- val local = if (rawLocal.startsWith(" /" ) || rawLocal.startsWith(File .separatorChar)) {
83
- rawLocal
84
- } else {
85
- " ${contextDirectory.normalizeDirectory(true )}$rawLocal "
86
- }
87
- val remote = if (rawRemote.startsWith(" /" ) || workDir == null ) {
88
- rawRemote
89
- } else {
90
- " ${workDir.normalizeDirectory()}$rawRemote "
91
- }
92
- CopyDirective (local, remote)
93
- }
94
- }
95
-
96
- return DockerfileDetails (command, portMappings, copyDirectives)
97
- }
98
-
99
- private fun groupByWorkDir (commands : List <PsiElement >): List <Pair <String ?, List <DockerPsiCommand >>> {
100
- val list = mutableListOf<Pair <String ?, List <DockerPsiCommand >>>()
101
- var workDir: String? = null
102
- val elements = mutableListOf<DockerPsiCommand >()
103
- commands.forEach {
104
- when (it) {
105
- is DockerFileWorkdirCommand -> {
106
- if (elements.isNotEmpty()) {
107
- list.add(workDir to elements.toList())
108
- elements.clear()
109
- }
110
- workDir = it.fileOrUrlList.first().text
111
- }
112
- is DockerPsiCommand -> elements.add(it)
113
- }
114
- }
115
- if (elements.isNotEmpty()) {
116
- list.add(workDir to elements.toList())
117
- }
118
- return list
119
- }
120
-
121
- private fun PsiElement.listChildren (): List <PsiElement > {
122
- var child: PsiElement ? = firstChild ? : return emptyList()
123
- val children = mutableListOf<PsiElement >()
124
- while (child != null ) {
125
- children.add(child)
126
- child = child.nextSibling
127
- }
128
- return children.toList()
129
- }
130
- }
131
-
132
- data class DockerfileDetails (val command : String? , val exposePorts : List <Int >, val copyDirectives : List <CopyDirective >)
133
-
134
- data class CopyDirective (val from : String , val to : String )
135
-
136
- fun String.normalizeDirectory (matchPlatform : Boolean = false): String {
137
- val ch = if (matchPlatform) File .separatorChar else ' /'
138
- return " ${trimEnd(ch)}$ch "
139
- }
0 commit comments