FUS: increment `toolwindow` group version
[idea/community.git] / java / idea-ui / src / org / jetbrains / idea / maven / utils / library / RepositoryUtils.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.idea.maven.utils.library;
3
4 import com.intellij.ide.JavaUiBundle;
5 import com.intellij.jarRepository.JarRepositoryManager;
6 import com.intellij.jarRepository.RepositoryLibraryType;
7 import com.intellij.notification.Notification;
8 import com.intellij.notification.NotificationType;
9 import com.intellij.notification.Notifications;
10 import com.intellij.openapi.application.ApplicationManager;
11 import com.intellij.openapi.application.WriteAction;
12 import com.intellij.openapi.diagnostic.Logger;
13 import com.intellij.openapi.project.Project;
14 import com.intellij.openapi.roots.AnnotationOrderRootType;
15 import com.intellij.openapi.roots.JavadocOrderRootType;
16 import com.intellij.openapi.roots.OrderRootType;
17 import com.intellij.openapi.roots.impl.libraries.LibraryEx;
18 import com.intellij.openapi.roots.libraries.Library;
19 import com.intellij.openapi.roots.libraries.ui.OrderRoot;
20 import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
21 import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
22 import com.intellij.openapi.util.io.FileUtil;
23 import com.intellij.openapi.util.text.StringUtil;
24 import com.intellij.openapi.vfs.JarFileSystem;
25 import com.intellij.openapi.vfs.VfsUtilCore;
26 import com.intellij.util.PathUtil;
27 import com.intellij.util.containers.JBIterable;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30 import org.jetbrains.concurrency.AsyncPromise;
31 import org.jetbrains.concurrency.Promise;
32 import org.jetbrains.concurrency.Promises;
33
34 import java.util.*;
35 import java.util.stream.Collectors;
36
37 public final class RepositoryUtils {
38   private static final Logger LOG = Logger.getInstance(RepositoryUtils.class);
39
40   public static boolean libraryHasSources(@Nullable Library library) {
41     return library != null && library.getUrls(OrderRootType.SOURCES).length > 0;
42   }
43
44   public static boolean libraryHasSources(@Nullable LibraryEditor libraryEditor) {
45     return libraryEditor != null && libraryEditor.getUrls(OrderRootType.SOURCES).length > 0;
46   }
47
48   public static boolean libraryHasJavaDocs(@Nullable Library library) {
49     return library != null && library.getUrls(JavadocOrderRootType.getInstance()).length > 0;
50   }
51
52   public static boolean libraryHasJavaDocs(@Nullable LibraryEditor libraryEditor) {
53     return libraryEditor != null && libraryEditor.getUrls(JavadocOrderRootType.getInstance()).length > 0;
54   }
55
56   public static boolean libraryHasExternalAnnotations(@Nullable LibraryEditor libraryEditor) {
57     return libraryEditor != null && libraryEditor.getUrls(AnnotationOrderRootType.getInstance()).length > 0;
58   }
59
60   public static String getStorageRoot(Library library, Project project) {
61     return getStorageRoot(library.getUrls(OrderRootType.CLASSES), project);
62   }
63
64
65   public static String getStorageRoot(String[] urls, Project project) {
66     if (urls.length == 0) {
67       return null;
68     }
69     final String localRepositoryPath = FileUtil.toSystemIndependentName(JarRepositoryManager.getLocalRepositoryPath().getAbsolutePath());
70     List<String> roots = JBIterable.of(urls).transform(urlWithPrefix -> {
71       String url = StringUtil.trimStart(urlWithPrefix, JarFileSystem.PROTOCOL_PREFIX);
72       return url.startsWith(localRepositoryPath) ? null : FileUtil.toSystemDependentName(PathUtil.getParentPath(url));
73     }).toList();
74     final Map<String, Integer> counts = new HashMap<>();
75     for (String root : roots) {
76       final Integer count = counts.get(root);
77       counts.put(root, count != null ? count + 1 : 1);
78     }
79     return Collections.max(counts.entrySet(), Map.Entry.comparingByValue()).getKey();
80   }
81
82   public static Promise<List<OrderRoot>> loadDependenciesToLibrary(@NotNull final Project project,
83                                                                    @NotNull final LibraryEx library,
84                                                                    boolean downloadSources,
85                                                                    boolean downloadJavaDocs,
86                                                                    @Nullable String copyTo) {
87     if (library.getKind() != RepositoryLibraryType.REPOSITORY_LIBRARY_KIND) {
88       return Promises.resolvedPromise(Collections.emptyList());
89     }
90     final RepositoryLibraryProperties properties = (RepositoryLibraryProperties)library.getProperties();
91     String[] annotationUrls = library.getUrls(AnnotationOrderRootType.getInstance());
92     String[] excludedRootUrls = library.getExcludedRootUrls();
93
94     return JarRepositoryManager.loadDependenciesAsync(
95       project, properties, downloadSources, downloadJavaDocs, null, copyTo).thenAsync(roots -> {
96       AsyncPromise<List<OrderRoot>> promise = new AsyncPromise<>();
97       ApplicationManager.getApplication().invokeLater(
98         roots == null || roots.isEmpty() ?
99         () -> {
100           String message = JavaUiBundle.message("notification.content.no.files.were.downloaded", properties.getMavenId());
101           Notifications.Bus.notify(new Notification("Repository", JavaUiBundle.message(
102             "notification.title.repository.library.synchronization"),
103                                                     message, NotificationType.ERROR), project);
104           promise.setError(message);
105         } :
106         () -> {
107           if (!library.isDisposed()) {
108             LOG.debug("Loaded dependencies for '" + properties.getMavenId() + "' repository library");
109             WriteAction.run(() -> {
110               final NewLibraryEditor editor = new NewLibraryEditor(null, properties);
111               editor.setKeepInvalidUrls(false);
112               editor.removeAllRoots();
113               editor.addRoots(roots);
114               for (String url : annotationUrls) {
115                 editor.addRoot(url, AnnotationOrderRootType.getInstance());
116               }
117               List<String> allRootUrls = editor.getOrderRootTypes().stream()
118                                                .flatMap(type -> Arrays.stream(editor.getUrls(type)))
119                                                .collect(Collectors.toList());
120               for (String excludedRootUrl: excludedRootUrls) {
121                 if (VfsUtilCore.isUnder(excludedRootUrl, allRootUrls)) {
122                   editor.addExcludedRoot(excludedRootUrl);
123                 }
124               }
125               final LibraryEx.ModifiableModelEx model = library.getModifiableModel();
126               editor.applyTo(model);
127               model.commit();
128             });
129           }
130           promise.setResult(roots);
131         });
132       return promise;
133     });
134   }
135
136   public static Promise<List<OrderRoot>> reloadDependencies(@NotNull final Project project, @NotNull final LibraryEx library) {
137     return loadDependenciesToLibrary(project, library, libraryHasSources(library), libraryHasJavaDocs(library), getStorageRoot(library, project));
138   }
139 }