Skip to content

Commit

Permalink
Don't write locks if both the locks and props change (#67)
Browse files Browse the repository at this point in the history
Don't write locks if both the locks and props change
  • Loading branch information
FinlayRJW authored Nov 12, 2024
1 parent 6e6d63e commit 3b8f38f
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 6 deletions.
5 changes: 5 additions & 0 deletions changelog/@unreleased/pr-67.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: fix
fix:
description: Don't write locks if both the locks and props change
links:
- https://github.com/palantir/gradle-consistent-versions-idea-plugin/pull/67
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.palantir.gradle.versions.intellij;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.vfs.AsyncFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.Alarm;
import com.intellij.util.SingleAlarm;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DebouncingAsyncFileListener implements AsyncFileListener {
private static final Logger log = LoggerFactory.getLogger(DebouncingAsyncFileListener.class);

private final AsyncFileListener delegate;
private final SingleAlarm alarm;
private final BlockingQueue<VFileEvent> bufferedEvents = new LinkedBlockingQueue<>();

DebouncingAsyncFileListener(AsyncFileListener delegate, int debounceDelayMillis, Disposable parentDisposable) {
this.delegate = delegate;
this.alarm = new SingleAlarm(
this::processEvents, debounceDelayMillis, parentDisposable, Alarm.ThreadToUse.POOLED_THREAD);
}

@Nullable
@Override
public ChangeApplier prepareChange(List<? extends VFileEvent> events) {
log.debug("Received events: {}", events);
bufferedEvents.addAll(events);
alarm.request();
return null;
}

private void processEvents() {
List<VFileEvent> eventsToProcess = new ArrayList<>();
int drained = bufferedEvents.drainTo(eventsToProcess);
if (drained == 0) {
return;
}

log.debug("Processing debounced events: {}", eventsToProcess);
AsyncFileListener.ChangeApplier applier = delegate.prepareChange(eventsToProcess);
if (applier != null) {
applier.afterVfsChange();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.palantir.gradle.versions.intellij;

import com.intellij.openapi.vfs.AsyncFileListener;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import java.util.List;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FilteringAsyncFileListener implements AsyncFileListener {
private static final Logger log = LoggerFactory.getLogger(FilteringAsyncFileListener.class);

private final AsyncFileListener delegate;
private final Predicate<VirtualFile> filter;

FilteringAsyncFileListener(AsyncFileListener delegate, Predicate<VirtualFile> filter) {
this.delegate = delegate;
this.filter = filter;
}

@Nullable
@Override
public final ChangeApplier prepareChange(List<? extends VFileEvent> events) {
List<? extends VFileEvent> filteredEvents = events.stream()
.filter(event -> {
VirtualFile file = event.getFile();
return file != null && filter.test(file);
})
.toList();

log.debug("Events after filtering {}", filteredEvents);

if (filteredEvents.isEmpty()) {
return null;
}

return delegate.prepareChange(filteredEvents);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.palantir.gradle.versions.intellij;

import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
Expand All @@ -25,6 +26,7 @@
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.AsyncFileListener;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
Expand Down Expand Up @@ -56,6 +58,12 @@ public ChangeApplier prepareChange(List<? extends VFileEvent> events) {
.filter(event -> "versions.props".equals(event.getFile().getName()))
.toList();

List<VFileContentChangeEvent> versionLockEvents = events.stream()
.filter(event -> event instanceof VFileContentChangeEvent)
.map(event -> (VFileContentChangeEvent) event)
.filter(event -> "versions.lock".equals(event.getFile().getName()))
.toList();

if (versionPropsEvents.isEmpty()) {
return null;
}
Expand All @@ -64,9 +72,12 @@ public ChangeApplier prepareChange(List<? extends VFileEvent> events) {
ProjectManager.getInstance().getOpenProjects())
.filter(Project::isInitialized)
.filter(Predicate.not(ComponentManager::isDisposed))
.filter(project -> project.getBasePath() != null)
.filter(project -> versionPropsEvents.stream()
.anyMatch(event -> event.getPath().startsWith(project.getBasePath() + "/")
&& !isFileMalformed(project, event.getFile())))
.filter(project -> versionLockEvents.stream()
.noneMatch(event -> event.getPath().startsWith(project.getBasePath())))
.toList();

return new ChangeApplier() {
Expand Down Expand Up @@ -138,12 +149,14 @@ private void refreshProject(Project project, ImportSpecBuilder importSpec) {
}

private static boolean isFileMalformed(Project project, VirtualFile file) {
PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>) () -> {
PsiFile psiFile = PsiManager.getInstance(project).findFile(file);

if (psiFile == null || !(psiFile.getFileType() instanceof VersionPropsFileType)) {
return true;
}
if (psiFile == null || !(psiFile.getFileType() instanceof VersionPropsFileType)) {
return true;
}

return PsiTreeUtil.hasErrorElements(psiFile);
return PsiTreeUtil.hasErrorElements(psiFile);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.palantir.gradle.versions.intellij;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.vfs.AsyncFileListener;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import java.util.List;
import org.jetbrains.annotations.Nullable;

public final class VersionPropsListenerRegistrar implements AsyncFileListener, Disposable {

private final FilteringAsyncFileListener changeListener;

VersionPropsListenerRegistrar() {
this.changeListener = new FilteringAsyncFileListener(
new DebouncingAsyncFileListener(new VersionPropsFileListener(), 250, this), this::isRelevantFile);
}

private boolean isRelevantFile(VirtualFile virtualFile) {
String fileName = virtualFile.getName();
return "versions.props".equals(fileName) || "versions.lock".equals(fileName);
}

@Nullable
@Override
public ChangeApplier prepareChange(List<? extends VFileEvent> events) {
return changeListener.prepareChange(events);
}

@Override
public void dispose() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<completion.contributor language="VersionProps"
implementationClass="com.palantir.gradle.versions.intellij.FolderCompletionContributor"/>
<lang.commenter language="VersionProps" implementationClass="com.palantir.gradle.versions.intellij.VersionPropsCommenter"/>
<vfs.asyncListener implementation="com.palantir.gradle.versions.intellij.VersionPropsFileListener"/>
<vfs.asyncListener implementation="com.palantir.gradle.versions.intellij.VersionPropsListenerRegistrar"/>
<annotator language="VersionProps" implementationClass="com.palantir.gradle.versions.intellij.CommentAnnotator" />
<externalSystemTaskNotificationListener implementation="com.palantir.gradle.versions.intellij.LoadCacheOnGradleProjectRefresh" />
<applicationService serviceImplementation="com.palantir.gradle.versions.intellij.GradleCacheExplorer" />
Expand Down

0 comments on commit 3b8f38f

Please sign in to comment.