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:
Denis.Zhdanov
2013-06-17 17:15:09 +04:00
parent ec056c432d
commit 608ac91ffe
4 changed files with 66 additions and 15 deletions
@@ -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();
}
}
@@ -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);
}
}
@@ -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);
@@ -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);