mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
vcs-ignore: ability to check and populate VCS ignored file holders without full repository rescan
This commit is contained in:
@@ -1,18 +1,16 @@
|
||||
// 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.
|
||||
package com.intellij.dvcs.ignore;
|
||||
|
||||
import com.intellij.dvcs.repo.AsyncFilesManagerListener;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface VcsIgnoredHolderUpdateListener extends AsyncFilesManagerListener {
|
||||
import java.util.Collection;
|
||||
import java.util.EventListener;
|
||||
|
||||
default void updateStarted(@NotNull String ignorePath) {}
|
||||
public interface VcsIgnoredHolderUpdateListener extends EventListener {
|
||||
|
||||
default void updateFinished(@NotNull String ignorePath) {}
|
||||
|
||||
@Override
|
||||
default void updateStarted() {}
|
||||
|
||||
@Override
|
||||
default void updateFinished() {}
|
||||
default void updateFinished(@NotNull Collection<FilePath> ignoredPaths) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -15,7 +14,7 @@ public interface VcsRepositoryIgnoredFilesHolder extends Disposable {
|
||||
|
||||
void addUpdateStateListener(@NotNull VcsIgnoredHolderUpdateListener listener);
|
||||
|
||||
void startRescan(@Nullable String ignoreFilePath);
|
||||
void startRescan();
|
||||
|
||||
boolean isInUpdateMode();
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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.intellij.dvcs.repo;
|
||||
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The listener interface for handling async {@link ChangeListManager} node models updating.
|
||||
* </p>
|
||||
* <p>
|
||||
* When model starts/finishes to update itself -> updateStarted/Finished will be called for all subscribers.<br/>
|
||||
* e.g. vcs updates its ignored file model after that we should trigger ui update in ChangesView;<br/>
|
||||
* moreover, when long duration update starts we should also trigger some action;
|
||||
* </p>
|
||||
*/
|
||||
public interface AsyncFilesManagerListener extends EventListener {
|
||||
|
||||
void updateStarted();
|
||||
|
||||
void updateFinished();
|
||||
}
|
||||
@@ -8,14 +8,11 @@ import com.intellij.openapi.vcs.changes.FileHolder
|
||||
import com.intellij.openapi.vcs.changes.VcsIgnoredFilesHolder
|
||||
import com.intellij.openapi.vcs.changes.VcsModifiableDirtyScope
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.EventDispatcher
|
||||
|
||||
abstract class VcsIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
private val repositoryManager: AbstractRepositoryManager<REPOSITORY>
|
||||
) : VcsIgnoredFilesHolder {
|
||||
|
||||
private val listeners = EventDispatcher.create(VcsIgnoredHolderUpdateListener::class.java)
|
||||
|
||||
private val vcsIgnoredHolderMap =
|
||||
repositoryManager.repositories.associateTo(
|
||||
hashMapOf<REPOSITORY, VcsRepositoryIgnoredFilesHolder>()) { it to getHolder(it) }
|
||||
@@ -39,9 +36,7 @@ abstract class VcsIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
override fun values() = vcsIgnoredHolderMap.flatMap { it.value.ignoredFiles }
|
||||
|
||||
override fun startRescan() {
|
||||
fireUpdateStarted()
|
||||
vcsIgnoredHolderMap.values.forEach { it.startRescan(null) }
|
||||
fireUpdateFinished()
|
||||
vcsIgnoredHolderMap.values.forEach { it.startRescan() }
|
||||
}
|
||||
|
||||
override fun cleanAll() {
|
||||
@@ -52,12 +47,4 @@ abstract class VcsIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
repositoryManager.getRepositoryForFileQuick(file)?.let { repositoryForFile ->
|
||||
vcsIgnoredHolderMap[repositoryForFile]
|
||||
}
|
||||
|
||||
private fun fireUpdateStarted() {
|
||||
listeners.multicaster.updateStarted()
|
||||
}
|
||||
|
||||
private fun fireUpdateFinished() {
|
||||
listeners.multicaster.updateFinished()
|
||||
}
|
||||
}
|
||||
+111
-49
@@ -2,16 +2,19 @@
|
||||
package com.intellij.dvcs.ignore
|
||||
|
||||
import com.intellij.dvcs.repo.Repository
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.newvfs.events.*
|
||||
import com.intellij.util.Alarm
|
||||
import com.intellij.util.EventDispatcher
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue
|
||||
import com.intellij.util.ui.update.Update
|
||||
import com.intellij.vcsUtil.VcsUtil
|
||||
import com.intellij.vfs.AsyncVfsEventsListener
|
||||
import com.intellij.vfs.AsyncVfsEventsPostProcessor
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
@@ -22,7 +25,7 @@ abstract class VcsRepositoryIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
protected val repository: REPOSITORY,
|
||||
updateQueueName: String,
|
||||
private val rescanIdentityName: String
|
||||
) : VcsRepositoryIgnoredFilesHolder {
|
||||
) : VcsRepositoryIgnoredFilesHolder, AsyncVfsEventsListener {
|
||||
|
||||
private val inUpdateMode = AtomicBoolean(false)
|
||||
private val updateQueue = MergingUpdateQueue(updateQueueName, 500, true, null, this, null, Alarm.ThreadToUse.POOLED_THREAD)
|
||||
@@ -38,9 +41,13 @@ abstract class VcsRepositoryIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
listeners.addListener(listener, this)
|
||||
}
|
||||
|
||||
override fun addFiles(files: Collection<VirtualFile>) { SET_LOCK.write { ignoredSet.addAll(files) } }
|
||||
override fun addFiles(files: Collection<VirtualFile>) {
|
||||
SET_LOCK.write { ignoredSet.addAll(files) }
|
||||
}
|
||||
|
||||
override fun addFile(file: VirtualFile) { SET_LOCK.write { ignoredSet.add(file) } }
|
||||
override fun addFile(file: VirtualFile) {
|
||||
SET_LOCK.write { ignoredSet.add(file) }
|
||||
}
|
||||
|
||||
override fun isInUpdateMode() = inUpdateMode.get()
|
||||
|
||||
@@ -57,64 +64,46 @@ abstract class VcsRepositoryIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun requestIgnored(ignoreFilePath: String?): Set<VirtualFile>
|
||||
override fun filesChanged(events: List<VFileEvent>) {
|
||||
val affectedFiles = events
|
||||
.asSequence()
|
||||
.mapNotNull(::getAffectedFile)
|
||||
.filter { repository.root == VcsUtil.getVcsRootFor(repository.project, it) }
|
||||
.map(VcsUtil::getFilePath)
|
||||
.toList()
|
||||
|
||||
if (affectedFiles.isNotEmpty()) {
|
||||
removeIgnoredFiles(affectedFiles)
|
||||
checkIgnored(affectedFiles)
|
||||
}
|
||||
}
|
||||
|
||||
fun setupVfsListener() =
|
||||
runReadAction {
|
||||
if (repository.project.isDisposed) return@runReadAction
|
||||
AsyncVfsEventsPostProcessor.getInstance().addListener(this, this)
|
||||
}
|
||||
|
||||
protected abstract fun requestIgnored(paths: Collection<FilePath>? = null): Set<VirtualFile>
|
||||
|
||||
protected abstract fun scanTurnedOff(): Boolean
|
||||
|
||||
override fun startRescan(ignoreFilePath: String?) {
|
||||
override fun startRescan() {
|
||||
if (scanTurnedOff()) return
|
||||
|
||||
updateQueue.queue(object : Update(rescanIdentityName) {
|
||||
override fun canEat(update: Update) = true
|
||||
|
||||
override fun run() {
|
||||
if (inUpdateMode.compareAndSet(false, true)) {
|
||||
fireUpdateStarted()
|
||||
doRescan()
|
||||
inUpdateMode.set(false)
|
||||
fireUpdateFinished()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun doRescan(ignoreFilePath: String? = null) {
|
||||
val ignored = when {
|
||||
ignoreFilePath == null -> requestIgnored(null)
|
||||
isIgnoreFileUnderRepositoryRoot(ignoreFilePath)-> requestIgnored(ignoreFilePath)
|
||||
else -> return
|
||||
}
|
||||
SET_LOCK.write {
|
||||
ignoredSet.clear()
|
||||
ignoredSet.addAll(ignored)
|
||||
queueIgnoreUpdate(isFullRescan = true) {
|
||||
doRescan()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isIgnoreFileUnderRepositoryRoot(ignoreFilePath: String): Boolean {
|
||||
return repository.root == VcsUtil.getVcsRootFor(repository.project, LocalFileSystem.getInstance().findFileByPath(ignoreFilePath))
|
||||
}
|
||||
|
||||
private fun fireUpdateStarted(ignoreFilePath: String? = null) {
|
||||
when (ignoreFilePath) {
|
||||
null -> listeners.multicaster.updateStarted()
|
||||
else -> listeners.multicaster.updateStarted(ignoreFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fireUpdateFinished(ignoreFilePath: String? = null) {
|
||||
when (ignoreFilePath) {
|
||||
null -> listeners.multicaster.updateFinished()
|
||||
else -> listeners.multicaster.updateFinished(ignoreFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeIgnoredFiles(files: Collection<FilePath>): List<FilePath> {
|
||||
override fun removeIgnoredFiles(filePaths: Collection<FilePath>): MutableList<FilePath> {
|
||||
val removedIgnoredFiles = arrayListOf<FilePath>()
|
||||
val filePathsSet = filePaths.toHashSet()
|
||||
SET_LOCK.write {
|
||||
val iter = ignoredSet.iterator()
|
||||
while (iter.hasNext()) {
|
||||
val filePath = VcsUtil.getFilePath(iter.next())
|
||||
if (files.contains(filePath)) {
|
||||
if (isUnder(filePathsSet, filePath)) {
|
||||
iter.remove()
|
||||
removedIgnoredFiles.add(filePath)
|
||||
}
|
||||
@@ -122,4 +111,77 @@ abstract class VcsRepositoryIgnoredFilesHolderBase<REPOSITORY : Repository>(
|
||||
}
|
||||
return removedIgnoredFiles
|
||||
}
|
||||
|
||||
private fun checkIgnored(paths: Collection<FilePath>) {
|
||||
if (scanTurnedOff()) return
|
||||
|
||||
queueIgnoreUpdate(isFullRescan = false) {
|
||||
doCheckIgnored(paths)
|
||||
}
|
||||
}
|
||||
|
||||
private fun queueIgnoreUpdate(isFullRescan: Boolean, action: () -> Set<FilePath>) {
|
||||
updateQueue.queue(object : Update(rescanIdentityName) {
|
||||
override fun canEat(update: Update) = isFullRescan
|
||||
|
||||
override fun run() {
|
||||
if (inUpdateMode.compareAndSet(false, true)) {
|
||||
fireUpdateStarted()
|
||||
val ignored = action()
|
||||
inUpdateMode.set(false)
|
||||
fireUpdateFinished(ignored)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun doCheckIgnored(paths: Collection<FilePath>): Set<FilePath> {
|
||||
val ignored = requestIgnored(paths)
|
||||
addNotContainedIgnores(ignored)
|
||||
return ignored.map(VcsUtil::getFilePath).toSet()
|
||||
}
|
||||
|
||||
private fun addNotContainedIgnores(ignored: Set<VirtualFile>) =
|
||||
SET_LOCK.write {
|
||||
ignored.forEach { ignored ->
|
||||
if (!isUnder(ignoredSet, ignored)) {
|
||||
ignoredSet.add(ignored)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doRescan(): Set<FilePath> {
|
||||
val ignored = requestIgnored()
|
||||
SET_LOCK.write {
|
||||
ignoredSet.clear()
|
||||
ignoredSet.addAll(ignored)
|
||||
}
|
||||
return ignored.map(VcsUtil::getFilePath).toSet()
|
||||
}
|
||||
|
||||
private fun fireUpdateStarted() {
|
||||
listeners.multicaster.updateStarted()
|
||||
}
|
||||
|
||||
private fun fireUpdateFinished(paths: Collection<FilePath>) {
|
||||
listeners.multicaster.updateFinished(paths)
|
||||
}
|
||||
|
||||
private fun isUnder(parents: Set<VirtualFile>, child: VirtualFile) = generateSequence(child) { it.parent }.any { it in parents }
|
||||
private fun isUnder(parents: Set<FilePath>, child: FilePath) = generateSequence(child) { it.parentPath }.any { it in parents }
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getAffectedFile(event: VFileEvent): VirtualFile? =
|
||||
runReadAction {
|
||||
when {
|
||||
event is VFileCreateEvent && event.parent.isValid -> event.file
|
||||
event is VFileDeleteEvent || event is VFileMoveEvent || event.isRename() -> event.file
|
||||
event is VFileCopyEvent && event.newParent.isValid -> event.newParent.findChild(event.newChildName)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun VFileEvent.isRename() = this is VFilePropertyChangeEvent && propertyName == VirtualFile.PROP_NAME
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package git4idea.commands;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.branch.GitRebaseParams;
|
||||
@@ -71,7 +72,10 @@ public interface Git {
|
||||
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners);
|
||||
|
||||
@NotNull
|
||||
Set<VirtualFile> ignoredFiles(@NotNull Project project, @NotNull VirtualFile root, @Nullable VirtualFile path) throws VcsException;
|
||||
Set<VirtualFile> ignoredFiles(@NotNull Project project, @NotNull VirtualFile root, @Nullable Collection<FilePath> paths) throws VcsException;
|
||||
|
||||
@NotNull
|
||||
Set<VirtualFile> ignoredFilesNoChunk(@NotNull Project project, @NotNull VirtualFile root, @Nullable List<String> paths) throws VcsException;
|
||||
|
||||
@NotNull
|
||||
Set<VirtualFile> untrackedFiles(@NotNull Project project, @NotNull VirtualFile root,
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -74,13 +75,30 @@ public class GitImpl extends GitImplBase {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VirtualFile> ignoredFiles(@NotNull Project project, @NotNull VirtualFile root, @Nullable VirtualFile path)
|
||||
public Set<VirtualFile> ignoredFiles(@NotNull Project project, @NotNull VirtualFile root, @Nullable Collection<FilePath> paths)
|
||||
throws VcsException {
|
||||
Set<VirtualFile> ignoredFiles = new HashSet<>();
|
||||
|
||||
if (paths == null) {
|
||||
ignoredFiles.addAll(ignoredFilesNoChunk(project, root, null));
|
||||
}
|
||||
else {
|
||||
for (List<String> relativePaths : VcsFileUtil.chunkPaths(root, paths)) {
|
||||
ignoredFiles.addAll(ignoredFilesNoChunk(project, root, relativePaths));
|
||||
}
|
||||
}
|
||||
return ignoredFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VirtualFile> ignoredFilesNoChunk(@NotNull Project project, @NotNull VirtualFile root, @Nullable List<String> paths)
|
||||
throws VcsException {
|
||||
GitLineHandler h = new GitLineHandler(project, root, GitCommand.STATUS);
|
||||
h.setSilent(true);
|
||||
h.addParameters("--ignored", "--porcelain", "-z");
|
||||
if (path != null) {
|
||||
h.addParameters(path.getPath());
|
||||
if (paths != null) {
|
||||
h.addParameters(paths);
|
||||
}
|
||||
h.endOptions();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class GitIgnoredFilesHolder(val project: Project, val manager: GitRepositoryMana
|
||||
override fun createHolder() = GitIgnoredFilesHolder(project, manager)
|
||||
|
||||
override fun refresh(project: Project) {
|
||||
manager.repositories.forEach { r -> r.ignoredFilesHolder.startRescan(null) }
|
||||
manager.repositories.forEach { r -> r.ignoredFilesHolder.startRescan() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,26 +4,17 @@ package git4idea.ignore
|
||||
import com.intellij.dvcs.ignore.VcsRepositoryIgnoredFilesHolderBase
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import git4idea.commands.Git
|
||||
import git4idea.repo.GitRepository
|
||||
import java.util.*
|
||||
|
||||
class GitRepositoryIgnoredFilesHolder(private val project: Project,
|
||||
repository: GitRepository,
|
||||
private val git: Git)
|
||||
: VcsRepositoryIgnoredFilesHolderBase<GitRepository>(repository, "GitIgnoreUpdate", "gitRescanIgnored") {
|
||||
|
||||
override fun requestIgnored(ignoreFilePath: String?) =
|
||||
HashSet(git.ignoredFiles(project, repository.root, findIgnoreFileVcsRootOrDefault(ignoreFilePath)))
|
||||
|
||||
private fun findIgnoreFileVcsRootOrDefault(ignoreFilePath: String?) =
|
||||
if (ignoreFilePath != null) {
|
||||
LocalFileSystem.getInstance().findFileByPath(ignoreFilePath)?.parent ?: repository.root
|
||||
}
|
||||
else {
|
||||
repository.root
|
||||
}
|
||||
override fun requestIgnored(paths: Collection<FilePath>?) =
|
||||
HashSet(git.ignoredFiles(project, repository.root, paths))
|
||||
|
||||
override fun scanTurnedOff() = !Registry.`is`("git.process.ignored")
|
||||
}
|
||||
@@ -7,13 +7,14 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.changes.ChangesViewI;
|
||||
import com.intellij.openapi.vcs.changes.ChangesViewManager;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.util.StopWatch;
|
||||
import com.intellij.vcsUtil.VcsFileUtil;
|
||||
import git4idea.GitLocalBranch;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
@@ -84,6 +85,7 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository {
|
||||
GitRepositoryImpl repository = new GitRepositoryImpl(root, gitDir, project, project, !listenToRepoChanges);
|
||||
if (listenToRepoChanges) {
|
||||
repository.getUntrackedFilesHolder().setupVfsListener(project);
|
||||
repository.getIgnoredFilesHolder().setupVfsListener();
|
||||
repository.setupUpdater();
|
||||
notifyListenersAsync(repository);
|
||||
}
|
||||
@@ -94,7 +96,7 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository {
|
||||
GitRepositoryUpdater updater = new GitRepositoryUpdater(this, myRepositoryFiles);
|
||||
Disposer.register(this, updater);
|
||||
if (myIgnoredRepositoryFilesHolder != null) {
|
||||
myIgnoredRepositoryFilesHolder.startRescan(null);
|
||||
myIgnoredRepositoryFilesHolder.startRescan();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,43 +268,24 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository {
|
||||
|
||||
private static class MyRepositoryIgnoredHolderUpdateListener implements VcsIgnoredHolderUpdateListener {
|
||||
@NotNull private final ChangesViewI myChangesViewI;
|
||||
@NotNull private final VcsDirtyScopeManager myDirtyScopeManager;
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
MyRepositoryIgnoredHolderUpdateListener(@NotNull Project project) {
|
||||
myChangesViewI = ChangesViewManager.getInstance(project);
|
||||
myDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStarted(@NotNull String gitIgnorePath) {
|
||||
myChangesViewI.scheduleRefresh(); //TODO optimize: remove additional refresh
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStarted() {
|
||||
myChangesViewI.scheduleRefresh();
|
||||
myChangesViewI.scheduleRefresh(); //TODO optimize: remove additional refresh
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFinished(@NotNull String gitIgnorePath) {
|
||||
markGitignoreContainingFolderAsDirty(gitIgnorePath);
|
||||
public void updateFinished(@NotNull Collection<FilePath> ignoredPaths) {
|
||||
if(myProject.isDisposed()) return;
|
||||
|
||||
VcsFileUtil.markFilesDirty(myProject, ContainerUtil.newArrayList(ignoredPaths));
|
||||
myChangesViewI.scheduleRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFinished() {
|
||||
myChangesViewI.scheduleRefresh();
|
||||
}
|
||||
|
||||
private void markGitignoreContainingFolderAsDirty(@NotNull String gitIgnorePath) {
|
||||
VirtualFile gitIgnore = LocalFileSystem.getInstance().findFileByPath(gitIgnorePath);
|
||||
if (gitIgnore != null) {
|
||||
VirtualFile gitIgnoreParent = gitIgnore.getParent();
|
||||
if (gitIgnoreParent != null) {
|
||||
myDirtyScopeManager.dirDirtyRecursively(gitIgnoreParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package git4idea.repo;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
@@ -25,7 +24,7 @@ import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.events.*;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.vfs.AsyncVfsEventsListener;
|
||||
import com.intellij.vfs.AsyncVfsEventsPostProcessor;
|
||||
import git4idea.GitLocalBranch;
|
||||
@@ -36,6 +35,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.dvcs.ignore.VcsRepositoryIgnoredFilesHolderBase.getAffectedFile;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Stores files which are untracked by the Git repository.
|
||||
@@ -295,35 +296,13 @@ public class GitUntrackedFilesHolder implements Disposable, AsyncVfsEventsListen
|
||||
boolean excludeChanged = myRepositoryFiles.isExclude(path);
|
||||
|
||||
if(gitIgnoreChanged || excludeChanged){
|
||||
rescanIgnoredFiles(path);
|
||||
rescanIgnoredFiles();
|
||||
}
|
||||
return gitIgnoreChanged || excludeChanged;
|
||||
}
|
||||
|
||||
private void rescanIgnoredFiles(@NotNull String gitIgnorePath) { //TODO move to ignore manager
|
||||
myRepository.getIgnoredFilesHolder().startRescan(gitIgnorePath);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile getAffectedFile(@NotNull VFileEvent event) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (event instanceof VFileCreateEvent) {
|
||||
return ((VFileCreateEvent)event).getParent().isValid() ? event.getFile() : null;
|
||||
}
|
||||
else if (event instanceof VFileDeleteEvent || event instanceof VFileMoveEvent || isRename(event)) {
|
||||
return event.getFile();
|
||||
}
|
||||
else if (event instanceof VFileCopyEvent) {
|
||||
VFileCopyEvent copyEvent = (VFileCopyEvent) event;
|
||||
VirtualFile newParent = copyEvent.getNewParent();
|
||||
return newParent.isValid() ? newParent.findChild(copyEvent.getNewChildName()) : null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isRename(@NotNull VFileEvent event) {
|
||||
return event instanceof VFilePropertyChangeEvent && ((VFilePropertyChangeEvent)event).getPropertyName().equals(VirtualFile.PROP_NAME);
|
||||
private void rescanIgnoredFiles() { //TODO move to ignore manager
|
||||
myRepository.getIgnoredFilesHolder().startRescan();
|
||||
}
|
||||
|
||||
private boolean notIgnored(@Nullable VirtualFile file) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
@@ -112,12 +111,7 @@ public class GitVFSListener extends VcsVFSListener {
|
||||
List<VirtualFile> files = e.getValue();
|
||||
pi.setText(root.getPresentableUrl());
|
||||
try {
|
||||
Set<VirtualFile> untrackedForRepo = myGit.untrackedFiles(myProject, root, files);
|
||||
if (Registry.is("git.process.ignored")) {
|
||||
Collection<VirtualFile> ignoredForRepo = ContainerUtil.subtract(files, untrackedForRepo);
|
||||
getIgnoreRepoHolder(root).addFiles(ignoredForRepo);
|
||||
}
|
||||
retainedFiles.addAll(untrackedForRepo);
|
||||
retainedFiles.addAll(myGit.untrackedFiles(myProject, root, files));
|
||||
}
|
||||
catch (VcsException ex) {
|
||||
myVcsConsoleWriter.showMessage(ex.getMessage());
|
||||
@@ -195,7 +189,6 @@ public class GitVFSListener extends VcsVFSListener {
|
||||
@Override
|
||||
public void execute(@NotNull VirtualFile root, @NotNull List<FilePath> files) throws VcsException {
|
||||
GitFileUtils.deletePaths(myProject, root, files, "--ignore-unmatch", "--cached");
|
||||
getIgnoreRepoHolder(root).removeIgnoredFiles(files);
|
||||
if (!myProject.isDisposed()) {
|
||||
VcsFileUtil.markFilesDirty(myProject, files);
|
||||
}
|
||||
|
||||
@@ -99,8 +99,6 @@ public class HgVFSListener extends VcsVFSListener {
|
||||
Collection<VirtualFile> untrackedForRepo = new HgStatusCommand.Builder(false).unknown(true).removed(true).build(myProject)
|
||||
.getFiles(repo, new ArrayList<>(files));
|
||||
untrackedFiles.addAll(untrackedForRepo);
|
||||
List<VirtualFile> ignoredForRepo = ContainerUtil.filter(files, file -> !untrackedForRepo.contains(file));
|
||||
getIgnoreRepoHolder(repo).addFiles(ignoredForRepo);
|
||||
}
|
||||
addedFiles.retainAll(untrackedFiles);
|
||||
// select files to add if there is something to select
|
||||
|
||||
@@ -238,8 +238,13 @@ public class HgStatusCommand {
|
||||
|
||||
@NotNull
|
||||
public Collection<VirtualFile> getFiles(@NotNull VirtualFile repo, @Nullable List<VirtualFile> files) {
|
||||
return getFiles(repo, files != null ? ObjectsConvertor.vf2fp(files): null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<VirtualFile> getFiles(@NotNull VirtualFile repo, @Nullable Collection<FilePath> paths) {
|
||||
Collection<VirtualFile> resultFiles = new HashSet<>();
|
||||
Set<HgChange> change = executeInCurrentThread(repo, files != null ? ObjectsConvertor.vf2fp(files) : null);
|
||||
Set<HgChange> change = executeInCurrentThread(repo, paths);
|
||||
for (HgChange hgChange : change) {
|
||||
resultFiles.add(hgChange.afterFile().toFilePath().getVirtualFile());
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class HgIgnoredFileHolder extends VcsIgnoredFilesHolderBase<HgRepository>
|
||||
|
||||
@Override
|
||||
public void refresh(Project project) {
|
||||
myManager.getRepositories().forEach(r -> r.getIgnoredFilesHolder().startRescan(null));
|
||||
myManager.getRepositories().forEach(r -> r.getIgnoredFilesHolder().startRescan());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.zmlx.hg4idea.provider;
|
||||
|
||||
import com.intellij.dvcs.ignore.VcsRepositoryIgnoredFilesHolderBase;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -24,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.command.HgStatusCommand;
|
||||
import org.zmlx.hg4idea.repo.HgRepository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public class HgLocalIgnoredHolder extends VcsRepositoryIgnoredFilesHolderBase<HgRepository> {
|
||||
@@ -34,10 +36,10 @@ public class HgLocalIgnoredHolder extends VcsRepositoryIgnoredFilesHolderBase<Hg
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Set<VirtualFile> requestIgnored(@Nullable String ignoreFilePath) {
|
||||
protected Set<VirtualFile> requestIgnored(@Nullable Collection<? extends FilePath> paths) {
|
||||
Set<VirtualFile> ignored = ContainerUtil.newHashSet();
|
||||
ignored.addAll(new HgStatusCommand.Builder(false).ignored(true).build(repository.getProject())
|
||||
.getFiles(repository.getRoot(), null));
|
||||
.getFiles(repository.getRoot(), paths != null ? ContainerUtil.newArrayList(paths) : null));
|
||||
return ignored;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.changes.ChangesViewI;
|
||||
import com.intellij.openapi.vcs.changes.ChangesViewManager;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcsUtil.VcsFileUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.HgNameWithHashInfo;
|
||||
@@ -53,6 +55,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
|
||||
myReader = new HgRepositoryReader(vcs, VfsUtilCore.virtualToIoFile(myHgDir));
|
||||
myConfig = HgConfig.getInstance(getProject(), rootDir);
|
||||
myLocalIgnoredHolder = new HgLocalIgnoredHolder(this);
|
||||
myLocalIgnoredHolder.setupVfsListener();
|
||||
Disposer.register(this, myLocalIgnoredHolder);
|
||||
myLocalIgnoredHolder.addUpdateStateListener(new MyIgnoredHolderAsyncListener(getProject()));
|
||||
update();
|
||||
@@ -73,7 +76,7 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
|
||||
private void setupUpdater() {
|
||||
HgRepositoryUpdater updater = new HgRepositoryUpdater(this);
|
||||
Disposer.register(this, updater);
|
||||
myLocalIgnoredHolder.startRescan(null);
|
||||
myLocalIgnoredHolder.startRescan();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -254,9 +257,11 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
|
||||
|
||||
private static class MyIgnoredHolderAsyncListener implements VcsIgnoredHolderUpdateListener {
|
||||
@NotNull private final ChangesViewI myChangesViewI;
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
MyIgnoredHolderAsyncListener(@NotNull Project project) {
|
||||
myChangesViewI = ChangesViewManager.getInstance(project);
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,7 +270,10 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFinished() {
|
||||
public void updateFinished(@NotNull Collection<FilePath> ignoredPaths) {
|
||||
if(myProject.isDisposed()) return;
|
||||
|
||||
VcsFileUtil.markFilesDirty(myProject, ContainerUtil.newArrayList(ignoredPaths));
|
||||
myChangesViewI.scheduleRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ final class HgRepositoryUpdater implements Disposable, BulkFileListener {
|
||||
});
|
||||
}
|
||||
if (dirstateFileChanged || hgIgnoreChanged) {
|
||||
myRepository.getIgnoredFilesHolder().startRescan(null);
|
||||
myRepository.getIgnoredFilesHolder().startRescan();
|
||||
final VirtualFile root = myRepository.getRoot();
|
||||
myDirtyScopeManager.dirDirtyRecursively(root);
|
||||
if (dirstateFileChanged) {
|
||||
|
||||
Reference in New Issue
Block a user