/*******************************************************************************
* 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.local.node.provider;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.util.SystemInfo;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.plugin.docker.machine.WindowsHostUtils;
import org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.lang.String.format;
/**
* Provides path to workspace folder in CHE.
*
* @author Alexander Garagatyi
*/
@Singleton
public class LocalWorkspaceFolderPathProvider implements WorkspaceFolderPathProvider {
public static final String ALLOW_FOLDERS_CREATION_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE_CREATE_FOLDERS";
public static final String WORKSPACE_STORAGE_PATH_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE";
private final Provider<WorkspaceManager> workspaceManager;
private final boolean isWindows;
/**
* Value provide path to directory on host machine where will by all created and mount to the
* created workspaces folder that become root of workspace inside machine.
* Inside machine it will point to the directory described by {@literal che.workspace.projects.storage}.
* <p>
* For example:
* if you set {@literal che.workspaces.storage} to the /home/user/che/workspaces after creating new workspace will be created new folder
* /home/user/che/workspaces/{workspaceName} and it will be mount to the dev-machine to {@literal che.workspace.projects.storage}
*/
private String workspacesMountPoint;
/**
* this value provide path to projects on local host
* if this value will be set all workspace will manage
* same projects from your host
*/
@Inject(optional = true)
@Named("host.projects.root")
private String hostProjectsFolder;
/**
* If environment variable with name {@link #ALLOW_FOLDERS_CREATION_ENV_VARIABLE} is equal (ignoring case) to
* {@literal false} then this field is set to false. Otherwise it is set to true.
* It is also possible to overwrite with named constant.
*/
@Inject(optional = true)
@Named("che.workspace.storage.create_folders")
private boolean createFolders = true;
@Inject(optional = true)
@Named("che.user.workspaces.storage")
private String oldWorkspacesMountPoint;
@Inject
public LocalWorkspaceFolderPathProvider(@Named("che.workspace.storage") String workspacesMountPoint,
Provider<WorkspaceManager> workspaceManager) throws IOException {
this.workspacesMountPoint = workspacesMountPoint;
this.workspaceManager = workspaceManager;
this.isWindows = SystemInfo.isWindows();
}
@VisibleForTesting
protected LocalWorkspaceFolderPathProvider(String workspacesMountPoint,
String oldWorkspacesMountPoint,
String projectsFolder,
Provider<WorkspaceManager> workspaceManager,
boolean createFolders,
boolean isWindows) throws IOException {
this.workspaceManager = workspaceManager;
this.workspacesMountPoint = workspacesMountPoint;
this.hostProjectsFolder = projectsFolder;
this.createFolders = createFolders;
this.oldWorkspacesMountPoint = oldWorkspacesMountPoint;
this.isWindows = isWindows;
}
@Override
public String getPath(@Assisted("workspace") String workspaceId) throws IOException {
if (!isWindows && hostProjectsFolder != null) {
return hostProjectsFolder;
}
try {
WorkspaceManager workspaceManager = this.workspaceManager.get();
Workspace workspace = workspaceManager.getWorkspace(workspaceId);
String wsName = workspace.getConfig().getName();
return doGetPathByName(wsName);
} catch (NotFoundException | ServerException e) {
throw new IOException(e.getLocalizedMessage());
}
}
public String getPathByName(String workspaceName) throws IOException {
if (!isWindows && hostProjectsFolder != null) {
return hostProjectsFolder;
}
return doGetPathByName(workspaceName);
}
private String doGetPathByName(String workspaceName) throws IOException {
final String workspaceFolderPath = Paths.get(workspacesMountPoint).resolve(workspaceName).toString();
ensureExist(workspaceFolderPath, null);
return workspaceFolderPath;
}
@VisibleForTesting
@PostConstruct
void init() throws IOException {
// check folders creation flag from environment variable
String allowFoldersCreationEnvVar = System.getenv(ALLOW_FOLDERS_CREATION_ENV_VARIABLE);
if ("false".equalsIgnoreCase(allowFoldersCreationEnvVar)) {
createFolders = false;
}
// Priority of workspace storage path sources:
// If Che is running on Windows
// che-home-location/vfs
// Otherwise
// If environment variable for storage location is set
// use value of that variable
// Otherwise
// If old property of workspace storage is set
// use value of that property for backward compatibility
// Otherwise
// use up-to-date property
// find root directory for projects in workspaces
if (isWindows) {
final Path vfs = WindowsHostUtils.getCheHome().resolve("vfs");
workspacesMountPoint = vfs.toString();
} else {
String workspaceStorageFromEnv = System.getenv(WORKSPACE_STORAGE_PATH_ENV_VARIABLE);
if (workspaceStorageFromEnv != null) {
workspacesMountPoint = workspaceStorageFromEnv;
} else if (oldWorkspacesMountPoint != null) {
workspacesMountPoint = oldWorkspacesMountPoint;
}
}
// create directories if needed
if (hostProjectsFolder == null) {
ensureExist(workspacesMountPoint,
oldWorkspacesMountPoint == null ? "che.workspace.storage" : "che.user.workspaces.storage");
} else {
ensureExist(hostProjectsFolder, "host.projects.root");
}
}
private void ensureExist(String path,
String prop) throws IOException {
if (createFolders) {
Path folder = Paths.get(path);
if (Files.exists(folder)) {
if (!Files.isDirectory(folder)) {
if (prop != null) {
throw new IOException(
format("Workspace folder '%s' is not directory. Check %s configuration property", path, prop));
} else {
throw new IOException(format("Workspace folder '%s' is not directory", path));
}
}
} else {
try {
// TODO we should not create folders in this provider
Files.createDirectories(folder);
} catch (AccessDeniedException e) {
throw new IOException(
format("Workspace folder '%s' creation failed. Please check permissions of this folder. Cause: %s",
path,
e.getLocalizedMessage()),
e);
} catch (IOException e) {
throw new IOException(format("Workspace folder '%s' creation failed. Cause: %s",
path,
e.getLocalizedMessage()),
e);
}
}
}
}
}