com.twitter.intellij.pants.components.impl.PantsProjectComponentImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.twitter.intellij.pants.components.impl.PantsProjectComponentImpl.java

Source

// Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

package com.twitter.intellij.pants.components.impl;

import com.intellij.compiler.server.BuildManagerListener;
import com.intellij.execution.RunManagerAdapter;
import com.intellij.execution.RunManagerEx;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.messages.MessageBusConnection;
import com.twitter.intellij.pants.PantsBundle;
import com.twitter.intellij.pants.components.PantsProjectComponent;
import com.twitter.intellij.pants.execution.PantsMakeBeforeRun;
import com.twitter.intellij.pants.service.project.PantsResolver;
import com.twitter.intellij.pants.settings.PantsProjectSettings;
import com.twitter.intellij.pants.settings.PantsSettings;
import com.twitter.intellij.pants.util.PantsConstants;
import com.twitter.intellij.pants.util.PantsUtil;
import icons.PantsIcons;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.List;
import java.util.UUID;

public class PantsProjectComponentImpl extends AbstractProjectComponent implements PantsProjectComponent {
    protected PantsProjectComponentImpl(Project project) {
        super(project);
    }

    @Override
    public void projectOpened() {
        super.projectOpened();
        if (myProject.isDefault()) {
            return;
        }
        StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
            @Override
            public void run() {
                /**
                 * Set project to allow dynamic classpath for JUnit run. Still requires any junit run to specify dynamic classpath in
                 * {@link com.twitter.intellij.pants.execution.PantsClasspathRunConfigurationExtension#updateJavaParameters}
                 * IDEA's logic: {@link com.intellij.execution.configurations.CommandLineBuilder}
                 */
                PropertiesComponent.getInstance(myProject).setValue("dynamic.classpath", true);

                if (PantsUtil.isSeedPantsProject(myProject)) {
                    convertToPantsProject();
                }

                registerExternalBuilderListener();
                subscribeToRunConfigurationAddition();
                final AbstractExternalSystemSettings pantsSettings = ExternalSystemApiUtil.getSettings(myProject,
                        PantsConstants.SYSTEM_ID);
                final boolean resolverVersionMismatch = pantsSettings instanceof PantsSettings
                        && ((PantsSettings) pantsSettings).getResolverVersion() != PantsResolver.VERSION;
                if (resolverVersionMismatch && PantsUtil.isPantsProject(myProject)) {
                    final int answer = Messages.showYesNoDialog(myProject,
                            PantsBundle.message("pants.project.generated.with.old.version", myProject.getName()),
                            PantsBundle.message("pants.name"), PantsIcons.Icon);
                    if (answer == Messages.YES) {
                        PantsUtil.refreshAllProjects(myProject);
                    }
                }
            }

            /**
             * To convert a seed Pants project to a full bloom pants project:
             * 1. Obtain the targets and project_path generated by `pants idea-plugin` from
             * workspace file `project.iws` via `PropertiesComponent` API.
             * 2. Generate a refresh spec based on the info above.
             * 3. Explicitly call {@link PantsUtil#refreshAllProjects}.
             */
            private void convertToPantsProject() {
                String serializedTargets = PropertiesComponent.getInstance(myProject).getValue("targets");
                String projectPath = PropertiesComponent.getInstance(myProject).getValue("project_path");
                if (serializedTargets == null || projectPath == null) {
                    return;
                }

                /**
                 * Generate the import spec for the next refresh.
                 */
                final List<String> targetSpecs = PantsUtil.gson.fromJson(serializedTargets,
                        PantsUtil.TYPE_LIST_STRING);
                final PantsProjectSettings pantsProjectSettings = new PantsProjectSettings(targetSpecs, projectPath,
                        false, true);

                /**
                 * Following procedures in {@link com.intellij.openapi.externalSystem.util.ExternalSystemUtil#refreshProjects}:
                 * Make sure the setting is injected into the project for refresh.
                 */
                ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil
                        .getManager(PantsConstants.SYSTEM_ID);
                if (manager == null) {
                    return;
                }
                AbstractExternalSystemSettings settings = manager.getSettingsProvider().fun(myProject);
                settings.setLinkedProjectsSettings(Collections.singleton(pantsProjectSettings));
                PantsUtil.refreshAllProjects(myProject);

                prepareGuiComponents();
            }

            /**
             * Ensure GUI is set correctly because empty IntelliJ project (seed project in this case)
             * does not have these set by default.
             * 1. Make sure the project view is opened so view switch will follow.
             * 2. Pants tool window is initialized; otherwise no message can be shown when invoking `PantsCompile`.
             */
            private void prepareGuiComponents() {
                if (!ApplicationManager.getApplication().isUnitTestMode()) {
                    if (ToolWindowManager.getInstance(myProject).getToolWindow("Project") != null) {
                        ToolWindowManager.getInstance(myProject).getToolWindow("Project").show(null);
                    }
                    ExternalSystemUtil.ensureToolWindowInitialized(myProject, PantsConstants.SYSTEM_ID);
                }
            }

            private void subscribeToRunConfigurationAddition() {
                RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerAdapter() {
                    @Override
                    public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) {
                        super.runConfigurationAdded(settings);
                        if (!PantsUtil.isPantsProject(myProject) && !PantsUtil.isSeedPantsProject(myProject)) {
                            return;
                        }
                        if (!PantsSettings.getInstance(myProject).isUsePantsMakeBeforeRun()) {
                            return;
                        }
                        PantsMakeBeforeRun.replaceDefaultMakeWithPantsMake(myProject, settings);
                    }
                });
            }
        });
    }

    /**
     * This registers the listener when IDEA external builder process calls Pants.
     */
    private void registerExternalBuilderListener() {
        MessageBusConnection connection = myProject.getMessageBus().connect();
        BuildManagerListener buildManagerListener = new BuildManagerListener() {
            @Override
            public void beforeBuildProcessStarted(Project project, UUID sessionId) {

            }

            @Override
            public void buildStarted(Project project, UUID sessionId, boolean isAutomake) {

            }

            @Override
            public void buildFinished(Project project, UUID sessionId, boolean isAutomake) {
                /**
                 * Sync files as generated sources may have changed after external compile,
                 * specifically when {@link com.twitter.intellij.pants.jps.incremental.PantsTargetBuilder} finishes,
                 * except this code is run within IDEA core, thus having access to file sync calls.
                 */
                PantsUtil.synchronizeFiles();
            }
        };
        connection.subscribe(BuildManagerListener.TOPIC, buildManagerListener);
    }
}