| /* |
| * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.codeInsight; |
| |
| import com.intellij.ProjectTopics; |
| import com.intellij.openapi.components.ServiceManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.externalSystem.model.DataNode; |
| import com.intellij.openapi.externalSystem.model.project.ProjectData; |
| import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; |
| import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; |
| import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; |
| import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; |
| import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; |
| import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; |
| import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; |
| import com.intellij.openapi.fileEditor.FileEditor; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleUtilCore; |
| import com.intellij.openapi.progress.ProcessCanceledException; |
| import com.intellij.openapi.project.IndexNotReadyException; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ModuleRootAdapter; |
| import com.intellij.openapi.roots.ModuleRootEvent; |
| import com.intellij.openapi.roots.ex.ProjectRootManagerEx; |
| import com.intellij.openapi.util.Key; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.LocalFileSystem; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.ui.EditorNotificationPanel; |
| import com.intellij.ui.EditorNotifications; |
| import org.gradle.util.GUtil; |
| import org.gradle.wrapper.WrapperConfiguration; |
| import org.gradle.wrapper.WrapperExecutor; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.plugins.gradle.settings.DistributionType; |
| import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; |
| import org.jetbrains.plugins.gradle.settings.GradleSettings; |
| import org.jetbrains.plugins.gradle.util.GradleBundle; |
| import org.jetbrains.plugins.gradle.util.GradleConstants; |
| import org.jetbrains.plugins.gradle.util.GradleUtil; |
| |
| import java.io.File; |
| import java.net.URI; |
| import java.util.Collections; |
| import java.util.Properties; |
| import java.util.regex.Pattern; |
| |
| /** |
| * @author Vladislav.Soroka |
| * @since 9/13/13 |
| */ |
| public class UseDistributionWithSourcesNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> { |
| public static final Pattern GRADLE_SRC_DISTRIBUTION_PATTERN; |
| private static final Logger LOG = Logger.getInstance("#" + UseDistributionWithSourcesNotificationProvider.class.getName()); |
| private static final Key<EditorNotificationPanel> KEY = Key.create("gradle.notifications.use.distribution.with.sources"); |
| private static final String ALL_ZIP_DISTRIBUTION_URI_SUFFIX = "-all.zip"; |
| private final Project myProject; |
| |
| static { |
| GRADLE_SRC_DISTRIBUTION_PATTERN = Pattern.compile("https?\\\\?://services\\.gradle\\.org.*" + ALL_ZIP_DISTRIBUTION_URI_SUFFIX); |
| } |
| |
| public UseDistributionWithSourcesNotificationProvider(Project project, final EditorNotifications notifications) { |
| myProject = project; |
| project.getMessageBus().connect(project).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { |
| @Override |
| public void rootsChanged(ModuleRootEvent event) { |
| notifications.updateAllNotifications(); |
| } |
| }); |
| } |
| |
| @NotNull |
| @Override |
| public Key<EditorNotificationPanel> getKey() { |
| return KEY; |
| } |
| |
| @Override |
| public EditorNotificationPanel createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) { |
| try { |
| if (GradleConstants.DEFAULT_SCRIPT_NAME.equals(file.getName()) || |
| GradleConstants.SETTINGS_FILE_NAME.equals(file.getName())) { |
| |
| final Module module = ModuleUtilCore.findModuleForFile(file, myProject); |
| if (module == null) return null; |
| final String rootProjectPath = getRootProjectPath(module); |
| if (rootProjectPath == null) return null; |
| final GradleProjectSettings settings = GradleSettings.getInstance(module.getProject()).getLinkedProjectSettings(rootProjectPath); |
| if (settings == null || settings.getDistributionType() != DistributionType.DEFAULT_WRAPPED) return null; |
| if (settings.isDisableWrapperSourceDistributionNotification()) return null; |
| if (isWrapperDistributionWithSourcesUsed(rootProjectPath)) return null; |
| |
| final EditorNotificationPanel panel = new EditorNotificationPanel(); |
| panel.setText(GradleBundle.message("gradle.notifications.use.distribution.with.sources")); |
| panel.createActionLabel(GradleBundle.message("gradle.notifications.hide.tip"), new Runnable() { |
| @Override |
| public void run() { |
| settings.setDisableWrapperSourceDistributionNotification(true); |
| EditorNotifications.getInstance(module.getProject()).updateAllNotifications(); |
| } |
| }); |
| panel.createActionLabel(GradleBundle.message("gradle.notifications.apply.suggestion"), new Runnable() { |
| @Override |
| public void run() { |
| updateDefaultWrapperConfiguration(rootProjectPath); |
| EditorNotifications.getInstance(module.getProject()).updateAllNotifications(); |
| final ProjectDataManager projectDataManager = ServiceManager.getService(ProjectDataManager.class); |
| ExternalSystemUtil.refreshProject( |
| module.getProject(), GradleConstants.SYSTEM_ID, settings.getExternalProjectPath(), |
| new ExternalProjectRefreshCallback() { |
| @Override |
| public void onSuccess(@Nullable final DataNode<ProjectData> externalProject) { |
| if (externalProject == null) { |
| return; |
| } |
| ExternalSystemApiUtil.executeProjectChangeAction(true, new DisposeAwareProjectChange(module.getProject()) { |
| @Override |
| public void execute() { |
| ProjectRootManagerEx.getInstanceEx(module.getProject()).mergeRootsChangesDuring(new Runnable() { |
| @Override |
| public void run() { |
| projectDataManager.importData(externalProject.getKey(), Collections.singleton(externalProject), module.getProject(), true); |
| } |
| }); |
| } |
| }); |
| } |
| |
| @Override |
| public void onFailure(@NotNull String errorMessage, @Nullable String errorDetails) { |
| } |
| }, true, ProgressExecutionMode.START_IN_FOREGROUND_ASYNC); |
| } |
| }); |
| return panel; |
| } |
| } |
| catch (ProcessCanceledException ignored) { |
| } |
| catch (IndexNotReadyException ignored) { |
| } |
| |
| return null; |
| } |
| |
| private static void updateDefaultWrapperConfiguration(@NotNull String linkedProjectPath) { |
| try { |
| final File wrapperPropertiesFile = GradleUtil.findDefaultWrapperPropertiesFile(linkedProjectPath); |
| if (wrapperPropertiesFile == null) return; |
| final WrapperConfiguration wrapperConfiguration = GradleUtil.getWrapperConfiguration(linkedProjectPath); |
| if (wrapperConfiguration == null) return; |
| String currentDistributionUri = wrapperConfiguration.getDistribution().toString(); |
| if (StringUtil.endsWith(currentDistributionUri, ALL_ZIP_DISTRIBUTION_URI_SUFFIX)) return; |
| |
| final String distributionUri = |
| currentDistributionUri.substring(0, currentDistributionUri.lastIndexOf('-')) + ALL_ZIP_DISTRIBUTION_URI_SUFFIX; |
| |
| wrapperConfiguration.setDistribution(new URI(distributionUri)); |
| Properties wrapperProperties = new Properties(); |
| wrapperProperties.setProperty(WrapperExecutor.DISTRIBUTION_URL_PROPERTY, wrapperConfiguration.getDistribution().toString()); |
| wrapperProperties.setProperty(WrapperExecutor.DISTRIBUTION_BASE_PROPERTY, wrapperConfiguration.getDistributionBase()); |
| wrapperProperties.setProperty(WrapperExecutor.DISTRIBUTION_PATH_PROPERTY, wrapperConfiguration.getDistributionPath()); |
| wrapperProperties.setProperty(WrapperExecutor.ZIP_STORE_BASE_PROPERTY, wrapperConfiguration.getZipBase()); |
| wrapperProperties.setProperty(WrapperExecutor.ZIP_STORE_PATH_PROPERTY, wrapperConfiguration.getZipPath()); |
| GUtil.saveProperties(wrapperProperties, new File(wrapperPropertiesFile.getPath())); |
| LocalFileSystem.getInstance().refreshIoFiles(Collections.singletonList(wrapperPropertiesFile)); |
| } |
| catch (Exception e) { |
| LOG.error(e); |
| } |
| } |
| |
| private static boolean isWrapperDistributionWithSourcesUsed(String linkedProjectPath) { |
| WrapperConfiguration wrapperConfiguration = GradleUtil.getWrapperConfiguration(linkedProjectPath); |
| // currently only wrapped distribution takes into account |
| if (wrapperConfiguration == null) return true; |
| String distributionUri = wrapperConfiguration.getDistribution().toString(); |
| return GRADLE_SRC_DISTRIBUTION_PATTERN.matcher(distributionUri).matches(); |
| } |
| |
| @Nullable |
| private static String getRootProjectPath(@NotNull Module module) { |
| String externalSystemId = module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY); |
| if (externalSystemId == null || !GradleConstants.SYSTEM_ID.toString().equals(externalSystemId)) { |
| return null; |
| } |
| |
| String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); |
| return StringUtil.isEmpty(path) ? null : path; |
| } |
| } |