mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-109042 External system: Don't perform automatic external project refresh on ide project opening if external config is up-to-date
1. Caching information about external project config file timestamp after successful refresh; 2. Don't perform auto-refresh if stored value is not less than the current timestamp;
This commit is contained in:
+28
-5
@@ -46,20 +46,22 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
= !SystemProperties.getBooleanProperty("external.system.forget.expand.nodes.state", false);
|
||||
|
||||
private final AtomicReference<Map<String/*tree path*/, Boolean/*expanded*/>> myExpandStates
|
||||
=
|
||||
=
|
||||
new AtomicReference<Map<String, Boolean>>(new HashMap<String, Boolean>());
|
||||
private final AtomicReference<List<ExternalTaskExecutionInfo>> myRecentTasks =
|
||||
private final AtomicReference<List<ExternalTaskExecutionInfo>> myRecentTasks =
|
||||
new AtomicReference<List<ExternalTaskExecutionInfo>>(
|
||||
ContainerUtilRt.<ExternalTaskExecutionInfo>newArrayList()
|
||||
);
|
||||
private final AtomicReference<Map<ExternalProjectPojo, Collection<ExternalProjectPojo>>> myAvailableProjects =
|
||||
private final AtomicReference<Map<ExternalProjectPojo, Collection<ExternalProjectPojo>>> myAvailableProjects =
|
||||
new AtomicReference<Map<ExternalProjectPojo, Collection<ExternalProjectPojo>>>(
|
||||
ContainerUtilRt.<ExternalProjectPojo, Collection<ExternalProjectPojo>>newHashMap()
|
||||
);
|
||||
private final AtomicReference<Map<String, Collection<ExternalTaskPojo>>> myAvailableTasks =
|
||||
private final AtomicReference<Map<String, Collection<ExternalTaskPojo>>> myAvailableTasks =
|
||||
new AtomicReference<Map<String, Collection<ExternalTaskPojo>>>(
|
||||
ContainerUtilRt.<String, Collection<ExternalTaskPojo>>newHashMap()
|
||||
);
|
||||
private final AtomicReference<Map<String/* external project config path */, Long>> myExternalConfigModificationStamps =
|
||||
new AtomicReference<Map<String, Long>>(ContainerUtilRt.<String, Long>newHashMap());
|
||||
|
||||
@NotNull private final ProjectSystemId myExternalSystemId;
|
||||
@NotNull private final Project myProject;
|
||||
@@ -71,7 +73,7 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
|
||||
/**
|
||||
* Asks current settings to drop all information related to external project which root config is located at the given path.
|
||||
*
|
||||
*
|
||||
* @param linkedProjectPathsToForget target root external project's path
|
||||
*/
|
||||
public void forgetExternalProject(@NotNull Set<String> linkedProjectPathsToForget) {
|
||||
@@ -101,6 +103,11 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Long> modificationStamps = myExternalConfigModificationStamps.get();
|
||||
for (String path : linkedProjectPathsToForget) {
|
||||
modificationStamps.remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@@ -135,7 +142,18 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
public void setRecentTasks(@NotNull List<ExternalTaskExecutionInfo> tasks) {
|
||||
myRecentTasks.set(tasks);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Long> getExternalConfigModificationStamps() {
|
||||
return myExternalConfigModificationStamps.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public void setExternalConfigModificationStamps(@NotNull Map<String, Long> modificationStamps) {
|
||||
// Required for IJ serialization.
|
||||
myExternalConfigModificationStamps.set(modificationStamps);
|
||||
}
|
||||
|
||||
public void fillState(@NotNull State state) {
|
||||
if (PRESERVE_EXPAND_STATE) {
|
||||
state.tasksExpandState = myExpandStates.get();
|
||||
@@ -146,12 +164,14 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
state.recentTasks = myRecentTasks.get();
|
||||
state.availableProjects = myAvailableProjects.get();
|
||||
state.availableTasks = myAvailableTasks.get();
|
||||
state.modificationStamps = myExternalConfigModificationStamps.get();
|
||||
}
|
||||
|
||||
public void loadState(@NotNull State state) {
|
||||
setIfNotNull(myExpandStates, state.tasksExpandState);
|
||||
setIfNotNull(myAvailableProjects, state.availableProjects);
|
||||
setIfNotNull(myAvailableTasks, state.availableTasks);
|
||||
setIfNotNull(myExternalConfigModificationStamps, state.modificationStamps);
|
||||
if (state.recentTasks != null) {
|
||||
List<ExternalTaskExecutionInfo> recentTasks = myRecentTasks.get();
|
||||
recentTasks.clear();
|
||||
@@ -172,5 +192,8 @@ public abstract class AbstractExternalSystemLocalSettings {
|
||||
public List<ExternalTaskExecutionInfo> recentTasks = ContainerUtilRt.newArrayList();
|
||||
public Map<ExternalProjectPojo, Collection<ExternalProjectPojo>> availableProjects = ContainerUtilRt.newHashMap();
|
||||
public Map<String/* project name */, Collection<ExternalTaskPojo>> availableTasks = ContainerUtilRt.newHashMap();
|
||||
|
||||
public Map<String/* linked project path */, Long/* last config modification stamp */> modificationStamps
|
||||
= ContainerUtilRt.newHashMap();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,6 +60,6 @@ public class RefreshAllExternalProjectsAction extends AnAction implements DumbAw
|
||||
// We save all documents because there is a possible case that there is an external system config file changed inside the ide.
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
|
||||
ExternalSystemUtil.refreshProjects(project, externalSystemId);
|
||||
ExternalSystemUtil.refreshProjects(project, externalSystemId, true);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public class ExternalSystemStartupActivity implements StartupActivity {
|
||||
public void run() {
|
||||
if (!SystemProperties.getBooleanProperty(ExternalSystemConstants.NEWLY_IMPORTED_PROJECT, false)) {
|
||||
for (ExternalSystemManager manager : ExternalSystemManager.EP_NAME.getExtensions()) {
|
||||
ExternalSystemUtil.refreshProjects(project, manager.getSystemId());
|
||||
ExternalSystemUtil.refreshProjects(project, manager.getSystemId(), false);
|
||||
}
|
||||
}
|
||||
ExternalSystemAutoImporter.letTheMagicBegin(project);
|
||||
|
||||
+36
-8
@@ -50,6 +50,8 @@ import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
@@ -160,8 +162,9 @@ public class ExternalSystemUtil {
|
||||
*
|
||||
* @param project target ide project
|
||||
* @param externalSystemId target external system which projects should be refreshed
|
||||
* @param force flag which defines if external project refresh should be performed if it's config is up-to-date
|
||||
*/
|
||||
public static void refreshProjects(@NotNull final Project project, @NotNull final ProjectSystemId externalSystemId) {
|
||||
public static void refreshProjects(@NotNull final Project project, @NotNull final ProjectSystemId externalSystemId, boolean force) {
|
||||
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
|
||||
if (manager == null) {
|
||||
return;
|
||||
@@ -173,12 +176,12 @@ public class ExternalSystemUtil {
|
||||
}
|
||||
|
||||
final ProjectDataManager projectDataManager = ServiceManager.getService(ProjectDataManager.class);
|
||||
final int[] counter = new int[1];
|
||||
|
||||
ExternalProjectRefreshCallback callback = new ExternalProjectRefreshCallback() {
|
||||
|
||||
@NotNull
|
||||
private final Set<String> myExternalModuleNames = ContainerUtilRt.newHashSet();
|
||||
private int myCounter = projectsSettings.size();
|
||||
|
||||
@Override
|
||||
public void onSuccess(@Nullable DataNode<ProjectData> externalProject) {
|
||||
@@ -190,14 +193,14 @@ public class ExternalSystemUtil {
|
||||
myExternalModuleNames.add(node.getData().getName());
|
||||
}
|
||||
projectDataManager.importData(externalProject.getKey(), Collections.singleton(externalProject), project, false);
|
||||
if (--myCounter <= 0) {
|
||||
if (--counter[0] <= 0) {
|
||||
processOrphanModules();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull String errorMessage, @Nullable String errorDetails) {
|
||||
myCounter = Integer.MAX_VALUE; // Don't process orphan modules if there was an error on refresh.
|
||||
counter[0] = Integer.MAX_VALUE; // Don't process orphan modules if there was an error on refresh.
|
||||
}
|
||||
|
||||
private void processOrphanModules() {
|
||||
@@ -211,15 +214,34 @@ public class ExternalSystemUtil {
|
||||
orphanIdeModules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!orphanIdeModules.isEmpty()) {
|
||||
ruleOrphanModules(orphanIdeModules, project, externalSystemId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Map<String, Long> modificationStamps = manager.getLocalSettingsProvider().fun(project).getExternalConfigModificationStamps();
|
||||
Set<String> toRefresh = ContainerUtilRt.newHashSet();
|
||||
for (ExternalProjectSettings setting : projectsSettings) {
|
||||
refreshProject(project, externalSystemId, setting.getExternalProjectPath(), callback, true, false);
|
||||
Long oldModificationStamp = modificationStamps.get(setting.getExternalProjectPath());
|
||||
long currentModificationStamp = getTimeStamp(setting.getExternalProjectPath());
|
||||
if (force || currentModificationStamp < 0 || oldModificationStamp == null || oldModificationStamp < currentModificationStamp) {
|
||||
toRefresh.add(setting.getExternalProjectPath());
|
||||
}
|
||||
}
|
||||
|
||||
if (!toRefresh.isEmpty()) {
|
||||
counter[0] = toRefresh.size();
|
||||
for (String path : toRefresh) {
|
||||
refreshProject(project, externalSystemId, path, callback, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long getTimeStamp(@NotNull String path) {
|
||||
VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(path));
|
||||
return vFile == null ? -1 : vFile.getTimeStamp();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,7 +254,7 @@ public class ExternalSystemUtil {
|
||||
* </ol>
|
||||
* </pre>
|
||||
* This method handles that situation, i.e. it asks a user what should be done and acts accordingly.
|
||||
*
|
||||
*
|
||||
* @param orphanModules modules which correspond to the un-linked external project
|
||||
* @param project current ide project
|
||||
* @param externalSystemId id of the external system which project has been un-linked from ide project
|
||||
@@ -336,6 +358,12 @@ public class ExternalSystemUtil {
|
||||
task.execute(indicator);
|
||||
final Throwable error = task.getError();
|
||||
if (error == null) {
|
||||
long stamp = getTimeStamp(externalProjectPath);
|
||||
if (stamp > 0) {
|
||||
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
|
||||
assert manager != null;
|
||||
manager.getLocalSettingsProvider().fun(project).getExternalConfigModificationStamps().put(externalProjectPath, stamp);
|
||||
}
|
||||
DataNode<ProjectData> externalProject = task.getExternalProject();
|
||||
callback.onSuccess(externalProject);
|
||||
return;
|
||||
@@ -347,7 +375,7 @@ public class ExternalSystemUtil {
|
||||
externalSystemId.getReadableName(), externalProjectPath, message
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
callback.onFailure(message, extractDetails(error));
|
||||
|
||||
ExternalSystemIdeNotificationManager notificationManager = ServiceManager.getService(ExternalSystemIdeNotificationManager.class);
|
||||
|
||||
Reference in New Issue
Block a user