Skip to content

Commit a323866

Browse files
committed
support more use cases for compiled service path detection
1 parent 963be4b commit a323866

File tree

4 files changed

+113
-12
lines changed

4 files changed

+113
-12
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/Settings.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,6 @@
2424
)
2525
public class Settings implements PersistentStateComponent<Settings> {
2626

27-
// Default Symfony 2, 3 and 4 paths
28-
public static String[] DEFAULT_CONTAINER_PATHS = new String[] {
29-
"app/cache/dev/appDevDebugProjectContainer.xml",
30-
"var/cache/dev/appDevDebugProjectContainer.xml",
31-
"var/cache/dev/srcDevDebugProjectContainer.xml",
32-
"var/cache/dev/srcApp_KernelDevDebugContainer.xml",
33-
"var/cache/dev/App_KernelDevDebugContainer.xml" // Symfony => 4 + flex
34-
};
35-
3627
// Default Symfony 2, 3 and 4 paths
3728
public static String[] DEFAULT_ROUTES = new String[] {
3829
"app/cache/dev/appDevUrlGenerator.php",

src/main/java/fr/adrienbrault/idea/symfony2plugin/Symfony2ProjectComponent.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.intellij.openapi.wm.WindowManager;
1313
import com.intellij.psi.PsiElement;
1414
import fr.adrienbrault.idea.symfony2plugin.dic.ContainerFile;
15+
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
1516
import fr.adrienbrault.idea.symfony2plugin.extension.PluginConfigurationExtension;
1617
import fr.adrienbrault.idea.symfony2plugin.extension.ServiceContainerLoader;
1718
import fr.adrienbrault.idea.symfony2plugin.extension.ServiceContainerLoaderParameter;
@@ -110,7 +111,7 @@ public Collection<File> getContainerFiles() {
110111
}
111112

112113
if(containerFiles.size() == 0) {
113-
for (String s : Settings.DEFAULT_CONTAINER_PATHS) {
114+
for (String s : ServiceContainerUtil.getContainerFiles(project)) {
114115
containerFiles.add(new ContainerFile(s));
115116
}
116117
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package fr.adrienbrault.idea.symfony2plugin.dic.container.util;
22

33
import com.intellij.openapi.project.Project;
4+
import com.intellij.openapi.util.Key;
5+
import com.intellij.openapi.util.ModificationTracker;
6+
import com.intellij.openapi.vfs.VfsUtil;
7+
import com.intellij.openapi.vfs.VirtualFile;
48
import com.intellij.patterns.PlatformPatterns;
59
import com.intellij.psi.PsiElement;
610
import com.intellij.psi.PsiFile;
711
import com.intellij.psi.search.GlobalSearchScope;
8-
import com.intellij.psi.util.PsiTreeUtil;
12+
import com.intellij.psi.util.*;
913
import com.intellij.psi.xml.*;
1014
import com.intellij.util.Consumer;
1115
import com.intellij.util.indexing.FileBasedIndex;
@@ -37,7 +41,10 @@
3741
import org.jetbrains.yaml.YAMLUtil;
3842
import org.jetbrains.yaml.psi.*;
3943

44+
import java.time.Instant;
4045
import java.util.*;
46+
import java.util.stream.Collectors;
47+
import java.util.stream.Stream;
4148

4249
/**
4350
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -55,6 +62,11 @@ public class ServiceContainerUtil {
5562
new MethodMatcher.CallToSignature("\\Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController", "get"),
5663
};
5764

65+
private static ModificationTracker TIMED_MODIFICATION_TRACKER = new TimeSecondModificationTracker(60);
66+
67+
private static final Key<CachedValue<Collection<String>>> SYMFONY_COMPILED_TIMED_SERVICE_WATCHER = new Key<>("SYMFONY_COMPILED_TIMED_SERVICE_WATCHER");
68+
private static final Key<CachedValue<Collection<String>>> SYMFONY_COMPILED_SERVICE_WATCHER = new Key<>("SYMFONY_COMPILED_SERVICE_WATCHER");
69+
5870
private static String[] LOWER_PRIORITY = new String[] {
5971
"debug", "default", "abstract", "inner", "chain", "decorate", "delegat"
6072
};
@@ -627,4 +639,100 @@ public static List<String> getSortedServiceId(@NotNull Project project, @NotNull
627639

628640
return myIds;
629641
}
642+
643+
/**
644+
* Provide a modification on nearest second value
645+
*/
646+
private static class TimeSecondModificationTracker implements ModificationTracker {
647+
private final int expiresAfter;
648+
649+
public TimeSecondModificationTracker(int expiresAfter) {
650+
this.expiresAfter = expiresAfter;
651+
}
652+
653+
@Override
654+
public long getModificationCount() {
655+
long unixTime = Instant.now().getEpochSecond();
656+
return roundNearest(unixTime);
657+
}
658+
659+
private long roundNearest(long n) {
660+
// Smaller multiple
661+
long a = (n / this.expiresAfter) * this.expiresAfter;
662+
663+
// Larger multiple
664+
long b = a + this.expiresAfter;
665+
666+
// Return of closest of two
667+
return (n - a > b - n) ? b : a;
668+
}
669+
}
670+
671+
/**
672+
* Find compiled and cache it until any psi change occur
673+
*
674+
* - "app/cache/dev/appDevDebugProjectContainer.xml"
675+
* - ...
676+
*/
677+
public static Collection<String> getContainerFiles(@NotNull Project project) {
678+
return CachedValuesManager.getManager(project)
679+
.getCachedValue(
680+
project,
681+
SYMFONY_COMPILED_SERVICE_WATCHER,
682+
() -> CachedValueProvider.Result.create(getContainerFilesInner(project), PsiModificationTracker.MODIFICATION_COUNT),
683+
false
684+
);
685+
}
686+
687+
/**
688+
* Find possible compiled service file with seconds cache
689+
*
690+
* - "app/cache/dev/appDevDebugProjectContainer.xml"
691+
* - "var/cache/dev/appDevDebugProjectContainer.xml"
692+
* - "var/cache/dev/srcDevDebugProjectContainer.xml"
693+
* - "var/cache/dev/srcApp_KernelDevDebugContainer.xml"
694+
* - "var/cache/dev/App_KernelDevDebugContainer.xml" // Symfony => 4 + flex
695+
* - "app/cache/dev_392373729/appDevDebugProjectContainer.xml"
696+
*/
697+
private static Collection<String> getContainerFilesInner(@NotNull Project project) {
698+
return CachedValuesManager.getManager(project).getCachedValue(project, SYMFONY_COMPILED_TIMED_SERVICE_WATCHER, () -> {
699+
Set<String> files = new HashSet<>();
700+
701+
// several Symfony cache folder structures
702+
for (String root : new String[] {"var/cache", "app/cache"}) {
703+
VirtualFile baseDir = project.getBaseDir();
704+
705+
VirtualFile relativeFile = VfsUtil.findRelativeFile(root, baseDir);
706+
if (relativeFile == null) {
707+
continue;
708+
}
709+
710+
// find a dev folder eg: "dev_392373729" or just "dev"
711+
Set<VirtualFile> devFolders = Stream.of(relativeFile.getChildren())
712+
.filter(virtualFile -> virtualFile.isDirectory() && virtualFile.getName().toLowerCase().startsWith("dev"))
713+
.collect(Collectors.toSet());
714+
715+
for (VirtualFile devFolder : devFolders) {
716+
Set<String> debugContainers = Stream.of(devFolder.getChildren())
717+
.filter(virtualFile -> {
718+
if (!"xml".equalsIgnoreCase(virtualFile.getExtension())) {
719+
return false;
720+
}
721+
722+
// Some examples: App_KernelDevDebugContainer, appDevDebugProjectContainer
723+
String filename = virtualFile.getName().toLowerCase();
724+
return filename.contains("debugcontainer")
725+
|| (filename.contains("debug") && filename.contains("container"))
726+
|| (filename.contains("kernel") && filename.contains("container"));
727+
})
728+
.map(virtualFile -> VfsUtil.getRelativePath(virtualFile, baseDir, '/'))
729+
.collect(Collectors.toSet());
730+
731+
files.addAll(debugContainers);
732+
}
733+
}
734+
735+
return CachedValueProvider.Result.create(files, TIMED_MODIFICATION_TRACKER);
736+
}, false);
737+
}
630738
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/ui/ContainerSettingsForm.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.jetbrains.plugins.webDeployment.config.WebServerConfig;
1515
import fr.adrienbrault.idea.symfony2plugin.Settings;
1616
import fr.adrienbrault.idea.symfony2plugin.dic.ContainerFile;
17+
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
1718
import fr.adrienbrault.idea.symfony2plugin.ui.utils.UiSettingsUtil;
1819
import fr.adrienbrault.idea.symfony2plugin.ui.utils.dict.UiPathColumnInfo;
1920
import fr.adrienbrault.idea.symfony2plugin.ui.utils.dict.WebServerFileDialogExtensionCallback;
@@ -68,7 +69,7 @@ public void mouseClicked(MouseEvent e) {
6869
resetContainerList();
6970

7071
// add default path
71-
for (String defaultContainerPath : Settings.DEFAULT_CONTAINER_PATHS) {
72+
for (String defaultContainerPath : ServiceContainerUtil.getContainerFiles(project)) {
7273
ContainerSettingsForm.this.modelList.addRow(new ContainerFile(defaultContainerPath));
7374
}
7475

0 commit comments

Comments
 (0)