org.eclipse.orion.server.git.servlets.GitSubmoduleHandlerV1.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.orion.server.git.servlets.GitSubmoduleHandlerV1.java

Source

/*******************************************************************************
 * Copyright (c) 2014, 2015 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 static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION;
import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.SubmoduleAddCommand;
import org.eclipse.jgit.api.SubmoduleInitCommand;
import org.eclipse.jgit.api.SubmoduleStatusCommand;
import org.eclipse.jgit.api.SubmoduleSyncCommand;
import org.eclipse.jgit.api.SubmoduleUpdateCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.submodule.SubmoduleStatus;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler;
import org.eclipse.orion.server.core.OrionConfiguration;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.core.metastore.IMetaStore;
import org.eclipse.orion.server.core.metastore.ProjectInfo;
import org.eclipse.orion.server.core.metastore.WorkspaceInfo;
import org.eclipse.orion.server.git.GitConstants;
import org.eclipse.orion.server.git.servlets.GitUtils.Traverse;
import org.eclipse.osgi.util.NLS;
import org.json.JSONObject;

public class GitSubmoduleHandlerV1 extends AbstractGitHandler {

    GitSubmoduleHandlerV1(ServletResourceHandler<IStatus> statusHandler) {
        super(statusHandler);
    }

    @Override
    protected boolean handlePost(RequestInfo requestInfo) throws ServletException {

        JSONObject toAdd = requestInfo.getJSONRequest();
        HttpServletRequest request = requestInfo.request;
        HttpServletResponse response = requestInfo.response;
        Repository db = requestInfo.db;

        try {
            String targetPath = null;
            String gitUrl = toAdd.optString(GitConstants.KEY_URL, null);
            String name = toAdd.optString(ProtocolConstants.KEY_NAME, null);
            if (gitUrl != null) {
                String workspacePath = ServletResourceHandler.toOrionLocation(request,
                        toAdd.optString(ProtocolConstants.KEY_LOCATION, null));
                // expected path /file/{workspaceId}/{projectName}[/{path}]
                String filePathString = ServletResourceHandler.toOrionLocation(request,
                        toAdd.optString(ProtocolConstants.KEY_PATH, null));
                IPath filePath = filePathString == null ? null : new Path(filePathString);
                if (filePath != null && filePath.segmentCount() < 3)
                    filePath = null;
                if (filePath == null && workspacePath == null) {
                    String msg = NLS.bind("Either {0} or {1} should be provided: {2}",
                            new Object[] { ProtocolConstants.KEY_PATH, ProtocolConstants.KEY_LOCATION, toAdd });
                    return statusHandler.handleRequest(request, response,
                            new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null));
                }
                ProjectInfo project = null;
                if (filePath != null) {
                    // path format is /file/{workspaceId}/{projectName}/[filePath]
                    project = GitUtils.projectFromPath(filePath);
                    // workspace path format needs to be used if project does not exist
                    if (project == null) {
                        String msg = NLS.bind("Specified project does not exist: {0}", filePath.segment(2));
                        return statusHandler.handleRequest(request, response,
                                new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null));
                    }
                    if (name == null)
                        name = project.getContentLocation().relativize(
                                project.getProjectStore().getFileStore(filePath.removeFirstSegments(3)).toURI())
                                .toString();
                } else if (workspacePath != null) {

                    // TODO: move this to CloneJob
                    // if so, modify init part to create a new project if necessary
                    if (name == null) {
                        IPath path = new Path(workspacePath);
                        final IMetaStore metaStore = OrionConfiguration.getMetaStore();
                        WorkspaceInfo workspace = metaStore.readWorkspace(path.segment(1));
                        name = new URIish(gitUrl).getHumanishName();
                        name = GitUtils.getUniqueProjectName(workspace, name);
                    }

                } else {
                    return false;
                }
                targetPath = targetPath == null ? name : targetPath;
                addSubmodules(db, gitUrl, targetPath);
            } else {
                return false;
            }

            return true;
        } catch (Exception ex) {
            String msg = "An error occured for add submodule command.";
            return statusHandler.handleRequest(request, response,
                    new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, ex));
        }
    }

    @Override
    protected boolean handlePut(RequestInfo requestInfo) throws ServletException {

        JSONObject requestPayload = requestInfo.getJSONRequest();
        HttpServletRequest request = requestInfo.request;
        HttpServletResponse response = requestInfo.response;
        Repository db = requestInfo.db;

        try {
            String operation = requestPayload.optString("Operation", null);
            if (operation == null) {
                return false;
            } else if (operation.equals("update")) {
                return updateSubmodules(db);
            } else if (operation.equals("sync")) {
                return syncSubmodules(db);
            }
            return false;

        } catch (Exception ex) {
            String msg = "An error occured for update submodule command.";
            return statusHandler.handleRequest(request, response,
                    new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, ex));
        }
    }

    @Override
    protected boolean handleDelete(RequestInfo requestInfo) throws ServletException {
        HttpServletRequest request = requestInfo.request;
        HttpServletResponse response = requestInfo.response;
        Repository db = requestInfo.db;
        Repository parentRepo = null;
        try {
            Map<IPath, File> parents = GitUtils.getGitDirs(requestInfo.filePath.removeLastSegments(1),
                    Traverse.GO_UP);
            if (parents.size() < 1)
                return false;
            parentRepo = FileRepositoryBuilder.create(parents.entrySet().iterator().next().getValue());
            String pathToSubmodule = db.getWorkTree().toString()
                    .substring(parentRepo.getWorkTree().toString().length() + 1);
            removeSubmodule(db, parentRepo, pathToSubmodule);
            return true;
        } catch (Exception ex) {
            String msg = "An error occured for delete submodule command.";
            return statusHandler.handleRequest(request, response,
                    new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, ex));
        } finally {
            if (parentRepo != null) {
                parentRepo.close();
            }
        }

    }

    public static boolean updateSubmodules(Repository repo) throws GitAPIException {
        SubmoduleInitCommand init = new SubmoduleInitCommand(repo);
        init.call();
        SubmoduleUpdateCommand update = new SubmoduleUpdateCommand(repo);
        Collection<String> updated = update.call();
        SubmoduleStatusCommand status = new SubmoduleStatusCommand(repo);
        Map<String, SubmoduleStatus> statusResult = status.call();
        return updated.size() == statusResult.size();
    }

    public static boolean syncSubmodules(Repository repo) throws GitAPIException {
        SubmoduleSyncCommand sync = new SubmoduleSyncCommand(repo);
        Map<String, String> synced = sync.call();
        SubmoduleStatusCommand status = new SubmoduleStatusCommand(repo);
        Map<String, SubmoduleStatus> statusResult = status.call();
        return synced.size() == statusResult.size();
    }

    public static void addSubmodules(Repository repo, String targetUrl, String targetPath) throws GitAPIException {
        SubmoduleAddCommand addCommand = new SubmoduleAddCommand(repo);
        addCommand.setURI(targetUrl);
        addCommand.setPath(targetPath);
        Repository repository = addCommand.call();
        repository.close();
    }

    public static void removeSubmodule(Repository db, Repository parentRepo, String pathToSubmodule)
            throws Exception {
        pathToSubmodule = pathToSubmodule.replace("\\", "/");
        StoredConfig gitSubmodulesConfig = getGitSubmodulesConfig(parentRepo);
        gitSubmodulesConfig.unsetSection(CONFIG_SUBMODULE_SECTION, pathToSubmodule);
        gitSubmodulesConfig.save();
        StoredConfig repositoryConfig = parentRepo.getConfig();
        repositoryConfig.unsetSection(CONFIG_SUBMODULE_SECTION, pathToSubmodule);
        repositoryConfig.save();
        Git git = Git.wrap(parentRepo);
        git.add().addFilepattern(DOT_GIT_MODULES).call();
        RmCommand rm = git.rm().addFilepattern(pathToSubmodule);
        if (gitSubmodulesConfig.getSections().size() == 0) {
            rm.addFilepattern(DOT_GIT_MODULES);
        }
        rm.call();
        FileUtils.delete(db.getWorkTree(), FileUtils.RECURSIVE);
        FileUtils.delete(db.getDirectory(), FileUtils.RECURSIVE);
    }

    private static StoredConfig getGitSubmodulesConfig(Repository repository)
            throws IOException, ConfigInvalidException {
        File gitSubmodulesFile = new File(repository.getWorkTree(), DOT_GIT_MODULES);
        FileBasedConfig gitSubmodulesConfig = new FileBasedConfig(null, gitSubmodulesFile, FS.DETECTED);
        gitSubmodulesConfig.load();
        return gitSubmodulesConfig;
    }
}