1 /*******************************************************************************
2 * Copyright (C) 2019, Alexander Nittka <alex@nittka.de> and others.
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11 package org
.eclipse
.egit
.ui
.internal
.groups
;
14 import java
.text
.MessageFormat
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collection
;
17 import java
.util
.HashMap
;
18 import java
.util
.List
;
20 import java
.util
.UUID
;
21 import java
.util
.stream
.Collectors
;
23 import org
.eclipse
.core
.runtime
.preferences
.IEclipsePreferences
;
24 import org
.eclipse
.egit
.core
.RepositoryUtil
;
25 import org
.eclipse
.egit
.core
.internal
.Utils
;
26 import org
.eclipse
.egit
.ui
.Activator
;
27 import org
.eclipse
.egit
.ui
.internal
.UIText
;
28 import org
.eclipse
.jgit
.util
.StringUtils
;
29 import org
.osgi
.service
.prefs
.BackingStoreException
;
32 * This singleton manages the repository groups. The data is stored in the
35 public enum RepositoryGroups
{
38 * The singleton {@link RepositoryGroups} instance.
42 private static final String PREFS_GROUP_NAME_PREFIX
= "RepositoryGroups."; //$NON-NLS-1$
44 private static final String PREFS_GROUPS
= PREFS_GROUP_NAME_PREFIX
45 + "uuids"; //$NON-NLS-1$
47 private static final String PREFS_GROUP_PREFIX
= PREFS_GROUP_NAME_PREFIX
48 + "group."; //$NON-NLS-1$
50 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
52 private static final String SEPARATOR
= "\n";//$NON-NLS-1$
54 private final Map
<UUID
, RepositoryGroup
> groupMap
= new HashMap
<>();
56 private final IEclipsePreferences preferences
= RepositoryUtil
.INSTANCE
60 * new repository groups initialized from preferences
62 private RepositoryGroups() {
63 List
<String
> groups
= split(
64 preferences
.get(PREFS_GROUPS
, EMPTY_STRING
));
65 List
<RepositoryGroup
> toDelete
= new ArrayList
<>();
66 for (String groupIdString
: groups
) {
67 UUID groupId
= UUID
.fromString(groupIdString
);
68 String name
= preferences
69 .get(PREFS_GROUP_NAME_PREFIX
+ groupIdString
, EMPTY_STRING
);
70 // Guard against corrupted preferences
71 if (isGroupNameInvalid(name
)) {
72 toDelete
.add(new RepositoryGroup(groupId
, name
));
73 Activator
.logWarning(MessageFormat
.format(
74 UIText
.RepositoryGroups_LoadPreferencesInvalidName
,
78 List
<File
> repos
= split(preferences
79 .get(PREFS_GROUP_PREFIX
+ groupIdString
, EMPTY_STRING
))
81 .map(RepositoryUtil
.INSTANCE
::getAbsoluteRepositoryPath
)
82 .map(File
::new).filter(File
::isDirectory
)
83 .collect(Collectors
.toList());
84 RepositoryGroup group
= new RepositoryGroup(groupId
, name
, repos
);
85 groupMap
.put(groupId
, group
);
87 if (!toDelete
.isEmpty()) {
92 private List
<String
> split(String input
) {
93 List
<String
> result
= new ArrayList
<>();
94 String
[] split
= input
.split(SEPARATOR
);
95 for (String string
: split
) {
97 String trimmed
= string
.trim();
98 if (trimmed
.length() > 0) {
107 * Determines whether there are any repository groups.
109 * @return {@code true} if there are repository groups, {@code false}
112 public boolean hasGroups() {
113 return !groupMap
.isEmpty();
117 * Creates a new group with the given name.
120 * valid name of the new group
121 * @return the new group
122 * @throws IllegalArgumentException
123 * if the name is invalid
124 * @throws IllegalStateException
125 * if a group with the given name already exists
127 public RepositoryGroup
createGroup(String groupName
) {
128 checkGroupName(groupName
);
129 if (!groupExists(groupName
)) {
130 UUID groupId
= UUID
.randomUUID();
131 RepositoryGroup group
= new RepositoryGroup(groupId
, groupName
);
132 groupMap
.put(groupId
, group
);
136 throw new IllegalStateException(
137 MessageFormat
.format(
138 UIText
.RepositoryGroups_DuplicateGroupNameError
,
145 * the group to rename
147 * new name of the group
149 public void renameGroup(RepositoryGroup group
, String newName
) {
150 checkGroupName(newName
);
151 RepositoryGroup myGroup
= groupMap
.get(group
.getGroupId());
152 if (myGroup
!= null && !newName
.equals(myGroup
.getName())) {
153 myGroup
.setGroupName(newName
);
161 * @return true if and only if a group of the given name already exists
163 public boolean groupExists(String groupName
) {
164 return groupMap
.values().stream()
165 .anyMatch(group
-> group
.getName().equals(groupName
));
168 private static boolean isGroupNameInvalid(String groupName
) {
169 return StringUtils
.isEmptyOrNull(groupName
)
170 || !groupName
.equals(groupName
.trim())
171 || Utils
.isMultiLine(groupName
);
174 private static void checkGroupName(String groupName
) {
175 if (isGroupNameInvalid(groupName
)) {
176 throw new IllegalArgumentException(
177 UIText
.RepositoryGroups_InvalidNameError
);
182 * adds repositories to the given group and removes them from all other
186 * to which the repositories are added
188 * repository directories to be added to the group
191 public void addRepositoriesToGroup(RepositoryGroup group
,
192 Collection
<File
> repoDirs
) {
193 if (!groupMap
.containsKey(group
.getGroupId())) {
194 throw new IllegalArgumentException();
196 Collection
<RepositoryGroup
> currentGroups
= groupMap
.values();
197 for (RepositoryGroup groups
: currentGroups
) {
198 groups
.removeRepositoryDirectories(repoDirs
);
201 group
.addRepositoryDirectories(repoDirs
);
207 * deletes repository groups, the repositories belonging to these groups are
210 * @param groupsToDelete
211 * groups to be deleted
213 public void delete(Collection
<RepositoryGroup
> groupsToDelete
) {
214 for (RepositoryGroup group
: groupsToDelete
) {
215 preferences
.remove(PREFS_GROUP_PREFIX
+ group
.getGroupId());
216 preferences
.remove(PREFS_GROUP_NAME_PREFIX
+ group
.getGroupId());
217 groupMap
.remove(group
.getGroupId());
222 private void savePreferences() {
224 List
<String
> groupIds
= new ArrayList
<>();
225 for (RepositoryGroup group
: groupMap
.values()) {
226 String groupId
= group
.getGroupId().toString();
227 groupIds
.add(groupId
);
228 String name
= group
.getName();
229 preferences
.put(PREFS_GROUP_NAME_PREFIX
+ groupId
, name
);
230 String repos
= group
.getRepositoryDirectories().stream()
232 .map(RepositoryUtil
.INSTANCE
::relativizeToWorkspace
)
233 .collect(Collectors
.joining(SEPARATOR
));
234 preferences
.put(PREFS_GROUP_PREFIX
+ groupId
, repos
);
236 preferences
.put(PREFS_GROUPS
,
237 StringUtils
.join(groupIds
, SEPARATOR
));
239 } catch (BackingStoreException e
) {
241 UIText
.RepositoryGroups_SavePreferencesError
, e
);
246 * @return existing repository groups
248 public List
<RepositoryGroup
> getGroups() {
249 return new ArrayList
<>(groupMap
.values());
253 * @param repositoryDirectory
254 * directory of the Repository
255 * @return whether the repository belongs to any group
257 public boolean belongsToGroup(File repositoryDirectory
) {
258 return groupMap
.values().stream().anyMatch(group
-> group
259 .getRepositoryDirectories().contains(repositoryDirectory
));
263 * @param repositoryDirectories
264 * repository directories to be removed from all groups
266 public void removeFromGroups(List
<File
> repositoryDirectories
) {
267 for (RepositoryGroup group
: groupMap
.values()) {
268 group
.removeRepositoryDirectories(repositoryDirectories
);