@Override
  public void importData(
      @NotNull Collection<DataNode<ProjectData>> toImport,
      @Nullable ProjectData projectData,
      @NotNull final Project project,
      @NotNull IdeModifiableModelsProvider modelsProvider) {
    // root project can be marked as ignored
    if (toImport.isEmpty()) return;

    if (toImport.size() != 1) {
      throw new IllegalArgumentException(
          String.format(
              "Expected to get a single project but got %d: %s", toImport.size(), toImport));
    }
    DataNode<ProjectData> node = toImport.iterator().next();
    assert projectData == node.getData();

    if (!ExternalSystemApiUtil.isOneToOneMapping(project, node)) {
      return;
    }

    if (!project.getName().equals(projectData.getInternalName())) {
      renameProject(projectData.getInternalName(), projectData.getOwner(), project);
    }
  }
Example #2
0
  /**
   * Allows to answer if given ide project has 1-1 mapping with the given external project, i.e. the
   * ide project has been imported from external system and no other external projects have been
   * added.
   *
   * <p>This might be necessary in a situation when project-level setting is changed (e.g. project
   * name). We don't want to rename ide project if it doesn't completely corresponds to the given
   * ide project then.
   *
   * @param ideProject target ide project
   * @param externalProject target external project
   * @return <code>true</code> if given ide project has 1-1 mapping to the given external project;
   *     <code>false</code> otherwise
   */
  public static boolean isOneToOneMapping(
      @NotNull Project ideProject, @NotNull DataNode<ProjectData> externalProject) {
    String linkedExternalProjectPath = null;
    for (ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
      ProjectSystemId externalSystemId = manager.getSystemId();
      AbstractExternalSystemSettings systemSettings =
          ExternalSystemApiUtil.getSettings(ideProject, externalSystemId);
      Collection projectsSettings = systemSettings.getLinkedProjectsSettings();
      int linkedProjectsNumber = projectsSettings.size();
      if (linkedProjectsNumber > 1) {
        // More than one external project of the same external system type is linked to the given
        // ide project.
        return false;
      } else if (linkedProjectsNumber == 1) {
        if (linkedExternalProjectPath == null) {
          // More than one external project of different external system types is linked to the
          // current ide project.
          linkedExternalProjectPath =
              ((ExternalProjectSettings) projectsSettings.iterator().next())
                  .getExternalProjectPath();
        } else {
          return false;
        }
      }
    }

    ProjectData projectData = externalProject.getData();
    if (linkedExternalProjectPath != null
        && !linkedExternalProjectPath.equals(projectData.getLinkedExternalProjectPath())) {
      // New external project is being linked.
      return false;
    }

    Set<String> externalModulePaths = ContainerUtilRt.newHashSet();
    for (DataNode<ModuleData> moduleNode :
        ExternalSystemApiUtil.findAll(externalProject, ProjectKeys.MODULE)) {
      externalModulePaths.add(moduleNode.getData().getLinkedExternalProjectPath());
    }
    externalModulePaths.remove(linkedExternalProjectPath);

    PlatformFacade platformFacade = ServiceManager.getService(PlatformFacade.class);
    for (Module module : platformFacade.getModules(ideProject)) {
      String path = module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY);
      if (!StringUtil.isEmpty(path) && !externalModulePaths.remove(path)) {
        return false;
      }
    }
    return externalModulePaths.isEmpty();
  }
  @Override
  public void actionPerformed(AnActionEvent e) {
    final Project project = getProject(e);
    final ProjectSystemId projectSystemId = getSystemId(e);

    final List<ExternalSystemNode> selectedNodes =
        ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext());

    final ExternalProjectInfo projectInfo;
    final ExternalSystemNode<?> externalSystemNode = ContainerUtil.getFirstItem(selectedNodes);
    if (externalSystemNode == null) {
      projectInfo =
          ContainerUtil.getFirstItem(
              ProjectDataManager.getInstance().getExternalProjectsData(project, projectSystemId));
    } else {
      final ProjectNode projectNode =
          externalSystemNode instanceof ProjectNode
              ? (ProjectNode) externalSystemNode
              : externalSystemNode.findParent(ProjectNode.class);
      assert projectNode != null;

      final ProjectData projectData = projectNode.getData();
      assert projectData != null;
      projectInfo =
          ProjectDataManager.getInstance()
              .getExternalProjectData(
                  project, projectSystemId, projectData.getLinkedExternalProjectPath());
    }

    final ExternalProjectDataSelectorDialog dialog;
    if (projectInfo != null) {
      dialog =
          new ExternalProjectDataSelectorDialog(
              project,
              projectInfo,
              externalSystemNode != null ? externalSystemNode.getData() : null);
      dialog.showAndGet();
    }
  }
  @NotNull
  private DataNode<ProjectData> doResolveProjectInfo(
      @NotNull final ProjectResolverContext resolverCtx,
      @NotNull final GradleProjectResolverExtension projectResolverChain)
      throws IllegalArgumentException, IllegalStateException {

    final ProjectImportAction projectImportAction =
        new ProjectImportAction(resolverCtx.isPreviewMode());

    // inject ProjectResolverContext into gradle project resolver extensions
    // collect extra JVM arguments provided by gradle project resolver extensions
    // and register classes of extra gradle project models required for extensions (e.g.
    // com.android.builder.model.AndroidProject)
    final List<KeyValue<String, String>> extraJvmArgs = new ArrayList<KeyValue<String, String>>();
    for (GradleProjectResolverExtension resolverExtension = projectResolverChain;
        resolverExtension != null;
        resolverExtension = resolverExtension.getNext()) {
      resolverExtension.setProjectResolverContext(resolverCtx);
      projectImportAction.addExtraProjectModelClasses(
          resolverExtension.getExtraProjectModelClasses());
      extraJvmArgs.addAll(resolverExtension.getExtraJvmArgs());
    }
    final ParametersList parametersList = new ParametersList();
    for (KeyValue<String, String> jvmArg : extraJvmArgs) {
      parametersList.addProperty(jvmArg.getKey(), jvmArg.getValue());
    }

    BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor =
        resolverCtx.getConnection().action(projectImportAction);
    GradleExecutionHelper.prepare(
        buildActionExecutor,
        resolverCtx.getExternalSystemTaskId(),
        resolverCtx.getSettings(),
        resolverCtx.getListener(),
        parametersList.getParameters(),
        resolverCtx.getConnection());

    // TODO [vlad] remove the check
    if (GradleEnvironment.USE_ENHANCED_TOOLING_API) {
      GradleExecutionHelper.setInitScript(buildActionExecutor);
    }

    ProjectImportAction.AllModels allModels;
    try {
      allModels = buildActionExecutor.run();
      if (allModels == null) {
        throw new IllegalStateException(
            "Unable to get project model for the project: " + resolverCtx.getProjectPath());
      }
    } catch (UnsupportedVersionException unsupportedVersionException) {
      // Old gradle distribution version used (before ver. 1.8)
      // fallback to use ModelBuilder gradle tooling API
      ModelBuilder<? extends IdeaProject> modelBuilder =
          myHelper.getModelBuilder(
              resolverCtx.isPreviewMode() ? BasicIdeaProject.class : IdeaProject.class,
              resolverCtx.getExternalSystemTaskId(),
              resolverCtx.getSettings(),
              resolverCtx.getConnection(),
              resolverCtx.getListener(),
              parametersList.getParameters());

      final IdeaProject ideaProject = modelBuilder.get();
      allModels = new ProjectImportAction.AllModels(ideaProject);
    }

    final BuildEnvironment buildEnvironment = getBuildEnvironment(resolverCtx);
    allModels.setBuildEnvironment(buildEnvironment);
    resolverCtx.setModels(allModels);

    // import project data
    ProjectData projectData = projectResolverChain.createProject();
    DataNode<ProjectData> projectDataNode =
        new DataNode<ProjectData>(ProjectKeys.PROJECT, projectData, null);

    // import java project data
    JavaProjectData javaProjectData = projectResolverChain.createJavaProjectData();
    projectDataNode.createChild(JavaProjectData.KEY, javaProjectData);

    IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject();
    DomainObjectSet<? extends IdeaModule> gradleModules = ideaProject.getModules();
    if (gradleModules == null || gradleModules.isEmpty()) {
      throw new IllegalStateException("No modules found for the target project: " + ideaProject);
    }
    final Map<String, Pair<DataNode<ModuleData>, IdeaModule>> moduleMap =
        ContainerUtilRt.newHashMap();

    // import modules data
    for (IdeaModule gradleModule : gradleModules) {
      if (gradleModule == null) {
        continue;
      }
      final String moduleName = gradleModule.getName();
      if (moduleName == null) {
        throw new IllegalStateException("Module with undefined name detected: " + gradleModule);
      }

      ModuleData moduleData = projectResolverChain.createModule(gradleModule, projectData);

      Pair<DataNode<ModuleData>, IdeaModule> previouslyParsedModule = moduleMap.get(moduleName);
      if (previouslyParsedModule != null) {
        throw new IllegalStateException(
            String.format(
                "Modules with duplicate name (%s) detected: '%s' and '%s'",
                moduleName, moduleData, previouslyParsedModule));
      }
      DataNode<ModuleData> moduleDataNode =
          projectDataNode.createChild(ProjectKeys.MODULE, moduleData);
      moduleMap.put(
          moduleName, new Pair<DataNode<ModuleData>, IdeaModule>(moduleDataNode, gradleModule));
    }

    // populate modules nodes
    final List<TaskData> allTasks = ContainerUtil.newArrayList();
    for (final Pair<DataNode<ModuleData>, IdeaModule> pair : moduleMap.values()) {
      final DataNode<ModuleData> moduleDataNode = pair.first;
      final IdeaModule ideaModule = pair.second;
      projectResolverChain.populateModuleExtraModels(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleContentRoots(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleCompileOutputSettings(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleDependencies(ideaModule, moduleDataNode, projectDataNode);
      final Collection<TaskData> moduleTasks =
          projectResolverChain.populateModuleTasks(ideaModule, moduleDataNode, projectDataNode);
      allTasks.addAll(moduleTasks);
    }

    // populate root project tasks
    final Collection<TaskData> rootProjectTaskCandidates =
        projectResolverChain.filterRootProjectTasks(allTasks);

    Set<Pair<String /* task name */, String /* task description */>> rootProjectTaskCandidatesMap =
        ContainerUtilRt.newHashSet();
    for (final TaskData taskData : rootProjectTaskCandidates) {
      rootProjectTaskCandidatesMap.add(Pair.create(taskData.getName(), taskData.getDescription()));
    }
    for (final Pair<String, String> p : rootProjectTaskCandidatesMap) {
      projectDataNode.createChild(
          ProjectKeys.TASK,
          new TaskData(
              GradleConstants.SYSTEM_ID,
              p.first,
              projectData.getLinkedExternalProjectPath(),
              p.second));
    }

    // ensure unique library names
    Collection<DataNode<LibraryData>> libraries =
        ExternalSystemApiUtil.getChildren(projectDataNode, ProjectKeys.LIBRARY);
    myLibraryNamesMixer.mixNames(libraries);

    return projectDataNode;
  }