mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 05:21:29 +07:00
IJPL-158385 SvnFileUrlMappingImpl - pass scope to MergingUpdateQueue instead of Disposable
GitOrigin-RevId: c3e6fa4c42cd57c99fedad533410af4e4b7f66a4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
331d6917e0
commit
cf8cf718ce
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
@@ -16,10 +15,12 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.impl.projectlevelman.MappingsToRoots;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.update.DisposableUpdate;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import kotlinx.coroutines.CoroutineScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.idea.svn.api.Url;
|
||||
import org.jetbrains.idea.svn.commandLine.SvnBindException;
|
||||
import org.jetbrains.idea.svn.info.Info;
|
||||
@@ -28,10 +29,11 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.intellij.openapi.application.ApplicationManager.getApplication;
|
||||
import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
|
||||
import static com.intellij.util.Alarm.ThreadToUse.POOLED_THREAD;
|
||||
import static com.intellij.util.containers.ContainerUtil.find;
|
||||
import static com.intellij.vcsUtil.VcsUtil.getFilePath;
|
||||
import static org.jetbrains.idea.svn.SvnFormatSelector.findRootAndGetFormat;
|
||||
@@ -39,35 +41,32 @@ import static org.jetbrains.idea.svn.SvnUtil.*;
|
||||
import static org.jetbrains.idea.svn.SvnUtilKtKt.putWcDbFilesToVfs;
|
||||
|
||||
@State(name = "SvnFileUrlMappingImpl", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
|
||||
public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentStateComponent<SvnMappingSavedPart>, Disposable {
|
||||
public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentStateComponent<SvnMappingSavedPart> {
|
||||
private static final Logger LOG = Logger.getInstance(SvnFileUrlMappingImpl.class);
|
||||
|
||||
@NotNull private final Object myMonitor = new Object();
|
||||
private final @NotNull Object myMonitor = new Object();
|
||||
// strictly: what real roots are under what vcs mappings
|
||||
@NotNull private final SvnMapping myMapping = new SvnMapping();
|
||||
private final @NotNull SvnMapping myMapping = new SvnMapping();
|
||||
// grouped; if there are several mappings one under another, will return the upmost
|
||||
@NotNull private final SvnMapping myMoreRealMapping = new SvnMapping();
|
||||
@NotNull private final List<RootUrlInfo> myErrorRoots = new ArrayList<>();
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final NestedCopiesHolder myNestedCopiesHolder = new NestedCopiesHolder();
|
||||
private final @NotNull SvnMapping myMoreRealMapping = new SvnMapping();
|
||||
private final @NotNull List<RootUrlInfo> myErrorRoots = new ArrayList<>();
|
||||
private final @NotNull Project myProject;
|
||||
private final @NotNull NestedCopiesHolder myNestedCopiesHolder = new NestedCopiesHolder();
|
||||
private boolean myInitialized;
|
||||
private boolean myInitedReloaded;
|
||||
|
||||
private final @NotNull MergingUpdateQueue myRefreshQueue =
|
||||
new MergingUpdateQueue("Refresh Working Copies", 100, true, null, this, null, POOLED_THREAD);
|
||||
private final @NotNull MergingUpdateQueue refreshQueue;
|
||||
@NotNull private final CoroutineScope coroutineScope;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private SvnFileUrlMappingImpl(@NotNull Project project) {
|
||||
private SvnFileUrlMappingImpl(@NotNull Project project, @NotNull CoroutineScope coroutineScope) {
|
||||
myProject = project;
|
||||
refreshQueue = MergingUpdateQueue.Companion.mergingUpdateQueue("Refresh Working Copies", 100, coroutineScope);
|
||||
this.coroutineScope = coroutineScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Url getUrlForFile(@NotNull File file) {
|
||||
public @Nullable Url getUrlForFile(@NotNull File file) {
|
||||
Url result = null;
|
||||
RootUrlInfo rootUrlInfo = getWcRootForFilePath(getFilePath(file));
|
||||
|
||||
@@ -84,15 +83,13 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public File getLocalPath(@NotNull Url url) {
|
||||
public @Nullable File getLocalPath(@NotNull Url url) {
|
||||
RootUrlInfo parentInfo = getWcRootForUrl(url);
|
||||
return parentInfo != null ? new File(parentInfo.getIoFile(), getRelativeUrl(parentInfo.getUrl(), url)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RootUrlInfo getWcRootForFilePath(@NotNull FilePath path) {
|
||||
public @Nullable RootUrlInfo getWcRootForFilePath(@NotNull FilePath path) {
|
||||
synchronized (myMonitor) {
|
||||
String root = myMoreRealMapping.getRootForPath(toSystemDependentName(path.toString()));
|
||||
|
||||
@@ -101,8 +98,7 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RootUrlInfo getWcRootForUrl(@NotNull Url url) {
|
||||
public @Nullable RootUrlInfo getWcRootForUrl(@NotNull Url url) {
|
||||
synchronized (myMonitor) {
|
||||
RootUrlInfo result = null;
|
||||
Url rootUrl = find(myMoreRealMapping.getUrls(), parentRootUrl -> isAncestor(parentRootUrl, url));
|
||||
@@ -122,25 +118,22 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
* Returns real working copies roots - if there is <Project Root> -> Subversion setting,
|
||||
* and there is one working copy, will return one root
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public List<RootUrlInfo> getAllWcInfos() {
|
||||
public @NotNull List<RootUrlInfo> getAllWcInfos() {
|
||||
synchronized (myMonitor) {
|
||||
return myMoreRealMapping.getAllCopies();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<RootUrlInfo> getErrorRoots() {
|
||||
public @NotNull List<RootUrlInfo> getErrorRoots() {
|
||||
synchronized (myMonitor) {
|
||||
return new ArrayList<>(myErrorRoots);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<VirtualFile> convertRoots(@NotNull List<VirtualFile> result) {
|
||||
public @NotNull List<VirtualFile> convertRoots(@NotNull List<VirtualFile> result) {
|
||||
List<VirtualFile> cachedRoots;
|
||||
List<VirtualFile> lonelyRoots;
|
||||
synchronized (myMonitor) {
|
||||
@@ -165,11 +158,11 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
}
|
||||
|
||||
public void scheduleRefresh() {
|
||||
myRefreshQueue.queue(DisposableUpdate.createDisposable(this, "refresh", () -> refresh()));
|
||||
refreshQueue.queue(Update.create("refresh", () -> refresh()));
|
||||
}
|
||||
|
||||
void scheduleRefresh(@NotNull Runnable callback) {
|
||||
myRefreshQueue.queue(DisposableUpdate.createDisposable(this, callback, () -> {
|
||||
refreshQueue.queue(Update.create(callback, () -> {
|
||||
try {
|
||||
refresh();
|
||||
}
|
||||
@@ -179,10 +172,15 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
}));
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
void waitForRefresh() throws TimeoutException {
|
||||
refreshQueue.waitForAllExecuted(5, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
SvnVcs vcs = SvnVcs.getInstance(myProject);
|
||||
VirtualFile[] roots = getNotFilteredRoots();
|
||||
SvnRootsDetector rootsDetector = new SvnRootsDetector(this, vcs, myNestedCopiesHolder);
|
||||
SvnRootsDetector rootsDetector = new SvnRootsDetector(coroutineScope, vcs, myNestedCopiesHolder);
|
||||
SvnRootsDetector.Result result = rootsDetector.detectCopyRoots(roots, init());
|
||||
|
||||
if (result != null) {
|
||||
@@ -193,9 +191,9 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
|
||||
private final class NewRootsApplier {
|
||||
|
||||
@NotNull private final SvnRootsDetector.Result myResult;
|
||||
@NotNull private final SvnMapping myNewMapping = new SvnMapping();
|
||||
@NotNull private final SvnMapping myNewFilteredMapping = new SvnMapping();
|
||||
private final @NotNull SvnRootsDetector.Result myResult;
|
||||
private final @NotNull SvnMapping myNewMapping = new SvnMapping();
|
||||
private final @NotNull SvnMapping myNewFilteredMapping = new SvnMapping();
|
||||
|
||||
private NewRootsApplier(@NotNull SvnRootsDetector.Result result) {
|
||||
myResult = result;
|
||||
@@ -281,7 +279,7 @@ public final class SvnFileUrlMappingImpl implements SvnFileUrlMapping, Persisten
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull final SvnMappingSavedPart state) {
|
||||
public void loadState(final @NotNull SvnMappingSavedPart state) {
|
||||
ProjectLevelVcsManager.getInstance(myProject).runAfterInitialization(
|
||||
() -> getApplication().executeOnPooledThread(() -> {
|
||||
SvnMapping mapping = new SvnMapping();
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.progress.ProgressManager.checkCanceled
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VfsUtilCore.virtualToIoFile
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.jetbrains.idea.svn.SvnUtil.*
|
||||
import org.jetbrains.idea.svn.api.Url
|
||||
import java.io.File
|
||||
|
||||
class SvnRootsDetector(private val parent: Disposable, private val myVcs: SvnVcs, private val myNestedCopiesHolder: NestedCopiesHolder) {
|
||||
internal class SvnRootsDetector(private val parent: CoroutineScope, private val myVcs: SvnVcs, private val myNestedCopiesHolder: NestedCopiesHolder) {
|
||||
private val myResult = Result()
|
||||
private val myRepositoryRoots = RepositoryRoots(myVcs)
|
||||
|
||||
|
||||
@@ -1,64 +1,69 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn
|
||||
|
||||
import com.intellij.ide.util.DelegatingProgressIndicator
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.job
|
||||
import org.jetbrains.concurrency.AsyncPromise
|
||||
import org.jetbrains.idea.svn.SvnUtil.getWcDb
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.stream.Collectors.toList
|
||||
|
||||
internal fun putWcDbFilesToVfs(infos: Collection<RootUrlInfo>) {
|
||||
val wcDbFiles = infos.stream()
|
||||
val wcDbFiles = infos
|
||||
.asSequence()
|
||||
.filter { it.format.isOrGreater(WorkingCopyFormat.ONE_DOT_SEVEN) }
|
||||
.filter { NestedCopyType.switched != it.type }
|
||||
.map { it.ioFile }
|
||||
.map { getWcDb(it) }
|
||||
.collect(toList())
|
||||
.map { getWcDb(it.ioFile) }
|
||||
.toList()
|
||||
|
||||
LocalFileSystem.getInstance().refreshIoFiles(wcDbFiles, true, false, null)
|
||||
}
|
||||
|
||||
internal fun <T : Any> computeAfterUpdateChanges(project: Project, parent: Disposable, block: () -> T): T? {
|
||||
internal fun <T : Any> computeAfterUpdateChanges(project: Project, parent: CoroutineScope, block: () -> T): T? {
|
||||
val promise = AsyncPromise<T>()
|
||||
val indicator = DelegatingProgressIndicator()
|
||||
val afterUpdateStarted = AtomicBoolean()
|
||||
val afterUpdateTracker = Disposable { // `afterUpdate` could be not called if project is disposed => treat dispose state manually
|
||||
if (promise.isDone) return@Disposable
|
||||
val afterUpdateTracker = t@{ // `afterUpdate` could be not called if a project is disposed => treat dispose state manually
|
||||
if (promise.isDone) return@t
|
||||
|
||||
if (indicator.isRunning) indicator.cancel()
|
||||
if (!afterUpdateStarted.get()) promise.cancel()
|
||||
}
|
||||
|
||||
Disposer.register(parent, afterUpdateTracker)
|
||||
ChangeListManager.getInstance(project).invokeAfterUpdate(false) {
|
||||
try {
|
||||
afterUpdateStarted.set(true)
|
||||
indicator.checkCanceled()
|
||||
|
||||
ProgressManager.getInstance().runProcess(
|
||||
{ promise.setResult(block()) },
|
||||
indicator
|
||||
)
|
||||
if (indicator.isRunning) {
|
||||
indicator.cancel()
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
if (!afterUpdateStarted.get()) {
|
||||
promise.cancel()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
promise.setError(e)
|
||||
}
|
||||
}
|
||||
|
||||
return try {
|
||||
promise.get()
|
||||
val handle = parent.coroutineContext.job.invokeOnCompletion {
|
||||
afterUpdateTracker()
|
||||
}
|
||||
|
||||
try {
|
||||
ChangeListManager.getInstance(project).invokeAfterUpdate(false) {
|
||||
try {
|
||||
afterUpdateStarted.set(true)
|
||||
indicator.checkCanceled()
|
||||
|
||||
ProgressManager.getInstance().runProcess(
|
||||
{ promise.setResult(block()) },
|
||||
indicator
|
||||
)
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
promise.cancel()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
promise.setError(e)
|
||||
}
|
||||
}
|
||||
return promise.get()
|
||||
}
|
||||
finally {
|
||||
Disposer.dispose(afterUpdateTracker)
|
||||
handle.dispose()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
@@ -11,6 +11,7 @@ import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.intellij.util.containers.ContainerUtil.ar;
|
||||
import static com.intellij.util.containers.ContainerUtil.map;
|
||||
@@ -156,7 +157,7 @@ public class SvnExternalTest extends SvnTestCase {
|
||||
uncommittedExternalCopyIsDetectedImpl();
|
||||
}
|
||||
|
||||
private void uncommittedExternalCopyIsDetectedImpl() {
|
||||
private void uncommittedExternalCopyIsDetectedImpl() throws TimeoutException {
|
||||
imitUpdate();
|
||||
refreshSvnMappingsSynchronously();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
@@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.intellij.testFramework.UsefulTestCase.assertExists;
|
||||
import static org.jetbrains.idea.svn.SvnUtil.parseUrl;
|
||||
@@ -496,7 +497,7 @@ public class SvnNativeClientAuthTest extends SvnTestCase {
|
||||
return file;
|
||||
}
|
||||
|
||||
private File testCheckoutImpl(@NotNull Url url) throws IOException {
|
||||
private File testCheckoutImpl(@NotNull Url url) throws IOException, TimeoutException {
|
||||
final File root = FileUtil.createTempDirectory("checkoutRoot", "");
|
||||
root.deleteOnExit();
|
||||
assertExists(root);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.svn;
|
||||
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
@@ -47,7 +47,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.intellij.openapi.application.PluginPathManager.getPluginHomePath;
|
||||
import static com.intellij.openapi.util.io.FileUtil.*;
|
||||
@@ -159,10 +159,9 @@ public abstract class SvnTestCase extends AbstractJunitVcsTestCase {
|
||||
return svnExecutable.getParentFile();
|
||||
}
|
||||
|
||||
protected void refreshSvnMappingsSynchronously() {
|
||||
CountDownLatch done = new CountDownLatch(1);
|
||||
vcs.getSvnFileUrlMappingImpl().scheduleRefresh(() -> done.countDown());
|
||||
RunAll.runAll(() -> done.await());
|
||||
protected void refreshSvnMappingsSynchronously() throws TimeoutException {
|
||||
vcs.getSvnFileUrlMappingImpl().scheduleRefresh();
|
||||
vcs.getSvnFileUrlMappingImpl().waitForRefresh();
|
||||
}
|
||||
|
||||
protected void refreshChanges() {
|
||||
|
||||
Reference in New Issue
Block a user