/*******************************************************************************
* Copyright (c) 2014 IBM Corporation and others
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.server.git.servlets;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler;
import org.eclipse.orion.internal.server.servlets.file.NewFileServlet;
import org.eclipse.orion.internal.server.servlets.workspace.authorization.AuthorizationService;
import org.eclipse.orion.server.core.EncodingUtils;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.git.servlets.GitUtils.Traverse;
import org.eclipse.orion.server.servlets.OrionServlet;
import org.eclipse.osgi.util.NLS;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class GitIgnoreHandlerV1 extends ServletResourceHandler<String> {
private final static String DOT_GIT_IGNORE = ".gitignore";
private ServletResourceHandler<IStatus> statusHandler;
GitIgnoreHandlerV1(ServletResourceHandler<IStatus> statusHandler) {
this.statusHandler = statusHandler;
}
@Override
public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, String pathInfo) throws ServletException {
try {
IPath path = pathInfo == null ? Path.ROOT : new Path(pathInfo);
IPath filePath = path.hasTrailingSeparator() ? path : path.removeLastSegments(1);
if (!AuthorizationService.checkRights(request.getRemoteUser(), "/" + filePath.toString(), request.getMethod())) {
String msg = NLS.bind("Forbidden: {0}", EncodingUtils.encodeForHTML(filePath.toString()));
ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_FORBIDDEN, msg, null);
return statusHandler.handleRequest(request, response, status);
}
/* TODO: Do not duplicate .gitignore entries. Traverse the working directory tree before adding .gitignore rules */
Set<Entry<IPath, File>> set = GitUtils.getGitDirs(filePath, Traverse.GO_UP).entrySet();
File gitDir = set.iterator().next().getValue();
if (gitDir == null)
return false; // TODO: or an error response code, 405?
switch (getMethod(request)) {
case PUT:
return handlePut(request, response, filePath);
default:
// fall through and return false below
}
return false;
} catch (Exception e) {
String msg = NLS.bind("Failed to process an ignore operation for {0}", EncodingUtils.encodeForHTML(pathInfo)); //$NON-NLS-1$
ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, e);
LogHelper.log(status);
return statusHandler.handleRequest(request, response, status);
}
}
private boolean handlePut(HttpServletRequest request, HttpServletResponse response, IPath filePath) throws JSONException, IOException, ServletException,
CoreException {
JSONObject toIgnore = OrionServlet.readJSONRequest(request);
JSONArray paths = toIgnore.optJSONArray(ProtocolConstants.KEY_PATH);
if (paths.length() < 1)
return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST,
"No paths to insert into .gitignore", null));
/* remove /file */
IFileStore projectStore = NewFileServlet.getFileStore(null, filePath.removeFirstSegments(1));
for (int i = 0; i < paths.length(); ++i) {
IPath path = new Path(paths.getString(i));
IFileStore pathStore = projectStore.getFileStore(path);
IFileStore gitignoreStore = pathStore.getParent().getFileStore(new Path(DOT_GIT_IGNORE));
if (!pathStore.fetchInfo().exists() || !projectStore.isParentOf(gitignoreStore)) {
String msg = NLS.bind("Invalid path: {0}", EncodingUtils.encodeForHTML(path.toString()));
ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null);
return statusHandler.handleRequest(request, response, status);
}
/* update the .gitignore file */
appendGitignore(gitignoreStore, pathStore.getName());
}
return true;
}
/**
* Appends a single rule in the given .gitignore file store. If necessary, the .gitignore file is created.
*
* @param gitignoreStore
* The .gitignore file store.
* @param rule
* The entry to be appended to the .gitignore.
* @throws CoreException
* @throws IOException
*/
private void appendGitignore(IFileStore gitignoreStore, String rule) throws CoreException, IOException {
OutputStream out = null;
try {
out = gitignoreStore.openOutputStream(EFS.APPEND, null);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write(System.getProperty("line.separator") + "/" + rule);
bw.flush();
} finally {
if (out != null)
out.close();
}
}
}