/* * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.remoteServer.util.importProject; import com.intellij.execution.RunManager; import com.intellij.execution.RunManagerListener; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.ide.actions.ImportModuleAction; import com.intellij.ide.util.importProject.RootsDetectionStep; import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.ide.util.newProjectWizard.StepSequence; import com.intellij.ide.util.projectWizard.ImportFromSourcesProvider; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.deployment.DeploymentSource; import com.intellij.remoteServer.configuration.deployment.ModuleDeploymentSource; import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerConfigurationTypesRegistrar; import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerRunConfiguration; import com.intellij.remoteServer.impl.configuration.deployment.ModuleDeploymentSourceImpl; import com.intellij.remoteServer.util.CloudBundle; import com.intellij.remoteServer.util.CloudGitDeploymentDetector; import com.intellij.remoteServer.util.CloudNotifier; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.messages.MessageBusConnection; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryChangeListener; import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import javax.swing.event.HyperlinkEvent; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author michael.golubev */ public class CloudGitRemoteDetector extends AbstractProjectComponent implements GitRepositoryChangeListener { private final GitRepositoryManager myRepositoryManager; private final CloudNotifier myNotifier; private final List<CloudTypeDelegate> myDelegates; public CloudGitRemoteDetector(Project project, GitRepositoryManager repositoryManager) { super(project); myRepositoryManager = repositoryManager; myNotifier = new CloudNotifier("Git remotes detector"); myDelegates = new ArrayList<>(); for (CloudGitDeploymentDetector deploymentDetector : CloudGitDeploymentDetector.EP_NAME.getExtensions()) { myDelegates.add(new CloudTypeDelegate(deploymentDetector)); } } @Override public void projectOpened() { MessageBusConnection connection = myProject.getMessageBus().connect(); connection.subscribe(GitRepository.GIT_REPO_CHANGE, this); connection.subscribe(RunManagerListener.TOPIC, new RunManagerListener() { @Override public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { onRunConfigurationAddedOrChanged(settings); } @Override public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { onRunConfigurationAddedOrChanged(settings); } }); } private void onRunConfigurationAddedOrChanged(RunnerAndConfigurationSettings settings) { RunConfiguration runConfiguration = settings.getConfiguration(); for (CloudTypeDelegate delegate : myDelegates) { delegate.onRunConfigurationAddedOrChanged(runConfiguration); } } @Override public void repositoryChanged(@NotNull GitRepository repository) { for (CloudTypeDelegate delegate : myDelegates) { delegate.repositoryChanged(repository); } } private class CloudTypeDelegate { private final CloudGitDeploymentDetector myDeploymentDetector; private Map<GitRepository, RepositoryNotifier> myRepositoryToNotifier = new HashMap<>(); public CloudTypeDelegate(CloudGitDeploymentDetector deploymentDetector) { myDeploymentDetector = deploymentDetector; } private ServerType getCloudType() { return myDeploymentDetector.getCloudType(); } public void repositoryChanged(@NotNull GitRepository repository) { String applicationName = myDeploymentDetector.getFirstApplicationName(repository); if (applicationName == null) { forget(repository); } else { RepositoryNotifier notifier = myRepositoryToNotifier.get(repository); if (notifier == null && !hasRunConfig4Repository(repository)) { notifier = new RepositoryNotifier(myDeploymentDetector, repository); myRepositoryToNotifier.put(repository, notifier); } if (notifier != null) { notifier.setApplicationName(applicationName); } } } private boolean hasRunConfig4Repository(GitRepository repository) { List<RunConfiguration> runConfigurations = RunManager.getInstance(myProject).getConfigurationsList(DeployToServerConfigurationTypesRegistrar.getDeployConfigurationType(getCloudType())); VirtualFile repositoryRoot = repository.getRoot(); for (RunConfiguration runConfiguration : runConfigurations) { if (repositoryRoot.equals(getContentRoot(runConfiguration))) { return true; } } return false; } private VirtualFile getContentRoot(RunConfiguration runConfiguration) { if (!(runConfiguration instanceof DeployToServerRunConfiguration)) { return null; } DeployToServerRunConfiguration deployRunConfiguration = (DeployToServerRunConfiguration)runConfiguration; if (deployRunConfiguration.getServerType() != getCloudType()) { return null; } DeploymentSource deploymentSource = deployRunConfiguration.getDeploymentSource(); if (!(deploymentSource instanceof ModuleDeploymentSource)) { return null; } return ((ModuleDeploymentSource)deploymentSource).getContentRoot(); } public void onRunConfigurationAddedOrChanged(RunConfiguration runConfiguration) { VirtualFile contentRoot = getContentRoot(runConfiguration); if (contentRoot == null) { return; } GitRepository repository = myRepositoryManager.getRepositoryForRoot(contentRoot); if (repository == null) { return; } forget(repository); } private void forget(GitRepository repository) { RepositoryNotifier notifier = myRepositoryToNotifier.remove(repository); if (notifier != null) { notifier.expire(); } } } private class RepositoryNotifier { private final CloudGitDeploymentDetector myDeploymentDetector; private final VirtualFile myRepositoryRoot; private final Notification myNotification; private final String myCloudName; private String myApplicationName; public RepositoryNotifier(CloudGitDeploymentDetector deploymentDetector, GitRepository repository) { myDeploymentDetector = deploymentDetector; myRepositoryRoot = repository.getRoot(); myCloudName = deploymentDetector.getCloudType().getPresentableName(); String path = FileUtil.toSystemDependentName(myRepositoryRoot.getPath()); myNotification = myNotifier.showMessage(CloudBundle.getText("git.cloud.app.detected", myCloudName, path), MessageType.INFO, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { setupRunConfiguration(); } }); } public void setApplicationName(String applicationName) { myApplicationName = applicationName; } public void expire() { myNotification.expire(); } public void setupRunConfiguration() { Module targetModule = null; for (Module module : ModuleManager.getInstance(myProject).getModules()) { if (myRepositoryRoot.equals(ModuleDeploymentSourceImpl.getContentRoot(module))) { targetModule = module; break; } } if (targetModule == null) { AddModuleWizard wizard = new AddModuleWizard(myProject, myRepositoryRoot.getPath(), new ImportFromSourcesProvider()); wizard.navigateToStep(step -> step instanceof RootsDetectionStep); if (wizard.getStepCount() > 0 && !wizard.showAndGet()) { return; } ImportModuleAction.createFromWizard(myProject, wizard); } else { final Ref<CloudGitChooseAccountStepBase> chooseAccountStepRef = new Ref<>(); if (!new AbstractProjectWizard(CloudBundle.getText("choose.account.wizzard.title", myCloudName), myProject, (String)null) { final StepSequence myStepSequence; { CloudGitChooseAccountStepBase chooseAccountStep = new CloudGitChooseAccountStepBase(myDeploymentDetector, myWizardContext); chooseAccountStepRef.set(chooseAccountStep); myStepSequence = new StepSequence(chooseAccountStep); addStep(chooseAccountStep); init(); } @Override public StepSequence getSequence() { return myStepSequence; } }.showAndGet()) { return; } chooseAccountStepRef.get().createRunConfiguration(targetModule, myApplicationName); } } } }