Skip to content

Commit

Permalink
Support of auto refresh via bsp (#502)
Browse files Browse the repository at this point in the history
There is already a file watcher that creates a popup notification with link to project refresh when BUILD file changes.
This PR updates the method that the hyperlink points to - `PantsUtil.refreshAllProjects`, so that in case of project imported from bsp rather than from pants, it would also refresh the project correctly.

Also the change in findBuildRoot was needed (look for pants root in module content roots if it was not found from .iml file) as otherwise the root module could not be found given layout generated by fastpass. Because of that the file watcher was never setup.
  • Loading branch information
lukaszwawrzyk authored Mar 12, 2020
1 parent f5a9c6e commit 9f38f76
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 43 deletions.
50 changes: 50 additions & 0 deletions common/com/twitter/intellij/pants/util/ExternalProjectUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

package com.twitter.intellij.pants.util;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;

public class ExternalProjectUtil {

public static void refresh(@NotNull Project project, ProjectSystemId id) {
// This code needs to run on the dispatch thread, but in some cases
// refreshAllProjects() is called on a non-dispatch thread; we use
// invokeLater() to run in the dispatch thread.
ApplicationManager.getApplication().invokeAndWait(
() -> {
ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveAllDocuments());

final ImportSpecBuilder specBuilder = new ImportSpecBuilder(project, id);
ProgressExecutionMode executionMode = ApplicationManager.getApplication().isUnitTestMode() ?
ProgressExecutionMode.MODAL_SYNC : ProgressExecutionMode.IN_BACKGROUND_ASYNC;
specBuilder.use(executionMode);
ExternalSystemUtil.refreshProjects(specBuilder);
});
}

public static boolean isExternalProject(@NotNull Project project, ProjectSystemId id) {
return ContainerUtil.exists(
ModuleManager.getInstance(project).getModules(),
module -> isExternalModule(module, id)
);
}

public static boolean isExternalModule(@NotNull Module module, ProjectSystemId id) {
final String systemId = module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY);
return StringUtil.equals(systemId, id.getId());
}

}
73 changes: 30 additions & 43 deletions common/com/twitter/intellij/pants/util/PantsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.internal.ExternalSystemExecuteTaskTask;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
Expand Down Expand Up @@ -303,24 +304,26 @@ public static Optional<VirtualFile> findBuildRoot(@NotNull PsiFile psiFile) {

public static Optional<VirtualFile> findBuildRoot(@NotNull Module module) {
final VirtualFile moduleFile = module.getModuleFile();
if (moduleFile != null) {
return findBuildRoot(moduleFile);
}
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
for (VirtualFile contentRoot : rootManager.getContentRoots()) {
final Optional<VirtualFile> buildRoot = findBuildRoot(contentRoot);
if (buildRoot.isPresent()) {
return buildRoot;
Optional<VirtualFile> fromModuleFile = Optional.ofNullable(moduleFile).flatMap(PantsUtil::findBuildRoot);
if (fromModuleFile.isPresent()) {
return fromModuleFile;
} else {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
for (VirtualFile contentRoot : rootManager.getContentRoots()) {
final Optional<VirtualFile> buildRoot = findBuildRoot(contentRoot);
if (buildRoot.isPresent()) {
return buildRoot;
}
}
}
for (ContentEntry contentEntry : rootManager.getContentEntries()) {
VirtualFile contentEntryFile = VirtualFileManager.getInstance().refreshAndFindFileByUrl(contentEntry.getUrl());
final Optional<VirtualFile> buildRoot = findBuildRoot(contentEntryFile);
if (buildRoot.isPresent()) {
return buildRoot;
for (ContentEntry contentEntry : rootManager.getContentEntries()) {
VirtualFile contentEntryFile = VirtualFileManager.getInstance().refreshAndFindFileByUrl(contentEntry.getUrl());
final Optional<VirtualFile> buildRoot = findBuildRoot(contentEntryFile);
if (buildRoot.isPresent()) {
return buildRoot;
}
}
return Optional.empty();
}
return Optional.empty();
}

public static Optional<VirtualFile> findBuildRoot(@Nullable VirtualFile file) {
Expand Down Expand Up @@ -499,15 +502,7 @@ public static List<String> getNonGenTargetAddresses(@NotNull List<PantsTargetAdd
}

public static boolean isPantsProject(@NotNull Project project) {
return ContainerUtil.exists(
ModuleManager.getInstance(project).getModules(),
new Condition<Module>() {
@Override
public boolean value(Module module) {
return isPantsModule(module);
}
}
);
return ExternalProjectUtil.isExternalProject(project, PantsConstants.SYSTEM_ID);
}

/**
Expand Down Expand Up @@ -536,8 +531,7 @@ class SeedPantsProjectKeys {
}

public static boolean isPantsModule(@NotNull Module module) {
final String systemId = module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY);
return StringUtil.equals(systemId, PantsConstants.SYSTEM_ID.getId());
return ExternalProjectUtil.isExternalModule(module, PantsConstants.SYSTEM_ID);
}

@NotNull
Expand Down Expand Up @@ -618,23 +612,16 @@ public static Optional<String> getRelativeProjectPath(@NotNull File workDirector
}

public static void refreshAllProjects(@NotNull Project project) {
if (!isPantsProject(project) && !isSeedPantsProject(project)) {
return;
}

// This code needs to run on the dispatch thread, but in some cases
// refreshAllProjects() is called on a non-dispatch thread; we use
// invokeLater() to run in the dispatch thread.
ApplicationManager.getApplication().invokeAndWait(
() -> {
ApplicationManager.getApplication().runWriteAction(() -> FileDocumentManager.getInstance().saveAllDocuments());

final ImportSpecBuilder specBuilder = new ImportSpecBuilder(project, PantsConstants.SYSTEM_ID);
ProgressExecutionMode executionMode = ApplicationManager.getApplication().isUnitTestMode() ?
ProgressExecutionMode.MODAL_SYNC : ProgressExecutionMode.IN_BACKGROUND_ASYNC;
specBuilder.use(executionMode);
ExternalSystemUtil.refreshProjects(specBuilder);
});
if (isPantsProject(project) || isSeedPantsProject(project)) {
ExternalProjectUtil.refresh(project, PantsConstants.SYSTEM_ID);
} else if (isBspProject(project)) {
ExternalProjectUtil.refresh(project, ProjectSystemId.findById("BSP"));
}
}

private static boolean isBspProject(Project project) {
ProjectSystemId id = ProjectSystemId.findById("BSP");
return id != null && ExternalProjectUtil.isExternalProject(project, id);
}

public static Optional<VirtualFile> findFileByAbsoluteOrRelativePath(
Expand Down

0 comments on commit 9f38f76

Please sign in to comment.