Skip to content

Commit 4b8f9b3

Browse files
committed
feat: use custom dumper for opcodes
1 parent 13c212b commit 4b8f9b3

File tree

3 files changed

+83
-38
lines changed

3 files changed

+83
-38
lines changed
Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.github.xepozz.php_dump.services
22

3-
import com.github.xepozz.php_dump.SeparateStringBufferProcessAdapter
43
import com.github.xepozz.php_dump.command.PathMapper
54
import com.github.xepozz.php_dump.command.PhpCommandExecutor
65
import com.github.xepozz.php_dump.configuration.PhpDumpSettingsService
7-
import com.intellij.execution.configurations.GeneralCommandLine
6+
import com.intellij.execution.process.CapturingProcessAdapter
7+
import com.intellij.execution.process.ProcessOutput
88
import com.intellij.openapi.components.Service
99
import com.intellij.openapi.project.Project
1010
import kotlinx.coroutines.Dispatchers
@@ -14,49 +14,94 @@ import kotlinx.coroutines.withContext
1414
class OpcodesDumperService(var project: Project) : DumperServiceInterface {
1515
val state = PhpDumpSettingsService.getInstance(project)
1616

17-
override suspend fun dump(file: String): Any {
17+
override suspend fun dump(file: String): ProcessOutput {
1818
val debugLevel = state.debugLevel.value
19-
val preloadFile = state.preloadFile
2019

2120
val localFile = PathMapper.map(project, file)
22-
val command = GeneralCommandLine(buildList {
23-
add("-l")
24-
addAll("-d display_errors=0".split(" "))
25-
addAll("-d error_reporting=0".split(" "))
26-
27-
addAll("-d opcache.enable_cli=1".split(" "))
28-
addAll("-d opcache.save_comments=1".split(" "))
29-
addAll("-d opcache.opt_debug_level=${debugLevel}".split(" "))
30-
if (preloadFile != null) {
31-
addAll("-d opcache.preload=${preloadFile}".split(" "))
32-
}
33-
add(localFile)
34-
}).commandLineString
21+
val preloadFile = state.preloadFile.let {
22+
if (!it.isNullOrBlank()) { PathMapper.map(project, it) } else { "" }
23+
}
3524

3625
// language=injectablephp
3726
val phpSnippet = $$"""
38-
opcache_compile_file($argv[1]); passthru(PHP_BINARY . ' $$command');
27+
if (!extension_loaded('opcache') && !extension_loaded('Zend OPcache')) {
28+
exit('Error: opcache extension is not loaded');
29+
}
30+
$file = $argv[1] ?? null;
31+
32+
if (!is_string($file) || !is_file($file)) {
33+
exit('Error: Could not open input file "' . addcslashes(print_r($file, true), '"') . '"');
34+
}
35+
36+
opcache_invalidate($file);
37+
opcache_compile_file($file);
38+
39+
$iterations = 0;
40+
while (!opcache_is_script_cached($file) && $iterations++ < 10) {
41+
usleep(100);
42+
opcache_compile_file($file);
43+
}
44+
45+
if (opcache_is_script_cached($file) === false) {
46+
exit('Error: Could not compile file "' . addcslashes(print_r($file, true), '"') . '"');
47+
}
48+
49+
$temp = sys_get_temp_dir() . '/opcache_dump';
50+
51+
if (!is_dir($temp)) {
52+
@mkdir($temp);
53+
}
54+
55+
passthru(implode(' ', [
56+
PHP_BINARY, '-l',
57+
'-d', escapeshellarg('display_errors=0'),
58+
'-d', escapeshellarg('error_reporting=0'),
59+
60+
'-d', escapeshellarg('opcache.file_cache_only=1'),
61+
'-d', escapeshellarg('opcache.file_cache=' . $temp),
62+
'-d', escapeshellarg('opcache.enable=1'),
63+
'-d', escapeshellarg('opcache.enable_cli=1'),
64+
'-d', escapeshellarg('opcache.save_comments=1'),
65+
'-d', escapeshellarg('opcache.opt_debug_level=$$debugLevel'),
66+
...(!empty('$$preloadFile') ? ['-d', escapeshellarg('opcache.preload=$$preloadFile')] : []),
67+
escapeshellarg('$$localFile'),
68+
]));
69+
70+
$files = new RecursiveIteratorIterator(
71+
new RecursiveDirectoryIterator($temp, FilesystemIterator::SKIP_DOTS),
72+
RecursiveIteratorIterator::CHILD_FIRST,
73+
);
74+
75+
foreach ($files as $info) {
76+
if ($info->isDir()) {
77+
@rmdir($info->getRealPath());
78+
} else {
79+
@unlink($info->getRealPath());
80+
}
81+
}
3982
""".trimIndent()
4083

4184
// println("command: $command")
4285
// println("phpSnippet: $phpSnippet")
4386
return withContext(Dispatchers.IO) {
44-
val opcodes = StringBuilder()
45-
val errors = StringBuilder()
87+
val output = ProcessOutput()
4688

4789
PhpCommandExecutor.execute(
4890
localFile,
4991
phpSnippet,
5092
project,
51-
SeparateStringBufferProcessAdapter(stderr = opcodes, stdout = errors),
52-
("-d opcache.enable_cli=1".split(" ")),
93+
CapturingProcessAdapter(output),
94+
buildList {
95+
addAll("-d display_errors=0".split(" "))
96+
addAll("-d error_reporting=0".split(" "))
97+
98+
addAll("-d opcache.enable=1".split(" "))
99+
addAll("-d opcache.enable_cli=1".split(" "))
100+
addAll("-d opcache.save_comments=1".split(" "))
101+
},
53102
)
54103

55-
if (opcodes.isEmpty()) {
56-
errors.toString()
57-
} else {
58-
opcodes.toString()
59-
}
104+
output
60105
}
61106
}
62107
}

src/main/kotlin/com/github/xepozz/php_dump/toolWindow/panel/CustomTreePanel.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class CustomTreePanel(
8181
val service: CustomTreeDumperService = project.getService(CustomTreeDumperService::class.java)
8282
val editorProvider: EditorProvider = project.getService(EditorProvider::class.java)
8383

84+
private var showRawOutputMode = false
85+
8486
val scrollPane = JBScrollPane(tree)
8587
var contentPanel: JComponent = JPanel(BorderLayout()).apply { add(scrollPane) }
8688
val rawVirtualFile = LightVirtualFile("Raw Output", "")
@@ -96,8 +98,6 @@ class CustomTreePanel(
9698

9799
SwingUtilities.invokeLater { refreshData() }
98100
}
99-
100-
private var showRawOutput = false
101101
fun createToolbar() {
102102
val actionGroup = DefaultActionGroup().apply {
103103
add(RefreshAction { refreshData() })
@@ -110,14 +110,14 @@ class CustomTreePanel(
110110
})
111111
add(object :
112112
ToggleAction("Use Object Tokens", "Switches engine to dump lexical tokens", AllIcons.FileTypes.Json) {
113-
override fun isSelected(event: AnActionEvent): Boolean = showRawOutput
113+
override fun isSelected(event: AnActionEvent): Boolean = showRawOutputMode
114114

115115
override fun setSelected(event: AnActionEvent, value: Boolean) {
116116
println("switch content")
117117
event.presentation.icon = if (value) AllIcons.FileTypes.Json else AllIcons.FileTypes.Text
118-
showRawOutput = value
118+
showRawOutputMode = value
119119
contentPanel.components.forEach { contentPanel.remove(it) }
120-
contentPanel.add(if (showRawOutput) rawPanel else scrollPane)
120+
contentPanel.add(if (showRawOutputMode) rawPanel else scrollPane)
121121
SwingUtilities.invokeLater { contentPanel.repaint() }
122122
}
123123

@@ -218,7 +218,7 @@ class CustomTreePanel(
218218
}
219219
}
220220

221-
if (error != null) {
221+
if (!showRawOutputMode && error != null) {
222222
NotificationUtil
223223
.sendNotification(
224224
project,

src/main/kotlin/com/github/xepozz/php_dump/toolWindow/panel/OpcodesTerminalPanel.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.github.xepozz.php_dump.configuration.PhpDumpSettingsService
77
import com.github.xepozz.php_dump.configuration.PhpOpcacheDebugLevel
88
import com.github.xepozz.php_dump.services.EditorProvider
99
import com.github.xepozz.php_dump.services.OpcodesDumperService
10+
import com.intellij.execution.process.ProcessOutput
1011
import com.intellij.icons.AllIcons
1112
import com.intellij.openapi.Disposable
1213
import com.intellij.openapi.actionSystem.ActionManager
@@ -15,7 +16,7 @@ import com.intellij.openapi.actionSystem.AnAction
1516
import com.intellij.openapi.actionSystem.AnActionEvent
1617
import com.intellij.openapi.actionSystem.DefaultActionGroup
1718
import com.intellij.openapi.application.EDT
18-
import com.intellij.openapi.command.WriteCommandAction
19+
import com.intellij.openapi.application.runWriteAction
1920
import com.intellij.openapi.editor.EditorFactory
2021
import com.intellij.openapi.fileChooser.FileChooser
2122
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
@@ -169,9 +170,9 @@ class OpcodesTerminalPanel(
169170
val virtualFile = editor.virtualFile ?: return
170171

171172
CoroutineScope(Dispatchers.IO).launch {
172-
val result = service.dump(virtualFile)
173+
val result = service.dump(virtualFile) as ProcessOutput
173174

174-
val content = result
175+
val content = result.stderr.ifEmpty { result.stdout }
175176
.asSafely<String>()
176177
?.replace("\r\n", "\n")
177178
?: "No output"
@@ -183,9 +184,8 @@ class OpcodesTerminalPanel(
183184
}
184185

185186
private fun setDocumentText(project: Project, content: String) {
186-
WriteCommandAction.runWriteCommandAction(project) {
187+
runWriteAction {
187188
editor.document.setText(content)
188-
documentManager.commitDocument(editor.document)
189189
}
190190
}
191191

0 commit comments

Comments
 (0)