Merge branch 'master' into spi

6.19.x
Artem Zatsarynnyi 2017-07-05 18:25:50 +03:00
commit a1dfdfb04e
123 changed files with 5897 additions and 2883 deletions

View File

@ -210,9 +210,14 @@ che.docker.ip.external=NULL
# - 'docker-local': internal address is address of container within docker network, and exposed ports
# are used.
# - 'custom': The evaluation strategy may be customized through a template property.
# - 'docker-local-custom': internal address is set as in docker-local strategy, external address is composed
# as in the custom strategy with the 'template' and the 'external.protocol' properties.
# The 'docker-local' strategy may be useful if a firewall prevents communication between che-server and
# workspace containers, but will prevent communication when che-server and workspace containers are not
# on the same Docker network.
# The 'docker-local-custom' strategy may be useful when Che and the workspace servers need to be exposed on the
# same single TCP port.
che.docker.server_evaluation_strategy=default
@ -317,12 +322,52 @@ che.openshift.project=eclipse-che
che.openshift.serviceaccountname=cheserviceaccount
che.openshift.liveness.probe.delay=300
che.openshift.liveness.probe.timeout=1
che.openshift.workspaces.pvc.name=claim-che-workspace
che.openshift.workspaces.pvc.quantity=10Gi
# Create secure route against HTTPS
# NOTE: In order to create routes against HTTPS
# Property 'strategy.che.docker.server_evaluation_strategy.secure.external.urls' should be also set to true
che.openshift.secure.routes=false
# Pod that is launched when performing persistent volume claim maintenance jobs on OpenShift
che.openshift.jobs.image=centos:centos7
che.openshift.jobs.memorylimit=250Mi
# Run job to create workspace subpath directories in persistent volume before launching workspace.
# Necessary in some versions of OpenShift/Kubernetes as workspace subpath volumemounts are created
# with root permissions, and thus cannot be modified by workspaces running as user (presents as error
# importing projects into workspace in Che). Default is "true", but should be set to false if version
# of Openshift/Kubernetes creates subdirectories with user permissions.
# Relevant issue: https://github.com/kubernetes/kubernetes/issues/41638
che.openshift.precreate.workspace.dirs=true
# Specifications of compute resources that can be consumed
# by the workspace container:
#
# - Amount of memory required for a workspace container to run e.g. 512Mi
che.openshift.workspace.memory.request=NULL
#
# - Maximum amount of memory a workspace container can use e.g. 1.3Gi
che.openshift.workspace.memory.override=NULL
# The Openshift will idle the server if no workspace is run for
# this length of time.
che.openshift.server.inactive.stop.timeout.ms=1800000
#
#
# Be aware that setting che.openshift.workspace.memory.override
# will override Che memory limits
#
# More information about setting Compute Resources in OpenShift can be
# found here: https://docs.openshift.org/latest/dev_guide/compute_resources.html#dev-compute-resources
# Which implementation of DockerConnector to use in managing containers. In general,
# the base implementation of DockerConnector is appropriate, but OpenShiftConnector
# is necessary for deploying Che on OpenShift. Options:
# - 'default' : Use DockerConnector
# - 'openshift' : use OpenShiftConnector
# Note that if 'openshift' connector is used, the property che.docker.ip.external
# MUST be set.
che.docker.connector=default
# Defines whether stacks loaded once or each time server starts.

View File

@ -255,6 +255,17 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- Exclude files until #3281 is resolved -->
<exclude>**/ServerIdleEvent.java</exclude>
<!-- End excluded files -->
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<profiles>

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.event;
/**
* Event informing about idling the che server.
*/
public class ServerIdleEvent {
private long timeout;
/**
* Implements the handler to handle idling.
*/
public ServerIdleEvent(long timeout) {
super();
this.timeout = timeout;
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
}

View File

@ -48,3 +48,6 @@ EXPOSE 8000 8080
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
ADD eclipse-che.tar.gz /home/user/
RUN mkdir /logs && chmod 0777 /logs
RUN chmod -R 0777 /home/user/
RUN mkdir /data && chmod 0777 /data

View File

@ -51,7 +51,7 @@ Variables:
export CHE_REGISTRY_HOST=${CHE_REGISTRY_HOST:-${DEFAULT_CHE_REGISTRY_HOST}}
DEFAULT_CHE_PORT=8080
CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}}
export CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}}
DEFAULT_CHE_IP=
CHE_IP=${CHE_IP:-${DEFAULT_CHE_IP}}
@ -246,18 +246,40 @@ init() {
fi
### Are we going to use the embedded che.properties or one provided by user?`
### CHE_LOCAL_CONF_DIR is internal Che variable that sets where to load
export CHE_LOCAL_CONF_DIR="/conf"
if [ -f "/conf/che.properties" ]; then
echo "Found custom che.properties..."
if [ "$CHE_USER" != "root" ]; then
sudo chown -R ${CHE_USER} ${CHE_LOCAL_CONF_DIR}
# check if we have permissions to create /conf folder.
if [ -w / ]; then
export CHE_LOCAL_CONF_DIR="/conf"
if [ -f "/conf/che.properties" ]; then
echo "Found custom che.properties..."
if [ "$CHE_USER" != "root" ]; then
sudo chown -R ${CHE_USER} ${CHE_LOCAL_CONF_DIR}
fi
else
if [ ! -d ${CHE_LOCAL_CONF_DIR} ]; then
mkdir -p ${CHE_LOCAL_CONF_DIR}
fi
if [ -w ${CHE_LOCAL_CONF_DIR} ];then
echo "ERROR: user ${CHE_USER} does OK have write permissions to ${CHE_LOCAL_CONF_DIR}"
echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties"
cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties
else
echo "ERROR: user ${CHE_USER} does not have write permissions to ${CHE_LOCAL_CONF_DIR}"
exit 1
fi
fi
else
if [ ! -d /conf ]; then
mkdir -p /conf
echo "WARN: parent dir is not writeable, CHE_LOCAL_CONF_DIR will be set to ${CHE_DATA}/conf"
export CHE_LOCAL_CONF_DIR="${CHE_DATA}/conf"
if [ ! -d ${CHE_LOCAL_CONF_DIR} ]; then
mkdir -p ${CHE_LOCAL_CONF_DIR}
fi
if [ -w ${CHE_LOCAL_CONF_DIR} ];then
echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties"
cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties
else
echo "ERROR: user ${CHE_USER} does not have write permissions to ${CHE_LOCAL_CONF_DIR}"
exit 1
fi
echo "Using embedded che.properties... Copying template to ${CHE_LOCAL_CONF_DIR}/che.properties"
cp -rf "${CHE_HOME}/conf/che.properties" ${CHE_LOCAL_CONF_DIR}/che.properties
fi
# Update the provided che.properties with the location of the /data mounts

View File

@ -30,4 +30,12 @@ public interface ModificationTracker {
* @return modification tracker value
*/
String getModificationStamp();
/**
* Update modification tracker value by content. Modification tracker is a value is changed by any modification of the content
* of the file.
*
* @param content actual file content
*/
void updateModificationStamp(String content);
}

View File

@ -87,9 +87,9 @@ public class CommandManagerImpl implements CommandManager {
this.commandNameGenerator = commandNameGenerator;
commands = new HashMap<>();
registerNative();
// FIXME: spi
// Temporary solution while a better mechanism of obtaining appContext.getProjects() with Promises is being considered...
// TODO (spi ide): Temporary solution while a better mechanism of obtaining appContext.getProjects() with Promises is being considered...
eventBus.addHandler(WorkspaceReadyEvent.getType(), e -> fetchCommands());
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, e -> {
commands.clear();
@ -380,4 +380,17 @@ public class CommandManagerImpl implements CommandManager {
private void notifyCommandUpdated(CommandImpl prevCommand, CommandImpl command) {
eventBus.fireEvent(new CommandUpdatedEvent(prevCommand, command));
}
/* Expose Command Manager's internal API to the world, to allow selenium tests or clients that use IDE to refresh commands. */
private native void registerNative() /*-{
var that = this;
var CommandManager = {};
CommandManager.refresh = $entry(function () {
that.@org.eclipse.che.ide.command.manager.CommandManagerImpl::fetchCommands()();
});
$wnd.IDE.CommandManager = CommandManager;
}-*/;
}

View File

@ -168,7 +168,7 @@ public class EditorGroupSynchronizationImpl implements EditorGroupSynchronizatio
});
}
private void updateContent(String newContent, String oldStamp, VirtualFile virtualFile) {
private void updateContent(String newContent, String eventModificationStamp, VirtualFile virtualFile) {
final DocumentHandle documentHandle = getDocumentHandleFor(groupLeaderEditor);
if (documentHandle == null) {
return;
@ -184,14 +184,14 @@ public class EditorGroupSynchronizationImpl implements EditorGroupSynchronizatio
}
final File file = (File)virtualFile;
final String newStamp = file.getModificationStamp();
final String currentStamp = file.getModificationStamp();
if (oldStamp == null && !Objects.equals(newContent, oldContent)) {
if (eventModificationStamp == null && !Objects.equals(newContent, oldContent)) {
replaceContent(document, newContent, oldContent, cursorPosition);
return;
}
if (!Objects.equals(oldStamp, newStamp)) {
if (!Objects.equals(eventModificationStamp, currentStamp)) {
replaceContent(document, newContent, oldContent, cursorPosition);
notificationManager.notify("External operation", "File '" + file.getName() + "' is updated", SUCCESS, EMERGE_MODE);

View File

@ -13,6 +13,8 @@ package org.eclipse.che.ide.factory.utils;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.api.core.model.workspace.config.SourceStorage;
import org.eclipse.che.api.git.shared.GitCheckoutEvent;
import org.eclipse.che.api.promises.client.Function;
@ -37,19 +39,17 @@ import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.user.AskCredentialsDialog;
import org.eclipse.che.ide.api.user.Credentials;
import org.eclipse.che.ide.api.workspace.model.ProjectConfigImpl;
import org.eclipse.che.ide.projectimport.wizard.ProjectImportOutputJsonRpcNotifier;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.rest.DtoUnmarshallerFactory;
import org.eclipse.che.ide.util.ExceptionUtils;
import org.eclipse.che.ide.util.StringUtils;
import org.eclipse.che.ide.websocket.MessageBus;
import org.eclipse.che.ide.websocket.MessageBusProvider;
import org.eclipse.che.ide.websocket.WebSocketException;
import org.eclipse.che.ide.websocket.rest.SubscriptionHandler;
import org.eclipse.che.security.oauth.OAuthStatus;
import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -73,17 +73,18 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUC
* @author Valeriy Svydenko
* @author Anton Korneta
*/
@Singleton
public class FactoryProjectImporter extends AbstractImporter {
private static final String CHANNEL = "git:checkout:";
private final AskCredentialsDialog askCredentialsDialog;
private final CoreLocalizationConstant locale;
private final NotificationManager notificationManager;
private final String restContext;
private final DialogFactory dialogFactory;
private final OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry;
private final RequestTransmitter requestTransmitter;
private final ProjectImportOutputJsonRpcNotifier subscriber;
private final MessageBusProvider messageBusProvider;
private final AskCredentialsDialog askCredentialsDialog;
private final CoreLocalizationConstant locale;
private final NotificationManager notificationManager;
private final String restContext;
private final DialogFactory dialogFactory;
private final OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry;
private final DtoUnmarshallerFactory dtoUnmarshallerFactory;
private final Map<String, CheckoutContext> checkoutContextRegistry = new HashMap<>();
private FactoryImpl factory;
private AsyncCallback<Void> callback;
@ -96,8 +97,8 @@ public class FactoryProjectImporter extends AbstractImporter {
ImportProjectNotificationSubscriberFactory subscriberFactory,
DialogFactory dialogFactory,
OAuth2AuthenticatorRegistry oAuth2AuthenticatorRegistry,
MessageBusProvider messageBusProvider,
DtoUnmarshallerFactory dtoUnmarshallerFactory) {
RequestTransmitter requestTransmitter,
ProjectImportOutputJsonRpcNotifier subscriber) {
super(appContext, subscriberFactory);
this.notificationManager = notificationManager;
this.askCredentialsDialog = askCredentialsDialog;
@ -105,8 +106,34 @@ public class FactoryProjectImporter extends AbstractImporter {
this.restContext = appContext.getMasterEndpoint();
this.dialogFactory = dialogFactory;
this.oAuth2AuthenticatorRegistry = oAuth2AuthenticatorRegistry;
this.messageBusProvider = messageBusProvider;
this.dtoUnmarshallerFactory = dtoUnmarshallerFactory;
this.requestTransmitter = requestTransmitter;
this.subscriber = subscriber;
}
@Inject
private void configure(RequestHandlerConfigurator requestHandlerConfigurator) {
requestHandlerConfigurator.newConfiguration()
.methodName("git/checkoutOutput")
.paramsAsDto(GitCheckoutEvent.class)
.noResult()
.withConsumer(this::consumeGitCheckoutEvent);
}
private void consumeGitCheckoutEvent(GitCheckoutEvent event) {
CheckoutContext context = checkoutContextRegistry.get(event.getWorkspaceId() + event.getProjectName());
if (context == null) {
return;
}
String projectName = context.projectName;
String reference = event.isCheckoutOnly() ? event.getBranchRef() : context.startPoint;
String repository = context.repository;
String branch = context.branch;
String title = locale.clonedSource(projectName);
String content = locale.clonedSourceWithCheckout(projectName, repository, reference, branch);
notificationManager.notify(title, content, SUCCESS, FLOAT_MODE);
}
public void startImporting(FactoryImpl factory, AsyncCallback<Void> callback) {
@ -183,7 +210,6 @@ public class FactoryProjectImporter extends AbstractImporter {
@NotNull final SourceStorage sourceStorage) {
final String projectName = pathToProject.lastSegment();
final StatusNotification notification = notificationManager.notify(locale.cloningSource(projectName), null, PROGRESS, FLOAT_MODE);
final ProjectNotificationSubscriber subscriber = subscriberFactory.createSubscriber();
subscriber.subscribe(projectName, notification);
String location = sourceStorage.getLocation();
// it's needed for extract repository name from repository url e.g https://github.com/codenvy/che-core.git
@ -192,37 +218,8 @@ public class FactoryProjectImporter extends AbstractImporter {
final Map<String, String> parameters = firstNonNull(sourceStorage.getParameters(), Collections.<String, String>emptyMap());
final String branch = parameters.get("branch");
final String startPoint = parameters.get("startPoint");
final MessageBus messageBus = messageBusProvider.getMachineMessageBus();
final String channel = CHANNEL + appContext.getWorkspaceId() + ':' + projectName;
final SubscriptionHandler<GitCheckoutEvent> successImportHandler = new SubscriptionHandler<GitCheckoutEvent>(
dtoUnmarshallerFactory.newWSUnmarshaller(GitCheckoutEvent.class)) {
@Override
protected void onMessageReceived(GitCheckoutEvent result) {
if (result.isCheckoutOnly()) {
notificationManager.notify(locale.clonedSource(projectName),
locale.clonedSourceWithCheckout(projectName, repository, result.getBranchRef(), branch),
SUCCESS,
FLOAT_MODE);
} else {
notificationManager.notify(locale.clonedSource(projectName),
locale.clonedWithCheckoutOnStartPoint(projectName, repository, startPoint, branch),
SUCCESS,
FLOAT_MODE);
}
}
@Override
protected void onErrorReceived(Throwable e) {
try {
messageBus.unsubscribe(channel, this);
} catch (WebSocketException ignore) {
}
}
};
try {
messageBus.subscribe(channel, successImportHandler);
} catch (WebSocketException ignore) {
}
subscribe(projectName, repository, branch, startPoint);
MutableProjectConfig importConfig = new MutableProjectConfig();
importConfig.setPath(pathToProject.toString());
@ -236,6 +233,8 @@ public class FactoryProjectImporter extends AbstractImporter {
@Override
public Project apply(Project project) throws FunctionException {
subscriber.onSuccess();
unsubscribe(projectName);
notification.setContent(locale.clonedSource(projectName));
notification.setStatus(SUCCESS);
@ -246,9 +245,11 @@ public class FactoryProjectImporter extends AbstractImporter {
@Override
public Promise<Project> apply(PromiseError err) throws FunctionException {
final int errorCode = ExceptionUtils.getErrorCode(err.getCause());
unsubscribe(projectName);
switch (errorCode) {
case UNAUTHORIZED_GIT_OPERATION:
subscriber.onFailure(err.getMessage());
final Map<String, String> attributes = ExceptionUtils.getAttributes(err.getCause());
final String providerName = attributes.get(PROVIDER_NAME);
final String authenticateUrl = attributes.get(AUTHENTICATE_URL);
@ -296,6 +297,28 @@ public class FactoryProjectImporter extends AbstractImporter {
});
}
private void subscribe(String projectName, String repository, String branch, String startPoint) {
String key = appContext.getWorkspaceId() + projectName;
checkoutContextRegistry.put(key, new CheckoutContext(projectName, repository, branch, startPoint));
requestTransmitter.newRequest()
.endpointId("ws-agent")
.methodName("git/checkoutOutput/subscribe")
.paramsAsString(key)
.sendAndSkipResult();
}
private void unsubscribe(String projectName) {
String key = appContext.getWorkspaceId() + projectName;
checkoutContextRegistry.remove(key);
requestTransmitter.newRequest()
.endpointId("ws-agent")
.methodName("git/checkoutOutput/unsubscribe")
.paramsAsString(key)
.sendAndSkipResult();
}
private Promise<Project> tryAuthenticateAndRepeatImport(@NotNull final String providerName,
@NotNull final String authenticateUrl,
@NotNull final Path pathToProject,
@ -337,4 +360,18 @@ public class FactoryProjectImporter extends AbstractImporter {
callback.onFailure(error.getCause());
});
}
private class CheckoutContext {
private final String projectName;
private final String repository;
private final String branch;
private final String startPoint;
private CheckoutContext(String projectName, String repository, String branch, String startPoint) {
this.projectName = projectName;
this.repository = repository;
this.branch = branch;
this.startPoint = startPoint;
}
}
}

View File

@ -28,7 +28,6 @@ import org.eclipse.che.ide.api.data.tree.TreeExpander;
import org.eclipse.che.ide.api.data.tree.settings.NodeSettings;
import org.eclipse.che.ide.api.data.tree.settings.SettingsProvider;
import org.eclipse.che.ide.api.extension.ExtensionsInitializedEvent;
import org.eclipse.che.ide.api.extension.ExtensionsInitializedEvent.ExtensionsInitializedHandler;
import org.eclipse.che.ide.api.mvp.View;
import org.eclipse.che.ide.api.parts.base.BasePresenter;
import org.eclipse.che.ide.api.resources.Container;
@ -49,12 +48,6 @@ import org.eclipse.che.ide.resources.reveal.RevealResourceEvent;
import org.eclipse.che.ide.resources.tree.ResourceNode;
import org.eclipse.che.ide.ui.smartTree.NodeDescriptor;
import org.eclipse.che.ide.ui.smartTree.Tree;
import org.eclipse.che.ide.ui.smartTree.event.BeforeExpandNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.CollapseNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.ExpandNodeEvent;
import org.eclipse.che.ide.ui.smartTree.event.PostLoadEvent;
import org.eclipse.che.ide.ui.smartTree.event.SelectionChangedEvent;
import org.eclipse.che.ide.ui.smartTree.event.SelectionChangedEvent.SelectionChangedHandler;
import org.eclipse.che.providers.DynaObject;
import org.vectomatic.dom.svg.ui.SVGResource;
@ -90,6 +83,7 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
private final CoreLocalizationConstant locale;
private final Resources resources;
private final TreeExpander treeExpander;
private final AppContext appContext;
private final RequestTransmitter requestTransmitter;
private final DtoFactory dtoFactory;
private UpdateTask updateTask = new UpdateTask();
@ -112,6 +106,7 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
this.settingsProvider = settingsProvider;
this.locale = locale;
this.resources = resources;
this.appContext = appContext;
this.requestTransmitter = requestTransmitter;
this.dtoFactory = dtoFactory;
this.view.setDelegate(this);
@ -119,40 +114,22 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
eventBus.addHandler(ResourceChangedEvent.getType(), this);
eventBus.addHandler(MarkerChangedEvent.getType(), this);
eventBus.addHandler(SyntheticNodeUpdateEvent.getType(), this);
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, new WorkspaceStoppedEvent.Handler() {
@Override
public void onWorkspaceStopped(WorkspaceStoppedEvent event) {
getTree().getNodeStorage().clear();
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, event -> getTree().getNodeStorage().clear());
view.getTree().getSelectionModel().addSelectionChangedHandler(event -> setSelection(new Selection<>(event.getSelection())));
view.getTree().addBeforeExpandHandler(event -> {
NodeDescriptor nodeDescriptor = view.getTree().getNodeDescriptor(event.getNode());
if (event.getNode() instanceof SyntheticNode && nodeDescriptor != null && nodeDescriptor.isExpandDeep()) {
event.setCancelled(true);
}
});
view.getTree().getSelectionModel().addSelectionChangedHandler(new SelectionChangedHandler() {
@Override
public void onSelectionChanged(SelectionChangedEvent event) {
setSelection(new Selection<>(event.getSelection()));
}
});
view.getTree().addBeforeExpandHandler(new BeforeExpandNodeEvent.BeforeExpandNodeHandler() {
@Override
public void onBeforeExpand(BeforeExpandNodeEvent event) {
final NodeDescriptor nodeDescriptor = view.getTree().getNodeDescriptor(event.getNode());
if (event.getNode() instanceof SyntheticNode && nodeDescriptor != null && nodeDescriptor.isExpandDeep()) {
event.setCancelled(true);
}
}
});
view.getTree().getNodeLoader().addPostLoadHandler(new PostLoadEvent.PostLoadHandler() {
@Override
public void onPostLoad(PostLoadEvent event) {
for (Node node : event.getReceivedNodes()) {
if (node instanceof ResourceNode && expandQueue.remove(((ResourceNode)node).getData().getLocation())) {
view.getTree().setExpanded(node, true);
}
view.getTree().getNodeLoader().addPostLoadHandler(event -> {
for (Node node : event.getReceivedNodes()) {
if (node instanceof ResourceNode && expandQueue.remove(((ResourceNode)node).getData().getLocation())) {
view.getTree().setExpanded(node, true);
}
}
});
@ -162,12 +139,9 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
registerNative();
// when ide has already initialized, then we force set focus to the current part
eventBus.addHandler(ExtensionsInitializedEvent.getType(), new ExtensionsInitializedHandler() {
@Override
public void onExtensionsInitialized(ExtensionsInitializedEvent event) {
if (partStack != null) {
partStack.setActivePart(ProjectExplorerPresenter.this);
}
eventBus.addHandler(ExtensionsInitializedEvent.getType(), event -> {
if (partStack != null) {
partStack.setActivePart(ProjectExplorerPresenter.this);
}
});
}
@ -177,41 +151,35 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
final String endpointId = "ws-agent";
final String method = "track:project-tree";
getTree().addExpandHandler(new ExpandNodeEvent.ExpandNodeHandler() {
@Override
public void onExpand(ExpandNodeEvent event) {
Node node = event.getNode();
getTree().addExpandHandler(event -> {
Node node = event.getNode();
if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.newRequest()
.endpointId(endpointId)
.methodName(method)
.paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(START))
.sendAndSkipResult();
if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.newRequest()
.endpointId(endpointId)
.methodName(method)
.paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(START))
.sendAndSkipResult();
}
}
});
getTree().addCollapseHandler(new CollapseNodeEvent.CollapseNodeHandler() {
@Override
public void onCollapse(CollapseNodeEvent event) {
Node node = event.getNode();
getTree().addCollapseHandler(event -> {
Node node = event.getNode();
if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.newRequest()
.endpointId(endpointId)
.methodName(method)
.paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(STOP))
.sendAndSkipResult();
if (node instanceof ResourceNode) {
Resource data = ((ResourceNode)node).getData();
requestTransmitter.newRequest()
.endpointId(endpointId)
.methodName(method)
.paramsAsDto(dtoFactory.createDto(ProjectTreeTrackingOperationDto.class)
.withPath(data.getLocation().toString())
.withType(STOP))
.sendAndSkipResult();
}
}
});
}
@ -232,7 +200,11 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
ProjectExplorer.reveal = $entry(function (path) {
that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doReveal(*)(path);
})
});
ProjectExplorer.refresh = $entry(function () {
that.@org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter::doRefresh()();
});
$wnd.IDE.ProjectExplorer = ProjectExplorer;
}-*/;
@ -253,6 +225,10 @@ public class ProjectExplorerPresenter extends BasePresenter implements ActionDel
eventBus.fireEvent(new RevealResourceEvent(Path.valueOf(path)));
}
private void doRefresh() {
appContext.getWorkspaceRoot().synchronize();
}
@Override
@SuppressWarnings("unchecked")
public void onResourceChanged(ResourceChangedEvent event) {

View File

@ -110,7 +110,7 @@ class FileImpl extends ResourceImpl implements File {
/** {@inheritDoc} */
@Override
public Promise<Void> updateContent(String content) {
setModificationStamp(TextUtils.md5(content));
updateModificationStamp(content);
return resourceManager.write(this, content);
}
@ -140,4 +140,9 @@ class FileImpl extends ResourceImpl implements File {
public String getModificationStamp() {
return modificationStamp;
}
@Override
public void updateModificationStamp(String content) {
this.modificationStamp = TextUtils.md5(content);
}
}

View File

@ -2618,5 +2618,69 @@
}
],
"creator": "Dharmit Shah"
},
{
"id": "centos-go",
"creator": "Dharmit Shah",
"name": "CentOS Go",
"description": "CentOS based Go Stack",
"scope": "advanced",
"tags": [
"CentOS",
"Go"
],
"components": [
{
"name": "CentOS",
"version": "7.3"
},
{
"name": "Go",
"version": "1.6.2"
}
],
"source": {
"type": "image",
"origin": "registry.centos.org/che-stacks/centos-go"
},
"workspaceConfig": {
"environments": {
"default": {
"machines": {
"dev-machine": {
"agents": [
"org.eclipse.che.exec", "org.eclipse.che.terminal", "org.eclipse.che.ws-agent", "org.eclipse.che.ssh"
],
"servers": {},
"attributes" : {
"memoryLimitBytes": "2147483648"
}
}
},
"recipe": {
"location": "registry.centos.org/che-stacks/centos-go",
"type": "dockerimage"
}
}
},
"name": "default",
"defaultEnv": "default",
"description": null,
"commands": [
{
"name": "run",
"type": "custom",
"commandLine": "cd ${current.project.path} && go get -d && go run main.go",
"attributes": {
"previewUrl": "http://${server.port.8080}",
"goal": "Run"
}
}
]
},
"stackIcon": {
"name": "type-go.svg",
"mediaType": "image/svg+xml"
}
}
]

View File

@ -12,6 +12,8 @@ package org.eclipse.che.ide.editor.orion.client;
import com.google.web.bindery.event.shared.HandlerRegistration;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.VirtualFile;
import org.eclipse.che.ide.editor.orion.client.jso.ModelChangedEventOverlay;
import org.eclipse.che.ide.editor.orion.client.jso.OrionEditorOverlay;
import org.eclipse.che.ide.editor.orion.client.jso.OrionPixelPositionOverlay;
@ -197,6 +199,7 @@ public class OrionDocument extends AbstractDocument {
public void replace(int offset, int length, String text) {
this.editorOverlay.getModel().setText(text, offset, offset + length);
updateModificationTimeStamp();
}
@Override
@ -205,6 +208,14 @@ public class OrionDocument extends AbstractDocument {
int lineStart = model.getLineStart(startLine);
int lineEnd = model.getLineStart(endLine);
editorOverlay.setText(text, lineStart + startChar, lineEnd + endChar);
updateModificationTimeStamp();
}
private void updateModificationTimeStamp() {
VirtualFile file = this.getFile();
if (file instanceof File) {
((File)file).updateModificationStamp(editorOverlay.getText());
}
}
public int getContentsCharCount() {

View File

@ -1015,7 +1015,13 @@ public class OrionEditorPresenter extends AbstractEditorPresenter implements Tex
editorView.setEditorWidget(editorWidget);
document = editorWidget.getDocument();
document.setFile(input.getFile());
final VirtualFile file = input.getFile();
document.setFile(file);
if (file instanceof File) {
((File)file).updateModificationStamp(content);
}
cursorModel = new OrionCursorModel(document);
editorWidget.setTabSize(configuration.getTabWidth());
@ -1032,7 +1038,7 @@ public class OrionEditorPresenter extends AbstractEditorPresenter implements Tex
if (delayedFocus) {
editorWidget.refresh();
editorWidget.setFocus();
setSelection(new Selection<>(input.getFile()));
setSelection(new Selection<>(file));
delayedFocus = false;
}

View File

@ -70,6 +70,10 @@
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
@ -198,8 +202,11 @@
<exclude>**/DefaultServerEvaluationStrategyTest.java</exclude>
<exclude>**/LocalDockerServerEvaluationStrategy.java</exclude>
<exclude>**/LocalDockerServerEvaluationStrategyTest.java</exclude>
<exclude>**/LocalDockerCustomServerEvaluationStrategy.java</exclude>
<exclude>**/LocalDockerCustomServerEvaluationStrategyTest.java</exclude>
<exclude>**/DockerInstanceRuntimeInfo.java</exclude>
<exclude>**/DockerInstanceRuntimeInfoTest.java</exclude>
<exclude>**/ServerIdleDetector.java</exclude>
<!-- End excluded files -->
</excludes>
</configuration>

View File

@ -614,6 +614,12 @@ public class DockerMachineStarter {
env = commonMachineEnvVariables;
volumes = commonMachineSystemVolumes;
}
// register workspace ID and Machine Name
env.put(CHE_WORKSPACE_ID, workspaceId);
// FIXME: spi
// env.put(DockerInstanceRuntimeInfo.CHE_MACHINE_NAME, machineName);
// env.put(DockerInstanceRuntimeInfo.CHE_IS_DEV_MACHINE, Boolean.toString(isDev));
containerConfig.getExpose().addAll(portsToExpose);
containerConfig.getEnvironment().putAll(env);
containerConfig.getVolumes().addAll(volumes);

View File

@ -16,15 +16,11 @@ import com.google.inject.name.Named;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.eclipse.che.workspace.infrastructure.docker.strategy.BaseServerEvaluationStrategy;
import org.eclipse.che.workspace.infrastructure.docker.strategy.ServerEvaluationStrategy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Represents a server evaluation strategy for the configuration where the workspace server and
* workspace containers are running on the same Docker network. Calling
@ -37,63 +33,11 @@ import static com.google.common.base.Strings.isNullOrEmpty;
* @author Angel Misevski <amisevsk@redhat.com>
* @see ServerEvaluationStrategy
*/
public class LocalDockerServerEvaluationStrategy extends ServerEvaluationStrategy {
/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String internalAddressProperty;
/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String externalAddressProperty;
public class LocalDockerServerEvaluationStrategy extends BaseServerEvaluationStrategy {
@Inject
public LocalDockerServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress,
@Nullable @Named("che.docker.ip.external") String externalAddress) {
this.internalAddressProperty = internalAddress;
this.externalAddressProperty = externalAddress;
}
@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress();
String internalAddress;
boolean useExposedPorts = true;
if (!isNullOrEmpty(internalAddressContainer)) {
internalAddress = internalAddressContainer;
} else {
internalAddress = internalHost;
useExposedPorts = false;
}
Map<String, List<PortBinding>> portBindings = containerInfo.getNetworkSettings().getPorts();
Map<String, String> addressesAndPorts = new HashMap<>();
for (Map.Entry<String, List<PortBinding>> portEntry : portBindings.entrySet()) {
String exposedPort = portEntry.getKey().split("/")[0];
String ephemeralPort = portEntry.getValue().get(0).getHostPort();
if (useExposedPorts) {
addressesAndPorts.put(portEntry.getKey(), internalAddress + ":" + exposedPort);
} else {
addressesAndPorts.put(portEntry.getKey(), internalAddress + ":" + ephemeralPort);
}
}
return addressesAndPorts;
}
@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
String externalAddressContainer = containerInfo.getNetworkSettings().getGateway();
String externalAddress = externalAddressProperty != null ?
externalAddressProperty :
!isNullOrEmpty(externalAddressContainer) ?
externalAddressContainer :
internalHost;
return getExposedPortsToAddressPorts(externalAddress, containerInfo.getNetworkSettings().getPorts());
super(internalAddress, externalAddress, null, null, null, true);
}
}

View File

@ -0,0 +1,514 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.docker.strategy;
import com.google.common.base.Strings;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.stringtemplate.v4.ST;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Represents a server evaluation strategy for the configuration where the strategy can be customized through template properties.
*
* @author Florent Benoit
* @see ServerEvaluationStrategy
*/
public abstract class BaseServerEvaluationStrategy extends ServerEvaluationStrategy {
/**
* Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references
*/
public static final String LABEL_CHE_SERVER_REF_KEY = "^che:server:(.*):ref$";
/**
* Name of the property for getting the workspace ID.
*/
public static final String CHE_WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=";
/**
* Name of the property to get the machine name property
*/
public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=";
/**
* Name of the property to get the property that indicates if the machine is the dev machine
*/
public static final String CHE_IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE=";
/**
* Prefix added in front of the generated name to build the workspaceId
*/
public static final String CHE_WORKSPACE_ID_PREFIX = "workspace";
/**
* name of the macro that indicates if the machine is the dev machine
*/
public static final String IS_DEV_MACHINE_MACRO = "isDevMachine";
/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String cheDockerIp;
/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String cheDockerIpExternal;
/**
* The current port of che.
*/
private final String chePort;
/**
* Secured or not ? (for example https vs http)
*/
private final String cheDockerCustomExternalProtocol;
/**
* Template for external addresses.
*/
private String cheDockerCustomExternalTemplate;
/**
* Option to enable the use of the container address, when searching for addresses.
*/
private boolean localDockerMode;
/**
* Option to tell if an exception should be thrown when the host defined in the `externalAddress` isn't known
* and cannot be converted into a valid IP.
*/
private boolean throwOnUnknownHost = true;
/**
* Default constructor
*/
public BaseServerEvaluationStrategy(String cheDockerIp,
String cheDockerIpExternal,
String cheDockerCustomExternalTemplate,
String cheDockerCustomExternalProtocol,
String chePort) {
this(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false);
}
/**
* Constructor to be called by derived strategies
*/
public BaseServerEvaluationStrategy(String cheDockerIp,
String cheDockerIpExternal,
String cheDockerCustomExternalTemplate,
String cheDockerCustomExternalProtocol,
String chePort,
boolean localDockerMode) {
this.cheDockerIp = cheDockerIp;
this.cheDockerIpExternal = cheDockerIpExternal;
this.chePort = chePort;
this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate;
this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol;
this.localDockerMode = localDockerMode;
}
@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
final String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress();
final String internalAddress;
if (localDockerMode) {
internalAddress = !isNullOrEmpty(internalAddressContainer) ?
internalAddressContainer :
internalHost;
} else {
internalAddress =
cheDockerIp != null ?
cheDockerIp :
internalHost;
}
boolean useExposedPorts = localDockerMode && internalAddress != internalHost;
return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts(), useExposedPorts);
}
/**
* Override the host for all ports by using the external template.
*/
@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
// create Rendering evaluation
RenderingEvaluation renderingEvaluation = getOnlineRenderingEvaluation(containerInfo, internalHost);
// get current ports
Map<String, List<PortBinding>> ports = containerInfo.getNetworkSettings().getPorts();
if (isNullOrEmpty(cheDockerCustomExternalTemplate)) {
return getExposedPortsToAddressPorts(renderingEvaluation.getExternalAddress(), ports, false);
}
return ports.keySet().stream()
.collect(Collectors.toMap(portKey -> portKey,
portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey)));
}
/**
* Constructs a map of {@link ServerImpl} from provided parameters, using selected strategy
* for evaluating addresses and ports.
*
* <p>Keys consist of port number and transport protocol (tcp or udp) separated by
* a forward slash (e.g. 8080/tcp)
*
* @param containerInfo
* the {@link ContainerInfo} describing the container.
* @param internalHost
* alternative hostname to use, if address cannot be obtained from containerInfo
* @param serverConfMap
* additional Map of {@link OldServerConfImpl}. Configurations here override those found
* in containerInfo.
* @return a Map of the servers exposed by the container.
*/
public Map<String, ServerImpl> getServers(ContainerInfo containerInfo,
String internalHost,
Map<String, OldServerConfImpl> serverConfMap) {
Map<String, ServerImpl> servers = super.getServers(containerInfo, internalHost, serverConfMap);
return servers.entrySet().stream().collect(Collectors.toMap(map -> map.getKey(), map -> updateServer(map.getValue())));
}
/**
* Updates the protocol for the given server by using given protocol (like https) for http URLs.
* @param server the server to update
* @return updated server object
*/
protected ServerImpl updateServer(ServerImpl server) {
if (!Strings.isNullOrEmpty(cheDockerCustomExternalProtocol)) {
// FIXME: spi
// if ("http".equals(server.getProtocol())) {
// server.setProtocol(cheDockerCustomExternalProtocol);
// String url = server.getUrl();
// int length = "http".length();
// server.setUrl(cheDockerCustomExternalProtocol.concat(url.substring(length)));
// }
}
return server;
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called online as in this case we have access to container info
*/
public RenderingEvaluation getOnlineRenderingEvaluation(ContainerInfo containerInfo, String internalHost) {
return new OnlineRenderingEvaluation(containerInfo).withInternalHost(internalHost);
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called offline as without container info, user need to provide merge of container and images data
*/
public RenderingEvaluation getOfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
return new OfflineRenderingEvaluation(labels, exposedPorts, env);
}
/**
* Simple interface for performing the rendering for a given portby using the given template
*
* @author Florent Benoit
*/
public interface RenderingEvaluation {
/**
* Gets the template rendering for the given port and using the given template
*
* @param template
* which can include <propertyName></propertyName>
* @param port
* the port for the mapping
* @return the rendering of the template
*/
String render(String template, String port);
/**
* Gets default external address.
*/
String getExternalAddress();
}
/**
* Online implementation (using the container info)
*/
protected class OnlineRenderingEvaluation extends OfflineRenderingEvaluation implements RenderingEvaluation {
private String gatewayAddressContainer;
private String internalHost;
protected OnlineRenderingEvaluation(ContainerInfo containerInfo) {
super(containerInfo.getConfig().getLabels(), containerInfo.getConfig().getExposedPorts().keySet(),
containerInfo.getConfig().getEnv());
this.gatewayAddressContainer = containerInfo.getNetworkSettings().getGateway();
}
protected OnlineRenderingEvaluation withInternalHost(String internalHost) {
this.internalHost = internalHost;
return this;
}
@Override
public String getExternalAddress() {
if (localDockerMode) {
return cheDockerIpExternal != null ?
cheDockerIpExternal :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}
return cheDockerIpExternal != null ?
cheDockerIpExternal :
cheDockerIp != null ?
cheDockerIp :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}
}
/**
* Offline implementation (container not yet created)
*/
protected class OfflineRenderingEvaluation extends DefaultRenderingEvaluation implements RenderingEvaluation {
public OfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
super(labels, exposedPorts, env);
}
}
/**
* Inner class used to perform the rendering
*/
protected abstract class DefaultRenderingEvaluation implements RenderingEvaluation {
/**
* Labels
*/
private Map<String, String> labels;
/**
* Ports
*/
private Set<String> exposedPorts;
/**
* Environment variables
*/
private final String[] env;
/**
* Map with properties for all ports
*/
private Map<String, String> globalPropertiesMap = new HashMap<>();
/**
* Mapping between a port and the server ref name
*/
private Map<String, String> portsToRefName;
/**
* Data initialized ?
*/
private boolean initialized;
/**
* Default constructor.
*/
protected DefaultRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
this.labels = labels;
this.exposedPorts = exposedPorts;
this.env = env;
}
/**
* Initialize data
*/
protected void init() {
this.initPortMapping();
this.populateGlobalProperties();
}
/**
* Compute port mapping with server ref name
*/
protected void initPortMapping() {
// ok, so now we have a map of labels and a map of exposed ports
// need to extract the name of the ref (if defined in a label) or then pickup default name "Server-<port>-<protocol>"
Pattern pattern = Pattern.compile(LABEL_CHE_SERVER_REF_KEY);
Map<String, String> portsToKnownRefName = labels.entrySet().stream()
.filter(map -> pattern.matcher(map.getKey()).matches())
.collect(Collectors.toMap(p -> {
Matcher matcher = pattern.matcher(p.getKey());
matcher.matches();
String val = matcher.group(1);
return val.contains("/") ? val : val.concat("/tcp");
}, p -> p.getValue()));
// add to this map only port without a known ref name
Map<String, String> portsToUnkownRefName =
exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port))
.collect(Collectors.toMap(p -> p, p -> "server-" + p.replace('/', '-')));
// list of all ports with refName (known/unknown)
this.portsToRefName = new HashMap(portsToKnownRefName);
portsToRefName.putAll(portsToUnkownRefName);
}
/**
* Gets default external address.
*/
public String getExternalAddress() {
return cheDockerIpExternal != null ?
cheDockerIpExternal : cheDockerIp;
}
/**
* Populate the template properties
*/
protected void populateGlobalProperties() {
String externalAddress = getExternalAddress();
String externalIP = getExternalIp(externalAddress);
globalPropertiesMap.put("internalIp", cheDockerIp);
globalPropertiesMap.put("externalAddress", externalAddress);
globalPropertiesMap.put("externalIP", externalIP);
globalPropertiesMap.put("workspaceId", getWorkspaceId());
globalPropertiesMap.put("workspaceIdWithoutPrefix", getWorkspaceId().replaceFirst(CHE_WORKSPACE_ID_PREFIX,""));
globalPropertiesMap.put("machineName", getMachineName());
globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress));
globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress));
globalPropertiesMap.put("chePort", chePort);
globalPropertiesMap.put(IS_DEV_MACHINE_MACRO, getIsDevMachine());
}
/**
* Rendering
*/
@Override
public String render(String template, String port) {
if (!this.initialized) {
init();
this.initialized = true;
}
ST stringTemplate = new ST(template);
globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key,
IS_DEV_MACHINE_MACRO.equals(key) ?
Boolean.parseBoolean(value)
: value));
stringTemplate.add("serverName", portsToRefName.get(port));
return stringTemplate.render();
}
/**
* returns if the current machine is the dev machine
*
* @return true if the curent machine is the dev machine
*/
protected String getIsDevMachine() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_IS_DEV_MACHINE_PROPERTY))
.map(s -> s.substring(CHE_IS_DEV_MACHINE_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the workspace ID from the config of the given container
*
* @return workspace ID
*/
protected String getWorkspaceId() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_WORKSPACE_ID_PROPERTY))
.map(s -> s.substring(CHE_WORKSPACE_ID_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the workspace Machine Name from the config of the given container
*
* @return machine name of the workspace
*/
protected String getMachineName() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_MACHINE_NAME_PROPERTY))
.map(s -> s.substring(CHE_MACHINE_NAME_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the IP address of the external address
*
* @return IP Address
*/
protected String getExternalIp(String externalAddress) {
try {
return InetAddress.getByName(externalAddress).getHostAddress();
} catch (UnknownHostException e) {
if (throwOnUnknownHost) {
throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e);
}
}
return null;
}
/**
* Gets a Wildcard domain based on the ip using an external provider nip.io
*
* @return wildcard domain
*/
protected String getWildcardNipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "nip.io");
}
/**
* Gets a Wildcard domain based on the ip using an external provider xip.io
*
* @return wildcard domain
*/
protected String getWildcardXipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "xip.io");
}
}
@Override
protected boolean useHttpsForExternalUrls() {
return "https".equals(cheDockerCustomExternalProtocol);
}
public BaseServerEvaluationStrategy withThrowOnUnknownHost(boolean throwOnUnknownHost) {
this.throwOnUnknownHost = throwOnUnknownHost;
return this;
}
}

View File

@ -31,42 +31,11 @@ import java.util.Map;
* @author Alexander Garagatyi
* @see ServerEvaluationStrategy
*/
public class DefaultServerEvaluationStrategy extends ServerEvaluationStrategy {
/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String internalAddressProperty;
/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String externalAddressProperty;
public class DefaultServerEvaluationStrategy extends BaseServerEvaluationStrategy {
@Inject
public DefaultServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress,
@Nullable @Named("che.docker.ip.external") String externalAddress) {
this.internalAddressProperty = internalAddress;
this.externalAddressProperty = externalAddress;
}
@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
String internalAddress = internalAddressProperty != null ?
internalAddressProperty :
internalHost;
return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts());
}
@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
String externalAddress = externalAddressProperty != null ?
externalAddressProperty :
internalAddressProperty != null ?
internalAddressProperty :
internalHost;
return super.getExposedPortsToAddressPorts(externalAddress, containerInfo.getNetworkSettings().getPorts());
super(internalAddress, externalAddress, null, null, null, false);
}
}

View File

@ -10,16 +10,16 @@
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.docker.strategy;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
/**
* Represents a strategy for resolving Servers associated with workspace containers.
* Used to extract relevant information from e.g. {@link ContainerInfo} into a map of
@ -27,14 +27,26 @@ import java.util.Map;
*
* @author Angel Misevski <amisevsk@redhat.com>
* @author Alexander Garagatyi
* @author Ilya Buziuk
* @see ServerEvaluationStrategyProvider
*/
public abstract class ServerEvaluationStrategy {
private static final String HTTP = "http";
private static final String HTTPS = "https";
protected static final String SERVER_CONF_LABEL_REF_KEY = "che:server:%s:ref";
protected static final String SERVER_CONF_LABEL_PROTOCOL_KEY = "che:server:%s:protocol";
protected static final String SERVER_CONF_LABEL_PATH_KEY = "che:server:%s:path";
/**
* @return true if <strong>external</strong> addresses need to be exposed against https, false otherwise
*/
protected boolean useHttpsForExternalUrls() {
return false;
}
/**
* Gets a map of all <strong>internal</strong> addresses exposed by the container in the form of
* {@code "<address>:<port>"}
@ -109,7 +121,11 @@ public abstract class ServerEvaluationStrategy {
// Add protocol and path to internal/external address, if applicable
String internalUrl = null;
String externalUrl = null;
if (serverConf.getProtocol() != null) {
String internalProtocol = serverConf.getProtocol();
String externalProtocol = getProtocolForExternalUrl(internalProtocol);
if (internalProtocol != null) {
String pathSuffix = serverConf.getPath();
if (pathSuffix != null && !pathSuffix.isEmpty()) {
if (pathSuffix.charAt(0) != '/') {
@ -118,8 +134,9 @@ public abstract class ServerEvaluationStrategy {
} else {
pathSuffix = "";
}
internalUrl = serverConf.getProtocol() + "://" + internalAddressAndPort + pathSuffix;
externalUrl = serverConf.getProtocol() + "://" + externalAddressAndPort + pathSuffix;
internalUrl = internalProtocol + "://" + internalAddressAndPort + pathSuffix;
externalUrl = externalProtocol + "://" + externalAddressAndPort + pathSuffix;
}
servers.put(serverConf.getRef(), new ServerImpl(externalUrl));
@ -215,14 +232,37 @@ public abstract class ServerEvaluationStrategy {
* "9090/udp" : "my-host.com:32722"
* }
* }</pre>
*
*/
protected Map<String, String> getExposedPortsToAddressPorts(String address, Map<String, List<PortBinding>> ports) {
protected Map<String, String> getExposedPortsToAddressPorts(String address, Map<String, List<PortBinding>> ports, boolean useExposedPorts) {
Map<String, String> addressesAndPorts = new HashMap<>();
for (Map.Entry<String, List<PortBinding>> portEntry : ports.entrySet()) {
String exposedPort = portEntry.getKey().split("/")[0];
// there is one value always
String port = portEntry.getValue().get(0).getHostPort();
addressesAndPorts.put(portEntry.getKey(), address + ":" + port);
String ephemeralPort = portEntry.getValue().get(0).getHostPort();
if (useExposedPorts) {
addressesAndPorts.put(portEntry.getKey(), address + ":" + exposedPort);
} else {
addressesAndPorts.put(portEntry.getKey(), address + ":" + ephemeralPort);
}
}
return addressesAndPorts;
}
protected Map<String, String> getExposedPortsToAddressPorts(String address, Map<String, List<PortBinding>> ports) {
return getExposedPortsToAddressPorts(address, ports, false);
}
/**
* @param protocolForInternalUrl
* @return https, if {@link #useHttpsForExternalUrls()} method in sub-class returns true and protocol for internal Url is http
*/
private String getProtocolForExternalUrl(final String protocolForInternalUrl) {
if (useHttpsForExternalUrls() && HTTP.equals(protocolForInternalUrl)) {
return HTTPS;
}
return protocolForInternalUrl;
}
}

View File

@ -60,7 +60,7 @@ public class ServerEvaluationStrategyTest {
expected.put("9090/udp", DEFAULT_HOSTNAME + ":" + "32101");
// when
Map<String, String> actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports);
Map<String, String> actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false);
// then
assertEquals(actual, expected);
@ -85,7 +85,7 @@ public class ServerEvaluationStrategyTest {
expected.put("9090/udp", DEFAULT_HOSTNAME + ":" + "32101");
// when
Map<String, String> actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports);
Map<String, String> actual = strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false);
// then
assertEquals(actual, expected);
@ -352,7 +352,7 @@ public class ServerEvaluationStrategyTest {
.withHostPort("32101")));
when(networkSettings.getPorts()).thenReturn(ports);
Map<String, String> exposedPortsToAddressPorts =
strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports);
strategy.getExposedPortsToAddressPorts(DEFAULT_HOSTNAME, ports, false);
when(strategy.getExternalAddressesAndPorts(containerInfo, DEFAULT_HOSTNAME))
.thenReturn(exposedPortsToAddressPorts);
when(strategy.getInternalAddressesAndPorts(containerInfo, DEFAULT_HOSTNAME))
@ -373,6 +373,11 @@ public class ServerEvaluationStrategyTest {
String internalAddress) {
return null;
}
@Override
protected boolean useHttpsForExternalUrls() {
return false;
}
}
*/
}

View File

@ -54,7 +54,7 @@ public class ComposerValueProviderFactory implements ValueProviderFactory {
JsonObject model = readModel(projectFolder);
String value = "";
if (attributeName.equals(PACKAGE)) {
if (attributeName.equals(PACKAGE) && model.has("name")) {
value = model.get("name").getAsString();
}

View File

@ -20,7 +20,7 @@ public class Exec {
private final String[] command;
private final String id;
Exec(String[] command, String id) {
public Exec(String[] command, String id) {
this.command = command;
this.id = id;
}

View File

@ -0,0 +1,517 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.machine;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl;
import org.eclipse.che.api.machine.server.model.impl.ServerImpl;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.stringtemplate.v4.ST;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Represents a server evaluation strategy for the configuration where the strategy can be customized through template properties.
*
* @author Florent Benoit
* @see ServerEvaluationStrategy
*/
public abstract class BaseServerEvaluationStrategy extends ServerEvaluationStrategy {
/**
* Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references
*/
public static final String LABEL_CHE_SERVER_REF_KEY = "^che:server:(.*):ref$";
/**
* Name of the property for getting the workspace ID.
*/
public static final String CHE_WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=";
/**
* Name of the property to get the machine name property
*/
public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=";
/**
* Name of the property to get the property that indicates if the machine is the dev machine
*/
public static final String CHE_IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE=";
/**
* Prefix added in front of the generated name to build the workspaceId
*/
public static final String CHE_WORKSPACE_ID_PREFIX = "workspace";
/**
* name of the macro that indicates if the machine is the dev machine
*/
public static final String IS_DEV_MACHINE_MACRO = "isDevMachine";
/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String cheDockerIp;
/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String cheDockerIpExternal;
/**
* The current port of che.
*/
private final String chePort;
/**
* Secured or not ? (for example https vs http)
*/
private final String cheDockerCustomExternalProtocol;
/**
* Template for external addresses.
*/
private String cheDockerCustomExternalTemplate;
/**
* Option to enable the use of the container address, when searching for addresses.
*/
private boolean localDockerMode;
/**
* Option to tell if an exception should be thrown when the host defined in the `externalAddress` isn't known
* and cannot be converted into a valid IP.
*/
private boolean throwOnUnknownHost = true;
/**
* Default constructor
*/
public BaseServerEvaluationStrategy(String cheDockerIp,
String cheDockerIpExternal,
String cheDockerCustomExternalTemplate,
String cheDockerCustomExternalProtocol,
String chePort) {
this(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false);
}
/**
* Constructor to be called by derived strategies
*/
public BaseServerEvaluationStrategy(String cheDockerIp,
String cheDockerIpExternal,
String cheDockerCustomExternalTemplate,
String cheDockerCustomExternalProtocol,
String chePort,
boolean localDockerMode) {
this.cheDockerIp = cheDockerIp;
this.cheDockerIpExternal = cheDockerIpExternal;
this.chePort = chePort;
this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate;
this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol;
this.localDockerMode = localDockerMode;
}
@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
final String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress();
final String internalAddress;
if (localDockerMode) {
internalAddress = !isNullOrEmpty(internalAddressContainer) ?
internalAddressContainer :
internalHost;
} else {
internalAddress =
cheDockerIp != null ?
cheDockerIp :
internalHost;
}
boolean useExposedPorts = localDockerMode && internalAddress != internalHost;
return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts(), useExposedPorts);
}
/**
* Override the host for all ports by using the external template.
*/
@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
// create Rendering evaluation
RenderingEvaluation renderingEvaluation = getOnlineRenderingEvaluation(containerInfo, internalHost);
// get current ports
Map<String, List<PortBinding>> ports = containerInfo.getNetworkSettings().getPorts();
if (isNullOrEmpty(cheDockerCustomExternalTemplate)) {
return getExposedPortsToAddressPorts(renderingEvaluation.getExternalAddress(), ports, false);
}
return ports.keySet().stream()
.collect(Collectors.toMap(portKey -> portKey,
portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey)));
}
/**
* Constructs a map of {@link ServerImpl} from provided parameters, using selected strategy
* for evaluating addresses and ports.
*
* <p>Keys consist of port number and transport protocol (tcp or udp) separated by
* a forward slash (e.g. 8080/tcp)
*
* @param containerInfo
* the {@link ContainerInfo} describing the container.
* @param internalHost
* alternative hostname to use, if address cannot be obtained from containerInfo
* @param serverConfMap
* additional Map of {@link ServerConfImpl}. Configurations here override those found
* in containerInfo.
* @return a Map of the servers exposed by the container.
*/
public Map<String, ServerImpl> getServers(ContainerInfo containerInfo,
String internalHost,
Map<String, ServerConfImpl> serverConfMap) {
Map<String, ServerImpl> servers = super.getServers(containerInfo, internalHost, serverConfMap);
return servers.entrySet().stream().collect(Collectors.toMap(map -> map.getKey(), map -> updateServer(map.getValue())));
}
/**
* Updates the protocol for the given server by using given protocol (like https) for http URLs.
* @param server the server to update
* @return updated server object
*/
protected ServerImpl updateServer(ServerImpl server) {
if (!Strings.isNullOrEmpty(cheDockerCustomExternalProtocol)) {
if ("http".equals(server.getProtocol())) {
server.setProtocol(cheDockerCustomExternalProtocol);
String url = server.getUrl();
int length = "http".length();
server.setUrl(cheDockerCustomExternalProtocol.concat(url.substring(length)));
}
}
return server;
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called online as in this case we have access to container info
*/
public RenderingEvaluation getOnlineRenderingEvaluation(ContainerInfo containerInfo, String internalHost) {
return new OnlineRenderingEvaluation(containerInfo).withInternalHost(internalHost);
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called offline as without container info, user need to provide merge of container and images data
*/
public RenderingEvaluation getOfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
return new OfflineRenderingEvaluation(labels, exposedPorts, env);
}
/**
* Simple interface for performing the rendering for a given portby using the given template
*
* @author Florent Benoit
*/
public interface RenderingEvaluation {
/**
* Gets the template rendering for the given port and using the given template
*
* @param template
* which can include <propertyName></propertyName>
* @param port
* the port for the mapping
* @return the rendering of the template
*/
String render(String template, String port);
/**
* Gets default external address.
*/
String getExternalAddress();
}
/**
* Online implementation (using the container info)
*/
protected class OnlineRenderingEvaluation extends OfflineRenderingEvaluation implements RenderingEvaluation {
private String gatewayAddressContainer;
private String internalHost;
protected OnlineRenderingEvaluation(ContainerInfo containerInfo) {
super(containerInfo.getConfig().getLabels(), containerInfo.getConfig().getExposedPorts().keySet(),
containerInfo.getConfig().getEnv());
this.gatewayAddressContainer = containerInfo.getNetworkSettings().getGateway();
}
protected OnlineRenderingEvaluation withInternalHost(String internalHost) {
this.internalHost = internalHost;
return this;
}
@Override
public String getExternalAddress() {
if (localDockerMode) {
return cheDockerIpExternal != null ?
cheDockerIpExternal :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}
return cheDockerIpExternal != null ?
cheDockerIpExternal :
cheDockerIp != null ?
cheDockerIp :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}
}
/**
* Offline implementation (container not yet created)
*/
protected class OfflineRenderingEvaluation extends DefaultRenderingEvaluation implements RenderingEvaluation {
public OfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
super(labels, exposedPorts, env);
}
}
/**
* Inner class used to perform the rendering
*/
protected abstract class DefaultRenderingEvaluation implements RenderingEvaluation {
/**
* Labels
*/
private Map<String, String> labels;
/**
* Ports
*/
private Set<String> exposedPorts;
/**
* Environment variables
*/
private final String[] env;
/**
* Map with properties for all ports
*/
private Map<String, String> globalPropertiesMap = new HashMap<>();
/**
* Mapping between a port and the server ref name
*/
private Map<String, String> portsToRefName;
/**
* Data initialized ?
*/
private boolean initialized;
/**
* Default constructor.
*/
protected DefaultRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
this.labels = labels;
this.exposedPorts = exposedPorts;
this.env = env;
}
/**
* Initialize data
*/
protected void init() {
this.initPortMapping();
this.populateGlobalProperties();
}
/**
* Compute port mapping with server ref name
*/
protected void initPortMapping() {
// ok, so now we have a map of labels and a map of exposed ports
// need to extract the name of the ref (if defined in a label) or then pickup default name "Server-<port>-<protocol>"
Pattern pattern = Pattern.compile(LABEL_CHE_SERVER_REF_KEY);
Map<String, String> portsToKnownRefName = labels.entrySet().stream()
.filter(map -> pattern.matcher(map.getKey()).matches())
.collect(Collectors.toMap(p -> {
Matcher matcher = pattern.matcher(p.getKey());
matcher.matches();
String val = matcher.group(1);
return val.contains("/") ? val : val.concat("/tcp");
}, p -> p.getValue()));
// add to this map only port without a known ref name
Map<String, String> portsToUnkownRefName =
exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port))
.collect(Collectors.toMap(p -> p, p -> "server-" + p.replace('/', '-')));
// list of all ports with refName (known/unknown)
this.portsToRefName = new HashMap(portsToKnownRefName);
portsToRefName.putAll(portsToUnkownRefName);
}
/**
* Gets default external address.
*/
public String getExternalAddress() {
return cheDockerIpExternal != null ?
cheDockerIpExternal : cheDockerIp;
}
/**
* Populate the template properties
*/
protected void populateGlobalProperties() {
String externalAddress = getExternalAddress();
String externalIP = getExternalIp(externalAddress);
globalPropertiesMap.put("internalIp", cheDockerIp);
globalPropertiesMap.put("externalAddress", externalAddress);
globalPropertiesMap.put("externalIP", externalIP);
globalPropertiesMap.put("workspaceId", getWorkspaceId());
globalPropertiesMap.put("workspaceIdWithoutPrefix", getWorkspaceId().replaceFirst(CHE_WORKSPACE_ID_PREFIX,""));
globalPropertiesMap.put("machineName", getMachineName());
globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress));
globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress));
globalPropertiesMap.put("chePort", chePort);
globalPropertiesMap.put(IS_DEV_MACHINE_MACRO, getIsDevMachine());
}
/**
* Rendering
*/
@Override
public String render(String template, String port) {
if (!this.initialized) {
init();
this.initialized = true;
}
ST stringTemplate = new ST(template);
globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key,
IS_DEV_MACHINE_MACRO.equals(key) ?
Boolean.parseBoolean(value)
: value));
stringTemplate.add("serverName", portsToRefName.get(port));
return stringTemplate.render();
}
/**
* returns if the current machine is the dev machine
*
* @return true if the curent machine is the dev machine
*/
protected String getIsDevMachine() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_IS_DEV_MACHINE_PROPERTY))
.map(s -> s.substring(CHE_IS_DEV_MACHINE_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the workspace ID from the config of the given container
*
* @return workspace ID
*/
protected String getWorkspaceId() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_WORKSPACE_ID_PROPERTY))
.map(s -> s.substring(CHE_WORKSPACE_ID_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the workspace Machine Name from the config of the given container
*
* @return machine name of the workspace
*/
protected String getMachineName() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_MACHINE_NAME_PROPERTY))
.map(s -> s.substring(CHE_MACHINE_NAME_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the IP address of the external address
*
* @return IP Address
*/
protected String getExternalIp(String externalAddress) {
try {
return InetAddress.getByName(externalAddress).getHostAddress();
} catch (UnknownHostException e) {
if (throwOnUnknownHost) {
throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e);
}
}
return null;
}
/**
* Gets a Wildcard domain based on the ip using an external provider nip.io
*
* @return wildcard domain
*/
protected String getWildcardNipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "nip.io");
}
/**
* Gets a Wildcard domain based on the ip using an external provider xip.io
*
* @return wildcard domain
*/
protected String getWildcardXipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "xip.io");
}
}
@Override
protected boolean useHttpsForExternalUrls() {
return "https".equals(cheDockerCustomExternalProtocol);
}
public BaseServerEvaluationStrategy withThrowOnUnknownHost(boolean throwOnUnknownHost) {
this.throwOnUnknownHost = throwOnUnknownHost;
return this;
}
}

View File

@ -10,29 +10,10 @@
*******************************************************************************/
package org.eclipse.che.plugin.docker.machine;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl;
import org.eclipse.che.api.machine.server.model.impl.ServerImpl;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.stringtemplate.v4.ST;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Represents a server evaluation strategy for the configuration where the strategy can be customized through template properties.
@ -40,39 +21,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
* @author Florent Benoit
* @see ServerEvaluationStrategy
*/
public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrategy {
/**
* Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references
*/
public static final String LABEL_CHE_SERVER_REF_KEY = "^che:server:(.*):ref$";
/**
* Name of the property for getting the workspace ID.
*/
public static final String CHE_WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=";
/**
* Name of the property to get the machine name property
*/
public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=";
/**
* The current port of che.
*/
private final String chePort;
/**
* Secured or not ? (for example https vs http)
*/
private final String cheDockerCustomExternalProtocol;
/**
* Template for external addresses.
*/
private String cheDockerCustomExternalTemplate;
public class CustomServerEvaluationStrategy extends BaseServerEvaluationStrategy {
/**
* Default constructor
*/
@ -82,317 +31,6 @@ public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrat
@Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol,
@Named("che.port") String chePort) {
super(cheDockerIp, cheDockerIpExternal);
this.chePort = chePort;
this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate;
this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol;
super(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false);
}
/**
* Override the host for all ports by using the external template.
*/
@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
// create Rendering evaluation
RenderingEvaluation renderingEvaluation = getOnlineRenderingEvaluation(containerInfo, internalHost);
// get current ports
Map<String, List<PortBinding>> ports = containerInfo.getNetworkSettings().getPorts();
return ports.keySet().stream()
.collect(Collectors.toMap(portKey -> portKey,
portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey)));
}
/**
* Constructs a map of {@link ServerImpl} from provided parameters, using selected strategy
* for evaluating addresses and ports.
*
* <p>Keys consist of port number and transport protocol (tcp or udp) separated by
* a forward slash (e.g. 8080/tcp)
*
* @param containerInfo
* the {@link ContainerInfo} describing the container.
* @param internalHost
* alternative hostname to use, if address cannot be obtained from containerInfo
* @param serverConfMap
* additional Map of {@link ServerConfImpl}. Configurations here override those found
* in containerInfo.
* @return a Map of the servers exposed by the container.
*/
public Map<String, ServerImpl> getServers(ContainerInfo containerInfo,
String internalHost,
Map<String, ServerConfImpl> serverConfMap) {
Map<String, ServerImpl> servers = super.getServers(containerInfo, internalHost, serverConfMap);
return servers.entrySet().stream().collect(Collectors.toMap(map -> map.getKey(), map -> updateServer(map.getValue())));
}
/**
* Updates the protocol for the given server by using given protocol (like https) for http URLs.
* @param server the server to update
* @return updated server object
*/
protected ServerImpl updateServer(ServerImpl server) {
if (!Strings.isNullOrEmpty(cheDockerCustomExternalProtocol)) {
if ("http".equals(server.getProtocol())) {
server.setProtocol(cheDockerCustomExternalProtocol);
String url = server.getUrl();
int length = "http".length();
server.setUrl(cheDockerCustomExternalProtocol.concat(url.substring(length)));
}
}
return server;
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called online as in this case we have access to container info
*/
public RenderingEvaluation getOnlineRenderingEvaluation(ContainerInfo containerInfo, String internalHost) {
return new OnlineRenderingEvaluation(containerInfo).withInternalHost(internalHost);
}
/**
* Allow to get the rendering outside of the evaluation strategies.
* It is called offline as without container info, user need to provide merge of container and images data
*/
public RenderingEvaluation getOfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
return new OfflineRenderingEvaluation(labels, exposedPorts, env);
}
/**
* Simple interface for performing the rendering for a given portby using the given template
*
* @author Florent Benoit
*/
public interface RenderingEvaluation {
/**
* Gets the template rendering for the given port and using the given template
*
* @param template
* which can include <propertyName></propertyName>
* @param port
* the port for the mapping
* @return the rendering of the template
*/
String render(String template, String port);
}
/**
* Online implementation (using the container info)
*/
protected class OnlineRenderingEvaluation extends OfflineRenderingEvaluation implements RenderingEvaluation {
private String gatewayAddressContainer;
private String internalHost;
protected OnlineRenderingEvaluation(ContainerInfo containerInfo) {
super(containerInfo.getConfig().getLabels(), containerInfo.getConfig().getExposedPorts().keySet(),
containerInfo.getConfig().getEnv());
this.gatewayAddressContainer = containerInfo.getNetworkSettings().getGateway();
}
protected OnlineRenderingEvaluation withInternalHost(String internalHost) {
this.internalHost = internalHost;
return this;
}
@Override
protected String getExternalAddress() {
return externalAddressProperty != null ?
externalAddressProperty :
internalAddressProperty != null ?
internalAddressProperty :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}
}
/**
* Offline implementation (container not yet created)
*/
protected class OfflineRenderingEvaluation extends DefaultRenderingEvaluation implements RenderingEvaluation {
public OfflineRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
super(labels, exposedPorts, env);
}
}
/**
* Inner class used to perform the rendering
*/
protected abstract class DefaultRenderingEvaluation implements RenderingEvaluation {
/**
* Labels
*/
private Map<String, String> labels;
/**
* Ports
*/
private Set<String> exposedPorts;
/**
* Environment variables
*/
private final String[] env;
/**
* Map with properties for all ports
*/
private Map<String, String> globalPropertiesMap = new HashMap<>();
/**
* Mapping between a port and the server ref name
*/
private Map<String, String> portsToRefName;
/**
* Data initialized ?
*/
private boolean initialized;
/**
* Default constructor.
*/
protected DefaultRenderingEvaluation(Map<String, String> labels, Set<String> exposedPorts, String[] env) {
this.labels = labels;
this.exposedPorts = exposedPorts;
this.env = env;
}
/**
* Initialize data
*/
protected void init() {
this.initPortMapping();
this.populateGlobalProperties();
}
/**
* Compute port mapping with server ref name
*/
protected void initPortMapping() {
// ok, so now we have a map of labels and a map of exposed ports
// need to extract the name of the ref (if defined in a label) or then pickup default name "Server-<port>-<protocol>"
Pattern pattern = Pattern.compile(LABEL_CHE_SERVER_REF_KEY);
Map<String, String> portsToKnownRefName = labels.entrySet().stream()
.filter(map -> pattern.matcher(map.getKey()).matches())
.collect(Collectors.toMap(p -> {
Matcher matcher = pattern.matcher(p.getKey());
matcher.matches();
String val = matcher.group(1);
return val.contains("/") ? val : val.concat("/tcp");
}, p -> p.getValue()));
// add to this map only port without a known ref name
Map<String, String> portsToUnkownRefName =
exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port))
.collect(Collectors.toMap(p -> p, p -> "Server-" + p.replace('/', '-')));
// list of all ports with refName (known/unknown)
this.portsToRefName = new HashMap(portsToKnownRefName);
portsToRefName.putAll(portsToUnkownRefName);
}
/**
* Gets default external address.
*/
protected String getExternalAddress() {
return externalAddressProperty != null ?
externalAddressProperty : internalAddressProperty;
}
/**
* Populate the template properties
*/
protected void populateGlobalProperties() {
String externalAddress = getExternalAddress();
String externalIP = getExternalIp(externalAddress);
globalPropertiesMap.put("internalIp", internalAddressProperty);
globalPropertiesMap.put("externalAddress", externalAddress);
globalPropertiesMap.put("externalIP", externalIP);
globalPropertiesMap.put("workspaceId", getWorkspaceId());
globalPropertiesMap.put("machineName", getMachineName());
globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress));
globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress));
globalPropertiesMap.put("chePort", chePort);
}
/**
* Rendering
*/
@Override
public String render(String template, String port) {
if (!this.initialized) {
init();
this.initialized = true;
}
ST stringTemplate = new ST(template);
globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key, value));
stringTemplate.add("serverName", portsToRefName.get(port));
return stringTemplate.render();
}
/**
* Gets the workspace ID from the config of the given container
*
* @return workspace ID
*/
protected String getWorkspaceId() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_WORKSPACE_ID_PROPERTY))
.map(s -> s.substring(CHE_WORKSPACE_ID_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the workspace Machine Name from the config of the given container
*
* @return machine name of the workspace
*/
protected String getMachineName() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_MACHINE_NAME_PROPERTY))
.map(s -> s.substring(CHE_MACHINE_NAME_PROPERTY.length()))
.findFirst().get();
}
/**
* Gets the IP address of the external address
*
* @return IP Address
*/
protected String getExternalIp(String externalAddress) {
try {
return InetAddress.getByName(externalAddress).getHostAddress();
} catch (UnknownHostException e) {
throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e);
}
}
/**
* Gets a Wildcard domain based on the ip using an external provider nip.io
*
* @return wildcard domain
*/
protected String getWildcardNipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "nip.io");
}
/**
* Gets a Wildcard domain based on the ip using an external provider xip.io
*
* @return wildcard domain
*/
protected String getWildcardXipDomain(String externalAddress) {
return String.format("%s.%s", getExternalIp(externalAddress), "xip.io");
}
}
}

View File

@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Red Hat Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.machine;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.eclipse.che.api.machine.server.model.impl.ServerImpl;
import org.eclipse.che.commons.annotation.Nullable;
/**
* Represents a server evaluation strategy for the configuration where the workspace server and workspace
* containers are running on the same Docker network and are exposed through the same single port.
*
* This server evaluation strategy will return a completed {@link ServerImpl} with internal addresses set
* as {@link LocalDockerServerEvaluationStrategy} does. Contrary external addresses will be managed by the
* `custom` evaluation strategy,and its template property `che.docker.server_evaluation_strategy.custom.template`
*
* <p>cheExternalAddress can be set using property {@code che.docker.ip.external}.
* This strategy is useful when Che and the workspace servers need to be exposed on the same single TCP port
*
* @author Mario Loriedo <mloriedo@redhat.com>
* @see ServerEvaluationStrategy
*/
public class LocalDockerCustomServerEvaluationStrategy extends BaseServerEvaluationStrategy {
@Inject
public LocalDockerCustomServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress,
@Nullable @Named("che.docker.ip.external") String externalAddress,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol,
@Named("che.port") String chePort) {
super(internalAddress, externalAddress, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, true);
}
}

View File

@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.machine.idle;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.core.event.ServerIdleEvent;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
/**
* Notifies about idling the che server
* Fires {@link org.eclipse.che.api.core.event.ServerIdleEvent} if no workspace
* is run for <b>che.openshift.server.inactive.stop.timeout.ms</b> milliseconds
*/
@Singleton
public class ServerIdleDetector implements EventSubscriber<WorkspaceStatusEvent> {
private static final Logger LOG = LoggerFactory.getLogger(ServerIdleDetector.class);
private static final String IDLING_CHE_SERVER_SCHEDULED = "Idling che server scheduled [timeout=%s] seconds]";
private final long timeout;
private ScheduledFuture<?> future;
private ScheduledExecutorService executor;
private WorkspaceManager workspaceManager;
private final EventService eventService;
@Inject
public ServerIdleDetector(WorkspaceManager workspaceManager,
EventService eventService,
@Named("che.openshift.server.inactive.stop.timeout.ms") long timeout) {
this.timeout = timeout;
this.eventService = eventService;
this.workspaceManager = workspaceManager;
if (timeout > 0) {
this.executor = Executors.newSingleThreadScheduledExecutor();
this.future = executor.schedule(this::run, timeout, TimeUnit.MILLISECONDS);
LOG.info(String.format(IDLING_CHE_SERVER_SCHEDULED, timeout/1000));
}
}
@Override
public void onEvent(WorkspaceStatusEvent event) {
if (future != null) {
String workspaceId = event.getWorkspaceId();
switch (event.getEventType()) {
case RUNNING:
if (!future.isCancelled()) {
future.cancel(true);
LOG.info("Idling che server canceled");
}
break;
case STOPPED:
Set<String> ids = workspaceManager.getRunningWorkspacesIds();
ids.remove(workspaceId);
if (ids.size() <= 0) {
if (!future.isCancelled()) {
future.cancel(true);
}
future = executor.schedule(this::run, timeout, TimeUnit.MILLISECONDS);
LOG.info(String.format(IDLING_CHE_SERVER_SCHEDULED, timeout/1000));
}
break;
default:
break;
}
}
}
private void run() {
Set<String> ids = workspaceManager.getRunningWorkspacesIds();
if (ids.size() <= 0) {
eventService.publish(new ServerIdleEvent(timeout));
}
}
@PostConstruct
private void subscribe() {
eventService.subscribe(this);
}
@PreDestroy
private void unsubscribe() {
eventService.unsubscribe(this);
if (future != null && !future.isCancelled()) {
future.cancel(true);
}
if (executor != null && !executor.isShutdown()) {
executor.shutdown();
}
}
}

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.eclipse.che.plugin.docker.machine.CustomServerEvaluationStrategy.CHE_WORKSPACE_ID_PREFIX;
import static org.mockito.Mockito.when;
/**
@ -43,11 +44,19 @@ public class CustomServerEvaluationStrategyTest {
private static final String ALL_IP_ADDRESS = "0.0.0.0";
private static final String WORKSPACE_ID_VALUE = "work123";
private static final String WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=" + WORKSPACE_ID_VALUE;
private static final String WORKSPACE_ID_WITHOUT_PREFIX_VALUE = "ABCDEFG";
private static final String WORKSPACE_ID_VALUE = CHE_WORKSPACE_ID_PREFIX + WORKSPACE_ID_WITHOUT_PREFIX_VALUE;
private static final String WORKSPACE_ID_PROPERTY_PREFIX = "CHE_WORKSPACE_ID=";
private static final String WORKSPACE_ID_PROPERTY = WORKSPACE_ID_PROPERTY_PREFIX + WORKSPACE_ID_VALUE;
private static final String MACHINE_NAME_VALUE = "myMachine";
private static final String MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=" + MACHINE_NAME_VALUE;
private static final String MACHINE_NAME_PROPERTY_PREFIX = "CHE_MACHINE_NAME=";
private static final String MACHINE_NAME_PROPERTY = MACHINE_NAME_PROPERTY_PREFIX + MACHINE_NAME_VALUE;
private static final String IS_DEV_MACHINE_PROPERTY_PREFIX = "CHE_IS_DEV_MACHINE=";
private static final String IS_DEV_MACHINE_PROPERTY_TRUE = IS_DEV_MACHINE_PROPERTY_PREFIX + "true";
private static final String IS_DEV_MACHINE_PROPERTY_FALSE = IS_DEV_MACHINE_PROPERTY_PREFIX + "false";
@Mock
private ContainerConfig containerConfig;
@ -76,7 +85,7 @@ public class CustomServerEvaluationStrategyTest {
when(containerConfig.getLabels()).thenReturn(containerLabels);
when(containerConfig.getExposedPorts()).thenReturn(containerExposedPorts);
envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY};
envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE};
when(containerConfig.getEnv()).thenReturn(envContainerConfig);
when(containerInfo.getNetworkSettings()).thenReturn(networkSettings);
@ -126,6 +135,52 @@ public class CustomServerEvaluationStrategyTest {
Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_VALUE);
}
/**
* Check workspace Id without prefix template
*/
@Test
public void testWorkspaceIdWithoutPrefixRule() throws Throwable {
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1", "<workspaceIdWithoutPrefix>", "http", "8080");
Map<String, String> portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost");
Assert.assertTrue(portMapping.containsKey("4401/tcp"));
Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_WITHOUT_PREFIX_VALUE);
}
/**
* Check the isDevMachine macro in template
*/
@Test
public void testIsDevMachineWhenTrue() throws Throwable {
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1",
"<if(isDevMachine)><workspaceId><else><machineName><endif>", "http", "8080");
Map<String, String> portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost");
Assert.assertTrue(portMapping.containsKey("4401/tcp"));
Assert.assertEquals(portMapping.get("4401/tcp"), WORKSPACE_ID_VALUE);
}
/**
* Check the isDevMachine macro in template
*/
@Test
public void testIsDevMachineWhenFalse() throws Throwable {
this.envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_FALSE};
when(containerConfig.getEnv()).thenReturn(envContainerConfig);
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("10.0.0.1", "192.168.1.1",
"<if(isDevMachine)><workspaceId><else><machineName><endif>", "http", "8080");
Map<String, String> portMapping = this.customServerEvaluationStrategy.getExternalAddressesAndPorts(containerInfo, "localhost");
Assert.assertTrue(portMapping.containsKey("4401/tcp"));
Assert.assertEquals(portMapping.get("4401/tcp"), MACHINE_NAME_VALUE);
}
/**
* Check workspace Id template
@ -213,7 +268,7 @@ public class CustomServerEvaluationStrategyTest {
exposedPorts.add("4401/tcp");
exposedPorts.add("4411/tcp");
exposedPorts.add("8080/tcp");
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY);
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE);
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("127.0.0.1", null, "<externalAddress>-<workspaceId>", "https", "8080");
CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy
@ -233,7 +288,7 @@ public class CustomServerEvaluationStrategyTest {
exposedPorts.add("4401/tcp");
exposedPorts.add("4411/tcp");
exposedPorts.add("8080/tcp");
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY);
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE);
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("127.0.0.1", "127.0.0.1", "<externalAddress>-<workspaceId>", "https", "8080");
CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy
@ -253,7 +308,7 @@ public class CustomServerEvaluationStrategyTest {
exposedPorts.add("4401/tcp");
exposedPorts.add("4411/tcp");
exposedPorts.add("8080/tcp");
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY);
List<String> env = Arrays.asList(WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY_TRUE);
this.customServerEvaluationStrategy =
new CustomServerEvaluationStrategy("127.0.0.1", "300.300.300.300", "<externalAddress>-<workspaceId>", "https", "8080");
CustomServerEvaluationStrategy.RenderingEvaluation renderingEvaluation = this.customServerEvaluationStrategy

View File

@ -0,0 +1,158 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Red Hat Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.machine;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl;
import org.eclipse.che.api.machine.server.model.impl.ServerImpl;
import org.eclipse.che.api.machine.server.model.impl.ServerPropertiesImpl;
import org.eclipse.che.plugin.docker.client.json.ContainerConfig;
import org.eclipse.che.plugin.docker.client.json.ContainerInfo;
import org.eclipse.che.plugin.docker.client.json.NetworkSettings;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(MockitoTestNGListener.class)
public class LocalDockerCustomServerEvaluationStrategyTest {
private static final String CHE_DOCKER_IP_EXTERNAL = "container-host-ext.com";
private static final String ALL_IP_ADDRESS = "0.0.0.0";
private static final String CONTAINERCONFIG_HOSTNAME = "che-ws-y6jwknht0efzczit-4086112300-fm0aj";
private static final String WORKSPACE_ID = "79rfwhqaztq2ru2k";
private static final String WORKSPACE_ID_VALUE = WORKSPACE_ID;
private static final String WORKSPACE_ID_PROPERTY = "CHE_WORKSPACE_ID=" + WORKSPACE_ID_VALUE;
private static final String MACHINE_NAME_VALUE = "myMachine";
private static final String MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=" + MACHINE_NAME_VALUE;
private static final String IS_DEV_MACHINE_VALUE = "true";
private static final String IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE=" + IS_DEV_MACHINE_VALUE;
private static final String CHE_DOCKER_SERVER_EVALUATION_STRATEGY_CUSTOM_TEMPLATE = "<serverName>-<if(isDevMachine)><workspaceIdWithoutPrefix><else><machineName><endif>-<externalAddress>";
@Mock
private ContainerInfo containerInfo;
@Mock
private ContainerConfig containerConfig;
@Mock
private NetworkSettings networkSettings;
private ServerEvaluationStrategy strategy;
private Map<String, ServerConfImpl> serverConfs;
private Map<String, List<PortBinding>> ports;
private Map<String, String> labels;
private String[] env;
private String[] envContainerConfig;
@BeforeMethod
public void setUp() {
serverConfs = new HashMap<>();
serverConfs.put("4301/tcp", new ServerConfImpl("sysServer1-tcp", "4301/tcp", "http", "/some/path1"));
serverConfs.put("4305/udp", new ServerConfImpl("devSysServer1-udp", "4305/udp", null, "some/path4"));
ports = new HashMap<>();
ports.put("4301/tcp", Collections.singletonList(new PortBinding().withHostIp(ALL_IP_ADDRESS )
.withHostPort("32100")));
ports.put("4305/udp", Collections.singletonList(new PortBinding().withHostIp(ALL_IP_ADDRESS )
.withHostPort("32103")));
labels = new HashMap<>();
labels.put("che:server:4301/tcp:ref", "sysServer1-tcp");
labels.put("che:server:4305/udp:ref", "devSysServer1-udp");
env = new String[]{"CHE_WORKSPACE_ID="+ WORKSPACE_ID};
when(containerInfo.getNetworkSettings()).thenReturn(networkSettings);
when(networkSettings.getIpAddress()).thenReturn(CONTAINERCONFIG_HOSTNAME);
when(networkSettings.getPorts()).thenReturn(ports);
when(containerInfo.getConfig()).thenReturn(containerConfig);
when(containerConfig.getHostname()).thenReturn(CONTAINERCONFIG_HOSTNAME);
when(containerConfig.getEnv()).thenReturn(env);
when(containerConfig.getLabels()).thenReturn(labels);
envContainerConfig = new String[]{WORKSPACE_ID_PROPERTY, MACHINE_NAME_PROPERTY, IS_DEV_MACHINE_PROPERTY};
when(containerConfig.getEnv()).thenReturn(envContainerConfig);
}
/**
* Test: single port strategy should use .
* @throws Exception
*/
@Test
public void shouldUseServerRefToBuildAddressWhenAvailable() throws Exception {
// given
strategy = new LocalDockerCustomServerEvaluationStrategy(null, null, CHE_DOCKER_SERVER_EVALUATION_STRATEGY_CUSTOM_TEMPLATE, "http", null).withThrowOnUnknownHost(false);
final Map<String, ServerImpl> expectedServers = getExpectedServers(CHE_DOCKER_IP_EXTERNAL,
CONTAINERCONFIG_HOSTNAME,
true);
// when
final Map<String, ServerImpl> servers = strategy.getServers(containerInfo,
CHE_DOCKER_IP_EXTERNAL,
serverConfs);
// then
assertEquals(servers, expectedServers);
}
private Map<String, ServerImpl> getExpectedServers(String externalAddress,
String internalAddress,
boolean useExposedPorts) {
String port1;
String port2;
if (useExposedPorts) {
port1 = ":4301";
port2 = ":4305";
} else {
port1 = ":32100";
port2 = ":32103";
}
Map<String, ServerImpl> expectedServers = new HashMap<>();
expectedServers.put("4301/tcp", new ServerImpl("sysServer1-tcp",
"http",
"sysServer1-tcp-" + WORKSPACE_ID + "-" + externalAddress,
"http://" + "sysServer1-tcp-" + WORKSPACE_ID + "-" + externalAddress + "/some/path1",
new ServerPropertiesImpl("/some/path1",
internalAddress + port1,
"http://" + internalAddress + port1 + "/some/path1")));
expectedServers.put("4305/udp", new ServerImpl("devSysServer1-udp",
null,
"devSysServer1-udp-" + WORKSPACE_ID + "-" + externalAddress,
null,
new ServerPropertiesImpl("some/path4",
internalAddress + port2,
null)));
return expectedServers;
}
}

View File

@ -55,6 +55,22 @@
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.plugin</groupId>
<artifactId>che-plugin-docker-client</artifactId>

View File

@ -0,0 +1,232 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodBuilder;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftClient;
/**
* Helper class for executing simple commands in a Persistent Volume on Openshift.
* <p>
* Creates a short-lived Pod using a CentOS image which mounts a specified PVC and
* executes a command (either {@code mkdir -p <path>} or {@code rm -rf <path}). Reports
* back whether the pod succeeded or failed. Supports multiple paths for one command.
* <p>
* For mkdir commands, an in-memory list of created workspaces is stored and used to avoid
* calling mkdir unnecessarily. However, this list is not persisted, so dir creation is
* not tracked between restarts.
*
* @author amisevsk
*/
public class OpenShiftPvcHelper {
private static final Logger LOG = LoggerFactory.getLogger(OpenShiftPvcHelper.class);
private static final String POD_PHASE_SUCCEEDED = "Succeeded";
private static final String POD_PHASE_FAILED = "Failed";
private static final String[] MKDIR_WORKSPACE_COMMAND = new String[] {"mkdir", "-p"};
private static final String[] RMDIR_WORKSPACE_COMMAND = new String[] {"rm", "-rf"};
private static final Set<String> createdWorkspaces = ConcurrentHashMap.newKeySet();
private final String jobImage;
private final String jobMemoryLimit;
protected enum Command {REMOVE, MAKE}
@Inject
protected OpenShiftPvcHelper(@Named("che.openshift.jobs.image") String jobImage,
@Named("che.openshift.jobs.memorylimit") String jobMemoryLimit) {
this.jobImage = jobImage;
this.jobMemoryLimit = jobMemoryLimit;
}
/**
* Creates a pod with {@code command} and reports whether it succeeded
* @param workspacesPvcName
* name of the PVC to mount
* @param projectNamespace
* OpenShift namespace
* @param jobNamePrefix
* prefix used for pod metadata name. Name structure will normally
* be {@code <prefix><workspaceDirs>} if only one path is passed, or
* {@code <prefix>batch} if multiple paths are provided
* @param command
* command to execute in PVC.
* @param workspaceDirs
* list of arguments attached to command. A list of directories to
* create/delete.
* @return true if Pod terminates with phase "Succeeded" or mkdir command issued
* for already created worksapce, false otherwise.
*
* @see Command
*/
protected boolean createJobPod(String workspacesPvcName,
String projectNamespace,
String jobNamePrefix,
Command command,
String... workspaceDirs) {
if (workspaceDirs.length == 0) {
return true;
}
if (Command.MAKE.equals(command)) {
String[] dirsToCreate = filterDirsToCreate(workspaceDirs);
if (dirsToCreate.length == 0) {
return true;
}
workspaceDirs = dirsToCreate;
}
VolumeMount vm = new VolumeMountBuilder()
.withMountPath("/projects")
.withName(workspacesPvcName)
.build();
PersistentVolumeClaimVolumeSource pvcs = new PersistentVolumeClaimVolumeSourceBuilder()
.withClaimName(workspacesPvcName)
.build();
Volume volume = new VolumeBuilder()
.withPersistentVolumeClaim(pvcs)
.withName(workspacesPvcName)
.build();
String[] jobCommand = getCommand(command, "/projects/", workspaceDirs);
LOG.info("Executing command {} in PVC {} for {} dirs", jobCommand[0], workspacesPvcName, workspaceDirs.length);
Map<String, Quantity> limit = Collections.singletonMap("memory", new Quantity(jobMemoryLimit));
String podName = workspaceDirs.length > 1 ? jobNamePrefix + "batch"
: jobNamePrefix + workspaceDirs[0];
Container container = new ContainerBuilder().withName(podName)
.withImage(jobImage)
.withImagePullPolicy("IfNotPresent")
.withNewSecurityContext()
.withPrivileged(false)
.endSecurityContext()
.withCommand(jobCommand)
.withVolumeMounts(vm)
.withNewResources()
.withLimits(limit)
.endResources()
.build();
Pod podSpec = new PodBuilder().withNewMetadata()
.withName(podName)
.endMetadata()
.withNewSpec()
.withContainers(container)
.withVolumes(volume)
.withRestartPolicy("Never")
.endSpec()
.build();
try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()){
openShiftClient.pods().inNamespace(projectNamespace).create(podSpec);
boolean completed = false;
while(!completed) {
Pod pod = openShiftClient.pods().inNamespace(projectNamespace).withName(podName).get();
String phase = pod.getStatus().getPhase();
switch (phase) {
case POD_PHASE_FAILED:
LOG.info("Pod command {} failed", Arrays.toString(jobCommand));
case POD_PHASE_SUCCEEDED:
openShiftClient.resource(pod).delete();
updateCreatedDirs(command, phase, workspaceDirs);
return POD_PHASE_SUCCEEDED.equals(phase);
default:
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
private String[] getCommand(Command commandType, String mountPath, String... dirs) {
String[] command = new String[0];
switch (commandType) {
case MAKE :
command = MKDIR_WORKSPACE_COMMAND;
break;
case REMOVE :
command = RMDIR_WORKSPACE_COMMAND;
break;
}
String[] dirsWithPath = Arrays.asList(dirs).stream()
.map(dir -> mountPath + dir)
.toArray(String[]::new);
String[] fullCommand = new String[command.length + dirsWithPath.length];
System.arraycopy(command, 0, fullCommand, 0, command.length);
System.arraycopy(dirsWithPath, 0, fullCommand, command.length, dirsWithPath.length);
return fullCommand;
}
private void updateCreatedDirs(Command command, String phase, String... workspaceDirs) {
if (!POD_PHASE_SUCCEEDED.equals(phase)) {
return;
}
List<String> dirs = Arrays.asList(workspaceDirs);
switch (command) {
case MAKE:
createdWorkspaces.addAll(dirs);
break;
case REMOVE:
createdWorkspaces.removeAll(dirs);
break;
}
}
private String[] filterDirsToCreate(String[] allDirs) {
List<String> dirs = Arrays.asList(allDirs);
List<String> dirsToCreate = new ArrayList<>();
for(String dir : dirs) {
if (!createdWorkspaces.contains(dir)) {
dirsToCreate.add(dir);
}
}
return dirsToCreate.toArray(new String[dirsToCreate.size()]);
}
}

View File

@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.fabric8.openshift.api.model.DoneableRoute;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.api.model.RouteFluent.SpecNested;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftClient;
public class OpenShiftRouteCreator {
private static final Logger LOG = LoggerFactory.getLogger(OpenShiftRouteCreator.class);
private static final String TLS_TERMINATION_EDGE = "edge";
private static final String REDIRECT_INSECURE_EDGE_TERMINATION_POLICY = "Redirect";
public static void createRoute (final String namespace,
final String openShiftNamespaceExternalAddress,
final String serverRef,
final String serviceName,
final String deploymentName,
final String routeId,
final boolean enableTls) {
if (openShiftNamespaceExternalAddress == null) {
throw new IllegalArgumentException("Property che.docker.ip.external must be set when using openshift.");
}
try (OpenShiftClient openShiftClient = new DefaultOpenShiftClient()) {
String routeName = generateRouteName(routeId, serverRef);
String serviceHost = generateRouteHost(routeName, openShiftNamespaceExternalAddress);
SpecNested<DoneableRoute> routeSpec = openShiftClient
.routes()
.inNamespace(namespace)
.createNew()
.withNewMetadata()
.withName(routeName)
.addToLabels(OpenShiftConnector.OPENSHIFT_DEPLOYMENT_LABEL, deploymentName)
.endMetadata()
.withNewSpec()
.withHost(serviceHost)
.withNewTo()
.withKind("Service")
.withName(serviceName)
.endTo()
.withNewPort()
.withNewTargetPort()
.withStrVal(serverRef)
.endTargetPort()
.endPort();
if (enableTls) {
routeSpec.withNewTls()
.withTermination(TLS_TERMINATION_EDGE)
.withInsecureEdgeTerminationPolicy(REDIRECT_INSECURE_EDGE_TERMINATION_POLICY)
.endTls();
}
Route route = routeSpec.endSpec().done();
LOG.info("OpenShift route {} created", route.getMetadata().getName());
}
}
private static String generateRouteName(final String serviceName, final String serverRef) {
return serverRef + "-" + serviceName;
}
private static String generateRouteHost(final String routeName, final String openShiftNamespaceExternalAddress) {
return routeName + "-" + openShiftNamespaceExternalAddress;
}
}

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.event.ServerIdleEvent;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.workspace.server.WorkspaceFilesCleaner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
/**
* Class used to remove workspace directories in Persistent Volume when a workspace
* is delete while running on OpenShift. Deleted workspace directories are stored
* in a list. Upon Che server idling, all of these workspaces are deleted simultaneously
* from the PVC using a {@link OpenShiftPvcHelper} job.
* <p>
* Since deleting a workspace does not immediately remove its files, re-creating a workspace
* with a previously used name can result in files from the previous workspace still being
* present.
*
* @see WorkspaceFilesCleaner
* @author amisevsk
*/
@Singleton
public class OpenShiftWorkspaceFilesCleaner implements WorkspaceFilesCleaner {
private static final Logger LOG = LoggerFactory.getLogger(OpenShiftConnector.class);
private static final Set<String> deleteQueue = ConcurrentHashMap.newKeySet();
private final String projectNamespace;
private final String workspacesPvcName;
private final OpenShiftPvcHelper openShiftPvcHelper;
@Inject
public OpenShiftWorkspaceFilesCleaner(EventService eventService,
OpenShiftPvcHelper openShiftPvcHelper,
@Named("che.openshift.project") String projectNamespace,
@Named("che.openshift.workspaces.pvc.name") String workspacesPvcName) {
this.projectNamespace = projectNamespace;
this.workspacesPvcName = workspacesPvcName;
this.openShiftPvcHelper = openShiftPvcHelper;
eventService.subscribe(new EventSubscriber<ServerIdleEvent>() {
@Override
public void onEvent(ServerIdleEvent event) {
deleteWorkspacesInQueue(event);
}
});
}
@Override
public void clear(Workspace workspace) throws IOException, ServerException {
String workspaceName = workspace.getConfig().getName();
if (isNullOrEmpty(workspaceName)) {
LOG.error("Could not get workspace name for files removal.");
return;
}
deleteQueue.add(workspaceName);
}
private void deleteWorkspacesInQueue(ServerIdleEvent event) {
List<String> deleteQueueCopy = new ArrayList<>(deleteQueue);
String[] dirsToDelete = deleteQueueCopy.toArray(new String[deleteQueueCopy.size()]);
LOG.info("Deleting {} workspaces on PVC {}", deleteQueueCopy.size(), workspacesPvcName);
boolean successful = openShiftPvcHelper.createJobPod(workspacesPvcName,
projectNamespace,
"delete-",
OpenShiftPvcHelper.Command.REMOVE,
dirsToDelete);
if (successful) {
deleteQueue.removeAll(deleteQueueCopy);
}
}
/**
* Clears the list of workspace directories to be deleted. Necessary for testing.
*/
@VisibleForTesting
protected static void clearDeleteQueue() {
deleteQueue.clear();
}
}

View File

@ -47,7 +47,7 @@ public final class KubernetesContainer {
int portNumber = Integer.parseInt(port);
String portName = CheServicePorts.get().get(portNumber);
portName = isNullOrEmpty(portName) ? exposedPort.replace("/", "-") : portName;
portName = isNullOrEmpty(portName) ? "server-" + exposedPort.replace("/", "-") : portName;
ContainerPort containerPort = new ContainerPortBuilder().withName(portName).withProtocol(protocol)
.withContainerPort(portNumber).build();

View File

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client.kubernetes;
import java.util.Arrays;
import org.eclipse.che.plugin.openshift.client.OpenShiftConnector;
/**
* Holder class for metadata about an exec, to be used with {@link OpenShiftConnector}.
*
* <p> In OpenShift, {@code createExec()} is not separate from {@code startExec()},
* so this class has to be used to pass data between {@code createExec()} and
* {@code startExec()} calls.
*
* @see OpenShiftConnector#createExec(org.eclipse.che.plugin.docker.client.params.CreateExecParams)
* @see OpenShiftConnector#startExec(org.eclipse.che.plugin.docker.client.params.StartExecParams, org.eclipse.che.plugin.docker.client.MessageProcessor)
*/
public class KubernetesExecHolder {
private String[] command;
private String podName;
public KubernetesExecHolder withCommand(String[] command) {
this.command = command;
return this;
}
public KubernetesExecHolder withPod(String podName) {
this.podName = podName;
return this;
}
public String[] getCommand() {
return command;
}
public String getPod() {
return podName;
}
public String toString() {
return String.format("KubernetesExecHolder {command=%s, podName=%s}",
Arrays.asList(command).toString(),
podName);
}
}

View File

@ -64,6 +64,9 @@ public final class KubernetesLabelConverter {
*/
public static Map<String, String> labelsToNames(Map<String, String> labels) {
Map<String, String> names = new HashMap<>();
if (labels == null) {
return names;
}
for (Map.Entry<String, String> label : labels.entrySet()) {
if (!hasConversionProblems(label)) {
@ -103,6 +106,9 @@ public final class KubernetesLabelConverter {
*/
public static Map<String, String> namesToLabels(Map<String, String> names) {
Map<String, String> labels = new HashMap<>();
if (names == null) {
return labels;
}
for (Map.Entry<String, String> entry: names.entrySet()){
String key = entry.getKey();
String value = entry.getValue();

View File

@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client.kubernetes;
import io.fabric8.kubernetes.client.Callback;
import io.fabric8.kubernetes.client.utils.InputStreamPumper;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.plugin.docker.client.LogMessage;
import org.eclipse.che.plugin.docker.client.MessageProcessor;
/**
* Adapter class for passing data from a {@code kubernetes-client} output stream (e.g.
* for an exec call) to {@link MessageProcessor}. This class should be passed to a
* {@link InputStreamPumper} along with the output of the exec call.
*
* <p> Output passed in via the {@link #call(byte[])} method is parsed into lines,
* (respecting {@code '\n'} and {@code CRLF} as line separators), and
* passed to the {@link MessageProcessor} as {@link LogMessage}s.
*/
public class KubernetesOutputAdapter implements Callback<byte[]> {
private LogMessage.Type type;
private MessageProcessor<LogMessage> execOutputProcessor;
private StringBuilder lineBuffer;
/**
* Create a new KubernetesOutputAdapter
*
* @param type
* the type of LogMessages being passed to the MessageProcessor
* @param processor
* the processor receiving LogMessages. If null, calling {@link #call(byte[])}
* will return immediately.
*/
public KubernetesOutputAdapter(LogMessage.Type type,
@Nullable MessageProcessor<LogMessage> processor) {
this.type = type;
this.execOutputProcessor = processor;
this.lineBuffer = new StringBuilder();
}
@Override
public void call(byte[] data) {
if (data == null || data.length == 0 || execOutputProcessor == null) {
return;
}
int start = 0;
int offset = 0;
for (int pos = 0; pos < data.length; pos++) {
if (data[pos] == '\n' || data[pos] == '\r') {
offset = pos - start;
String line = new String(data, start, offset);
lineBuffer.append(line);
execOutputProcessor.process(new LogMessage(type, lineBuffer.toString()));
lineBuffer.setLength(0);
if (data[pos] == '\r') {
pos += 1;
}
start = pos + 1;
}
}
String trailingChars = new String(data, start, data.length - start);
lineBuffer.append(trailingChars);
}
}

View File

@ -47,7 +47,7 @@ public final class KubernetesService {
int portNumber = Integer.parseInt(port);
String portName = CheServicePorts.get().get(portNumber);
portName = isNullOrEmpty(portName) ? exposedPort.replace("/", "-") : portName;
portName = isNullOrEmpty(portName) ? "server-" + exposedPort.replace("/", "-") : portName;
int targetPortNumber = portNumber;
ServicePort servicePort = new ServicePort();

View File

@ -16,6 +16,7 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.plugin.docker.client.DockerApiVersionPathPrefixProvider;
import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration;
import org.eclipse.che.plugin.docker.client.DockerRegistryAuthResolver;
@ -31,9 +32,17 @@ import org.testng.annotations.Test;
public class OpenShiftConnectorTest {
private static final String[] CONTAINER_ENV_VARIABLES = {"CHE_WORKSPACE_ID=abcd1234"};
private static final String CHE_DEFAULT_OPENSHIFT_PROJECT_NAME = "eclipse-che";
private static final String CHE_DEFAULT_OPENSHIFT_SERVICEACCOUNT = "cheserviceaccount";
private static final int OPENSHIFT_LIVENESS_PROBE_DELAY = 300;
private static final int OPENSHIFT_LIVENESS_PROBE_TIMEOUT = 1;
private static final String OPENSHIFT_DEFAULT_WORKSPACE_PERSISTENT_VOLUME_CLAIM = "che_claim_data";
private static final String OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY = "10Gi";
private static final String OPENSHIFT_DEFAULT_WORKSPACE_STORAGE = "/data/workspaces";
private static final String OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE = "/projects";
private static final String CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS = "che.openshift.mini";
private static final String CHE_WORKSPACE_CPU_LIMIT = "1";
private static final boolean SECURE_ROUTES = false;
private static final boolean CREATE_WORKSPACE_DIRS = true;
@Mock
private DockerConnectorConfiguration dockerConnectorConfiguration;
@ -45,6 +54,10 @@ public class OpenShiftConnectorTest {
private DockerApiVersionPathPrefixProvider dockerApiVersionPathPrefixProvider;
@Mock
private CreateContainerParams createContainerParams;
@Mock
private EventService eventService;
@Mock
private OpenShiftPvcHelper openShiftPvcHelper;
private OpenShiftConnector openShiftConnector;
@ -62,10 +75,20 @@ public class OpenShiftConnectorTest {
dockerConnectionFactory,
authManager,
dockerApiVersionPathPrefixProvider,
openShiftPvcHelper,
eventService,
CHE_DEFAULT_SERVER_EXTERNAL_ADDRESS,
CHE_DEFAULT_OPENSHIFT_PROJECT_NAME,
CHE_DEFAULT_OPENSHIFT_SERVICEACCOUNT,
OPENSHIFT_LIVENESS_PROBE_DELAY,
OPENSHIFT_LIVENESS_PROBE_TIMEOUT);
OPENSHIFT_LIVENESS_PROBE_TIMEOUT,
OPENSHIFT_DEFAULT_WORKSPACE_PERSISTENT_VOLUME_CLAIM,
OPENSHIFT_DEFAULT_WORKSPACE_QUANTITY,
OPENSHIFT_DEFAULT_WORKSPACE_STORAGE,
OPENSHIFT_DEFAULT_WORKSPACE_PROJECTS_STORAGE,
CHE_WORKSPACE_CPU_LIMIT,
null,
SECURE_ROUTES,
CREATE_WORKSPACE_DIRS);
String workspaceID = openShiftConnector.getCheWorkspaceId(createContainerParams);
//Then

View File

@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.event.ServerIdleEvent;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class OpenShiftWorkspaceFilesCleanerTest {
private static final String CHE_OPENSHIFT_PROJECT = "eclipse-che";
private static final String WORKSPACES_PVC_NAME = "che-data-volume";
private static final String WORKSPACE_ONE = "testworkspaceone";
private static final String WORKSPACE_TWO = "testworkspacetwo";
@Mock
private OpenShiftPvcHelper pvcHelper;
@Mock
private ServerIdleEvent serverIdleEvent;
private EventService eventService;
private OpenShiftWorkspaceFilesCleaner cleaner;
@BeforeMethod
public void setup() {
OpenShiftWorkspaceFilesCleaner.clearDeleteQueue();
MockitoAnnotations.initMocks(this);
eventService = new EventService();
cleaner = new OpenShiftWorkspaceFilesCleaner(eventService,
pvcHelper,
CHE_OPENSHIFT_PROJECT,
WORKSPACES_PVC_NAME);
}
@Test
public void shouldDoNothingWithoutIdleEvent() throws ServerException, IOException {
// Given
Workspace workspace = generateWorkspace(WORKSPACE_ONE);
// When
cleaner.clear(workspace);
// Then
verify(pvcHelper, never()).createJobPod(anyString(),
anyString(),
anyString(),
any(OpenShiftPvcHelper.Command.class),
any(String[].class));
}
@Test
public void shouldDeleteWorkspaceOnIdleEvent() throws ServerException, IOException {
// Given
Workspace workspace = generateWorkspace(WORKSPACE_ONE);
// When
cleaner.clear(workspace);
eventService.publish(serverIdleEvent);
// Then
verify(pvcHelper, times(1)).createJobPod(anyString(),
anyString(),
anyString(),
eq(OpenShiftPvcHelper.Command.REMOVE),
eq(WORKSPACE_ONE));
}
@Test
public void shouldDeleteMultipleQueuedWorkspacesAtOnce() throws ServerException, IOException {
// Given
Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE);
Workspace workspaceTwo = generateWorkspace(WORKSPACE_TWO);
String[] expectedDirs = new String[] {WORKSPACE_ONE, WORKSPACE_TWO};
ArgumentCaptor<String> dirCaptor = ArgumentCaptor.forClass(String.class);
// When
cleaner.clear(workspaceOne);
cleaner.clear(workspaceTwo);
eventService.publish(serverIdleEvent);
// Then
verify(pvcHelper, times(1)).createJobPod(anyString(),
anyString(),
anyString(),
eq(OpenShiftPvcHelper.Command.REMOVE),
dirCaptor.capture(), // Varargs capture doesn't seem to work.
dirCaptor.capture());
List<String> dirs = dirCaptor.getAllValues();
String[] actualDirs = dirs.toArray(new String[dirs.size()]);
// Sort arrays to ignore order
Arrays.sort(actualDirs);
Arrays.sort(expectedDirs);
assertEquals(actualDirs, expectedDirs, "Expected all dirs to be deleted when server is idled.");
}
@Test
public void shouldRetainQueueIfDeletionFails() throws ServerException, IOException {
// Given
Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE);
when(pvcHelper.createJobPod(any(), any(), any(), any(), any())).thenReturn(false);
// When
cleaner.clear(workspaceOne);
eventService.publish(serverIdleEvent);
// Then
verify(pvcHelper, times(1)).createJobPod(anyString(),
anyString(),
anyString(),
eq(OpenShiftPvcHelper.Command.REMOVE),
eq(WORKSPACE_ONE));
// When
eventService.publish(serverIdleEvent);
// Then
verify(pvcHelper, times(2)).createJobPod(anyString(),
anyString(),
anyString(),
eq(OpenShiftPvcHelper.Command.REMOVE),
eq(WORKSPACE_ONE));
}
@Test
public void shouldUseProjectNamespaceAndPvcNameAsParameters() throws ServerException, IOException {
// Given
Workspace workspaceOne = generateWorkspace(WORKSPACE_ONE);
// When
cleaner.clear(workspaceOne);
eventService.publish(serverIdleEvent);
// Then
verify(pvcHelper, times(1)).createJobPod(eq(WORKSPACES_PVC_NAME),
eq(CHE_OPENSHIFT_PROJECT),
anyString(),
eq(OpenShiftPvcHelper.Command.REMOVE),
eq(WORKSPACE_ONE));
}
private Workspace generateWorkspace(String id) {
WorkspaceConfigImpl config = new WorkspaceConfigImpl();
config.setName(id);
return new WorkspaceImpl(id, null, config);
}
}

View File

@ -44,7 +44,7 @@ public class KubernetesContainerTest {
map(p -> Integer.toString(p.getContainerPort()) +
"/" +
p.getProtocol().toLowerCase()).collect(Collectors.toList());
assertTrue(exposedPorts.stream().anyMatch(portsAndProtocols::contains));
assertTrue(exposedPorts.stream().allMatch(portsAndProtocols::contains));
}
@Test
@ -61,7 +61,7 @@ public class KubernetesContainerTest {
map(p -> Integer.toString(p.getContainerPort()) +
"/" +
p.getProtocol().toLowerCase()).collect(Collectors.toList());
assertTrue(imageExposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains));
assertTrue(imageExposedPorts.keySet().stream().allMatch(portsAndProtocols::contains));
}
}

View File

@ -44,7 +44,7 @@ public class KubernetesEnvVarTest {
// Then
List<String> keysAndValues = env.stream().map(k -> k.getName() + "=" + k.getValue()).collect(Collectors.toList());
assertTrue(Arrays.stream(envVariables).anyMatch(keysAndValues::contains));
assertTrue(Arrays.stream(envVariables).allMatch(keysAndValues::contains));
}
}

View File

@ -16,15 +16,15 @@ import static org.testng.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class KubernetesLabelConverterTest {
private final String prefix = KubernetesLabelConverter.getCheServerLabelPrefix();
@Test
public void shouldConvertLabelsToValidKubernetesLabelNames() {
String validLabelRegex = "([A-Za-z0-9][-A-Za-z0-9_\\.]*)?[A-Za-z0-9]";
String prefix = KubernetesLabelConverter.getCheServerLabelPrefix();
// Given
Map<String, String> labels = new HashMap<>();
@ -46,7 +46,6 @@ public class KubernetesLabelConverterTest {
@Test
public void shouldBeAbleToRecoverOriginalLabelsAfterConversion() {
// Given
String prefix = KubernetesLabelConverter.getCheServerLabelPrefix();
Map<String, String> originalLabels = new HashMap<>();
originalLabels.put(prefix + "4401/tcp:path:", "/api");
originalLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug");
@ -59,4 +58,58 @@ public class KubernetesLabelConverterTest {
assertEquals(originalLabels, unconverted);
}
@Test
public void shouldIgnoreAndLogProblemLabels() {
// Given
Map<String, String> originalLabels = new HashMap<>();
Map<String, String> validLabels = new HashMap<>();
validLabels.put(prefix + "4401/tcp:path:", "/api");
validLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug");
Map<String, String> invalidLabels = new HashMap<>();
invalidLabels.put(prefix + "9999/t.cp:path:", "/api");
invalidLabels.put(prefix + "1111/tcp:path:", "/a_pi");
originalLabels.putAll(validLabels);
originalLabels.putAll(invalidLabels);
// When
Map<String, String> converted = KubernetesLabelConverter.labelsToNames(originalLabels);
Map<String, String> unconverted = KubernetesLabelConverter.namesToLabels(converted);
// Then
assertTrue(validLabels.entrySet().stream().allMatch(unconverted.entrySet()::contains),
"Valid labels should be there when converting + unconverting");
assertTrue(invalidLabels.entrySet().stream().noneMatch(unconverted.entrySet()::contains),
"Labels with invalid characters should be ignored");
}
@Test
public void shouldIgnoreEmptyValues() {
// Given
Map<String, String> originalLabels = new HashMap<>();
originalLabels.put(prefix + "4401/tcp:path:", null);
originalLabels.put(prefix + "4402/tcp:path:", "");
originalLabels.put(prefix + "4403/tcp:path:", " ");
// When
Map<String, String> converted = KubernetesLabelConverter.labelsToNames(originalLabels);
// Then
assertTrue(converted.isEmpty(), "Labels with null, empty, or whitespace values should be ignored");
}
@Test
public void shouldNotIgnoreValuesWithoutPrefix() {
// Given
Map<String, String> originalLabels = new HashMap<>();
originalLabels.put("4401/tcp:path:", "/api");
originalLabels.put(prefix + "8000/tcp:ref:", "tomcat-debug");
// When
Map<String, String> converted = KubernetesLabelConverter.labelsToNames(originalLabels);
// Then
// Currently we put a warning in the logs but convert these labels anyways.
assertTrue(converted.size() == 2, "Should convert labels even without prefix");
}
}

View File

@ -0,0 +1,245 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.openshift.client.kubernetes;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.che.plugin.docker.client.LogMessage;
import org.eclipse.che.plugin.docker.client.MessageProcessor;
public class KubernetesOutputAdapterTest {
private static LogMessage.Type LOG_TYPE = LogMessage.Type.DOCKER;
private testMessageProcessor processor;
private KubernetesOutputAdapter adapter;
private class testMessageProcessor implements MessageProcessor<LogMessage> {
private List<String> messages;
private LogMessage.Type type = null;
public testMessageProcessor() {
this.messages = new ArrayList<>();
}
@Override
public void process(LogMessage message) {
LogMessage.Type messageType = message.getType();
if (type == null) {
type = messageType;
}
messages.add(message.getContent());
}
public List<String> getMessages() {
return new ArrayList<>(messages);
}
public LogMessage.Type getType() {
return type;
}
};
@BeforeMethod
public void setUp() {
processor = new testMessageProcessor();
adapter = new KubernetesOutputAdapter(LOG_TYPE, processor);
}
@Test
public void shouldBreakLinesCorrectly() {
// Given
byte[] input = "line1\nline2\n".getBytes();
List<String> expected = generateExpected("line1", "line2");
// When
adapter.call(input);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should break lines on \\n char");
}
@Test
public void shouldCacheUnfinishedLinesBetweenCalls() {
// Given
byte[] firstInput = "line1\nlin".getBytes();
byte[] secondInput = "e2\nline3\n".getBytes();
List<String> expected = generateExpected("line1", "line2", "line3");
// When
adapter.call(firstInput);
adapter.call(secondInput);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should store unfinished lines between calls");
}
@Test
public void shouldUseProvidedLogMessageType() {
for (LogMessage.Type type : LogMessage.Type.values()) {
// Given
byte[] input = "line1\n".getBytes();
LogMessage.Type expected = type;
processor = new testMessageProcessor();
adapter = new KubernetesOutputAdapter(type, processor);
// When
adapter.call(input);
// Then
LogMessage.Type actual = processor.getType();
assertEquals(actual, expected, "Should call MessageProcessor with provided type");
}
}
@Test
public void shouldBreakLinesNormallyWithCarriageReturn() {
// Given
byte[] input = "line1\r\nline2\n".getBytes();
List<String> expected = generateExpected("line1", "line2");
// When
adapter.call(input);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should break lines normally on \\r\\n characters");
}
@Test
public void shouldNotIgnoreEmptyLines() {
// Given
byte[] input = "line1\n\nline2\n".getBytes();
List<String> expected = generateExpected("line1", "", "line2");
// When
adapter.call(input);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should call processor.process() with empty Strings");
}
@Test
public void shouldNotCallWithoutFinalNewline() {
// Given
byte[] input = "line1\nline2".getBytes(); // No trailing \n
List<String> firstExpected = generateExpected("line1");
List<String> secondExpected = generateExpected("line1", "line2");
// When
adapter.call(input);
// Then
List<String> firstActual = processor.getMessages();
assertEquals(firstActual, firstExpected, "Should only process lines when they are terminated by \\n or \\r\\n");
// When
adapter.call("\n".getBytes());
// Then
List<String> secondActual = processor.getMessages();
assertEquals(secondActual, secondExpected, "Should buffer lines until newline is encountered.");
}
@Test
public void shouldIgnoreNullCalls() {
// Given
byte[] firstInput = "line1\n".getBytes();
byte[] secondInput = "line2\n".getBytes();
List<String> expected = generateExpected("line1", "line2");
// When
adapter.call(firstInput);
adapter.call(null);
adapter.call(secondInput);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should ignore calls with null arguments");
}
@Test
public void shouldKeepBufferPastNullCalls() {
// Given
byte[] firstInput = "lin".getBytes();
byte[] secondInput = "e1\nline2\n".getBytes();
List<String> expected = generateExpected("line1", "line2");
// When
adapter.call(firstInput);
adapter.call(null);
adapter.call(secondInput);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "Should ignore calls with null arguments");
}
@Test
public void shouldDoNothingWhenExecOutputProcessorIsNull() {
// Given
byte[] firstInput = "line1\n".getBytes();
byte[] secondInput = "line2\n".getBytes();
adapter = new KubernetesOutputAdapter(LOG_TYPE, null);
// When
adapter.call(firstInput);
adapter.call(secondInput);
// Then
List<String> actual = processor.getMessages();
assertTrue(actual.isEmpty(), "Should do nothing when ExecOutputProcessor is null");
}
@Test
public void shouldIgnoreCallsWhenDataIsEmpty() {
// Given
byte[] emptyInput = "".getBytes();
byte[] firstInput = "line1\n".getBytes();
byte[] secondInput = "line2\n".getBytes();
List<String> expected = generateExpected("line1", "line2");
// When
adapter.call(emptyInput);
adapter.call(firstInput);
adapter.call(emptyInput);
adapter.call(secondInput);
adapter.call(emptyInput);
// Then
List<String> actual = processor.getMessages();
assertEquals(actual, expected, "KubernetesOutputAdapter ignore empty data calls");
}
private List<String> generateExpected(String... strings) {
List<String> expected = new ArrayList<>();
for (String string : strings) {
expected.add(string);
}
return expected;
}
}

View File

@ -40,7 +40,7 @@ public class KubernetesServiceTest {
map(p -> Integer.toString(p.getPort()) +
"/" +
p.getProtocol()).collect(Collectors.toList());
assertTrue(imageExposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains));
assertTrue(imageExposedPorts.keySet().stream().allMatch(portsAndProtocols::contains));
}
@Test
@ -60,7 +60,7 @@ public class KubernetesServiceTest {
map(p -> Integer.toString(p.getPort()) +
"/" +
p.getProtocol()).collect(Collectors.toList());
assertTrue(exposedPorts.keySet().stream().anyMatch(portsAndProtocols::contains));
assertTrue(exposedPorts.keySet().stream().allMatch(portsAndProtocols::contains));
}
@Test
@ -73,13 +73,13 @@ public class KubernetesServiceTest {
exposedPorts.put("4411/tcp",null);
exposedPorts.put("4412/tcp",null);
exposedPorts.put("8080/tcp",null);
exposedPorts.put("8888/tcp",null);
exposedPorts.put("8000/tcp",null);
exposedPorts.put("9876/tcp",null);
Set<String> expectedPortNames = new HashSet<>();
expectedPortNames.add("sshd");
expectedPortNames.add("wsagent");
expectedPortNames.add("wsagent-pda");
expectedPortNames.add("wsagent-jpda");
expectedPortNames.add("terminal");
expectedPortNames.add("exec-agent");
expectedPortNames.add("tomcat");
@ -92,7 +92,7 @@ public class KubernetesServiceTest {
map(p -> p.getName()).collect(Collectors.toList());
// Then
assertTrue(actualPortNames.stream().anyMatch(expectedPortNames::contains));
assertTrue(actualPortNames.stream().allMatch(expectedPortNames::contains));
}
@Test
@ -102,7 +102,7 @@ public class KubernetesServiceTest {
exposedPorts.put("55/tcp",null);
Set<String> expectedPortNames = new HashSet<>();
expectedPortNames.add("55-tcp");
expectedPortNames.add("server-55-tcp");
// When
List<ServicePort> servicePorts = KubernetesService.getServicePortsFrom(exposedPorts.keySet());
@ -110,7 +110,7 @@ public class KubernetesServiceTest {
map(p -> p.getName()).collect(Collectors.toList());
// Then
assertTrue(actualPortNames.stream().anyMatch(expectedPortNames::contains));
assertTrue(actualPortNames.stream().allMatch(expectedPortNames::contains));
}
}

View File

@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client;
import org.eclipse.che.api.core.model.workspace.config.ProjectConfig;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.BranchListMode;
import org.eclipse.che.api.git.shared.CheckoutRequest;
@ -28,9 +27,6 @@ import org.eclipse.che.api.git.shared.StatusFormat;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import org.eclipse.che.ide.websocket.WebSocketException;
import org.eclipse.che.ide.websocket.rest.RequestCallback;
import java.util.List;
import java.util.Map;
@ -40,29 +36,10 @@ import java.util.Map;
*
* @author Ann Zhuleva
* @author Vlad Zhukovskyi
* @author Igor Vinokur
*/
public interface GitServiceClient {
/**
* Add changes to Git index (temporary storage). Sends request over WebSocket.
*
* @param projectConfig
* project (root of GIT repository)
* @param update
* if <code>true</code> then never stage new files, but stage modified new contents of tracked files and remove files from
* the index if the corresponding files in the working tree have been removed
* @param filePattern
* pattern of the files to be added, default is "." (all files are added)
* @param callback
* callback
* @throws WebSocketException
* @deprecated use {@link #add(Path, boolean, Path[])}
*/
void add(ProjectConfig projectConfig,
boolean update,
List<String> filePattern,
RequestCallback<Void> callback) throws WebSocketException;
/**
* Add changes to Git index (temporary storage). Sends request over WebSocket.
*
@ -73,7 +50,6 @@ public interface GitServiceClient {
* the index if the corresponding files in the working tree have been removed
* @param paths
* pattern of the files to be added, default is "." (all files are added)
* @throws WebSocketException
*/
Promise<Void> add(Path project, boolean update, Path[] paths);
@ -95,7 +71,6 @@ public interface GitServiceClient {
* </ul>
* @param removeDeletedRefs
* if <code>true</code> then delete removed refs from local repository
* @throws WebSocketException
*/
Promise<Void> fetch(Path project, String remote, List<String> refspec, boolean removeDeletedRefs);
@ -107,51 +82,42 @@ public interface GitServiceClient {
* project (root of GIT repository)
* @param mode
* get remote branches
* @param callback
* @deprecated use {@link #branchList(Path, BranchListMode)}
*/
@Deprecated
void branchList(ProjectConfig project,
@Nullable BranchListMode mode,
AsyncRequestCallback<List<Branch>> callback);
/**
* Get the list of the branches. For now, all branches cannot be returned at once, so the parameter <code>remote</code> tells to get
* remote branches if <code>true</code> or local ones (if <code>false</code>).
* @param project
* project (root of GIT repository)
* @param mode
*/
Promise<List<Branch>> branchList(Path project, BranchListMode mode);
/**
* Delete branch.
* @param project
*
* @param project
* project (root of GIT repository)
* @param name
* name of the branch to delete
* @param force
* force if <code>true</code> delete branch {@code name} even if it is not fully merged
* force if <code>true</code> delete branch {@code name} even if it is not fully merged
*/
Promise<Void> branchDelete(Path project, String name, boolean force);
/**
* Checkout the branch with pointed name.
* @param project
*
* @param project
* project (root of GIT repository)
* @param oldName
* branch's current name
* @param newName
* branch's new name
*/
Promise<Void> branchRename(Path project, String oldName, String newName);
/**
* Create new branch with pointed name.
* @param project
*
* @param project
* project (root of GIT repository)
* @param name
* new branch's name
* @param startPoint
* name of a commit at which to start the new branch
*/
Promise<Branch> branchCreate(Path project, String name, String startPoint);
@ -160,38 +126,10 @@ public interface GitServiceClient {
*
* @param project
* project (root of GIT repository)
* @param checkoutRequest
* checkout request
* @deprecated {@link #checkout(Path, CheckoutRequest)}
*/
@Deprecated
void checkout(ProjectConfig project,
CheckoutRequest checkoutRequest,
AsyncRequestCallback<String> callback);
/**
* Checkout the branch with pointed name.
* @param project
* project (root of GIT repository)
* @param request
* checkout request
*/
Promise<Void> checkout(Path project, CheckoutRequest request);
/**
* Get the list of remote repositories for pointed by {@code projectConfig} parameter one.
*
* @param projectConfig
* project (root of GIT repository)
* @param remoteName
* remote repository's name. Can be null in case when it is need to fetch all {@link Remote}
* @param verbose
* If <code>true</code> show remote url and name otherwise show remote name
* @return a promise that provides list {@link Remote} repositories for the {@code workspaceId}, {@code projectConfig},
* {@code remoteName}, {@code verbose} or rejects with an error.
* @deprecated use {@link #remoteList(Path, String, boolean)}
*/
@Deprecated
Promise<List<Remote>> remoteList(ProjectConfig projectConfig, @Nullable String remoteName, boolean verbose);
Promise<String> checkout(Path project, CheckoutRequest request);
/**
* Get the list of remote repositories for pointed by {@code projectConfig} parameter one.
@ -204,7 +142,6 @@ public interface GitServiceClient {
* If <code>true</code> show remote url and name otherwise show remote name
* @return a promise that provides list {@link Remote} repositories for the {@code workspaceId}, {@code projectConfig},
* {@code remoteName}, {@code verbose} or rejects with an error.
* @deprecated use {@link #remoteList(Path, String, boolean)}
*/
Promise<List<Remote>> remoteList(Path project, String remote, boolean verbose);
@ -217,21 +154,6 @@ public interface GitServiceClient {
* remote repository's name
* @param url
* remote repository's URL
* @deprecated use {@link #remoteAdd(Path, String, String)}
*/
@Deprecated
void remoteAdd(ProjectConfig project,
String name,
String url,
AsyncRequestCallback<String> callback);
/**
* Adds remote repository to the list of remote repositories.
* @param project
* project (root of GIT repository)
* @param name
* remote repository's name
* @param url
*/
Promise<Void> remoteAdd(Path project, String name, String url);
@ -242,28 +164,18 @@ public interface GitServiceClient {
* project (root of GIT repository)
* @param name
* remote repository name to delete
* @deprecated use {@link #remoteDelete(Path, String)}
*/
@Deprecated
void remoteDelete(ProjectConfig project,
String name,
AsyncRequestCallback<String> callback);
/**
* Deletes the pointed(by name) remote repository from the list of repositories.
* @param project
* project (root of GIT repository)
* @param name
*/
Promise<Void> remoteDelete(Path project, String name);
/**
* Remove items from the working tree and the index.
* @param project
*
* @param project
* project (root of GIT repository)
* @param items
* items to remove
* @param cached
* is for removal only from index
*/
Promise<Void> remove(Path project, Path[] items, boolean cached);
@ -272,28 +184,33 @@ public interface GitServiceClient {
* 1. Reset files in index - content of files is untouched. Typically it is useful to remove from index mistakenly added files.<br>
* <code>git reset [paths]</code> is the opposite of <code>git add [paths]</code>. 2. Reset the current branch head to [commit] and
* possibly updates the index (resetting it to the tree of [commit]) and the working tree depending on [mode].
* @param project
*
* @param project
* project (root of GIT repository)
* @param commit
* commit to which current head should be reset
* @param resetType
* type of the reset
* type of the reset
* @param files
* pattern of the files to reset the index. If <code>null</code> then reset the current branch head to [commit],
* pattern of the files to reset the index. If <code>null</code> then reset the current branch head to [commit],
* else reset received files in index.
*/
Promise<Void> reset(Path project, String commit, ResetRequest.ResetType resetType, Path[] files);
/**
* Initializes new Git repository (over WebSocket).
* @param project
*
* @param project
* project (root of GIT repository)
* @param bare
* to create bare repository or not
*/
Promise<Void> init(Path project, boolean bare);
/**
* Pull (fetch and merge) changes from remote repository to local one (sends request over WebSocket).
* @param project
*
* @param project
* project (root of GIT repository)
* @param refSpec
* list of refspec to fetch.
@ -305,6 +222,7 @@ public interface GitServiceClient {
* <li>featured - remote branch name.</li>
* </ul>
* @param remote
* remote remote repository's name
*/
Promise<PullResponse> pull(Path project, String refSpec, String remote);
@ -320,50 +238,22 @@ public interface GitServiceClient {
* @param force
* push refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. If <code>true</code>
* disables the check. This can cause the remote repository to lose commits
* @deprecated use {@link #push(Path, List, String, boolean)}
*/
@Deprecated
Promise<PushResponse> push(ProjectConfig project,
List<String> refSpec,
String remote,
boolean force);
/**
* Push changes from local repository to remote one (sends request over WebSocket).
* @param project
* project
* @param refSpec
* list of refspec to push
* @param remote
* remote repository name or url
* @param force
* push refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. If <code>true</code>
*/
Promise<PushResponse> push(Path project, List<String> refSpec, String remote, boolean force);
/**
* Performs commit changes from index to repository. The result of the commit is represented by {@link Revision}, which is returned by
* callback in <code>onSuccess(Revision result)</code>. Sends request over WebSocket.
* Clones one remote repository to local one (over WebSocket).
*
* @param project
* project (root of GIT repository)
* @param message
* commit log message
* @param all
* automatically stage files that have been modified and deleted
* @param amend
* indicates that previous commit must be overwritten
* @param callback
* callback
* @throws WebSocketException
* @deprecated use {@link #commit(Path, String, boolean, boolean)}
* @param remoteUri
* the location of the remote repository
* @param remoteName
* remote name instead of "origin"
*/
@Deprecated
void commit(ProjectConfig project,
String message,
boolean all,
boolean amend,
AsyncRequestCallback<Revision> callback);
Promise<Void> clone(Path project,
String remoteUri,
String remoteName);
/**
* Performs commit changes from index to repository. The result of the commit is represented by {@link Revision}, which is returned by
@ -377,62 +267,50 @@ public interface GitServiceClient {
* automatically stage files that have been modified and deleted
* @param amend
* indicates that previous commit must be overwritten
* @throws WebSocketException
*/
Promise<Revision> commit(Path project, String message, boolean all, boolean amend);
/**
* Performs commit for the given files (ignoring git index).
* Performs commit changes from index to repository.
*
* @param project
* project (root of GIT repository)
* @param message
* commit log message
* @param files
* the list of iles that are commited, ignoring the index
* @param amend
* indicates that previous commit must be overwritten
* @throws WebSocketException
*/
Promise<Revision> commit(Path project, String message, Path[] files, boolean amend);
/**
* Performs commit changes from index to repository.
* @param project
* project (root of GIT repository)
* @param message
* commit log message
* @param all
* automatically stage files that have been modified and deleted
* @param files
* the list of files that are committed, ignoring the index
* @param amend
* the list of files that are committed, ignoring the index
*/
Promise<Revision> commit(Path project, String message, boolean all, Path[] files, boolean amend);
Promise<Revision> commit(Path project, String message, boolean amend, Path[] files);
/**
* Get repository options.
* @param project
*
* @param project
* project (root of GIT repository)
* @param requestedConfig
* list of config keys
*/
Promise<Map<String, String>> config(Path project, List<String> requestedConfig);
/**
* Compare two commits, get the diff for pointed file(s) or for the whole project in text format.
* @param project
*
* @param project
* project (root of GIT repository)
* @param fileFilter
* files for which to show changes
* @param type
* type of diff format
* type of diff format
* @param noRenames
* don't show renamed files
* don't show renamed files
* @param renameLimit
* the limit of shown renamed files
* the limit of shown renamed files
* @param commitA
* first commit to compare
* first commit to compare
* @param commitB
* second commit to be compared
*/
Promise<String> diff(Path project,
List<String> fileFilter,
@ -445,19 +323,21 @@ public interface GitServiceClient {
/**
* Compare commit with index or working tree (depends on {@code cached}), get the diff for pointed file(s) or for the whole project in
* text format.
* @param project
*
* @param project
* project (root of GIT repository)
* @param files
* files for which to show changes
* @param type
* type of diff format
* type of diff format
* @param noRenames
* don't show renamed files
* don't show renamed files
* @param renameLimit
* the limit of shown renamed files
* the limit of shown renamed files
* @param commitA
* commit to compare
* commit to compare
* @param cached
* if <code>true</code> then compare commit with index, if <code>false</code>, then compare with working tree.
*/
Promise<String> diff(Path project,
List<String> files,
@ -469,47 +349,39 @@ public interface GitServiceClient {
/**
* Get the file content from specified revision or branch.
* @param project
*
* @param project
* project configuration of root GIT repository
* @param file
* file name with its full path
* @param version
* revision or branch where the showed file is present
*/
Promise<ShowFileContentResponse> showFileContent(Path project, Path file, String version);
/**
* Get log of commits.
*
* Method is deprecated. Use {@link #log(Path, Path[], int, int, boolean)} to pass
* {@code skip} and {@code maxCount} parameters to limit the number of returning entries.
* @param project
* project (root of GIT repository)
* @param fileFilter
* range of files to filter revisions list
* @param plainText
*/
@Deprecated
Promise<LogResponse> log(Path project, @Nullable Path[] fileFilter, boolean plainText);
/**
* Get log of commits.
* @param project
* @param project
* project (root of GIT repository)
* @param fileFilter
* range of files to filter revisions list
* @param skip
* the number of commits that will be skipped
* the number of commits that will be skipped
* @param maxCount
* the number of commits that will be returned
* the number of commits that will be returned
* @param plainText
* if <code>true</code> the loq response will be in text format
*/
Promise<LogResponse> log(Path project, @Nullable Path[] fileFilter, int skip, int maxCount, boolean plainText);
/**
* Merge the pointed commit with current HEAD.
* @param project
*
* @param project
* project (root of GIT repository)
* @param commit
* commit's reference to merge with
*/
Promise<MergeResult> merge(Path project, String commit);
@ -535,9 +407,11 @@ public interface GitServiceClient {
* D 123.txt
* ?? folder/test.css
* </pre>
* @param project
*
* @param project
* project (root of GIT repository)
* @param format
* to show in short format or not
*/
Promise<String> statusText(Path project, StatusFormat format);

View File

@ -10,17 +10,17 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.model.workspace.config.ProjectConfig;
import org.eclipse.che.api.git.shared.AddRequest;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.BranchCreateRequest;
import org.eclipse.che.api.git.shared.BranchListMode;
import org.eclipse.che.api.git.shared.CheckoutRequest;
import org.eclipse.che.api.git.shared.CloneRequest;
import org.eclipse.che.api.git.shared.CommitRequest;
import org.eclipse.che.api.git.shared.Commiters;
import org.eclipse.che.api.git.shared.DiffType;
import org.eclipse.che.api.git.shared.FetchRequest;
import org.eclipse.che.api.git.shared.LogResponse;
@ -37,39 +37,26 @@ import org.eclipse.che.api.git.shared.Revision;
import org.eclipse.che.api.git.shared.ShowFileContentResponse;
import org.eclipse.che.api.git.shared.Status;
import org.eclipse.che.api.git.shared.StatusFormat;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper.RequestCall;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.MimeType;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.machine.WsAgentStateController;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.rest.AsyncRequest;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
import org.eclipse.che.ide.rest.AsyncRequestLoader;
import org.eclipse.che.ide.rest.DtoUnmarshallerFactory;
import org.eclipse.che.ide.rest.StringMapUnmarshaller;
import org.eclipse.che.ide.rest.StringUnmarshaller;
import org.eclipse.che.ide.ui.loaders.request.LoaderFactory;
import org.eclipse.che.ide.websocket.Message;
import org.eclipse.che.ide.websocket.MessageBuilder;
import org.eclipse.che.ide.websocket.MessageBus;
import org.eclipse.che.ide.websocket.WebSocketException;
import org.eclipse.che.ide.websocket.rest.RequestCallback;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.google.gwt.http.client.RequestBuilder.DELETE;
import static com.google.gwt.http.client.RequestBuilder.POST;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;
import static org.eclipse.che.api.git.shared.AddRequest.DEFAULT_PATTERN;
import static org.eclipse.che.api.git.shared.StatusFormat.PORCELAIN;
import static org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper.createFromAsyncRequest;
import static org.eclipse.che.ide.MimeType.APPLICATION_JSON;
import static org.eclipse.che.ide.MimeType.TEXT_PLAIN;
import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT;
@ -83,41 +70,39 @@ import static org.eclipse.che.ide.rest.HTTPHeader.CONTENTTYPE;
*/
@Singleton
public class GitServiceClientImpl implements GitServiceClient {
private static final String ADD = "/git/add";
private static final String BRANCH = "/git/branch";
private static final String CHECKOUT = "/git/checkout";
private static final String COMMIT = "/git/commit";
private static final String CONFIG = "/git/config";
private static final String DIFF = "/git/diff";
private static final String FETCH = "/git/fetch";
private static final String INIT = "/git/init";
private static final String LOG = "/git/log";
private static final String SHOW = "/git/show";
private static final String MERGE = "/git/merge";
private static final String STATUS = "/git/status";
private static final String PUSH = "/git/push";
private static final String PULL = "/git/pull";
private static final String REMOTE = "/git/remote";
private static final String REMOVE = "/git/remove";
private static final String RESET = "/git/reset";
private static final String REPOSITORY = "/git/repository";
private static final String ADD = "/git/add";
private static final String BRANCH = "/git/branch";
private static final String CHECKOUT = "/git/checkout";
private static final String CLONE = "/git/clone";
private static final String COMMIT = "/git/commit";
private static final String CONFIG = "/git/config";
private static final String DIFF = "/git/diff";
private static final String FETCH = "/git/fetch";
private static final String INIT = "/git/init";
private static final String LOG = "/git/log";
private static final String SHOW = "/git/show";
private static final String MERGE = "/git/merge";
private static final String STATUS = "/git/status";
private static final String PUSH = "/git/push";
private static final String PULL = "/git/pull";
private static final String REMOTE = "/git/remote";
private static final String REMOVE = "/git/remove";
private static final String RESET = "/git/reset";
private static final String REPOSITORY = "/git/repository";
/** Loader to be displayed. */
private final AsyncRequestLoader loader;
private final DtoFactory dtoFactory;
private final DtoUnmarshallerFactory dtoUnmarshallerFactory;
private final AsyncRequestFactory asyncRequestFactory;
private final WsAgentStateController wsAgentStateController;
private final AppContext appContext;
@Inject
protected GitServiceClientImpl(LoaderFactory loaderFactory,
WsAgentStateController wsAgentStateController,
DtoFactory dtoFactory,
AsyncRequestFactory asyncRequestFactory,
DtoUnmarshallerFactory dtoUnmarshallerFactory,
AppContext appContext) {
this.wsAgentStateController = wsAgentStateController;
this.appContext = appContext;
this.loader = loaderFactory.newLoader();
this.dtoFactory = dtoFactory;
@ -126,46 +111,30 @@ public class GitServiceClientImpl implements GitServiceClient {
}
@Override
public Promise<Void> init(final Path project, final boolean bare) {
return createFromAsyncRequest(new RequestCall<Void>() {
@Override
public void makeCall(final AsyncCallback<Void> callback) {
String url = INIT + "?projectPath=" + project.toString() + "&bare=" + bare;
Message message = new MessageBuilder(POST, url).header(ACCEPT, TEXT_PLAIN).build();
sendMessageToWS(message, new RequestCallback<Void>() {
@Override
protected void onSuccess(Void result) {
callback.onSuccess(result);
}
@Override
protected void onFailure(Throwable exception) {
callback.onFailure(exception);
}
});
}
});
public Promise<Void> init(Path project, boolean bare) {
String url = getWsAgentBaseUrl() + INIT + "?projectPath=" + project + "&bare=" + bare;
return asyncRequestFactory.createPostRequest(url, null).loader(loader).send();
}
private void sendMessageToWS(final @NotNull Message message, final @NotNull RequestCallback<?> callback) {
wsAgentStateController.getMessageBus().then(new Operation<MessageBus>() {
@Override
public void apply(MessageBus arg) throws OperationException {
try {
arg.send(message, callback);
} catch (WebSocketException e) {
throw new OperationException(e.getMessage(), e);
}
}
});
@Override
public Promise<Void> clone(Path project,
String remoteUri,
String remoteName) {
CloneRequest cloneRequest = dtoFactory.createDto(CloneRequest.class)
.withRemoteName(remoteName)
.withRemoteUri(remoteUri)
.withWorkingDir(project.toString());
String params = "?projectPath=" + project;
String url = CLONE + params;
return asyncRequestFactory.createPostRequest(url, cloneRequest).loader(loader).send();
}
@Override
public Promise<String> statusText(Path project, StatusFormat format) {
String params = "?projectPath=" + project.toString() + "&format=" + format;
String url = appContext.getDevAgentEndpoint() + STATUS + params;
String params = "?projectPath=" + project + "&format=" + format;
String url = getWsAgentBaseUrl() + STATUS + params;
return asyncRequestFactory.createGetRequest(url)
.loader(loader)
@ -175,78 +144,13 @@ public class GitServiceClientImpl implements GitServiceClient {
}
@Override
public void add(ProjectConfig project,
boolean update,
@Nullable List<String> filePattern,
RequestCallback<Void> callback) throws WebSocketException {
AddRequest addRequest = dtoFactory.createDto(AddRequest.class).withUpdate(update);
if (filePattern == null) {
addRequest.setFilePattern(AddRequest.DEFAULT_PATTERN);
} else {
addRequest.setFilePattern(filePattern);
}
String url = ADD + "?projectPath=" + project.getPath();
MessageBuilder builder = new MessageBuilder(POST, url);
builder.data(dtoFactory.toJson(addRequest))
.header(CONTENTTYPE, APPLICATION_JSON);
Message message = builder.build();
sendMessageToWS(message, callback);
}
@Override
public Promise<Void> add(final Path project, final boolean update, final Path[] paths) {
return createFromAsyncRequest(new RequestCall<Void>() {
@Override
public void makeCall(final AsyncCallback<Void> callback) {
final AddRequest addRequest = dtoFactory.createDto(AddRequest.class).withUpdate(update);
if (paths == null) {
addRequest.setFilePattern(AddRequest.DEFAULT_PATTERN);
} else {
final List<String> patterns = new ArrayList<>(); //need for compatible with server side
for (Path path : paths) {
patterns.add(path.isEmpty() ? "." : path.toString());
}
addRequest.setFilePattern(patterns);
}
final String url = ADD + "?projectPath=" + project.toString();
final Message message = new MessageBuilder(POST, url).data(dtoFactory.toJson(addRequest))
.header(CONTENTTYPE, APPLICATION_JSON)
.build();
sendMessageToWS(message, new RequestCallback<Void>() {
@Override
protected void onSuccess(Void result) {
callback.onSuccess(result);
}
@Override
protected void onFailure(Throwable exception) {
callback.onFailure(exception);
}
});
}
});
}
@Override
public void commit(ProjectConfig project,
String message,
boolean all,
boolean amend,
AsyncRequestCallback<Revision> callback) {
CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class)
.withMessage(message)
.withAmend(amend)
.withAll(all);
String url = appContext.getDevAgentEndpoint() + COMMIT + "?projectPath=" + project.getPath();
asyncRequestFactory.createPostRequest(url, commitRequest).loader(loader).send(callback);
public Promise<Void> add(Path project, boolean update, Path[] paths) {
AddRequest addRequest = dtoFactory.createDto(AddRequest.class)
.withUpdate(update);
addRequest.setFilePattern(paths == null ? DEFAULT_PATTERN :
stream(paths).map(path -> path.isEmpty() ? "." : path.toString()).collect(toList()));
String url = getWsAgentBaseUrl() + ADD + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, addRequest).loader(loader).send();
}
@Override
@ -255,34 +159,22 @@ public class GitServiceClientImpl implements GitServiceClient {
.withMessage(message)
.withAmend(amend)
.withAll(all);
String url = appContext.getDevAgentEndpoint() + COMMIT + "?projectPath=" + project;
String url = getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, commitRequest)
.loader(loader)
.send(dtoUnmarshallerFactory.newUnmarshaller(Revision.class));
}
@Override
public Promise<Revision> commit(Path project, String message, Path[] files, boolean amend) {
return commit(project, message, false, files, amend);
}
@Override
public Promise<Revision> commit(Path project, String message, boolean all, Path[] files, boolean amend) {
List<String> paths = new ArrayList<>(files.length);
for (Path file : files) {
if (!file.isEmpty()) {
paths.add(file.toString());
}
}
public Promise<Revision> commit(Path project, String message, boolean amend, Path[] files) {
CommitRequest commitRequest = dtoFactory.createDto(CommitRequest.class)
.withMessage(message)
.withAmend(amend)
.withAll(all)
.withFiles(paths);
String url = appContext.getDevAgentEndpoint() + COMMIT + "?projectPath=" + project;
.withFiles(stream(files).filter(file -> !file.isEmpty())
.map(Path::toString)
.collect(toList()));
String url = getWsAgentBaseUrl() + COMMIT + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, commitRequest)
.loader(loader)
@ -291,80 +183,48 @@ public class GitServiceClientImpl implements GitServiceClient {
@Override
public Promise<Map<String, String>> config(Path project, List<String> requestedConfig) {
String params = "?projectPath=" + project.toString();
String params = "?projectPath=" + project;
if (requestedConfig != null) {
for (String entry : requestedConfig) {
params += "&requestedConfig=" + entry;
}
}
String url = appContext.getDevAgentEndpoint() + CONFIG + params;
String url = getWsAgentBaseUrl() + CONFIG + params;
return asyncRequestFactory.createGetRequest(url).loader(loader).send(new StringMapUnmarshaller());
}
@Override
public Promise<PushResponse> push(ProjectConfig project, List<String> refSpec, String remote, boolean force) {
PushRequest pushRequest = dtoFactory.createDto(PushRequest.class)
.withRemote(remote)
.withRefSpec(refSpec)
.withForce(force);
return asyncRequestFactory.createPostRequest(appContext.getDevAgentEndpoint() + PUSH +
"?projectPath=" + project.getPath(), pushRequest)
.send(dtoUnmarshallerFactory.newUnmarshaller(PushResponse.class));
}
@Override
public Promise<PushResponse> push(Path project, List<String> refSpec, String remote, boolean force) {
PushRequest pushRequest = dtoFactory.createDto(PushRequest.class)
.withRemote(remote)
.withRefSpec(refSpec)
.withForce(force);
return asyncRequestFactory.createPostRequest(appContext.getDevAgentEndpoint() + PUSH + "?projectPath=" + project, pushRequest)
String url = getWsAgentBaseUrl() + PUSH + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, pushRequest)
.send(dtoUnmarshallerFactory.newUnmarshaller(PushResponse.class));
}
@Override
public Promise<List<Remote>> remoteList(ProjectConfig project, @Nullable String remoteName, boolean verbose) {
String params = "?projectPath=" + project.getPath() + "&verbose=" + String.valueOf(verbose);
if (remoteName != null) {
params += "&remoteName=" + remoteName;
}
String url = appContext.getDevAgentEndpoint() + REMOTE + params;
return asyncRequestFactory.createGetRequest(url)
.loader(loader)
.send(dtoUnmarshallerFactory.newListUnmarshaller(Remote.class));
}
@Override
public Promise<List<Remote>> remoteList(Path project, String remoteName, boolean verbose) {
String params = "?projectPath=" + project.toString() + (remoteName != null ? "&remoteName=" + remoteName : "") +
String params = "?projectPath=" + project +
(remoteName != null ? "&remoteName=" + remoteName : "") +
"&verbose=" + String.valueOf(verbose);
String url = appContext.getDevAgentEndpoint() + REMOTE + params;
String url = getWsAgentBaseUrl() + REMOTE + params;
return asyncRequestFactory.createGetRequest(url)
.loader(loader)
.send(dtoUnmarshallerFactory.newListUnmarshaller(Remote.class));
}
@Override
@Deprecated
public void branchList(ProjectConfig project,
BranchListMode listMode,
AsyncRequestCallback<List<Branch>> callback) {
String url = appContext.getDevAgentEndpoint() + BRANCH + "?projectPath=" + project.getPath() +
(listMode == null ? "" : "&listMode=" + listMode);
asyncRequestFactory.createGetRequest(url).send(callback);
}
@Override
public Promise<List<Branch>> branchList(Path project, BranchListMode listMode) {
String url = appContext.getDevAgentEndpoint() + BRANCH + "?projectPath=" + project.toString() +
(listMode == null ? "" : "&listMode=" + listMode);
String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project + (listMode == null ? "" : "&listMode=" + listMode);
return asyncRequestFactory.createGetRequest(url).send(dtoUnmarshallerFactory.newListUnmarshaller(Branch.class));
}
@Override
public Promise<Status> getStatus(Path project) {
final String params = "?projectPath=" + project.toString() + "&format=" + PORCELAIN;
final String url = appContext.getDevAgentEndpoint() + STATUS + params;
String params = "?projectPath=" + project + "&format=" + PORCELAIN;
String url = getWsAgentBaseUrl() + STATUS + params;
return asyncRequestFactory.createGetRequest(url)
.loader(loader)
.header(CONTENTTYPE, APPLICATION_JSON)
@ -374,15 +234,14 @@ public class GitServiceClientImpl implements GitServiceClient {
@Override
public Promise<Void> branchDelete(Path project, String name, boolean force) {
String url = appContext.getDevAgentEndpoint() + BRANCH + "?projectPath=" + project.toString()
+ "&name=" + name + "&force=" + force;
String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project + "&name=" + name + "&force=" + force;
return asyncRequestFactory.createDeleteRequest(url).loader(loader).send();
}
@Override
public Promise<Void> branchRename(Path project, String oldName, String newName) {
String params = "?projectPath=" + project.toString() + "&oldName=" + oldName + "&newName=" + newName;
String url = appContext.getDevAgentEndpoint() + BRANCH + params;
String params = "?projectPath=" + project + "&oldName=" + oldName + "&newName=" + newName;
String url = getWsAgentBaseUrl() + BRANCH + params;
return asyncRequestFactory.createPostRequest(url, null).loader(loader)
.header(CONTENTTYPE, MimeType.APPLICATION_FORM_URLENCODED)
.send();
@ -391,7 +250,7 @@ public class GitServiceClientImpl implements GitServiceClient {
@Override
public Promise<Branch> branchCreate(Path project, String name, String startPoint) {
BranchCreateRequest branchCreateRequest = dtoFactory.createDto(BranchCreateRequest.class).withName(name).withStartPoint(startPoint);
String url = appContext.getDevAgentEndpoint() + BRANCH + "?projectPath=" + project.toString();
String url = getWsAgentBaseUrl() + BRANCH + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, branchCreateRequest)
.loader(loader)
.header(ACCEPT, APPLICATION_JSON)
@ -399,31 +258,21 @@ public class GitServiceClientImpl implements GitServiceClient {
}
@Override
public void checkout(ProjectConfig project,
CheckoutRequest checkoutRequest,
AsyncRequestCallback<String> callback) {
String url = appContext.getDevAgentEndpoint() + CHECKOUT + "?projectPath=" + project.getPath();
asyncRequestFactory.createPostRequest(url, checkoutRequest).loader(loader).send(callback);
}
@Override
public Promise<Void> checkout(Path project,
CheckoutRequest request) {
final String url = appContext.getDevAgentEndpoint() + CHECKOUT + "?projectPath=" + project.toString();
return asyncRequestFactory.createPostRequest(url, request).loader(loader).send();
public Promise<String> checkout(Path project, CheckoutRequest request) {
String url = getWsAgentBaseUrl() + CHECKOUT + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, request).loader(loader).send(new StringUnmarshaller());
}
@Override
public Promise<Void> remove(Path project, Path[] items, boolean cached) {
String params = "?projectPath=" + project.toString();
String params = "?projectPath=" + project;
if (items != null) {
for (Path item : items) {
params += "&items=" + item.toString();
}
}
params += "&cached=" + String.valueOf(cached);
String url = appContext.getDevAgentEndpoint() + REMOVE + params;
String url = getWsAgentBaseUrl() + REMOVE + params;
return asyncRequestFactory.createDeleteRequest(url).loader(loader).send();
}
@ -434,32 +283,24 @@ public class GitServiceClientImpl implements GitServiceClient {
resetRequest.setType(resetType);
}
if (files != null) {
List<String> fileList = new ArrayList<>(files.length);
for (Path file : files) {
fileList.add(file.isEmpty() ? "." : file.toString());
}
resetRequest.setFilePattern(fileList);
resetRequest.setFilePattern(stream(files).map(file -> file.isEmpty() ? "." : file.toString()).collect(toList()));
}
String url = appContext.getDevAgentEndpoint() + RESET + "?projectPath=" + project;
String url = getWsAgentBaseUrl() + RESET + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, resetRequest).loader(loader).send();
}
@Override
public Promise<LogResponse> log(Path project, Path[] fileFilter, boolean plainText) {
return log(project, fileFilter, -1, -1, plainText);
}
@Override
public Promise<LogResponse> log(Path project, Path[] fileFilter, int skip, int maxCount, boolean plainText) {
StringBuilder params = new StringBuilder().append("?projectPath=").append(project.toString());
StringBuilder params = new StringBuilder().append("?projectPath=")
.append(project)
.append("&skip=")
.append(skip)
.append("&maxCount=")
.append(maxCount);
if (fileFilter != null) {
for (Path file : fileFilter) {
params.append("&fileFilter=").append(file.toString());
}
stream(fileFilter).forEach(file -> params.append("&fileFilter=").append(file));
}
params.append("&skip=").append(skip);
params.append("&maxCount=").append(maxCount);
String url = appContext.getDevAgentEndpoint() + LOG + params;
String url = getWsAgentBaseUrl() + LOG + params;
if (plainText) {
return asyncRequestFactory.createGetRequest(url)
.send(dtoUnmarshallerFactory.newUnmarshaller(LogResponse.class));
@ -470,34 +311,16 @@ public class GitServiceClientImpl implements GitServiceClient {
}
}
@Override
public void remoteAdd(ProjectConfig project,
String name,
String repositoryURL,
AsyncRequestCallback<String> callback) {
RemoteAddRequest remoteAddRequest = dtoFactory.createDto(RemoteAddRequest.class).withName(name).withUrl(repositoryURL);
String url = appContext.getDevAgentEndpoint() + REMOTE + "?projectPath=" + project.getPath();
asyncRequestFactory.createPutRequest(url, remoteAddRequest).loader(loader).send(callback);
}
@Override
public Promise<Void> remoteAdd(Path project, String name, String url) {
RemoteAddRequest remoteAddRequest = dtoFactory.createDto(RemoteAddRequest.class).withName(name).withUrl(url);
String requestUrl = appContext.getDevAgentEndpoint() + REMOTE + "?projectPath=" + project.toString();
String requestUrl = getWsAgentBaseUrl() + REMOTE + "?projectPath=" + project;
return asyncRequestFactory.createPutRequest(requestUrl, remoteAddRequest).loader(loader).send();
}
@Override
public void remoteDelete(ProjectConfig project,
String name,
AsyncRequestCallback<String> callback) {
String url = appContext.getDevAgentEndpoint() + REMOTE + '/' + name + "?projectPath=" + project.getPath();
asyncRequestFactory.createDeleteRequest(url).loader(loader).send(callback);
}
@Override
public Promise<Void> remoteDelete(Path project, String name) {
String url = appContext.getDevAgentEndpoint() + REMOTE + '/' + name + "?projectPath=" + project.toString();
String url = getWsAgentBaseUrl() + REMOTE + '/' + name + "?projectPath=" + project;
return asyncRequestFactory.createDeleteRequest(url).loader(loader).send();
}
@ -507,37 +330,49 @@ public class GitServiceClientImpl implements GitServiceClient {
.withRefSpec(refspec)
.withRemote(remote)
.withRemoveDeletedRefs(removeDeletedRefs);
String url = appContext.getDevAgentEndpoint() + FETCH + "?projectPath=" + project;
String url = getWsAgentBaseUrl() + FETCH + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, fetchRequest).send();
}
@Override
public Promise<PullResponse> pull(Path project, String refSpec, String remote) {
PullRequest pullRequest = dtoFactory.createDto(PullRequest.class).withRemote(remote).withRefSpec(refSpec);
String url = appContext.getDevAgentEndpoint() + PULL + "?projectPath=" + project;
String url = getWsAgentBaseUrl() + PULL + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, pullRequest).send(dtoUnmarshallerFactory.newUnmarshaller(PullResponse.class));
}
@Override
public Promise<String> diff(Path project,
List<String> fileFilter,
public Promise<String> diff(Path project, List<String> fileFilter,
DiffType type,
boolean noRenames,
int renameLimit,
String commitA,
String commitB) {
return diff(project, fileFilter, type, noRenames, renameLimit, commitA, commitB, false).send(new StringUnmarshaller());
return diff(project,
fileFilter,
type,
noRenames,
renameLimit,
commitA,
commitB,
false).send(new StringUnmarshaller());
}
@Override
public Promise<String> diff(Path project,
List<String> files,
public Promise<String> diff(Path project, List<String> files,
DiffType type,
boolean noRenames,
int renameLimit,
String commitA,
boolean cached) {
return diff(project, files, type, noRenames, renameLimit, commitA, null, cached).send(new StringUnmarshaller());
return diff(project,
files,
type,
noRenames,
renameLimit,
commitA,
null,
cached).send(new StringUnmarshaller());
}
private AsyncRequest diff(Path project,
@ -548,36 +383,31 @@ public class GitServiceClientImpl implements GitServiceClient {
String commitA,
String commitB,
boolean cached) {
StringBuilder params = new StringBuilder().append("?projectPath=").append(project.toString());
StringBuilder params = new StringBuilder().append("?projectPath=")
.append(project)
.append("&noRenames=").append(noRenames)
.append("&renameLimit=").append(renameLimit)
.append("&cached=").append(cached);
if (fileFilter != null) {
for (String file : fileFilter) {
if (file.isEmpty()) {
continue;
}
params.append("&fileFilter=").append(file);
}
fileFilter.stream().filter(file -> !file.isEmpty()).forEach(file -> params.append("&fileFilter=").append(file));
}
if (type != null) {
params.append("&diffType=").append(type);
}
params.append("&noRenames=").append(noRenames);
params.append("&renameLimit=").append(renameLimit);
if (commitA != null) {
params.append("&commitA=").append(commitA);
}
if (commitB != null) {
params.append("&commitB=").append(commitB);
}
params.append("&cached=").append(cached);
String url = appContext.getDevAgentEndpoint() + DIFF + params;
String url = getWsAgentBaseUrl() + DIFF + params;
return asyncRequestFactory.createGetRequest(url).loader(loader);
}
@Override
public Promise<ShowFileContentResponse> showFileContent(Path project, Path file, String version) {
String params = "?projectPath=" + project.toString() + "&file=" + file + "&version=" + version ;
String url = appContext.getDevAgentEndpoint() + SHOW + params;
String params = "?projectPath=" + project + "&file=" + file + "&version=" + version;
String url = getWsAgentBaseUrl() + SHOW + params;
return asyncRequestFactory.createGetRequest(url)
.loader(loader)
.send(dtoUnmarshallerFactory.newUnmarshaller(ShowFileContentResponse.class));
@ -586,7 +416,7 @@ public class GitServiceClientImpl implements GitServiceClient {
@Override
public Promise<MergeResult> merge(Path project, String commit) {
MergeRequest mergeRequest = dtoFactory.createDto(MergeRequest.class).withCommit(commit);
String url = appContext.getDevAgentEndpoint() + MERGE + "?projectPath=" + project;
String url = getWsAgentBaseUrl() + MERGE + "?projectPath=" + project;
return asyncRequestFactory.createPostRequest(url, mergeRequest)
.loader(loader)
.header(ACCEPT, APPLICATION_JSON)
@ -594,26 +424,12 @@ public class GitServiceClientImpl implements GitServiceClient {
}
@Override
public Promise<Void> deleteRepository(final Path project) {
return createFromAsyncRequest(new RequestCall<Void>() {
@Override
public void makeCall(final AsyncCallback<Void> callback) {
String url = REPOSITORY + "?projectPath=" + project.toString();
final Message message = new MessageBuilder(DELETE, url).header(ACCEPT, TEXT_PLAIN)
.build();
public Promise<Void> deleteRepository(Path project) {
String url = getWsAgentBaseUrl() + REPOSITORY + "?projectPath=" + project;
return asyncRequestFactory.createDeleteRequest(url).loader(loader).send();
}
sendMessageToWS(message, new RequestCallback<Void>() {
@Override
protected void onSuccess(Void result) {
callback.onSuccess(result);
}
@Override
protected void onFailure(Throwable exception) {
callback.onFailure(exception);
}
});
}
});
private String getWsAgentBaseUrl() {
return appContext.getDevMachine().getWsAgentBaseUrl();
}
}

View File

@ -109,9 +109,8 @@ public class AddToIndexAction extends GitAction {
}
private boolean containsInSelected(List<String> items) {
Resource[] appContextResources = appContext.getResources();
for (String item : items) {
for (Resource selectedItem : appContextResources) {
for (Resource selectedItem : appContext.getResources()) {
String selectedItemPath = selectedItem.getLocation()
.removeFirstSegments(1) // remove project name from path
.toString();

View File

@ -10,18 +10,13 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client.action;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.action.ActionEvent;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
@ -89,44 +84,33 @@ public class CompareWithLatestAction extends GitAction {
.removeTrailingSeparator()
.toString();
service.diff(
project.getLocation(),
selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath),
NAME_STATUS, false, 0, REVISION, false)
.then(new Operation<String>() {
@Override
public void apply(String diff) throws OperationException {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
project.getFile(changedFiles[0].substring(2)).then(new Operation<Optional<File>>() {
@Override
public void apply(Optional<File> file) throws OperationException {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(),
defineStatus(changedFiles[0].substring(0, 1)),
REVISION);
}
}
});
} else {
Map<String, Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
service.diff(project.getLocation(),
selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath), NAME_STATUS, false, 0, REVISION, false)
.then(diff -> {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
project.getFile(changedFiles[0].substring(2)).then(file -> {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(),
defineStatus(changedFiles[0].substring(0, 1)),
REVISION);
}
changesListPresenter.show(items, REVISION, null, project);
});
} else {
Map<String, Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
}
changesListPresenter.show(items, REVISION, null, project);
}
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
}
.catchError(arg -> {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
});
}
}

View File

@ -19,7 +19,6 @@ import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.GitResources;
import org.eclipse.che.ide.ext.git.client.delete.DeleteRepositoryPresenter;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import static com.google.common.base.Preconditions.checkState;
@ -52,11 +51,6 @@ public class DeleteRepositoryAction extends GitAction {
dialogFactory.createConfirmDialog(constant.deleteGitRepositoryTitle(),
constant.deleteGitRepositoryQuestion(project.getName()),
new ConfirmCallback() {
@Override
public void accepted() {
presenter.deleteRepository(project);
}
}, null).show();
() -> presenter.deleteRepository(project), null).show();
}
}

View File

@ -20,7 +20,6 @@ import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.GitResources;
import org.eclipse.che.ide.ext.git.client.GitUtil;
import org.eclipse.che.ide.ext.git.client.init.InitRepositoryPresenter;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import javax.validation.constraints.NotNull;
@ -58,12 +57,7 @@ public class InitRepositoryAction extends GitAction {
dialogFactory.createConfirmDialog(constant.createTitle(),
constant.messagesInitRepoQuestion(project.getName()),
new ConfirmCallback() {
@Override
public void accepted() {
presenter.initRepository(project);
}
}, null).show();
() -> presenter.initRepository(project), null).show();
}
@Override

View File

@ -13,11 +13,9 @@ package org.eclipse.che.ide.ext.git.client.add;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.machine.DevMachine;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.ide.api.resources.Resource;
@ -84,7 +82,6 @@ public class AddToIndexPresenter implements AddToIndexView.ActionDelegate {
view.showDialog();
}
/** {@inheritDoc} */
@Override
public void onAddClicked() {
Resource[] resources = appContext.getResources();
@ -97,25 +94,18 @@ public class AddToIndexPresenter implements AddToIndexView.ActionDelegate {
final GitOutputConsole console = gitOutputConsoleFactory.create(constant.addToIndexCommandName());
consolesPanelPresenter.addCommandOutput(console);
service.add(projectLocation, view.isUpdated(), paths)
.then(new Operation<Void>() {
@Override
public void apply(Void arg) throws OperationException {
console.print(constant.addSuccess());
notificationManager.notify(constant.addSuccess());
view.close();
}
.then(arg -> {
console.print(constant.addSuccess());
notificationManager.notify(constant.addSuccess());
view.close();
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
console.printError(constant.addFailed());
notificationManager.notify(constant.addFailed(), FAIL, FLOAT_MODE);
view.close();
}
.catchError(arg -> {
console.printError(constant.addFailed());
notificationManager.notify(constant.addFailed(), FAIL, FLOAT_MODE);
view.close();
});
}
/** {@inheritDoc} */
@Override
public void onCancelClicked() {
view.close();

View File

@ -16,13 +16,8 @@ import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.CheckoutRequest;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.api.dialogs.InputCallback;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Project;
@ -33,7 +28,6 @@ import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import javax.validation.constraints.NotNull;
import java.util.List;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_ALL;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
@ -48,11 +42,12 @@ import static org.eclipse.che.ide.util.ExceptionUtils.getErrorCode;
*/
@Singleton
public class BranchPresenter implements BranchView.ActionDelegate {
public static final String BRANCH_RENAME_COMMAND_NAME = "Git rename branch";
public static final String BRANCH_DELETE_COMMAND_NAME = "Git delete branch";
public static final String BRANCH_CHECKOUT_COMMAND_NAME = "Git checkout branch";
public static final String BRANCH_CREATE_COMMAND_NAME = "Git create branch";
public static final String BRANCH_LIST_COMMAND_NAME = "Git list of branches";
private static final String BRANCH_RENAME_COMMAND_NAME = "Git rename branch";
private static final String BRANCH_DELETE_COMMAND_NAME = "Git delete branch";
private static final String BRANCH_CHECKOUT_COMMAND_NAME = "Git checkout branch";
private static final String BRANCH_CREATE_COMMAND_NAME = "Git create branch";
private static final String BRANCH_LIST_COMMAND_NAME = "Git list of branches";
private final DtoFactory dtoFactory;
private final BranchView view;
@ -96,24 +91,17 @@ public class BranchPresenter implements BranchView.ActionDelegate {
getBranches();
}
/** {@inheritDoc} */
@Override
public void onCloseClicked() {
view.close();
}
/** {@inheritDoc} */
@Override
public void onRenameClicked() {
if (selectedBranch.isRemote()) {
dialogFactory.createConfirmDialog(constant.branchConfirmRenameTitle(),
constant.branchConfirmRenameMessage(),
new ConfirmCallback() {
@Override
public void accepted() {
renameBranch();
}
},
this::renameBranch,
null).show();
} else {
renameBranch();
@ -127,29 +115,18 @@ public class BranchPresenter implements BranchView.ActionDelegate {
selectedBranchName,
0,
selectedBranchName.length(),
new InputCallback() {
@Override
public void accepted(String newBranchName) {
renameBranch(newBranchName);
}
},
this::renameBranch,
null).show();
}
private void renameBranch(String newName) {
service.branchRename(project.getLocation(), selectedBranch.getDisplayName(), newName)
.then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
getBranches();
}
.then(ignored -> {
getBranches();
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_RENAME_COMMAND_NAME);
getBranches();//rename of remote branch occurs in three stages, so needs update list of branches on view
}
.catchError(error -> {
handleError(error.getCause(), BRANCH_RENAME_COMMAND_NAME);
getBranches();//rename of remote branch occurs in three stages, so needs update list of branches on view
});
}
@ -160,24 +137,18 @@ public class BranchPresenter implements BranchView.ActionDelegate {
return tokens.length > 0 ? tokens[tokens.length - 1] : selectedBranchName;
}
/** {@inheritDoc} */
@Override
public void onDeleteClicked() {
service.branchDelete(project.getLocation(), selectedBranch.getName(), true).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
getBranches();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_DELETE_COMMAND_NAME);
}
});
service.branchDelete(project.getLocation(), selectedBranch.getName(), true)
.then(ignored -> {
getBranches();
})
.catchError(error -> {
handleError(error.getCause(), BRANCH_DELETE_COMMAND_NAME);
});
}
/** {@inheritDoc} */
@Override
public void onCheckoutClicked() {
final CheckoutRequest checkoutRequest = dtoFactory.createDto(CheckoutRequest.class);
@ -187,65 +158,48 @@ public class BranchPresenter implements BranchView.ActionDelegate {
checkoutRequest.setName(selectedBranch.getDisplayName());
}
service.checkout(project.getLocation(), checkoutRequest).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
getBranches();
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_CHECKOUT_COMMAND_NAME);
}
});
service.checkout(project.getLocation(), checkoutRequest)
.then(ignored -> {
getBranches();
project.synchronize();
})
.catchError(error -> {
handleError(error.getCause(), BRANCH_CHECKOUT_COMMAND_NAME);
});
}
/** Get the list of branches. */
private void getBranches() {
service.branchList(project.getLocation(), LIST_ALL).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
if (branches.isEmpty()) {
dialogFactory.createMessageDialog(constant.branchTitle(),
constant.initCommitWasNotPerformed(),
null).show();
} else {
view.setBranches(branches);
view.showDialogIfClosed();
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME);
}
});
service.branchList(project.getLocation(), LIST_ALL)
.then(branches -> {
if (branches.isEmpty()) {
dialogFactory.createMessageDialog(constant.branchTitle(),
constant.initCommitWasNotPerformed(),
null).show();
} else {
view.setBranches(branches);
view.showDialogIfClosed();
}
})
.catchError(error -> {
handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME);
});
}
/** {@inheritDoc} */
@Override
public void onCreateClicked() {
dialogFactory.createInputDialog(constant.branchCreateNew(), constant.branchTypeNew(), new InputCallback() {
@Override
public void accepted(String value) {
if (value.isEmpty()) {
return;
}
service.branchCreate(project.getLocation(), value, null).then(new Operation<Branch>() {
@Override
public void apply(Branch branch) throws OperationException {
getBranches();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_CREATE_COMMAND_NAME);
}
});
dialogFactory.createInputDialog(constant.branchCreateNew(), constant.branchTypeNew(), value -> {
if (value.isEmpty()) {
return;
}
service.branchCreate(project.getLocation(), value, null)
.then(branch -> {
getBranches();
})
.catchError(error -> {
handleError(error.getCause(), BRANCH_CREATE_COMMAND_NAME);
});
}, null).show();
}
@ -258,7 +212,6 @@ public class BranchPresenter implements BranchView.ActionDelegate {
view.setEnableDeleteButton(false);
}
/** {@inheritDoc} */
@Override
public void onBranchSelected(@NotNull Branch branch) {
selectedBranch = branch;

View File

@ -14,14 +14,10 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.git.shared.CheckoutRequest;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole;
@ -88,29 +84,21 @@ public class CheckoutReferencePresenter implements CheckoutReferenceView.ActionD
public void onCheckoutClicked(final String reference) {
service.checkout(project.getLocation(), dtoFactory.createDto(CheckoutRequest.class).withName(reference))
.then(new Operation<Void>() {
@Override
public void apply(Void arg) throws OperationException {
project.synchronize().then(new Operation<Resource[]>() {
@Override
public void apply(Resource[] arg) throws OperationException {
view.close();
}
});
}
.then(branchName -> {
appContext.getRootProject().synchronize()
.then(arg -> {
view.close();
});
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
final String errorMessage = (error.getMessage() != null)
? error.getMessage()
: constant.checkoutFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(CHECKOUT_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.checkoutFailed(), FAIL, FLOAT_MODE);
view.close();
}
.catchError(error -> {
final String errorMessage = (error.getMessage() != null)
? error.getMessage()
: constant.checkoutFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(CHECKOUT_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.checkoutFailed(), FAIL, FLOAT_MODE);
view.close();
});
}

View File

@ -25,9 +25,9 @@ import org.eclipse.che.ide.commons.exception.ServerException;
import org.eclipse.che.ide.ext.git.client.DateTimeFormatter;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status;
import org.eclipse.che.ide.ext.git.client.compare.changespanel.ChangesPanelPresenter;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.ext.git.client.compare.changespanel.ChangesPanelPresenter;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import org.eclipse.che.ide.resource.Path;
@ -194,9 +194,8 @@ public class CommitPresenter implements CommitView.ActionDelegate {
.then(arg -> {
service.commit(location,
view.getMessage(),
false,
filesToCommitArray,
view.isAmend())
view.isAmend(),
filesToCommitArray)
.then(revision -> {
onCommitSuccess(revision);
if (view.isPushAfterCommit()) {

View File

@ -15,23 +15,19 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.git.shared.ShowFileContentResponse;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.CancelCallback;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.api.event.FileContentUpdateEvent;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status;
import org.eclipse.che.ide.api.dialogs.CancelCallback;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.resource.Path;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.NOT_EMERGE_MODE;
@ -109,39 +105,26 @@ public class ComparePresenter implements CompareView.ActionDelegate {
if (status.equals(DELETED)) {
service.showFileContent(project.get().getLocation(), relPath, revision)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(ShowFileContentResponse content) throws OperationException {
view.setTitle(file.getLocation().toString());
view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle());
view.show(content.getContent(), "", file.getLocation().toString(), false);
}
.then(content -> {
view.setTitle(file.getLocation().toString());
view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle());
view.show(content.getContent(), "", file.getLocation().toString(), false);
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
});
} else {
service.showFileContent(project.get().getLocation(), relPath, revision)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(ShowFileContentResponse content) throws OperationException {
showCompare(content.getContent());
}
.then(content -> {
showCompare(content.getContent());
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
});
}
}
/**
*
* @param file
* path of the file
* @param status
@ -164,56 +147,35 @@ public class ComparePresenter implements CompareView.ActionDelegate {
view.setTitle(file.toString());
if (status == Status.ADDED) {
service.showFileContent(projectLocation, file, revisionB)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(ShowFileContentResponse response) throws OperationException {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(),
revisionA == null ? "" : revisionA + locale.compareReadOnlyTitle());
view.show("", response.getContent(), file.toString(), true);
}
.then(response -> {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(),
revisionA == null ? "" : revisionA + locale.compareReadOnlyTitle());
view.show("", response.getContent(), file.toString(), true);
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
});
} else if (status == Status.DELETED) {
service.showFileContent(projectLocation, file, revisionA)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(ShowFileContentResponse response) throws OperationException {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), revisionA + locale.compareReadOnlyTitle());
view.show(response.getContent(), "", file.toString(), true);
}
.then(response -> {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(), revisionA + locale.compareReadOnlyTitle());
view.show(response.getContent(), "", file.toString(), true);
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
});
} else {
service.showFileContent(projectLocation, file, revisionA)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(final ShowFileContentResponse contentAResponse) throws OperationException {
service.showFileContent(projectLocation, file, revisionB)
.then(new Operation<ShowFileContentResponse>() {
@Override
public void apply(ShowFileContentResponse contentBResponse) throws OperationException {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(),
revisionA + locale.compareReadOnlyTitle());
view.show(contentAResponse.getContent(), contentBResponse.getContent(), file.toString(), true);
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
}
});
}
.then(contentAResponse -> {
service.showFileContent(projectLocation, file, revisionB)
.then(contentBResponse -> {
view.setColumnTitles(revisionB + locale.compareReadOnlyTitle(),
revisionA + locale.compareReadOnlyTitle());
view.show(contentAResponse.getContent(), contentBResponse.getContent(), file.toString(), true);
})
.catchError(error -> {
notificationManager.notify(error.getMessage(), FAIL, NOT_EMERGE_MODE);
});
});
}
}
@ -225,46 +187,32 @@ public class ComparePresenter implements CompareView.ActionDelegate {
return;
}
ConfirmCallback confirmCallback = new ConfirmCallback() {
@Override
public void accepted() {
comparedFile.updateContent(newContent).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
final Container parent = comparedFile.getParent();
ConfirmCallback confirmCallback = () -> comparedFile.updateContent(newContent)
.then(ignored -> {
final Container parent = comparedFile.getParent();
if (parent != null) {
parent.synchronize();
}
if (parent != null) {
parent.synchronize();
}
eventBus.fireEvent(new FileContentUpdateEvent(comparedFile.getLocation().toString()));
view.hide();
}
});
}
};
eventBus.fireEvent(new FileContentUpdateEvent(comparedFile.getLocation()
.toString()));
view.hide();
});
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void cancelled() {
view.hide();
}
};
CancelCallback cancelCallback = view::hide;
dialogFactory.createConfirmDialog(locale.compareSaveTitle(), locale.compareSaveQuestion(), locale.buttonYes(), locale.buttonNo(),
confirmCallback, cancelCallback).show();
}
private void showCompare(final String remoteContent) {
comparedFile.getContent().then(new Operation<String>() {
@Override
public void apply(String local) throws OperationException {
localContent = local;
final String path = comparedFile.getLocation().removeFirstSegments(1).toString();
view.setTitle(path);
view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle());
view.show(remoteContent, localContent, path, false);
}
comparedFile.getContent().then(local -> {
localContent = local;
final String path = comparedFile.getLocation().removeFirstSegments(1).toString();
view.setTitle(path);
view.setColumnTitles(locale.compareYourVersionTitle(), revision + locale.compareReadOnlyTitle());
view.show(remoteContent, localContent, path, false);
});
}
}

View File

@ -10,19 +10,14 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client.compare.branchlist;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
@ -35,7 +30,6 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkState;
@ -105,13 +99,11 @@ public class BranchListPresenter implements BranchListView.ActionDelegate {
getBranches();
}
/** {@inheritDoc} */
@Override
public void onCloseClicked() {
view.close();
}
/** {@inheritDoc} */
@Override
public void onCompareClicked() {
@ -120,61 +112,49 @@ public class BranchListPresenter implements BranchListView.ActionDelegate {
.removeTrailingSeparator()
.toString();
service.diff(
project.getLocation(),
service.diff(project.getLocation(),
selectedItemPath.isEmpty() ? null : singletonList(selectedItemPath),
NAME_STATUS,
false,
0,
selectedBranch.getName(),
false)
.then(new Operation<String>() {
@Override
public void apply(String diff) throws OperationException {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
project.getFile(changedFiles[0].substring(2)).then(new Operation<Optional<File>>() {
@Override
public void apply(Optional<File> file) throws OperationException {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(),
defineStatus(changedFiles[0].substring(0, 1)),
selectedBranch.getName());
}
}
});
} else {
Map<String, Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
.then(diff -> {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
project.getFile(changedFiles[0].substring(2)).then(file -> {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(),
defineStatus(changedFiles[0].substring(0, 1)),
selectedBranch.getName());
}
changesListPresenter.show(items, selectedBranch.getName(), null, project);
});
} else {
Map<String, Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
}
changesListPresenter.show(items, selectedBranch.getName(), null, project);
}
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
});
view.close();
}
/** {@inheritDoc} */
@Override
public void onBranchUnselected() {
selectedBranch = null;
view.setEnableCompareButton(false);
}
/** {@inheritDoc} */
@Override
public void onBranchSelected(@NotNull Branch branch) {
selectedBranch = branch;
@ -184,21 +164,17 @@ public class BranchListPresenter implements BranchListView.ActionDelegate {
/** Get list of branches from selected project. */
private void getBranches() {
service.branchList(project.getLocation(), LIST_ALL).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
view.setBranches(branches);
view.showDialog();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
final String errorMessage = (error.getMessage() != null) ? error.getMessage() : locale.branchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(locale.branchesListFailed(), FAIL, NOT_EMERGE_MODE);
}
});
service.branchList(project.getLocation(), LIST_ALL)
.then(branches -> {
view.setBranches(branches);
view.showDialog();
})
.catchError(error -> {
final String errorMessage = (error.getMessage() != null) ? error.getMessage() : locale.branchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(locale.branchesListFailed(), FAIL, NOT_EMERGE_MODE);
});
}
}

View File

@ -10,18 +10,13 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client.compare.revisionslist;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.api.git.shared.LogResponse;
import org.eclipse.che.api.git.shared.Revision;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.Project;
@ -127,60 +122,45 @@ public class RevisionListPresenter implements RevisionListView.ActionDelegate {
/** Get list of revisions. */
private void getRevisions() {
service.log(project.getLocation(), new Path[]{selectedFilePath}, false)
.then(new Operation<LogResponse>() {
@Override
public void apply(LogResponse log) throws OperationException {
view.setRevisions(log.getCommits());
view.showDialog();
service.log(project.getLocation(), new Path[]{selectedFilePath}, -1, -1, false)
.then(log -> {
view.setRevisions(log.getCommits());
view.showDialog();
}).catchError(error -> {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(locale.compareWithRevisionTitle(),
locale.initCommitWasNotPerformed(),
null).show();
} else {
notificationManager.notify(locale.logFailed(), FAIL, NOT_EMERGE_MODE);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(locale.compareWithRevisionTitle(),
locale.initCommitWasNotPerformed(),
null).show();
} else {
notificationManager.notify(locale.logFailed(), FAIL, NOT_EMERGE_MODE);
}
}
});
});
}
private void compare() {
service.diff(
project.getLocation(),
service.diff(project.getLocation(),
singletonList(selectedFilePath.toString()),
NAME_STATUS,
false,
0,
selectedRevision.getId(),
false)
.then(new Operation<String>() {
@Override
public void apply(final String diff) throws OperationException {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
project.getFile(diff.substring(2)).then(new Operation<Optional<File>>() {
@Override
public void apply(Optional<File> file) throws OperationException {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(), defineStatus(diff.substring(0, 1)), selectedRevision.getId());
}
}
});
.then(diff -> {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
appContext.getRootProject().getFile(diff.substring(2)).then(file -> {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(), defineStatus(diff.substring(0, 1)),
selectedRevision.getId());
}
});
}
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
}
.catchError(arg -> {
notificationManager.notify(locale.diffFailed(), FAIL, NOT_EMERGE_MODE);
});
}
}

View File

@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.delete;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -36,7 +33,7 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAI
*/
@Singleton
public class DeleteRepositoryPresenter {
public static final String DELETE_REPO_COMMAND_NAME = "Git delete repository";
private static final String DELETE_REPO_COMMAND_NAME = "Git delete repository";
private final GitServiceClient service;
private final GitLocalizationConstant constant;
@ -61,25 +58,19 @@ public class DeleteRepositoryPresenter {
}
/** Delete Git repository. */
public void deleteRepository(final Project project) {
public void deleteRepository(Project project) {
final GitOutputConsole console = gitOutputConsoleFactory.create(DELETE_REPO_COMMAND_NAME);
service.deleteRepository(project.getLocation()).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.deleteGitRepositorySuccess());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.deleteGitRepositorySuccess());
service.deleteRepository(project.getLocation()).then(ignored -> {
console.print(constant.deleteGitRepositorySuccess());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.deleteGitRepositorySuccess());
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.failedToDeleteRepository(), FAIL, FLOAT_MODE);
}
appContext.getRootProject().synchronize();
}).catchError(error -> {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.failedToDeleteRepository(), FAIL, FLOAT_MODE);
});
}
}

View File

@ -16,10 +16,6 @@ import com.google.inject.Singleton;
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
import org.eclipse.che.api.git.shared.BranchListMode;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.Remote;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -101,24 +97,20 @@ public class FetchPresenter implements FetchView.ActionDelegate {
* local).
*/
private void updateRemotes() {
service.remoteList(project.getLocation(), null, true).then(new Operation<List<Remote>>() {
@Override
public void apply(List<Remote> remotes) throws OperationException {
view.setRepositories(remotes);
updateBranches(LIST_REMOTE);
view.setEnableFetchButton(!remotes.isEmpty());
view.showDialog();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME);
console.printError(constant.remoteListFailed());
processesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE);
view.setEnableFetchButton(false);
}
});
service.remoteList(project.getLocation(), null, true)
.then(remotes -> {
view.setRepositories(remotes);
updateBranches(LIST_REMOTE);
view.setEnableFetchButton(!remotes.isEmpty());
view.showDialog();
})
.catchError(error -> {
GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME);
console.printError(constant.remoteListFailed());
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE);
view.setEnableFetchButton(false);
});
}
/**
@ -128,33 +120,29 @@ public class FetchPresenter implements FetchView.ActionDelegate {
* is a remote mode
*/
private void updateBranches(@NotNull final BranchListMode remoteMode) {
service.branchList(project.getLocation(), remoteMode).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
if (LIST_REMOTE.equals(remoteMode)) {
view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches));
updateBranches(LIST_LOCAL);
} else {
view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches));
for (Branch branch : branches) {
if (branch.isActive()) {
view.selectRemoteBranch(branch.getDisplayName());
break;
}
}
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
final String errorMessage = error.getMessage() != null ? error.getMessage() : constant.branchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
view.setEnableFetchButton(false);
}
});
service.branchList(project.getLocation(), remoteMode)
.then(branches -> {
if (LIST_REMOTE.equals(remoteMode)) {
view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches));
updateBranches(LIST_LOCAL);
} else {
view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches));
for (Branch branch : branches) {
if (branch.isActive()) {
view.selectRemoteBranch(branch.getDisplayName());
break;
}
}
}
})
.catchError(error -> {
final String errorMessage = error.getMessage() != null ? error.getMessage() : constant.branchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
view.setEnableFetchButton(false);
});
}
/** {@inheritDoc} */
@ -166,22 +154,16 @@ public class FetchPresenter implements FetchView.ActionDelegate {
final GitOutputConsole console = gitOutputConsoleFactory.create(FETCH_COMMAND_NAME);
service.fetch(project.getLocation(), view.getRepositoryName(), getRefs(), view.isRemoveDeletedRefs())
.then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.fetchSuccess(remoteUrl));
processesPanelPresenter.addCommandOutput(console);
notification.setStatus(SUCCESS);
notification.setTitle(constant.fetchSuccess(remoteUrl));
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), remoteUrl, notification, console);
processesPanelPresenter.addCommandOutput(console);
}
});
.then(ignored -> {
console.print(constant.fetchSuccess(remoteUrl));
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notification.setStatus(SUCCESS);
notification.setTitle(constant.fetchSuccess(remoteUrl));
})
.catchError(error -> {
handleError(error.getCause(), remoteUrl, notification, console);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
});
view.close();
}
@ -231,13 +213,11 @@ public class FetchPresenter implements FetchView.ActionDelegate {
}
}
/** {@inheritDoc} */
@Override
public void onCancelClicked() {
view.close();
}
/** {@inheritDoc} */
@Override
public void onValueChanged() {
boolean isFetchAll = view.isFetchAllBranches();
@ -245,13 +225,11 @@ public class FetchPresenter implements FetchView.ActionDelegate {
view.setEnableRemoteBranchField(!isFetchAll);
}
/** {@inheritDoc} */
@Override
public void onRemoteBranchChanged() {
view.selectLocalBranch(view.getRemoteBranch());
}
/** {@inheritDoc} */
@Override
public void onRemoteRepositoryChanged() {
updateBranches(LIST_REMOTE);

View File

@ -14,11 +14,7 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.api.git.shared.LogResponse;
import org.eclipse.che.api.git.shared.Revision;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
@ -136,34 +132,26 @@ public class HistoryPresenter implements HistoryView.ActionDelegate {
}
private void fetchRevisions() {
service.log(
project.getLocation(),
selectedPath.isEmpty() ? null : new Path[]{selectedPath},
service.log(project.getLocation(), selectedPath.isEmpty() ? null : new Path[]{selectedPath},
skip,
DEFAULT_PAGE_SIZE,
false)
.then(new Operation<LogResponse>() {
@Override
public void apply(LogResponse log) throws OperationException {
List<Revision> commits = log.getCommits();
if (!commits.isEmpty()) {
skip += commits.size();
revisions.addAll(commits);
view.setRevisions(revisions);
view.showDialog();
}
.then(log -> {
List<Revision> commits = log.getCommits();
if (!commits.isEmpty()) {
skip += commits.size();
revisions.addAll(commits);
view.setRevisions(revisions);
view.showDialog();
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(locale.historyTitle(),
locale.initCommitWasNotPerformed(),
null).show();
} else {
notificationManager.notify(locale.logFailed(), FAIL, EMERGE_MODE);
}
.catchError(error -> {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(locale.historyTitle(),
locale.initCommitWasNotPerformed(),
null).show();
} else {
notificationManager.notify(locale.logFailed(), FAIL, EMERGE_MODE);
}
});
}
@ -172,40 +160,33 @@ public class HistoryPresenter implements HistoryView.ActionDelegate {
final String revisionA = revisions.indexOf(selectedRevision) + 1 == revisions.size() ? null :
revisions.get(revisions.indexOf(selectedRevision) + 1).getId();
final String revisionB = selectedRevision.getId();
service.diff(project.getLocation(),
singletonList(selectedPath.toString()),
service.diff(project.getLocation(), singletonList(selectedPath.toString()),
NAME_STATUS,
true,
0,
revisionA,
revisionB)
.then(new Operation<String>() {
@Override
public void apply(final String diff) throws OperationException {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.historyTitle(), locale.historyNothingToDisplay(), null).show();
return;
}
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
comparePresenter.showCompareBetweenRevisions(Path.valueOf(diff.substring(2)),
defineStatus(diff.substring(0, 1)),
revisionA,
revisionB);
} else {
Map<String, FileStatus.Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
}
changesListPresenter.show(items, revisionA, revisionB, project);
.then(diff -> {
if (diff.isEmpty()) {
dialogFactory.createMessageDialog(locale.historyTitle(), locale.historyNothingToDisplay(), null).show();
return;
}
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
comparePresenter.showCompareBetweenRevisions(Path.valueOf(diff.substring(2)),
defineStatus(diff.substring(0, 1)),
revisionA,
revisionB);
} else {
Map<String, FileStatus.Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
}
changesListPresenter.show(items, revisionA, revisionB, project);
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(locale.diffFailed(), FAIL, EMERGE_MODE);
}
.catchError(error -> {
notificationManager.notify(locale.diffFailed(), FAIL, EMERGE_MODE);
});
}
}

View File

@ -13,9 +13,6 @@ package org.eclipse.che.ide.ext.git.client.init;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -66,22 +63,18 @@ public class InitRepositoryPresenter {
public void initRepository(final Project project) {
final GitOutputConsole console = gitOutputConsoleFactory.create(INIT_COMMAND_NAME);
service.init(project.getLocation(), false).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.initSuccess());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.initSuccess());
service.init(project.getLocation(), false)
.then(ignored -> {
console.print(constant.initSuccess());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.initSuccess());
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), console);
consolesPanelPresenter.addCommandOutput(console);
}
});
project.synchronize();
})
.catchError(error -> {
handleError(error.getCause(), console);
consolesPanelPresenter.addCommandOutput(console);
});
}
/**

View File

@ -16,11 +16,7 @@ import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.MergeResult;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -95,59 +91,49 @@ public class MergePresenter implements MergeView.ActionDelegate {
selectedReference = null;
view.setEnableMergeButton(false);
service.branchList(project.getLocation(), LIST_LOCAL).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
List<Reference> references = new ArrayList<>();
for (Branch branch : branches) {
if (!branch.isActive()) {
Reference reference = new Reference(branch.getName(), branch.getDisplayName(), LOCAL_BRANCH);
references.add(reference);
}
}
view.setLocalBranches(references);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
}
});
service.branchList(project.getLocation(), LIST_LOCAL)
.then(branches -> {
List<Reference> references = new ArrayList<>();
for (Branch branch : branches) {
if (!branch.isActive()) {
Reference reference = new Reference(branch.getName(), branch.getDisplayName(), LOCAL_BRANCH);
references.add(reference);
}
}
view.setLocalBranches(references);
})
.catchError(error -> {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
});
service.branchList(project.getLocation(), LIST_REMOTE).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
List<Reference> references = new ArrayList<>();
for (Branch branch : branches) {
if (!branch.isActive()) {
Reference reference =
new Reference(branch.getName(), branch.getDisplayName(), REMOTE_BRANCH);
references.add(reference);
}
}
view.setRemoteBranches(references);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
}
});
service.branchList(project.getLocation(), LIST_REMOTE)
.then(branches -> {
List<Reference> references = new ArrayList<>();
for (Branch branch : branches) {
if (!branch.isActive()) {
Reference reference =
new Reference(branch.getName(), branch.getDisplayName(), REMOTE_BRANCH);
references.add(reference);
}
}
view.setRemoteBranches(references);
})
.catchError(error -> {
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.branchesListFailed(), FAIL, FLOAT_MODE);
});
view.showDialog();
}
/** {@inheritDoc} */
@Override
public void onCancelClicked() {
view.close();
}
/** {@inheritDoc} */
@Override
public void onMergeClicked() {
view.close();
@ -155,34 +141,26 @@ public class MergePresenter implements MergeView.ActionDelegate {
final GitOutputConsole console = gitOutputConsoleFactory.create(MERGE_COMMAND_NAME);
service.merge(project.getLocation(), selectedReference.getDisplayName())
.then(new Operation<MergeResult>() {
@Override
public void apply(MergeResult result) throws OperationException {
console.print(formMergeMessage(result));
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(formMergeMessage(result));
.then(result -> {
console.print(formMergeMessage(result));
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(formMergeMessage(result));
project.synchronize();
project.synchronize();
})
.catchError(error -> {
if (error.getCause() instanceof ServerException &&
((ServerException)error.getCause()).getErrorCode() == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) {
dialogFactory.createMessageDialog(constant.mergeTitle(), constant.committerIdentityInfoEmpty(),
() -> {
//do nothing
}).show();
return;
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
if (error.getCause() instanceof ServerException &&
((ServerException)error.getCause()).getErrorCode() == ErrorCodes.NO_COMMITTER_NAME_OR_EMAIL_DEFINED) {
dialogFactory.createMessageDialog(constant.mergeTitle(), constant.committerIdentityInfoEmpty(),
new ConfirmCallback() {
@Override
public void accepted() {
//do nothing
}
}).show();
return;
}
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.mergeFailed(), FAIL, FLOAT_MODE);
}
});
console.printError(error.getMessage());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.mergeFailed(), FAIL, FLOAT_MODE);
});
}
/**

View File

@ -16,11 +16,6 @@ import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.api.git.shared.BranchListMode;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.PullResponse;
import org.eclipse.che.api.git.shared.Remote;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
@ -34,7 +29,6 @@ import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import javax.validation.constraints.NotNull;
import java.util.List;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_REMOTE;
@ -98,21 +92,15 @@ public class PullPresenter implements PullView.ActionDelegate {
view.setEnablePullButton(false);
service.remoteList(project.getLocation(), null, true)
.then(new Operation<List<Remote>>() {
@Override
public void apply(List<Remote> remotes) throws OperationException {
updateBranches(LIST_REMOTE);
view.setRepositories(remotes);
view.setEnablePullButton(!remotes.isEmpty());
view.showDialog();
}
.then(remotes -> {
updateBranches(LIST_REMOTE);
view.setRepositories(remotes);
view.setEnablePullButton(!remotes.isEmpty());
view.showDialog();
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), REMOTE_REPO_COMMAND_NAME);
view.setEnablePullButton(false);
}
.catchError(error -> {
handleError(error.getCause(), REMOTE_REPO_COMMAND_NAME);
view.setEnablePullButton(false);
});
}
@ -125,29 +113,25 @@ public class PullPresenter implements PullView.ActionDelegate {
*/
private void updateBranches(@NotNull final BranchListMode remoteMode) {
service.branchList(project.getLocation(), remoteMode).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
if (LIST_REMOTE.equals(remoteMode)) {
view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches));
updateBranches(LIST_LOCAL);
} else {
view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches));
for (Branch branch : branches) {
if (branch.isActive()) {
view.selectRemoteBranch(branch.getDisplayName());
break;
}
}
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME);
view.setEnablePullButton(false);
}
});
service.branchList(project.getLocation(), remoteMode)
.then(branches -> {
if (LIST_REMOTE.equals(remoteMode)) {
view.setRemoteBranches(branchSearcher.getRemoteBranchesToDisplay(view.getRepositoryName(), branches));
updateBranches(LIST_LOCAL);
} else {
view.setLocalBranches(branchSearcher.getLocalBranchesToDisplay(branches));
for (Branch branch : branches) {
if (branch.isActive()) {
view.selectRemoteBranch(branch.getDisplayName());
break;
}
}
}
})
.catchError(error -> {
handleError(error.getCause(), BRANCH_LIST_COMMAND_NAME);
view.setEnablePullButton(false);
});
}
/** {@inheritDoc} */
@ -158,30 +142,26 @@ public class PullPresenter implements PullView.ActionDelegate {
final StatusNotification notification =
notificationManager.notify(constant.pullProcess(), PROGRESS, FLOAT_MODE);
service.pull(project.getLocation(), getRefs(), view.getRepositoryName()).then(new Operation<PullResponse>() {
@Override
public void apply(PullResponse response) throws OperationException {
GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME);
console.print(response.getCommandOutput(), GREEN_COLOR);
consolesPanelPresenter.addCommandOutput(console);
notification.setStatus(SUCCESS);
if (response.getCommandOutput().contains("Already up-to-date")) {
notification.setTitle(constant.pullUpToDate());
} else {
project.synchronize();
notification.setTitle(constant.pullSuccess(view.getRepositoryUrl()));
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notification.setStatus(FAIL);
if (getErrorCode(error.getCause()) == ErrorCodes.MERGE_CONFLICT) {
project.synchronize();
}
handleError(error.getCause(), PULL_COMMAND_NAME);
}
});
service.pull(project.getLocation(), getRefs(), view.getRepositoryName())
.then(response -> {
GitOutputConsole console = gitOutputConsoleFactory.create(PULL_COMMAND_NAME);
console.print(response.getCommandOutput(), GREEN_COLOR);
consolesPanelPresenter.addCommandOutput(console);
notification.setStatus(SUCCESS);
if (response.getCommandOutput().contains("Already up-to-date")) {
notification.setTitle(constant.pullUpToDate());
} else {
project.synchronize();
notification.setTitle(constant.pullSuccess(view.getRepositoryUrl()));
}
})
.catchError(error -> {
notification.setStatus(FAIL);
if (getErrorCode(error.getCause()) == ErrorCodes.MERGE_CONFLICT) {
project.synchronize();
}
handleError(error.getCause(), PULL_COMMAND_NAME);
});
}
/** @return list of refs to fetch */

View File

@ -15,12 +15,9 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.BranchListMode;
import org.eclipse.che.api.git.shared.Remote;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.notification.StatusNotification;
@ -30,7 +27,6 @@ import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.git.client.BranchFilterByRemote;
import org.eclipse.che.ide.ext.git.client.BranchSearcher;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
@ -38,7 +34,6 @@ import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static java.util.Collections.singletonList;
import static org.eclipse.che.api.git.shared.BranchListMode.LIST_LOCAL;
@ -106,26 +101,22 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
* If remote repositories are found, then get the list of branches (remote and local).
*/
void updateRemotes() {
service.remoteList(project.getLocation(), null, true).then(new Operation<List<Remote>>() {
@Override
public void apply(List<Remote> remotes) throws OperationException {
updateLocalBranches();
view.setRepositories(remotes);
view.setEnablePushButton(!remotes.isEmpty());
view.setSelectedForcePushCheckBox(false);
view.showDialog();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE);
view.setEnablePushButton(false);
}
});
service.remoteList(project.getLocation(), null, true)
.then(remotes -> {
updateLocalBranches();
view.setRepositories(remotes);
view.setEnablePushButton(!remotes.isEmpty());
view.setSelectedForcePushCheckBox(false);
view.showDialog();
})
.catchError(error -> {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.remoteListFailed(), FAIL, FLOAT_MODE);
view.setEnablePushButton(false);
});
}
/**
@ -155,7 +146,7 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
String errorMessage = exception.getMessage() != null ? exception.getMessage() : constant.localBranchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(console);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.localBranchesListFailed(), FAIL, FLOAT_MODE);
view.setEnablePushButton(false);
}
@ -205,7 +196,7 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
public void onFailure(Throwable caught) {
GitOutputConsole console = gitOutputConsoleFactory.create(CONFIG_COMMAND_NAME);
console.printError(constant.failedGettingConfig());
processesPanelPresenter.addCommandOutput(console);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.failedGettingConfig(), FAIL, FLOAT_MODE);
}
});
@ -216,7 +207,7 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
String errorMessage = exception.getMessage() != null ? exception.getMessage() : constant.remoteBranchesListFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(BRANCH_LIST_COMMAND_NAME);
console.printError(errorMessage);
processesPanelPresenter.addCommandOutput(console);
processesPanelPresenter.addCommandOutput(appContext.getDevMachine().getId(), console);
notificationManager.notify(constant.remoteBranchesListFailed(), FAIL, FLOAT_MODE);
view.setEnablePushButton(false);
}
@ -233,28 +224,23 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
final String configBranchRemote = "branch." + view.getLocalBranch() + ".remote";
final String configUpstreamBranch = "branch." + view.getLocalBranch() + ".merge";
service.config(project.getLocation(), Arrays.asList(configUpstreamBranch, configBranchRemote))
.then(new Operation<Map<String, String>>() {
@Override
public void apply(Map<String, String> configs) throws OperationException {
if (configs.containsKey(configBranchRemote) && configs.containsKey(configUpstreamBranch)) {
String displayName = configs.get(configBranchRemote) + "/" + configs.get(configUpstreamBranch);
Branch upstream = dtoFactory.createDto(Branch.class)
.withActive(false)
.withRemote(true)
.withDisplayName(displayName)
.withName("refs/remotes/" + displayName);
.then(configs -> {
if (configs.containsKey(configBranchRemote) && configs.containsKey(configUpstreamBranch)) {
String displayName = configs.get(configBranchRemote) + "/" + configs.get(configUpstreamBranch);
Branch upstream = dtoFactory.createDto(Branch.class)
.withActive(false)
.withRemote(true)
.withDisplayName(displayName)
.withName("refs/remotes/" + displayName);
result.onSuccess(upstream);
} else {
result.onSuccess(null);
}
result.onSuccess(upstream);
} else {
result.onSuccess(null);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
result.onFailure(error.getCause());
}
});
})
.catchError(error -> {
result.onFailure(error.getCause());
});
}
/**
@ -264,17 +250,13 @@ public class PushToRemotePresenter implements PushToRemoteView.ActionDelegate {
* is a remote mode
*/
void getBranchesForCurrentProject(@NotNull final BranchListMode remoteMode, final AsyncCallback<List<Branch>> asyncResult) {
service.branchList(project.getLocation(), remoteMode).then(new Operation<List<Branch>>() {
@Override
public void apply(List<Branch> branches) throws OperationException {
asyncResult.onSuccess(branches);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
asyncResult.onFailure(error.getCause());
}
});
service.branchList(project.getLocation(), remoteMode)
.then(branches -> {
asyncResult.onSuccess(branches);
})
.catchError(error -> {
asyncResult.onFailure(error.getCause());
});
}
/** {@inheritDoc} */

View File

@ -15,9 +15,6 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.git.shared.Remote;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -29,7 +26,6 @@ import org.eclipse.che.ide.ext.git.client.remote.add.AddRemoteRepositoryPresente
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import javax.validation.constraints.NotNull;
import java.util.List;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
@ -89,22 +85,18 @@ public class RemotePresenter implements RemoteView.ActionDelegate {
* then get the list of branches (remote and local).
*/
private void getRemotes() {
service.remoteList(project.getLocation(), null, true).then(new Operation<List<Remote>>() {
@Override
public void apply(List<Remote> remotes) throws OperationException {
view.setEnableDeleteButton(selectedRemote != null);
view.setRemotes(remotes);
if (!view.isShown()) {
view.showDialog();
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed();
handleError(errorMessage);
}
});
service.remoteList(project.getLocation(), null, true)
.then(remotes -> {
view.setEnableDeleteButton(selectedRemote != null);
view.setRemotes(remotes);
if (!view.isShown()) {
view.showDialog();
}
})
.catchError(error -> {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteListFailed();
handleError(errorMessage);
});
}
/**
@ -149,23 +141,19 @@ public class RemotePresenter implements RemoteView.ActionDelegate {
return;
}
service.remoteDelete(project.getLocation(), selectedRemote.getName()).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
getRemotes();
service.remoteDelete(project.getLocation(), selectedRemote.getName())
.then(ignored -> {
getRemotes();
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteDeleteFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.remoteDeleteFailed(), FAIL, FLOAT_MODE);
}
});
project.synchronize();
})
.catchError(error -> {
String errorMessage = error.getMessage() != null ? error.getMessage() : constant.remoteDeleteFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(REMOTE_REPO_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.remoteDeleteFailed(), FAIL, FLOAT_MODE);
});
}
/**

View File

@ -14,9 +14,6 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.resources.Project;
@ -67,18 +64,14 @@ public class AddRemoteRepositoryPresenter implements AddRemoteRepositoryView.Act
final String url = view.getUrl().trim();
final Project project = appContext.getRootProject();
service.remoteAdd(project.getLocation(), name, url).then(new Operation<Void>() {
@Override
public void apply(Void arg) throws OperationException {
callback.onSuccess(null);
view.close();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
callback.onFailure(error.getCause());
}
});
service.remoteAdd(project.getLocation(), name, url)
.then(arg -> {
callback.onSuccess(null);
view.close();
})
.catchError(error -> {
callback.onFailure(error.getCause());
});
}
/** {@inheritDoc} */

View File

@ -12,9 +12,6 @@ package org.eclipse.che.ide.ext.git.client.remove;
import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -99,22 +96,18 @@ public class RemoveFromIndexPresenter implements RemoveFromIndexView.ActionDeleg
checkState(!isNullOrEmpty(resources));
service.remove(project.getLocation(), toRelativePaths(resources), view.isRemoved()).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.removeFilesSuccessfull());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.removeFilesSuccessfull());
service.remove(project.getLocation(), toRelativePaths(resources), view.isRemoved())
.then(ignored -> {
console.print(constant.removeFilesSuccessfull());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.removeFilesSuccessfull());
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
handleError(error.getCause(), console);
consolesPanelPresenter.addCommandOutput(console);
}
});
project.synchronize();
})
.catchError(error -> {
handleError(error.getCause(), console);
consolesPanelPresenter.addCommandOutput(console);
});
view.close();
}

View File

@ -14,12 +14,8 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.ErrorCodes;
import org.eclipse.che.api.git.shared.LogResponse;
import org.eclipse.che.api.git.shared.ResetRequest;
import org.eclipse.che.api.git.shared.Revision;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
@ -82,32 +78,28 @@ public class ResetToCommitPresenter implements ResetToCommitView.ActionDelegate
public void showDialog(final Project project) {
this.project = project;
service.log(project.getLocation(), null, false).then(new Operation<LogResponse>() {
@Override
public void apply(LogResponse log) throws OperationException {
view.setRevisions(log.getCommits());
view.setMixMode(true);
view.setEnableResetButton(selectedRevision != null);
view.showDialog();
service.log(project.getLocation(), null, -1, -1, false)
.then(log -> {
view.setRevisions(log.getCommits());
view.setMixMode(true);
view.setEnableResetButton(selectedRevision != null);
view.showDialog();
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(constant.resetCommitViewTitle(),
constant.initCommitWasNotPerformed(),
null).show();
return;
}
String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.logFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(LOG_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.logFailed(), FAIL, FLOAT_MODE);
}
});
project.synchronize();
})
.catchError(error -> {
if (getErrorCode(error.getCause()) == ErrorCodes.INIT_COMMIT_WAS_NOT_PERFORMED) {
dialogFactory.createMessageDialog(constant.resetCommitViewTitle(),
constant.initCommitWasNotPerformed(),
null).show();
return;
}
String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.logFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(LOG_COMMAND_NAME);
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.logFailed(), FAIL, FLOAT_MODE);
});
}
/**
@ -146,24 +138,20 @@ public class ResetToCommitPresenter implements ResetToCommitView.ActionDelegate
final GitOutputConsole console = gitOutputConsoleFactory.create(RESET_COMMAND_NAME);
service.reset(project.getLocation(), selectedRevision.getId(), type, null).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.resetSuccessfully());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetSuccessfully());
service.reset(project.getLocation(), selectedRevision.getId(), type, null)
.then(ignored -> {
console.print(constant.resetSuccessfully());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetSuccessfully());
project.synchronize();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.resetFail();
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetFail(), FAIL, FLOAT_MODE);
}
});
project.synchronize();
})
.catchError(error -> {
String errorMessage = (error.getMessage() != null) ? error.getMessage() : constant.resetFail();
console.printError(errorMessage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetFail(), FAIL, FLOAT_MODE);
});
}
}

View File

@ -14,10 +14,6 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.git.shared.IndexFile;
import org.eclipse.che.api.git.shared.Status;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
@ -90,58 +86,54 @@ public class ResetFilesPresenter implements ResetFilesView.ActionDelegate {
public void showDialog(Project project) {
this.project = project;
service.getStatus(project.getLocation()).then(new Operation<Status>() {
@Override
public void apply(Status status) throws OperationException {
if (status.isClean()) {
dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show();
return;
}
service.getStatus(project.getLocation())
.then(status -> {
if (status.isClean()) {
dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show();
return;
}
indexedFiles = new IndexFile[0];
indexedFiles = new IndexFile[0];
for (String path : status.getAdded()) {
indexedFiles = add(indexedFiles, wrap(path));
}
for (String path : status.getAdded()) {
indexedFiles = add(indexedFiles, wrap(path));
}
for (String path : status.getChanged()) {
indexedFiles = add(indexedFiles, wrap(path));
}
for (String path : status.getChanged()) {
indexedFiles = add(indexedFiles, wrap(path));
}
for (String path : status.getRemoved()) {
indexedFiles = add(indexedFiles, wrap(path));
}
for (String path : status.getRemoved()) {
indexedFiles = add(indexedFiles, wrap(path));
}
if (indexedFiles.length == 0) {
dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show();
return;
}
if (indexedFiles.length == 0) {
dialogFactory.createMessageDialog(constant.messagesWarningTitle(), constant.indexIsEmpty(), null).show();
return;
}
//Mark selected items to reset from index
Resource[] resources = appContext.getResources();
if (resources != null) {
for (Resource selectedItem : resources) {
String selectedItemPath = selectedItem.getLocation().removeFirstSegments(1).toString();
for (IndexFile file : indexedFiles)
if (file.getPath().startsWith(selectedItemPath)) {
file.setIndexed(false);
}
}
}
//Mark selected items to reset from index
Resource[] resources = appContext.getResources();
if (resources != null) {
for (Resource selectedItem : resources) {
String selectedItemPath = selectedItem.getLocation().removeFirstSegments(1).toString();
for (IndexFile file : indexedFiles)
if (file.getPath().startsWith(selectedItemPath)) {
file.setIndexed(false);
}
}
}
view.setIndexedFiles(indexedFiles);
view.showDialog();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMassage = error.getMessage() != null ? error.getMessage() : constant.statusFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(STATUS_COMMAND_NAME);
console.printError(errorMassage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(errorMassage);
}
});
view.setIndexedFiles(indexedFiles);
view.showDialog();
})
.catchError(error -> {
String errorMassage = error.getMessage() != null ? error.getMessage() : constant.statusFailed();
GitOutputConsole console = gitOutputConsoleFactory.create(STATUS_COMMAND_NAME);
console.printError(errorMassage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(errorMassage);
});
}
protected IndexFile wrap(String path) {
@ -169,22 +161,18 @@ public class ResetFilesPresenter implements ResetFilesView.ActionDelegate {
}
view.close();
service.reset(project.getLocation(), "HEAD", ResetType.MIXED, paths).then(new Operation<Void>() {
@Override
public void apply(Void ignored) throws OperationException {
console.print(constant.resetFilesSuccessfully());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetFilesSuccessfully());
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
String errorMassage = error.getMessage() != null ? error.getMessage() : constant.resetFilesFailed();
console.printError(errorMassage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(errorMassage);
}
});
service.reset(project.getLocation(), "HEAD", ResetType.MIXED, paths)
.then(ignored -> {
console.print(constant.resetFilesSuccessfully());
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(constant.resetFilesSuccessfully());
})
.catchError(error -> {
String errorMassage = error.getMessage() != null ? error.getMessage() : constant.resetFilesFailed();
console.printError(errorMassage);
consolesPanelPresenter.addCommandOutput(console);
notificationManager.notify(errorMassage);
});
}
/** {@inheritDoc} */

View File

@ -13,10 +13,6 @@ package org.eclipse.che.ide.ext.git.client.status;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.ext.git.client.GitServiceClient;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Project;
@ -44,7 +40,6 @@ public class StatusCommandPresenter {
public static final String STATUS_COMMAND_NAME = "Git status";
private final GitServiceClient service;
private final AppContext appContext;
private final GitOutputConsoleFactory gitOutputConsoleFactory;
private final ProcessesPanelPresenter consolesPanelPresenter;
private final GitLocalizationConstant constant;
@ -55,13 +50,11 @@ public class StatusCommandPresenter {
*/
@Inject
public StatusCommandPresenter(GitServiceClient service,
AppContext appContext,
GitOutputConsoleFactory gitOutputConsoleFactory,
ProcessesPanelPresenter processesPanelPresenter,
GitLocalizationConstant constant,
NotificationManager notificationManager) {
this.service = service;
this.appContext = appContext;
this.gitOutputConsoleFactory = gitOutputConsoleFactory;
this.consolesPanelPresenter = processesPanelPresenter;
this.constant = constant;
@ -70,17 +63,13 @@ public class StatusCommandPresenter {
/** Show status. */
public void showStatus(Project project) {
service.statusText(project.getLocation(), LONG).then(new Operation<String>() {
@Override
public void apply(String status) throws OperationException {
printGitStatus(status);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(constant.statusFailed(), FAIL, FLOAT_MODE);
}
});
service.statusText(project.getLocation(), LONG)
.then(status -> {
printGitStatus(status);
})
.catchError(error -> {
notificationManager.notify(constant.statusFailed(), FAIL, FLOAT_MODE);
});
}
/**

View File

@ -14,7 +14,6 @@ import org.eclipse.che.api.git.shared.Branch;
import org.eclipse.che.api.git.shared.CheckoutRequest;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.ide.api.parts.WorkspaceAgent;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.git.client.BaseTest;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
@ -69,8 +68,6 @@ public class BranchPresenterTest extends BaseTest {
@Mock
private Branch selectedBranch;
@Mock
private WorkspaceAgent workspaceAgent;
@Mock
private DialogFactory dialogFactory;
@Mock
private DtoFactory dtoFactory;
@ -224,9 +221,9 @@ public class BranchPresenterTest extends BaseTest {
@Test
public void testOnCheckoutClickedWhenSelectedNotRemoteBranch() throws Exception {
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise);
when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise);
when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise);
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise);
when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise);
when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise);
when(selectedBranch.isRemote()).thenReturn(false);
when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest);
@ -234,8 +231,8 @@ public class BranchPresenterTest extends BaseTest {
selectBranch();
presenter.onCheckoutClicked();
verify(voidPromise).then(voidPromiseCaptor.capture());
voidPromiseCaptor.getValue().apply(null);
verify(stringPromise).then(stringCaptor.capture());
stringCaptor.getValue().apply(null);
verify(checkoutRequest).setName(eq(BRANCH_NAME));
verifyNoMoreInteractions(checkoutRequest);
@ -243,17 +240,17 @@ public class BranchPresenterTest extends BaseTest {
@Test
public void testOnCheckoutClickedWhenSelectedRemoteBranch() throws Exception {
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise);
when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise);
when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise);
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise);
when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise);
when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise);
when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest);
selectBranch();
presenter.onCheckoutClicked();
verify(voidPromise).then(voidPromiseCaptor.capture());
voidPromiseCaptor.getValue().apply(null);
verify(stringPromise).then(stringCaptor.capture());
stringCaptor.getValue().apply(null);
verify(checkoutRequest).setTrackBranch(eq(BRANCH_NAME));
verifyNoMoreInteractions(checkoutRequest);

View File

@ -102,20 +102,21 @@ public class CheckoutReferenceTest extends BaseTest {
@Test
public void onEnterClickedWhenValueIsCorrect() throws Exception {
when(appContext.getRootProject()).thenReturn(project);
when(dtoFactory.createDto(CheckoutRequest.class)).thenReturn(checkoutRequest);
when(checkoutRequest.withName(anyString())).thenReturn(checkoutRequest);
when(checkoutRequest.withCreateNew(anyBoolean())).thenReturn(checkoutRequest);
reset(service);
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(voidPromise);
when(voidPromise.then(any(Operation.class))).thenReturn(voidPromise);
when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise);
when(service.checkout(any(Path.class), any(CheckoutRequest.class))).thenReturn(stringPromise);
when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise);
when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise);
when(view.getReference()).thenReturn(CORRECT_REFERENCE);
presenter.showDialog(project);
presenter.onEnterClicked();
verify(voidPromise).then(voidPromiseCaptor.capture());
voidPromiseCaptor.getValue().apply(null);
verify(stringPromise).then(stringCaptor.capture());
stringCaptor.getValue().apply(null);
verify(synchronizePromise).then(synchronizeCaptor.capture());
synchronizeCaptor.getValue().apply(new Resource[0]);

View File

@ -98,8 +98,6 @@ public class CommitPresenterTest extends BaseTest {
when(voidPromise.catchError(any(Operation.class))).thenReturn(voidPromise);
when(revisionPromise.then(any(Operation.class))).thenReturn(revisionPromise);
when(revisionPromise.catchError(any(Operation.class))).thenReturn(revisionPromise);
when(service.add(any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise);
when(service.commit(any(Path.class), anyString(), anyBoolean(), any(Path[].class), anyBoolean())).thenReturn(revisionPromise);
when(stringPromise.then(any(Operation.class))).thenReturn(stringPromise);
when(stringPromise.catchError(any(Operation.class))).thenReturn(stringPromise);
when(branchListPromise.then(any(Operation.class))).thenReturn(branchListPromise);
@ -109,7 +107,7 @@ public class CommitPresenterTest extends BaseTest {
when(logPromise.catchError(any(Operation.class))).thenReturn(logPromise);
when(statusPromise.then(any(Operation.class))).thenReturn(statusPromise);
when(service.add(any(Path.class), anyBoolean(), any(Path[].class))).thenReturn(voidPromise);
when(service.commit(any(Path.class), anyString(), anyBoolean(), any(Path[].class), anyBoolean()))
when(service.commit(any(Path.class), anyString(), anyBoolean(), any(Path[].class)))
.thenReturn(revisionPromise);
when(service.diff(any(Path.class),
eq(null),

View File

@ -68,15 +68,13 @@ public class HistoryPresenterTest extends BaseTest {
when(appContext.getResource()).thenReturn(resource);
when(appContext.getRootProject()).thenReturn(project);
when(service.log(
any(Path.class),
when(service.log(any(Path.class),
any(Path[].class),
anyInt(),
anyInt(),
anyBoolean()))
.thenReturn(logPromise);
when(service.diff(
any(Path.class),
when(service.diff(any(Path.class),
anyList(),
any(DiffType.class),
anyBoolean(),
@ -84,8 +82,7 @@ public class HistoryPresenterTest extends BaseTest {
anyString(),
anyString()))
.thenReturn(stringPromise);
when(service.showFileContent(
any(Path.class),
when(service.showFileContent(any(Path.class),
any(Path.class),
anyString()))
.thenReturn(showPromise);

View File

@ -13,7 +13,6 @@ package org.eclipse.che.ide.ext.git.client.status;
import org.eclipse.che.api.git.shared.StatusFormat;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.ide.api.notification.StatusNotification;
import org.eclipse.che.ide.api.parts.WorkspaceAgent;
import org.eclipse.che.ide.ext.git.client.BaseTest;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
@ -39,9 +38,6 @@ public class StatusCommandPresenterTest extends BaseTest {
@InjectMocks
private StatusCommandPresenter presenter;
@Mock
private WorkspaceAgent workspaceAgent;
@Mock
private GitOutputConsoleFactory gitOutputConsoleFactory;
@ -53,7 +49,6 @@ public class StatusCommandPresenterTest extends BaseTest {
super.disarm();
presenter = new StatusCommandPresenter(service,
appContext,
gitOutputConsoleFactory,
processesPanelPresenter,
constant,

View File

@ -26,7 +26,6 @@ import org.eclipse.che.ide.api.event.ng.DeletedFilesController;
import org.eclipse.che.ide.api.parts.PartPresenter;
import org.eclipse.che.ide.api.parts.WorkspaceAgent;
import org.eclipse.che.ide.api.resources.ExternalResourceDelta;
import org.eclipse.che.ide.api.resources.ModificationTracker;
import org.eclipse.che.ide.api.resources.ResourceDelta;
import org.eclipse.che.ide.api.resources.VirtualFile;
import org.eclipse.che.ide.ext.java.shared.dto.refactoring.ChangeInfo;
@ -167,12 +166,6 @@ public class RefactoringUpdater {
private void updateFileContent(VirtualFile virtualFile) {
String path = virtualFile.getLocation().toString();
if (virtualFile instanceof ModificationTracker) {
String modificationStamp = ((ModificationTracker)virtualFile).getModificationStamp();
eventBus.fireEvent(new FileContentUpdateEvent(path, modificationStamp));
return;
}
eventBus.fireEvent(new FileContentUpdateEvent(path));
}

View File

@ -30,6 +30,18 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>

View File

@ -11,13 +11,13 @@
package org.eclipse.che.plugin.maven.generator.archetype;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.util.AbstractLineConsumer;
import org.eclipse.che.api.core.util.CommandLine;
import org.eclipse.che.api.core.util.LineConsumer;
import org.eclipse.che.api.core.util.ProcessUtil;
import org.eclipse.che.api.core.util.ValueHolder;
import org.eclipse.che.api.core.util.Watchdog;
import org.eclipse.che.api.core.util.WebsocketMessageConsumer;
import org.eclipse.che.ide.maven.tools.MavenArtifact;
import org.eclipse.che.ide.maven.tools.MavenUtils;
import org.eclipse.che.plugin.maven.shared.MavenArchetype;
@ -25,6 +25,7 @@ import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import java.io.File;
@ -35,7 +36,8 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_NAME;
import static org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput.State.DONE;
import static org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput.State.ERROR;
/**
* Generates projects with maven-archetype-plugin.
@ -46,6 +48,13 @@ import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYP
public class ArchetypeGenerator {
private static final Logger LOG = LoggerFactory.getLogger(ArchetypeGenerator.class);
private EventService eventService;
@Inject
public ArchetypeGenerator(EventService eventService) {
this.eventService = eventService;
}
/**
* Generates a new project from the specified archetype by given maven artifact descriptor.
* @param workDir
@ -100,12 +109,13 @@ public class ArchetypeGenerator {
*/
private void execute(String[] commandLine, File workDir) throws TimeoutException, IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder(commandLine).redirectErrorStream(true).directory(workDir);
WebsocketMessageConsumer<ArchetypeOutput> websocketMessageConsumer = new WebsocketMessageConsumer(MAVEN_ARCHETYPE_CHANEL_NAME);
websocketMessageConsumer.consume(new ArchetypeOutputImpl("Start Project generation", ArchetypeOutput.State.START));
eventService.publish(new ArchetypeOutputImpl("Start Project generation", ArchetypeOutput.State.START));
LineConsumer lineConsumer = new AbstractLineConsumer() {
@Override
public void writeLine(String line) throws IOException {
websocketMessageConsumer.consume(new ArchetypeOutputImpl(line, ArchetypeOutput.State.IN_PROGRESS));
eventService.publish(new ArchetypeOutputImpl(line, ArchetypeOutput.State.IN_PROGRESS));
}
};
@ -122,14 +132,14 @@ public class ArchetypeGenerator {
// consume logs until process ends
ProcessUtil.process(process, lineConsumer);
process.waitFor();
websocketMessageConsumer.consume(new ArchetypeOutputImpl("Done", ArchetypeOutput.State.DONE));
eventService.publish(new ArchetypeOutputImpl("Done", DONE));
if (isTimeoutExceeded.get()) {
LOG.error("Generation project time expired : command-line " + Arrays.toString(commandLine));
websocketMessageConsumer.consume(new ArchetypeOutputImpl("Generation project time expired", ArchetypeOutput.State.ERROR));
eventService.publish(new ArchetypeOutputImpl("Generation project time expired", ERROR));
throw new TimeoutException();
} else if (process.exitValue() != 0) {
LOG.error("Generation project fail : command-line " + Arrays.toString(commandLine));
websocketMessageConsumer.consume(new ArchetypeOutputImpl("Generation project occurs error", ArchetypeOutput.State.ERROR));
eventService.publish(new ArchetypeOutputImpl("Generation project occurs error", ERROR));
throw new IOException("Process failed. Exit code " + process.exitValue() + " command-line : " + Arrays.toString(commandLine));
}
} finally {

View File

@ -13,14 +13,12 @@ package org.eclipse.che.plugin.maven.generator.archetype;
import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput;
/**
* Describes information about output object of maven archetype project generation.
*
* @author Vitalii Parfonov
*/
public class ArchetypeOutputImpl implements ArchetypeOutput {
private String output;
private State state;
public ArchetypeOutputImpl(String output, State state) {
@ -37,4 +35,14 @@ public class ArchetypeOutputImpl implements ArchetypeOutput {
public State getState() {
return state;
}
@Override
public void setOutput(String output) {
this.output = output;
}
@Override
public void setState(State state) {
this.state = state;
}
}

View File

@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.generator.archetype;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import java.util.Set;
import static com.google.common.collect.Sets.newConcurrentHashSet;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_OUTPUT;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE;
/**
* Mechanism which sends events of maven archetype generation by using JSON RPC to the client.
*/
@Singleton
public class MavenArchetypeJsonRpcMessenger implements EventSubscriber<ArchetypeOutput> {
private final Set<String> endpointIds = newConcurrentHashSet();
private EventService eventService;
private RequestTransmitter transmitter;
@Inject
public MavenArchetypeJsonRpcMessenger(EventService eventService, RequestTransmitter transmitter) {
this.eventService = eventService;
this.transmitter = transmitter;
}
@PostConstruct
private void subscribe() {
eventService.subscribe(this);
}
@PreDestroy
private void unsubscribe() {
eventService.unsubscribe(this);
}
@Inject
private void configureHandlers(RequestHandlerConfigurator configurator) {
configurator.newConfiguration()
.methodName(MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE)
.noParams()
.noResult()
.withConsumer(endpointIds::add);
configurator.newConfiguration()
.methodName(MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE)
.noParams()
.noResult()
.withConsumer(endpointIds::remove);
}
@Override
public void onEvent(ArchetypeOutput event) {
ArchetypeOutput archetypeOutput = DtoFactory.newDto(ArchetypeOutput.class);
archetypeOutput.setOutput(event.getOutput());
archetypeOutput.setState(event.getState());
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_ARCHETYPE_CHANEL_OUTPUT)
.paramsAsDto(archetypeOutput)
.sendAndSkipResult());
}
}

View File

@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.che.plugin.maven.generator.archetype;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.commons.lang.NameGenerator;
import org.eclipse.che.ide.maven.tools.MavenArtifact;
import org.eclipse.che.plugin.maven.shared.MavenArchetype;
@ -26,6 +27,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link ArchetypeGenerator}
*
* @author Vitalii Parfonov
*/
@ -36,11 +38,12 @@ public class ArchetypeGeneratorTest {
@Ignore
public void generateFromArchetype() throws Exception {
MavenArchetype mavenArchetype = mock(MavenArchetype.class);
EventService eventService = mock(EventService.class);
when(mavenArchetype.getArtifactId()).thenReturn("tomee-webapp-archetype");
when(mavenArchetype.getGroupId()).thenReturn("org.apache.openejb.maven");
when(mavenArchetype.getVersion()).thenReturn("1.7.1");
File workDir = Files.createTempDirectory("workDir").toFile();
ArchetypeGenerator archetypeGenerator = new ArchetypeGenerator();
ArchetypeGenerator archetypeGenerator = new ArchetypeGenerator(eventService);
String artifactId = NameGenerator.generate("artifactId", 5);
String groupId = NameGenerator.generate("groupId", 5);
MavenArtifact mavenArtifact = new MavenArtifact();

View File

@ -0,0 +1,181 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.client;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput;
import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.PercentUndefinedMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage;
import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification;
import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_OUTPUT;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_SUBSCRIBE;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_START_STOP_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_TEXT_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_UPDATE_METHOD;
/**
* A mechanism for handling all messages from the Maven server and applying registered consumers.
*/
@Singleton
public class MavenJsonRpcHandler {
private static final String WS_AGENT_ENDPOINT = "ws-agent";
private RequestHandlerConfigurator configurator;
private Set<Consumer<TextMessageDto>> textConsumers = new HashSet<>();
private Set<Consumer<StartStopNotification>> startStopConsumers = new HashSet<>();
private Set<Consumer<PercentUndefinedMessageDto>> percentUndefinedConsumers = new HashSet<>();
private Set<Consumer<PercentMessageDto>> percentConsumers = new HashSet<>();
private Set<Consumer<ProjectsUpdateMessage>> projectsUpdateConsumers = new HashSet<>();
private Set<Consumer<ArchetypeOutput>> archetypeOutputConsumers = new HashSet<>();
private boolean isSubscribed = false;
@Inject
public MavenJsonRpcHandler(RequestHandlerConfigurator configurator) {
this.configurator = configurator;
handleMavenServerMessages();
}
@Inject
private void subscribe(RequestTransmitter requestTransmitter) {
if (isSubscribed) {
return;
}
requestTransmitter.newRequest()
.endpointId(WS_AGENT_ENDPOINT)
.methodName(MAVEN_CHANEL_SUBSCRIBE)
.noParams()
.sendAndSkipResult();
requestTransmitter.newRequest()
.endpointId(WS_AGENT_ENDPOINT)
.methodName(MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE)
.noParams()
.sendAndSkipResult();
isSubscribed = true;
}
/**
* Adds consumer for the event with {@link TextMessageDto}.
*
* @param consumer
* new consumer
*/
public void addTextHandler(Consumer<TextMessageDto> consumer) {
textConsumers.add(consumer);
}
/**
* Adds consumer for the event with {@link StartStopNotification}.
*
* @param consumer
* new consumer
*/
public void addStartStopHandler(Consumer<StartStopNotification> consumer) {
startStopConsumers.add(consumer);
}
/**
* Adds consumer for the event with {@link PercentUndefinedMessageDto}.
*
* @param consumer
* new consumer
*/
public void addPercentUndefinedHandler(Consumer<PercentUndefinedMessageDto> consumer) {
percentUndefinedConsumers.add(consumer);
}
/**
* Adds consumer for the event with {@link PercentMessageDto}.
*
* @param consumer
* new consumer
*/
public void addPercentHandler(Consumer<PercentMessageDto> consumer) {
percentConsumers.add(consumer);
}
/**
* Adds consumer for the event with {@link ProjectsUpdateMessage}.
*
* @param consumer
* new consumer
*/
public void addProjectsUpdateHandler(Consumer<ProjectsUpdateMessage> consumer) {
projectsUpdateConsumers.add(consumer);
}
/**
* Adds consumer for the event with {@link ArchetypeOutput}.
*
* @param consumer
* new consumer
*/
public void addArchetypeOutputHandler(Consumer<ArchetypeOutput> consumer) {
archetypeOutputConsumers.add(consumer);
}
private void handleMavenServerMessages() {
configurator.newConfiguration()
.methodName(MAVEN_OUTPUT_TEXT_METHOD)
.paramsAsDto(TextMessageDto.class)
.noResult()
.withConsumer(textNotification -> textConsumers.forEach(it -> it.accept(textNotification)));
configurator.newConfiguration()
.methodName(MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD)
.paramsAsDto(PercentUndefinedMessageDto.class)
.noResult()
.withConsumer(percentUndefinedMessage -> percentUndefinedConsumers.forEach(it -> it.accept(percentUndefinedMessage)));
configurator.newConfiguration()
.methodName(MAVEN_OUTPUT_PERCENT_METHOD)
.paramsAsDto(PercentMessageDto.class)
.noResult()
.withConsumer(percentMessage -> percentConsumers.forEach(it -> it.accept(percentMessage)));
configurator.newConfiguration()
.methodName(MAVEN_OUTPUT_START_STOP_METHOD)
.paramsAsDto(StartStopNotification.class)
.noResult()
.withConsumer(startStopNotification -> startStopConsumers.forEach(it -> it.accept(startStopNotification)));
configurator.newConfiguration()
.methodName(MAVEN_OUTPUT_UPDATE_METHOD)
.paramsAsDto(ProjectsUpdateMessage.class)
.noResult()
.withConsumer(projectsUpdateMessage -> projectsUpdateConsumers.forEach(it -> it.accept(projectsUpdateMessage)));
configurator.newConfiguration()
.methodName(MAVEN_ARCHETYPE_CHANEL_OUTPUT)
.paramsAsDto(ArchetypeOutput.class)
.noResult()
.withConsumer(archetypeOutput -> archetypeOutputConsumers.forEach(it -> it.accept(archetypeOutput)));
}
}

View File

@ -10,41 +10,27 @@
*******************************************************************************/
package org.eclipse.che.plugin.maven.client.comunnication;
import elemental.json.Json;
import elemental.json.JsonObject;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.machine.WsAgentStateController;
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent;
import org.eclipse.che.ide.console.CommandConsoleFactory;
import org.eclipse.che.ide.console.DefaultOutputConsole;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.ide.websocket.MessageBus;
import org.eclipse.che.ide.websocket.WebSocketException;
import org.eclipse.che.ide.websocket.events.MessageHandler;
import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler;
import org.eclipse.che.plugin.maven.client.comunnication.progressor.background.BackgroundLoaderPresenter;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.shared.dto.ArchetypeOutput;
import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage;
import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage;
import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification;
import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto;
import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.toSet;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ARCHETYPE_CHANEL_NAME;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME;
/**
* Handler which receives messages from the maven server.
@ -54,127 +40,70 @@ import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_N
*/
@Singleton
public class MavenMessagesHandler {
private final EventBus eventBus;
private final DtoFactory factory;
private final BackgroundLoaderPresenter dependencyResolver;
private final PomEditorReconciler pomEditorReconciler;
private final ProcessesPanelPresenter processesPanelPresenter;
private final CommandConsoleFactory commandConsoleFactory;
private final AppContext appContext;
private DefaultOutputConsole outputConsole;
@Inject
public MavenMessagesHandler(EventBus eventBus,
DtoFactory factory,
MavenJsonRpcHandler mavenJsonRpcHandler,
BackgroundLoaderPresenter dependencyResolver,
PomEditorReconciler pomEditorReconciler,
WsAgentStateController wsAgentStateController,
ProcessesPanelPresenter processesPanelPresenter,
CommandConsoleFactory commandConsoleFactory,
AppContext appContext) {
this.eventBus = eventBus;
this.factory = factory;
this.dependencyResolver = dependencyResolver;
this.pomEditorReconciler = pomEditorReconciler;
this.processesPanelPresenter = processesPanelPresenter;
this.commandConsoleFactory = commandConsoleFactory;
this.appContext = appContext;
handleOperations(wsAgentStateController);
mavenJsonRpcHandler.addTextHandler(this::handleTextNotification);
mavenJsonRpcHandler.addStartStopHandler(this::handleStartStop);
mavenJsonRpcHandler.addPercentHandler(this::handlePercentNotification);
mavenJsonRpcHandler.addProjectsUpdateHandler(this::handleUpdate);
mavenJsonRpcHandler.addArchetypeOutputHandler(this::onMavenArchetypeReceive);
handleOperations();
outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Maven Archetype");
}
private void handleOperations(final WsAgentStateController wsAgentStateController) {
eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() {
@Override
public void onWsAgentStarted(WsAgentStateEvent event) {
wsAgentStateController.getMessageBus().then(new Operation<MessageBus>() {
@Override
public void apply(MessageBus messageBus) throws OperationException {
try {
handleMavenServerEvents(messageBus);
handleMavenArchetype(messageBus);
} catch (WebSocketException e) {
dependencyResolver.hide();
Log.error(getClass(), e);
}
}
});
}
@Override
public void onWsAgentStopped(WsAgentStateEvent event) {
dependencyResolver.hide();
}
});
private void handleOperations() {
eventBus.addHandler(WorkspaceStoppedEvent.TYPE, event -> dependencyResolver.hide());
}
private void handleMavenServerEvents(final MessageBus messageBus) throws WebSocketException {
messageBus.subscribe(MAVEN_CHANEL_NAME, new MessageHandler() {
@Override
public void onMessage(String message) {
final JsonObject jsonObject = Json.parse(message);
final int type = (int)jsonObject.getNumber("$type");
MessageType messageType = MessageType.valueOf(type);
switch (messageType) {
case NOTIFICATION:
NotificationMessage dto = factory.createDtoFromJson(message, NotificationMessage.class);
handleNotification(dto);
break;
case UPDATE:
handleUpdate(factory.createDtoFromJson(message, ProjectsUpdateMessage.class));
break;
case START_STOP:
handleStartStop(factory.createDtoFromJson(message, StartStopNotification.class));
break;
default:
Log.error(getClass(), "Unknown message type:" + messageType);
}
}
});
/**
* Updates progress bar when the percent of project resolving is changed.
*
* @param percentMessageDto
* object with value of percent
*/
protected void handlePercentNotification(PercentMessageDto percentMessageDto) {
dependencyResolver.updateProgressBar((int)(percentMessageDto.getPercent() * 100));
}
private void handleMavenArchetype(final MessageBus messageBus) {
final DefaultOutputConsole outputConsole = (DefaultOutputConsole)commandConsoleFactory.create("Maven Archetype");
try {
messageBus.subscribe(MAVEN_ARCHETYPE_CHANEL_NAME, new MessageHandler() {
@Override
public void onMessage(String message) {
Log.info(getClass(), message);
ArchetypeOutput archetypeOutput = factory.createDtoFromJson(message, ArchetypeOutput.class);
processesPanelPresenter.addCommandOutput(outputConsole);
switch (archetypeOutput.getState()) {
case START:
outputConsole.clearOutputsButtonClicked();
outputConsole.printText(archetypeOutput.getOutput(), "green");
break;
case IN_PROGRESS:
outputConsole.printText(archetypeOutput.getOutput());
break;
case DONE:
outputConsole.printText(archetypeOutput.getOutput(), "green");
break;
case ERROR:
outputConsole.printText(archetypeOutput.getOutput(), "red");
break;
default:
break;
}
}
});
} catch (WebSocketException e) {
e.printStackTrace();
}
/**
* Updates progress label when the resolved project is changed.
*
* @param textMessageDto
* object with name of new label
*/
protected void handleTextNotification(TextMessageDto textMessageDto) {
dependencyResolver.show();
dependencyResolver.setProgressLabel(textMessageDto.getText());
}
private void handleStartStop(StartStopNotification dto) {
/**
* Hides or shows a progress bar.
*
* @param dto
* describes a state of the project resolving
*/
protected void handleStartStop(StartStopNotification dto) {
if (dto.isStart()) {
dependencyResolver.show();
} else {
@ -182,7 +111,13 @@ public class MavenMessagesHandler {
}
}
private void handleUpdate(ProjectsUpdateMessage dto) {
/**
* Updates the tree of projects which were modified.
*
* @param dto
* describes a projects which were modified
*/
protected void handleUpdate(ProjectsUpdateMessage dto) {
List<String> updatedProjects = dto.getUpdatedProjects();
Set<String> projectToRefresh = computeUniqueHiLevelProjects(updatedProjects);
for (final String path : projectToRefresh) {
@ -196,24 +131,38 @@ public class MavenMessagesHandler {
pomEditorReconciler.reconcilePoms(updatedProjects);
}
private void onMavenArchetypeReceive(ArchetypeOutput output) {
String message = output.getOutput();
switch (output.getState()) {
case START:
processesPanelPresenter.addCommandOutput(outputConsole);
outputConsole.clearOutputsButtonClicked();
outputConsole.printText(message, "green");
break;
case IN_PROGRESS:
outputConsole.printText(message);
break;
case DONE:
outputConsole.printText(message, "green");
break;
case ERROR:
outputConsole.printText(message, "red");
break;
default:
break;
}
}
private Set<String> computeUniqueHiLevelProjects(List<String> updatedProjects) {
return updatedProjects.stream().filter(each -> shouldBeUpdated(updatedProjects, each)).collect(toSet());
}
private boolean shouldBeUpdated(List<String> updatedProjects, String project) {
for (String each : updatedProjects) {
if (!project.equals(each) && project.startsWith(each)){
if (!project.equals(each) && project.startsWith(each)) {
return false;
}
}
return true;
}
private void handleNotification(NotificationMessage message) {
if (message.getPercent() != 0) {
dependencyResolver.updateProgressBar((int)(message.getPercent() * 100));
} else {
dependencyResolver.setProgressLabel(message.getText());
}
}
}

View File

@ -15,19 +15,8 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.ide.api.machine.WsAgentStateController;
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
import org.eclipse.che.ide.collections.Jso;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.project.ResolvingProjectStateHolder;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.ide.websocket.MessageBus;
import org.eclipse.che.ide.websocket.WebSocketException;
import org.eclipse.che.ide.websocket.events.MessageHandler;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler;
import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification;
import java.util.HashSet;
@ -35,9 +24,7 @@ import java.util.HashSet;
import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.IN_PROGRESS;
import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.NOT_RESOLVED;
import static org.eclipse.che.ide.project.ResolvingProjectStateHolder.ResolvingProjectState.RESOLVED;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ID;
import static org.eclipse.che.plugin.maven.shared.MessageType.START_STOP;
/**
* Keeper for the state of Resolving Project process.
@ -51,22 +38,16 @@ import static org.eclipse.che.plugin.maven.shared.MessageType.START_STOP;
* @author Roman Nikitenko
*/
@Singleton
public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHolder, WsAgentStateHandler {
private final DtoFactory factory;
private final WsAgentStateController wsAgentStateController;
public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHolder {
private ResolvingProjectState state;
private HashSet<ResolvingProjectStateListener> listeners;
@Inject
public ResolvingMavenProjectStateHolder(DtoFactory factory,
EventBus eventBus,
WsAgentStateController wsAgentStateController) {
this.factory = factory;
this.wsAgentStateController = wsAgentStateController;
public ResolvingMavenProjectStateHolder(MavenJsonRpcHandler mavenJsonRpcHandler, EventBus eventBus) {
this.state = NOT_RESOLVED;
this.listeners = new HashSet<>();
eventBus.addHandler(WsAgentStateEvent.TYPE, this);
mavenJsonRpcHandler.addStartStopHandler(this::handleStartStop);
}
@Override
@ -89,36 +70,6 @@ public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHo
listeners.remove(listener);
}
@Override
public void onWsAgentStarted(WsAgentStateEvent event) {
wsAgentStateController.getMessageBus().then(new Operation<MessageBus>() {
@Override
public void apply(MessageBus messageBus) throws OperationException {
try {
messageBus.subscribe(MAVEN_CHANEL_NAME, new MessageHandler() {
@Override
public void onMessage(String message) {
Jso jso = Jso.deserialize(message);
int type = jso.getFieldCastedToInteger("$type");
MessageType messageType = MessageType.valueOf(type);
if (messageType == START_STOP) {
handleStartStop(factory.createDtoFromJson(message, StartStopNotification.class));
}
}
});
} catch (WebSocketException e) {
Log.error(getClass(), e);
}
}
});
}
@Override
public void onWsAgentStopped(WsAgentStateEvent event) {
}
private void handleStartStop(StartStopNotification startStopNotification) {
if (startStopNotification.isStart()) {
state = IN_PROGRESS;
@ -138,4 +89,5 @@ public class ResolvingMavenProjectStateHolder implements ResolvingProjectStateHo
}
}
};
}

View File

@ -13,107 +13,69 @@ package org.eclipse.che.plugin.maven.client.comunnication;
import com.google.common.base.Optional;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.machine.WsAgentStateController;
import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent;
import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.ide.console.CommandConsoleFactory;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import org.eclipse.che.ide.websocket.MessageBus;
import org.eclipse.che.ide.websocket.events.MessageHandler;
import org.eclipse.che.plugin.maven.client.MavenJsonRpcHandler;
import org.eclipse.che.plugin.maven.client.comunnication.progressor.background.BackgroundLoaderPresenter;
import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage;
import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_NAME;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class MavenMessagesHandlerTest {
private static final String JSON_MESSAGE = "{\n" +
" \"deletedProjects\": [],\n" +
" \"updatedProjects\": [\n" +
" \"/che/core\",\n" +
" \"/project\",\n" +
" \"/che/core/che-core-db-vendor-postgresql\",\n" +
" \"/che/plugins/plugin-svn\",\n" +
" \"/che/samples/sample-plugin-json\",\n" +
" \"/che/wsmaster/che-core-api-auth\",\n" +
" \"/project/api\",\n" +
" \"/che/wsagent\",\n" +
" \"/che\",\n" +
" \"/che/plugins/plugin-github/che-plugin-github-pullrequest\",\n" +
" \"/che/plugins/plugin-java-debugger\"\n" +
" ],\n" +
" \"$type\": 2\n" +
"}";
@Mock
private EventBus eventBus;
@Mock
private DtoFactory factory;
@Mock
private BackgroundLoaderPresenter dependencyResolver;
@Mock
private PomEditorReconciler pomEditorReconciler;
@Mock
private WsAgentStateController wsAgentStateController;
@Mock
private ProcessesPanelPresenter processesPanelPresenter;
@Mock
private CommandConsoleFactory commandConsoleFactory;
@Mock
private MavenJsonRpcHandler mavenJsonRpcHandler;
@Mock
private AppContext appContext;
@Mock
private WsAgentStateEvent wsAgentStateEvent;
private ProjectsUpdateMessage projectsUpdateMessage;
@Mock
private ProjectsUpdateMessage projectsUpdateMessage;
private Promise<Optional<Container>> optionalContainer;
@Mock
private Promise<MessageBus> messageBusPromise;
@Mock
private Promise<Optional<Container>> optionalContainer;
@Mock
private MessageBus messageBus;
@Mock
private Container rootContainer;
@Captor
private ArgumentCaptor<WsAgentStateHandler> wsAgentStateHandlerArgumentCaptor;
@Captor
private ArgumentCaptor<Operation<MessageBus>> operationArgumentCaptor;
@Captor
private ArgumentCaptor<MessageHandler> messageHandlerArgumentCaptor;
private Container rootContainer;
private MavenMessagesHandler mavenMessagesHandler;
@Before
public void setUp() throws Exception {
when(wsAgentStateController.getMessageBus()).thenReturn(messageBusPromise);
when(appContext.getWorkspaceRoot()).thenReturn(rootContainer);
new MavenMessagesHandler(eventBus,
factory,
dependencyResolver,
pomEditorReconciler,
wsAgentStateController,
processesPanelPresenter,
commandConsoleFactory,
appContext);
mavenMessagesHandler = new MavenMessagesHandler(eventBus,
mavenJsonRpcHandler,
dependencyResolver,
pomEditorReconciler,
processesPanelPresenter,
commandConsoleFactory,
appContext);
}
@Test
@ -130,22 +92,34 @@ public class MavenMessagesHandlerTest {
"/che/plugins/plugin-github/che-plugin-github-pullrequest",
"/che/plugins/plugin-java-debugger");
when(factory.createDtoFromJson(eq(JSON_MESSAGE), eq(ProjectsUpdateMessage.class))).thenReturn(projectsUpdateMessage);
when(projectsUpdateMessage.getUpdatedProjects()).thenReturn(updatedProjects);
when(rootContainer.getContainer(anyString())).thenReturn(optionalContainer);
verify(eventBus).addHandler(eq(WsAgentStateEvent.TYPE), wsAgentStateHandlerArgumentCaptor.capture());
wsAgentStateHandlerArgumentCaptor.getValue().onWsAgentStarted(wsAgentStateEvent);
mavenMessagesHandler.handleUpdate(projectsUpdateMessage);
verify(messageBusPromise).then(operationArgumentCaptor.capture());
operationArgumentCaptor.getValue().apply(messageBus);
verify(messageBus).subscribe(eq(MAVEN_CHANEL_NAME), messageHandlerArgumentCaptor.capture());
messageHandlerArgumentCaptor.getValue().onMessage(JSON_MESSAGE);
verify(factory).createDtoFromJson(JSON_MESSAGE, ProjectsUpdateMessage.class);
verify(pomEditorReconciler).reconcilePoms(updatedProjects);
verify(rootContainer).getContainer(eq("/che"));
verify(rootContainer).getContainer(eq("/project"));
}
@Test
public void percentNotificationShouldBeHandled() throws Exception {
PercentMessageDto percentMessageDto = Mockito.mock(PercentMessageDto.class);
when(percentMessageDto.getPercent()).thenReturn(0.7);
mavenMessagesHandler.handlePercentNotification(percentMessageDto);
verify(dependencyResolver).updateProgressBar(70);
}
@Test
public void textNotificationShouldBeUpdated() throws Exception {
TextMessageDto textMessageDto = mock(TextMessageDto.class);
String textMessage = "textMessage";
when(textMessageDto.getText()).thenReturn(textMessage);
mavenMessagesHandler.handleTextNotification(textMessageDto);
verify(dependencyResolver).setProgressLabel(textMessage);
}
}

View File

@ -26,6 +26,7 @@ import java.util.Set;
* @author Evgen Vidolob
*/
@ImplementedBy(MavenWebSocketCommunication.class)
@Deprecated
public interface MavenCommunication {
void sendUpdateMassage(Set<MavenProject> updated, List<MavenProject> removed);

View File

@ -0,0 +1,172 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.server.core;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.jsonrpc.commons.RequestHandlerConfigurator;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.plugin.maven.shared.dto.PercentMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.PercentUndefinedMessageDto;
import org.eclipse.che.plugin.maven.shared.dto.ProjectsUpdateMessage;
import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification;
import org.eclipse.che.plugin.maven.shared.dto.TextMessageDto;
import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent;
import org.eclipse.che.plugin.maven.shared.event.MavenPercentMessageEvent;
import org.eclipse.che.plugin.maven.shared.event.MavenPercentUndefinedEvent;
import org.eclipse.che.plugin.maven.shared.event.MavenStartStopEvent;
import org.eclipse.che.plugin.maven.shared.event.MavenTextMessageEvent;
import org.eclipse.che.plugin.maven.shared.event.MavenUpdateEvent;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import java.util.List;
import java.util.Set;
import static com.google.common.collect.Sets.newConcurrentHashSet;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_SUBSCRIBE;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_CHANEL_UNSUBSCRIBE;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_START_STOP_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_TEXT_METHOD;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_OUTPUT_UPDATE_METHOD;
import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.PERCENT;
import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.PERCENT_UNDEFINED;
import static org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent.TYPE.START_STOP;
/**
* Send maven events using JSON RPC to the clients.
*/
@Singleton
public class MavenJsonRpcCommunication implements EventSubscriber<MavenOutputEvent> {
private final Set<String> endpointIds = newConcurrentHashSet();
private EventService eventService;
private RequestTransmitter transmitter;
@Inject
public MavenJsonRpcCommunication(EventService eventService, RequestTransmitter transmitter) {
this.eventService = eventService;
this.transmitter = transmitter;
}
@PostConstruct
private void subscribe() {
eventService.subscribe(this);
}
@PreDestroy
private void unsubscribe() {
eventService.unsubscribe(this);
}
@Inject
private void configureHandlers(RequestHandlerConfigurator configurator) {
configurator.newConfiguration()
.methodName(MAVEN_CHANEL_SUBSCRIBE)
.noParams()
.noResult()
.withConsumer(endpointIds::add);
configurator.newConfiguration()
.methodName(MAVEN_CHANEL_UNSUBSCRIBE)
.noParams()
.noResult()
.withConsumer(endpointIds::remove);
}
@Override
public void onEvent(MavenOutputEvent event) {
switch (event.getType()) {
case TEXT:
sendTextNotification((MavenTextMessageEvent)event);
break;
case UPDATE:
sendUpdateNotification((MavenUpdateEvent)event);
break;
case START_STOP:
sendStartStopNotification((MavenStartStopEvent)event);
break;
case PERCENT:
senPercentNotification((MavenPercentMessageEvent)event);
break;
case PERCENT_UNDEFINED:
sendPercentUndefinedNotification((MavenPercentUndefinedEvent)event);
break;
}
}
private void senPercentNotification(MavenPercentMessageEvent event) {
PercentMessageDto percentMessageDto = DtoFactory.newDto(PercentMessageDto.class).withPercent(event.getPercent());
percentMessageDto.setType(PERCENT);
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_OUTPUT_PERCENT_METHOD)
.paramsAsDto(percentMessageDto)
.sendAndSkipResult());
}
private void sendPercentUndefinedNotification(MavenPercentUndefinedEvent event) {
PercentUndefinedMessageDto percentUndefinedMessageDto = DtoFactory.newDto(PercentUndefinedMessageDto.class);
percentUndefinedMessageDto.setPercentUndefined(event.isPercentUndefined());
percentUndefinedMessageDto.setType(PERCENT_UNDEFINED);
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD)
.paramsAsDto(percentUndefinedMessageDto)
.sendAndSkipResult());
}
private void sendStartStopNotification(MavenStartStopEvent event) {
StartStopNotification startEventDto = DtoFactory.newDto(StartStopNotification.class);
startEventDto.setStart(event.isStart());
startEventDto.setType(START_STOP);
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_OUTPUT_START_STOP_METHOD)
.paramsAsDto(startEventDto)
.sendAndSkipResult());
}
private void sendUpdateNotification(MavenUpdateEvent event) {
ProjectsUpdateMessage updateEventDto = DtoFactory.newDto(ProjectsUpdateMessage.class);
List<String> updatedPaths = event.getUpdatedProjects();
List<String> removedPaths = event.getRemovedProjects();
updateEventDto.setUpdatedProjects(updatedPaths);
updateEventDto.setDeletedProjects(removedPaths);
updateEventDto.setType(MavenOutputEvent.TYPE.UPDATE);
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_OUTPUT_UPDATE_METHOD)
.paramsAsDto(updateEventDto)
.sendAndSkipResult());
}
private void sendTextNotification(MavenTextMessageEvent event) {
TextMessageDto notification = DtoFactory.newDto(TextMessageDto.class).withText(event.getMessage());
notification.setType(MavenOutputEvent.TYPE.TEXT);
endpointIds.forEach(it -> transmitter.newRequest()
.endpointId(it)
.methodName(MAVEN_OUTPUT_TEXT_METHOD)
.paramsAsDto(notification)
.sendAndSkipResult());
}
}

View File

@ -13,11 +13,13 @@ package org.eclipse.che.plugin.maven.server.core;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage;
import org.eclipse.che.plugin.maven.shared.dto.StartStopNotification;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.maven.server.MavenServerProgressNotifier;
import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent;
import org.eclipse.che.plugin.maven.shared.impl.MavenPercentEventImpl;
import org.eclipse.che.plugin.maven.shared.impl.MavenPercentUndefinedEventImpl;
import org.eclipse.che.plugin.maven.shared.impl.MavenStartStopEventImpl;
import org.eclipse.che.plugin.maven.shared.impl.MavenTextMessageEventImpl;
/**
* Default implementation of {@link MavenServerProgressNotifier}
@ -27,32 +29,26 @@ import org.eclipse.che.maven.server.MavenServerProgressNotifier;
@Singleton
public class MavenServerNotifier implements MavenProgressNotifier {
private final MavenCommunication communication;
private EventService eventService;
@Inject
public MavenServerNotifier(MavenCommunication communication) {
this.communication = communication;
public MavenServerNotifier(EventService eventService) {
this.eventService = eventService;
}
@Override
public void setText(String text) {
NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class);
dto.setText(text);
communication.sendNotification(dto);
eventService.publish(new MavenTextMessageEventImpl(text, MavenOutputEvent.TYPE.TEXT));
}
@Override
public void setPercent(double percent) {
NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class);
dto.setPercent(percent);
communication.sendNotification(dto);
eventService.publish(new MavenPercentEventImpl(percent, MavenOutputEvent.TYPE.PERCENT));
}
@Override
public void setPercentUndefined(boolean undefined) {
NotificationMessage dto = DtoFactory.newDto(NotificationMessage.class);
dto.setPercentUndefined(undefined);
communication.sendNotification(dto);
eventService.publish(new MavenPercentUndefinedEventImpl(undefined, MavenOutputEvent.TYPE.PERCENT_UNDEFINED));
}
@Override
@ -66,9 +62,7 @@ public class MavenServerNotifier implements MavenProgressNotifier {
}
private void sendStartStop(boolean isStart) {
StartStopNotification dto = DtoFactory.newDto(StartStopNotification.class);
dto.setStart(isStart);
communication.send(DtoFactory.getInstance().toJsonElement(dto).getAsJsonObject(), MessageType.START_STOP);
eventService.publish(new MavenStartStopEventImpl(isStart, MavenOutputEvent.TYPE.START_STOP));
}
@Override

View File

@ -34,6 +34,7 @@ import java.util.stream.Collectors;
* @author Evgen Vidolob
*/
@Singleton
@Deprecated
public class MavenWebSocketCommunication implements MavenCommunication {
private static final Logger LOG = LoggerFactory.getLogger(MavenWebSocketCommunication.class);

View File

@ -30,7 +30,10 @@ import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager;
import org.eclipse.che.plugin.maven.server.core.project.MavenProject;
import org.eclipse.che.plugin.maven.server.core.project.MavenProjectModifications;
import org.eclipse.che.plugin.maven.shared.MavenAttributes;
import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent;
import org.eclipse.che.plugin.maven.shared.impl.MavenUpdateEventImpl;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
@ -50,6 +53,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import static java.util.stream.Collectors.toList;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.MAVEN_ID;
/**
@ -62,7 +66,6 @@ public class MavenWorkspace {
private final MavenProjectManager manager;
private final Provider<ProjectRegistry> projectRegistryProvider;
private final MavenCommunication communication;
private final ClasspathManager classpathManager;
private MavenTaskExecutor resolveExecutor;
@ -76,12 +79,10 @@ public class MavenWorkspace {
MavenProgressNotifier notifier,
MavenExecutorService executorService,
Provider<ProjectRegistry> projectRegistryProvider,
MavenCommunication communication,
ClasspathManager classpathManager,
EventService eventService,
EclipseWorkspaceProvider workspaceProvider) {
this.projectRegistryProvider = projectRegistryProvider;
this.communication = communication;
this.classpathManager = classpathManager;
this.manager = manager;
resolveExecutor = new MavenTaskExecutor(executorService, notifier);
@ -110,9 +111,20 @@ public class MavenWorkspace {
List<MavenProject> needResolve = manager.findDependentProjects(allChangedProjects);
needResolve.addAll(updated.keySet());
List<String> updatedPaths = updated.keySet().stream()
.map(MavenProject::getProject)
.map(IResource::getFullPath)
.map(IPath::toOSString)
.collect(toList());
List<String> removedPaths = removed.stream()
.map(MavenProject::getProject)
.map(IResource::getFullPath)
.map(IPath::toOSString)
.collect(toList());
addResolveProjects(needResolve);
communication.sendUpdateMassage(updated.keySet(), removed);
eventService.publish(new MavenUpdateEventImpl(updatedPaths, removedPaths, MavenOutputEvent.TYPE.UPDATE));
}
});
}

View File

@ -19,7 +19,9 @@ import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ValueProviderFactory;
import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.maven.server.MavenTerminal;
import org.eclipse.che.plugin.maven.generator.archetype.MavenArchetypeJsonRpcMessenger;
import org.eclipse.che.plugin.maven.server.PomModificationDetector;
import org.eclipse.che.plugin.maven.server.core.MavenJsonRpcCommunication;
import org.eclipse.che.plugin.maven.server.core.MavenProgressNotifier;
import org.eclipse.che.plugin.maven.server.core.MavenServerNotifier;
import org.eclipse.che.plugin.maven.server.core.MavenTerminalImpl;
@ -60,6 +62,8 @@ public class MavenModule extends AbstractModule {
bind(MavenProgressNotifier.class).to(MavenServerNotifier.class).in(Singleton.class);
bind(MavenServerService.class);
bind(MavenJsonRpcCommunication.class);
bind(MavenArchetypeJsonRpcMessenger.class);
bind(PomChangeListener.class).asEagerSingleton();
bind(PomModificationDetector.class).asEagerSingleton();

View File

@ -10,8 +10,8 @@
*******************************************************************************/
package org.eclipse.che.plugin.maven.server;
import com.google.gson.JsonObject;
import com.google.inject.Provider;
import org.eclipse.che.api.project.server.FolderEntry;
import org.eclipse.che.api.project.server.ProjectRegistry;
import org.eclipse.che.api.project.server.RegisteredProject;
@ -22,15 +22,12 @@ import org.eclipse.che.maven.data.MavenArtifact;
import org.eclipse.che.maven.data.MavenKey;
import org.eclipse.che.maven.server.MavenTerminal;
import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider;
import org.eclipse.che.plugin.maven.server.core.MavenCommunication;
import org.eclipse.che.plugin.maven.server.core.MavenExecutorService;
import org.eclipse.che.plugin.maven.server.core.MavenProjectManager;
import org.eclipse.che.plugin.maven.server.core.MavenWorkspace;
import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager;
import org.eclipse.che.plugin.maven.server.core.project.MavenProject;
import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
@ -51,7 +48,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -92,22 +88,7 @@ public class WorkspaceTest extends BaseTest {
mavenNotifier,
new MavenExecutorService(),
projectRegistryProvider,
new MavenCommunication() {
@Override
public void sendUpdateMassage(Set<MavenProject> updated, List<MavenProject> removed) {
}
@Override
public void sendNotification(NotificationMessage message) {
System.out.println(message.toString());
}
@Override
public void send(JsonObject object, MessageType type) {
}
}, new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal,
new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal,
mavenNotifier), eventService, new EclipseWorkspaceProvider());
}

View File

@ -10,24 +10,19 @@
*******************************************************************************/
package org.eclipse.che.plugin.maven.server.classpath;
import com.google.gson.JsonObject;
import com.google.inject.Provider;
import org.eclipse.che.api.project.server.ProjectRegistry;
import org.eclipse.che.commons.lang.IoUtil;
import org.eclipse.che.maven.server.MavenTerminal;
import org.eclipse.che.plugin.maven.server.BaseTest;
import org.eclipse.che.plugin.maven.server.MavenWrapperManager;
import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider;
import org.eclipse.che.plugin.maven.server.core.MavenCommunication;
import org.eclipse.che.plugin.maven.server.core.MavenExecutorService;
import org.eclipse.che.plugin.maven.server.core.MavenProjectManager;
import org.eclipse.che.plugin.maven.server.core.MavenWorkspace;
import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager;
import org.eclipse.che.plugin.maven.server.core.project.MavenProject;
import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage;
import org.eclipse.che.maven.server.MavenTerminal;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.IJavaProject;
@ -40,8 +35,6 @@ import org.testng.annotations.Test;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -81,22 +74,7 @@ public class ClasspathManagerTest extends BaseTest {
new MavenProjectManager(wrapperManager, mavenServerManager, terminal, mavenNotifier, new EclipseWorkspaceProvider());
classpathManager = new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, mavenNotifier);
mavenWorkspace = new MavenWorkspace(mavenProjectManager, mavenNotifier, new MavenExecutorService(), projectRegistryProvider,
new MavenCommunication() {
@Override
public void sendUpdateMassage(Set<MavenProject> updated, List<MavenProject> removed) {
}
@Override
public void sendNotification(NotificationMessage message) {
System.out.println(message.toString());
}
@Override
public void send(JsonObject object, MessageType type) {
}
}, classpathManager, eventService, new EclipseWorkspaceProvider());
classpathManager, eventService, new EclipseWorkspaceProvider());
}
@AfterMethod

View File

@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.che.plugin.maven.server.core.reconcile;
import com.google.gson.JsonObject;
import com.google.inject.Provider;
import org.eclipse.che.api.core.jsonrpc.commons.RequestTransmitter;
@ -24,15 +23,11 @@ import org.eclipse.che.maven.server.MavenTerminal;
import org.eclipse.che.plugin.maven.server.BaseTest;
import org.eclipse.che.plugin.maven.server.MavenWrapperManager;
import org.eclipse.che.plugin.maven.server.core.EclipseWorkspaceProvider;
import org.eclipse.che.plugin.maven.server.core.MavenCommunication;
import org.eclipse.che.plugin.maven.server.core.MavenExecutorService;
import org.eclipse.che.plugin.maven.server.core.MavenProjectManager;
import org.eclipse.che.plugin.maven.server.core.MavenWorkspace;
import org.eclipse.che.plugin.maven.server.core.classpath.ClasspathManager;
import org.eclipse.che.plugin.maven.server.core.project.MavenProject;
import org.eclipse.che.plugin.maven.server.rmi.MavenServerManagerTest;
import org.eclipse.che.plugin.maven.shared.MessageType;
import org.eclipse.che.plugin.maven.shared.dto.NotificationMessage;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.testng.annotations.BeforeMethod;
@ -42,7 +37,6 @@ import java.io.File;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static java.lang.String.format;
import static org.fest.assertions.Assertions.assertThat;
@ -89,23 +83,13 @@ public class PomReconcilerTest extends BaseTest {
ClasspathManager classpathManager =
new ClasspathManager(root.getAbsolutePath(), wrapperManager, mavenProjectManager, terminal, mavenNotifier);
mavenWorkspace = new MavenWorkspace(mavenProjectManager, mavenNotifier, new MavenExecutorService(), projectRegistryProvider,
new MavenCommunication() {
@Override
public void sendUpdateMassage(Set<MavenProject> updated, List<MavenProject> removed) {
}
@Override
public void sendNotification(NotificationMessage message) {
System.out.println(message.toString());
}
@Override
public void send(JsonObject object, MessageType type) {
}
}, classpathManager, eventService, new EclipseWorkspaceProvider());
mavenWorkspace = new MavenWorkspace(mavenProjectManager,
mavenNotifier,
new MavenExecutorService(),
projectRegistryProvider,
classpathManager,
eventService,
new EclipseWorkspaceProvider());
EditorWorkingCopyManager editorWorkingCopyManager =
new EditorWorkingCopyManager(projectManagerProvider, eventService, requestTransmitter);
pomReconciler =

View File

@ -36,7 +36,7 @@ public interface MavenAttributes {
String PARENT_VERSION = "maven.parent.version";
String TEST_SOURCE_FOLDER = "maven.test.source.folder";
String RESOURCE_FOLDER = "maven.resource.folder";
String RESOURCE_FOLDER = "maven.resource.folder";
String DEFAULT_SOURCE_FOLDER = "src/main/java";
String DEFAULT_RESOURCES_FOLDER = "src/main/resources";
@ -50,6 +50,17 @@ public interface MavenAttributes {
/** Name of WebSocket chanel */
String MAVEN_CHANEL_NAME = "maven:workspace";
/** Name of WebSocket chanel for Maven Archetype output */
String MAVEN_ARCHETYPE_CHANEL_NAME = "maven:archetype:output";
String MAVEN_CHANEL_UNSUBSCRIBE = "mavenOutput/subscribe";
String MAVEN_CHANEL_SUBSCRIBE = "mavenOutput/unsubscribe";
String MAVEN_OUTPUT_TEXT_METHOD = "mavenOutput/text";
String MAVEN_OUTPUT_UPDATE_METHOD = "mavenOutput/update";
String MAVEN_OUTPUT_START_STOP_METHOD = "mavenOutput/start_stop";
String MAVEN_OUTPUT_PERCENT_METHOD = "mavenOutput/percent";
String MAVEN_OUTPUT_PERCENT_UNDEFINED_METHOD = "mavenOutput/percentUndefined";
String MAVEN_ARCHETYPE_CHANEL_UNSUBSCRIBE = "mavenArchetype/unsubscribe";
String MAVEN_ARCHETYPE_CHANEL_SUBSCRIBE = "mavenArchetype/subscribe";
String MAVEN_ARCHETYPE_CHANEL_OUTPUT = "mavenArchetype/output";
}

View File

@ -41,4 +41,7 @@ public interface ArchetypeOutput {
*/
State getState();
void setOutput(String output);
void setState(State state);
}

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.shared.dto;
import org.eclipse.che.dto.shared.DTO;
import org.eclipse.che.plugin.maven.shared.event.MavenOutputEvent;
/**
* DTO object which describes base maven output event.
*/
@DTO
public interface MavenOutputEventDto extends MavenOutputEvent {
TYPE getType();
/** Returns a type of the output event. */
void setType(TYPE type);
MavenOutputEventDto withType(TYPE type);
}

View File

@ -18,6 +18,7 @@ import org.eclipse.che.dto.shared.DTO;
* @author Evgen Vidolob
*/
@DTO
@Deprecated
public interface NotificationMessage {
String getText();

Some files were not shown because too many files have changed in this diff Show More