Skip to content

Commit 6bc14af

Browse files
RomanNikitenkovparfonov
authored andcommitted
CHE-5215. Add ability to exclude tracking files by file watcher (eclipse-che#5495)
* CHE-5215. Add ability to exclude tracking files by file watcher Signed-off-by: Roman Nikitenko <rnikiten@redhat.com>
1 parent f39f382 commit 6bc14af

15 files changed

Lines changed: 940 additions & 33 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.api.event.ng;
12+
13+
import com.google.gwt.user.client.rpc.AsyncCallback;
14+
import com.google.web.bindery.event.shared.EventBus;
15+
16+
import org.eclipse.che.api.core.jsonrpc.commons.JsonRpcPromise;
17+
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
18+
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
19+
import org.eclipse.che.api.promises.client.Promise;
20+
import org.eclipse.che.api.promises.client.PromiseProvider;
21+
import org.eclipse.che.ide.api.event.WindowActionEvent;
22+
import org.eclipse.che.ide.api.event.WindowActionHandler;
23+
24+
import javax.inject.Inject;
25+
import javax.inject.Singleton;
26+
import java.util.ArrayList;
27+
import java.util.HashSet;
28+
import java.util.Set;
29+
30+
/**
31+
* Tracks and allows to manage the file watcher exclude patterns for tracking creation,
32+
* modification and deletion events for corresponding entries.
33+
*
34+
* @author Roman Nikitenko
35+
*/
36+
@Singleton
37+
public class FileWatcherExcludesOperation implements WindowActionHandler {
38+
private static final String ENDPOINT_ID = "ws-agent";
39+
private static final String EXCLUDES_SUBSCRIBE = "fileWatcher/excludes/subscribe";
40+
private static final String EXCLUDES_UNSUBSCRIBE = "fileWatcher/excludes/unsubscribe";
41+
private static final String EXCLUDES_CHANGED = "fileWatcher/excludes/changed";
42+
private static final String ADD_TO_EXCLUDES = "fileWatcher/excludes/addToExcludes";
43+
private static final String REMOVE_FROM_EXCLUDES = "fileWatcher/excludes/removeFromExcludes";
44+
private static final String EXCLUDES_CLEAN_UP = "fileWatcher/excludes/cleanup";
45+
46+
private PromiseProvider promises;
47+
private RequestTransmitter requestTransmitter;
48+
private Set<String> excludes = new HashSet<>();
49+
50+
@Inject
51+
public FileWatcherExcludesOperation(EventBus eventBus,
52+
PromiseProvider promises,
53+
RequestTransmitter requestTransmitter) {
54+
this.promises = promises;
55+
this.requestTransmitter = requestTransmitter;
56+
eventBus.addHandler(WindowActionEvent.TYPE, this);
57+
subscribe();
58+
}
59+
60+
@Inject
61+
private void configureHandlers(RequestHandlerConfigurator configurator) {
62+
configurator.newConfiguration()
63+
.methodName(EXCLUDES_CHANGED)
64+
.paramsAsListOfString()
65+
.noResult()
66+
.withConsumer(newExcludes -> {
67+
excludes.clear();
68+
excludes.addAll(newExcludes);
69+
});
70+
71+
configurator.newConfiguration()
72+
.methodName(EXCLUDES_CLEAN_UP)
73+
.noParams()
74+
.noResult()
75+
.withConsumer(s -> excludes.clear());
76+
}
77+
78+
/**
79+
* Checks if specified path is within excludes
80+
*
81+
* @param pathToTest
82+
* path being examined
83+
* @return true if path is within excludes, false otherwise
84+
*/
85+
public boolean isExcluded(String pathToTest) {
86+
return excludes.contains(pathToTest);
87+
}
88+
89+
/**
90+
* Registers a set of paths to skip tracking of creation,
91+
* modification and deletion events for corresponding entries.
92+
*
93+
* @param pathsToExclude
94+
* entries' paths to adding to excludes
95+
*/
96+
public Promise<Boolean> addToFileWatcherExcludes(Set<String> pathsToExclude) {
97+
JsonRpcPromise<Boolean> jsonRpcPromise = requestTransmitter.newRequest()
98+
.endpointId(ENDPOINT_ID)
99+
.methodName(ADD_TO_EXCLUDES)
100+
.paramsAsListOfString(new ArrayList<>(pathsToExclude))
101+
.sendAndReceiveResultAsBoolean();
102+
return toPromise(jsonRpcPromise);
103+
}
104+
105+
/**
106+
* Removes a set of paths from excludes to resume tracking of corresponding entries creation,
107+
* modification and deletion events.
108+
*
109+
* @param paths
110+
* entries' paths to remove from excludes
111+
*/
112+
public Promise<Boolean> removeFromFileWatcherExcludes(Set<String> paths) {
113+
JsonRpcPromise<Boolean> jsonRpcPromise = requestTransmitter.newRequest()
114+
.endpointId(ENDPOINT_ID)
115+
.methodName(REMOVE_FROM_EXCLUDES)
116+
.paramsAsListOfString(new ArrayList<>(paths))
117+
.sendAndReceiveResultAsBoolean();
118+
return toPromise(jsonRpcPromise);
119+
}
120+
121+
private Promise<Boolean> toPromise(JsonRpcPromise<Boolean> jsonRpcPromise) {
122+
return promises.create((AsyncCallback<Boolean> callback) -> {
123+
124+
jsonRpcPromise.onSuccess(callback::onSuccess);
125+
126+
jsonRpcPromise.onFailure(jsonRpcError -> callback.onFailure(new Throwable(jsonRpcError.getMessage())));
127+
});
128+
}
129+
130+
@Override
131+
public void onWindowClosing(WindowActionEvent event) {
132+
}
133+
134+
@Override
135+
public void onWindowClosed(WindowActionEvent event) {
136+
unSubscribe();
137+
}
138+
139+
private void subscribe() {
140+
requestTransmitter.newRequest()
141+
.endpointId(ENDPOINT_ID)
142+
.methodName(EXCLUDES_SUBSCRIBE)
143+
.noParams()
144+
.sendAndSkipResult();
145+
}
146+
147+
private void unSubscribe() {
148+
requestTransmitter.newRequest()
149+
.endpointId(ENDPOINT_ID)
150+
.methodName(EXCLUDES_UNSUBSCRIBE)
151+
.noParams()
152+
.sendAndSkipResult();
153+
}
154+
}

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/CoreLocalizationConstant.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ public interface CoreLocalizationConstant extends Messages {
5050
@Key("appearance.category")
5151
String appearanceCategory();
5252

53+
/* Add resources to File Watcher excludes */
54+
@Key("action.fileWatcher.add.excludes.text")
55+
String addToFileWatcherExludesName();
56+
57+
@Key("action.fileWatcher.add.excludes.description")
58+
String addToFileWatcherExludesDescription();
59+
60+
/* Remove resources from File Watcher excludes */
61+
@Key("action.fileWatcher.remove.excludes.text")
62+
String removeFromFileWatcherExludesName();
63+
64+
@Key("action.fileWatcher.remove.excludes.description")
65+
String removeFromFileWatcherExludesDescription();
66+
5367
/* DeleteItem */
5468
@Key("action.delete.text")
5569
String deleteItemActionText();
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.actions;
12+
13+
import com.google.inject.Inject;
14+
import com.google.inject.Singleton;
15+
16+
import org.eclipse.che.ide.CoreLocalizationConstant;
17+
import org.eclipse.che.ide.api.action.AbstractPerspectiveAction;
18+
import org.eclipse.che.ide.api.action.ActionEvent;
19+
import org.eclipse.che.ide.api.app.AppContext;
20+
import org.eclipse.che.ide.api.event.ng.FileWatcherExcludesOperation;
21+
import org.eclipse.che.ide.api.notification.NotificationManager;
22+
import org.eclipse.che.ide.api.resources.Resource;
23+
24+
import javax.validation.constraints.NotNull;
25+
import java.util.List;
26+
import java.util.Set;
27+
28+
import static java.util.Arrays.asList;
29+
import static java.util.Arrays.stream;
30+
import static java.util.Collections.singletonList;
31+
import static java.util.stream.Collectors.toSet;
32+
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE;
33+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
34+
import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID;
35+
36+
/**
37+
* Adds resources which are in application context to File Watcher excludes.
38+
*
39+
* @author Roman Nikitenko
40+
*/
41+
@Singleton
42+
public class AddToFileWatcherExcludesAction extends AbstractPerspectiveAction {
43+
44+
private AppContext appContext;
45+
private NotificationManager notificationManager;
46+
private FileWatcherExcludesOperation fileWatcherExcludesOperation;
47+
48+
@Inject
49+
public AddToFileWatcherExcludesAction(AppContext appContext,
50+
CoreLocalizationConstant locale,
51+
NotificationManager notificationManager,
52+
FileWatcherExcludesOperation fileWatcherExcludesOperation) {
53+
super(singletonList(PROJECT_PERSPECTIVE_ID),
54+
locale.addToFileWatcherExludesName(),
55+
locale.addToFileWatcherExludesDescription(),
56+
null,
57+
null);
58+
this.appContext = appContext;
59+
this.notificationManager = notificationManager;
60+
this.fileWatcherExcludesOperation = fileWatcherExcludesOperation;
61+
}
62+
63+
@Override
64+
public void actionPerformed(ActionEvent e) {
65+
final Resource[] resources = appContext.getResources();
66+
Set<String> pathsToExclude = stream(resources).map(resource -> resource.getLocation().toString())
67+
.collect(toSet());
68+
69+
fileWatcherExcludesOperation.addToFileWatcherExcludes(pathsToExclude)
70+
.catchError(error -> {
71+
notificationManager.notify(error.getMessage(), FAIL, EMERGE_MODE);
72+
});
73+
}
74+
75+
@Override
76+
public void updateInPerspective(@NotNull ActionEvent e) {
77+
Resource[] resources = appContext.getResources();
78+
79+
e.getPresentation().setVisible(true);
80+
e.getPresentation().setEnabled(containsResourcesToExcludes(resources));
81+
}
82+
83+
private boolean containsResourcesToExcludes(Resource[] resources) {
84+
if (resources == null || resources.length <= 0) {
85+
return false;
86+
}
87+
88+
List<Resource> resourcesToExclude = asList(resources);
89+
return resourcesToExclude.stream()
90+
.map(resource -> resource.getLocation().toString())
91+
.anyMatch(pathToExclude -> !fileWatcherExcludesOperation.isExcluded(pathToExclude));
92+
}
93+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2012-2017 Codenvy, S.A.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Codenvy, S.A. - initial API and implementation
10+
*******************************************************************************/
11+
package org.eclipse.che.ide.actions;
12+
13+
import com.google.inject.Inject;
14+
import com.google.inject.Singleton;
15+
16+
import org.eclipse.che.ide.CoreLocalizationConstant;
17+
import org.eclipse.che.ide.api.action.AbstractPerspectiveAction;
18+
import org.eclipse.che.ide.api.action.ActionEvent;
19+
import org.eclipse.che.ide.api.app.AppContext;
20+
import org.eclipse.che.ide.api.event.ng.FileWatcherExcludesOperation;
21+
import org.eclipse.che.ide.api.notification.NotificationManager;
22+
import org.eclipse.che.ide.api.resources.Resource;
23+
24+
import javax.validation.constraints.NotNull;
25+
import java.util.List;
26+
import java.util.Set;
27+
28+
import static java.util.Arrays.asList;
29+
import static java.util.Arrays.stream;
30+
import static java.util.Collections.singletonList;
31+
import static java.util.stream.Collectors.toSet;
32+
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE;
33+
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
34+
import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID;
35+
36+
/**
37+
* Removes resources which are in application context from File Watcher excludes.
38+
*
39+
* @author Roman Nikitenko
40+
*/
41+
@Singleton
42+
public class RemoveFromFileWatcherExcludesAction extends AbstractPerspectiveAction {
43+
44+
private AppContext appContext;
45+
private NotificationManager notificationManager;
46+
private FileWatcherExcludesOperation fileWatcherExcludesOperation;
47+
48+
@Inject
49+
public RemoveFromFileWatcherExcludesAction(AppContext appContext,
50+
CoreLocalizationConstant locale,
51+
NotificationManager notificationManager,
52+
FileWatcherExcludesOperation fileWatcherExcludesOperation) {
53+
super(singletonList(PROJECT_PERSPECTIVE_ID),
54+
locale.removeFromFileWatcherExludesName(),
55+
locale.removeFromFileWatcherExludesDescription(),
56+
null,
57+
null);
58+
this.appContext = appContext;
59+
this.notificationManager = notificationManager;
60+
this.fileWatcherExcludesOperation = fileWatcherExcludesOperation;
61+
}
62+
63+
@Override
64+
public void actionPerformed(ActionEvent e) {
65+
final Resource[] resources = appContext.getResources();
66+
Set<String> pathsToRemove = stream(resources).map(resource -> resource.getLocation().toString())
67+
.collect(toSet());
68+
69+
fileWatcherExcludesOperation.removeFromFileWatcherExcludes(pathsToRemove)
70+
.catchError(error -> {
71+
notificationManager.notify(error.getMessage(), FAIL, EMERGE_MODE);
72+
});
73+
}
74+
75+
76+
@Override
77+
public void updateInPerspective(@NotNull ActionEvent e) {
78+
Resource[] resources = appContext.getResources();
79+
80+
e.getPresentation().setVisible(true);
81+
e.getPresentation().setEnabled(containsResourcesToRemoveFromExcludes(resources));
82+
}
83+
84+
private boolean containsResourcesToRemoveFromExcludes(Resource[] resources) {
85+
if (resources == null || resources.length <= 0) {
86+
return false;
87+
}
88+
89+
List<Resource> resourcesToExclude = asList(resources);
90+
return resourcesToExclude.stream()
91+
.map(resource -> resource.getLocation().toString())
92+
.anyMatch(pathToExclude -> fileWatcherExcludesOperation.isExcluded(pathToExclude));
93+
}
94+
}

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/ClientServerEventModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.eclipse.che.ide.api.event.ng.ClientServerEventServiceImpl;
1818
import org.eclipse.che.ide.api.event.ng.EditorFileStatusNotificationOperation;
1919
import org.eclipse.che.ide.api.event.ng.FileOpenCloseEventListener;
20+
import org.eclipse.che.ide.api.event.ng.FileWatcherExcludesOperation;
2021
import org.eclipse.che.ide.api.event.ng.ProjectTreeStateNotificationOperation;
2122

2223
/**
@@ -41,5 +42,6 @@ private void requestFunctions() {
4142
private void notificationOperations() {
4243
bind(EditorFileStatusNotificationOperation.class).asEagerSingleton();
4344
bind(ProjectTreeStateNotificationOperation.class).asEagerSingleton();
45+
bind(FileWatcherExcludesOperation.class).asEagerSingleton();
4446
}
4547
}

0 commit comments

Comments
 (0)