Package org.eclipse.orion.server.git

Source Code of org.eclipse.orion.server.git.GitFileDecorator

/*******************************************************************************
* Copyright (c) 2011, 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;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.http.HttpServletRequest;

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.Path;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler.Method;
import org.eclipse.orion.internal.server.servlets.workspace.WorkspaceResourceHandler;
import org.eclipse.orion.server.core.IWebResourceDecorator;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.OrionConfiguration;
import org.eclipse.orion.server.core.PreferenceHelper;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerConstants;
import org.eclipse.orion.server.core.metastore.IMetaStore;
import org.eclipse.orion.server.core.metastore.ProjectInfo;
import org.eclipse.orion.server.git.objects.Blame;
import org.eclipse.orion.server.git.objects.Clone;
import org.eclipse.orion.server.git.objects.Commit;
import org.eclipse.orion.server.git.objects.ConfigOption;
import org.eclipse.orion.server.git.objects.Diff;
import org.eclipse.orion.server.git.objects.Ignore;
import org.eclipse.orion.server.git.objects.Index;
import org.eclipse.orion.server.git.objects.Remote;
import org.eclipse.orion.server.git.objects.RemoteBranch;
import org.eclipse.orion.server.git.objects.Status;
import org.eclipse.orion.server.git.objects.Tag;
import org.eclipse.orion.server.git.objects.Tree;
import org.eclipse.orion.server.git.servlets.GitServlet;
import org.eclipse.orion.server.git.servlets.GitUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
* Adds links to workspace and file resources referring to related git resources.
*/
public class GitFileDecorator implements IWebResourceDecorator {

  @Override
  public void addAtributesFor(HttpServletRequest request, URI resource, JSONObject representation) {
    String requestPath = request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo());
    IPath targetPath = new Path(requestPath);
    if (targetPath.segmentCount() <= 1)
      return;
    String servlet = request.getServletPath();
    if (!"/file".equals(servlet) && !"/workspace".equals(servlet)) //$NON-NLS-1$ //$NON-NLS-2$
      return;

    boolean isWorkspace = ("/workspace".equals(servlet)); //$NON-NLS-1$

    try {
      if (isWorkspace && Method.POST.equals(Method.fromString(request.getMethod()))) {
        String contentLocation = representation.getString(ProtocolConstants.KEY_CONTENT_LOCATION);

        // initialize a new git repository on project creation if specified by configuration
        initGitRepository(request, targetPath, representation);
        addGitLinks(request, new URI(contentLocation), representation);
        return;
      }

      if (isWorkspace && Method.GET.equals(Method.fromString(request.getMethod()))) {
        JSONArray children = representation.optJSONArray(ProtocolConstants.KEY_CHILDREN);
        if (children != null) {
          for (int i = 0; i < children.length(); i++) {
            JSONObject child = children.getJSONObject(i);
            String location = child.getString(ProtocolConstants.KEY_LOCATION);
            if (location == null || location.length() == 0) {
              String childName = child.optString(ProtocolConstants.KEY_NAME);
              LogHelper.log(new RuntimeException("Unexpected null location for child" + childName + " of resource " + resource));
            }
            addGitLinks(request, new URI(location), child);
          }
        }
        return;
      }

      if (!isWorkspace && Method.GET.equals(Method.fromString(request.getMethod()))) {
        // compute all git properties in advance because it will be same for all children
        Repository db = null;
        try {
          db = repositoryForPath(request, new Path(resource.getPath()));
          URI cloneLocation = BaseToCloneConverter.getCloneLocation(resource, BaseToCloneConverter.FILE);
          String branch = db == null ? null : db.getBranch();
          Remote defaultRemote = db == null ? null : new Remote(cloneLocation, db, Constants.DEFAULT_REMOTE_NAME);
          RemoteBranch defaultRemoteBranch = db == null ? null : new RemoteBranch(cloneLocation, db, defaultRemote, branch);
          addGitLinks(request, resource, representation, cloneLocation, db, defaultRemoteBranch, branch);

          JSONArray children = representation.optJSONArray(ProtocolConstants.KEY_CHILDREN);
          if (children != null) {
            for (int i = 0; i < children.length(); i++) {
              JSONObject child = children.getJSONObject(i);
              String location = child.getString(ProtocolConstants.KEY_LOCATION);
              if (db != null) {
                // if parent was a git repository we can reuse information computed above
                addGitLinks(request, new URI(location), child, cloneLocation, db, defaultRemoteBranch, branch);
              } else {
                // maybe the child is the root of a git repository
                addGitLinks(request, new URI(location), child);
              }
            }
          }
        } finally {
          if (db != null) {
            db.close();
          }
        }
      }
    } catch (Exception e) {
      // log and continue
      LogHelper.log(e);
    }
  }

  private void addGitLinks(HttpServletRequest request, URI location, JSONObject representation) throws URISyntaxException, JSONException, CoreException,
      IOException {
    Repository db = null;
    try {
      db = repositoryForPath(request, new Path(location.getPath()));
      if (db != null) {
        URI cloneLocation = BaseToCloneConverter.getCloneLocation(location, BaseToCloneConverter.FILE);
        String branch = db.getBranch();
        Remote defaultRemote = new Remote(cloneLocation, db, Constants.DEFAULT_REMOTE_NAME);
        RemoteBranch defaultRemoteBranch = new RemoteBranch(cloneLocation, db, defaultRemote, branch);
        addGitLinks(request, location, representation, cloneLocation, db, defaultRemoteBranch, branch);
      }
    } finally {
      if (db != null) {
        db.close();
      }
    }
  }

  private void addGitLinks(HttpServletRequest request, URI location, JSONObject representation, URI cloneLocation, Repository db,
      RemoteBranch defaultRemoteBranch, String branchName) throws URISyntaxException, JSONException {
    if (db == null)
      return;
    IPath targetPath = new Path(location.getPath());

    JSONObject gitSection = new JSONObject();

    // add Git Diff URI
    IPath path = new Path(GitServlet.GIT_URI + '/' + Diff.RESOURCE + '/' + GitConstants.KEY_DIFF_DEFAULT).append(targetPath);
    URI link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_DIFF, link);

    // add Git Status URI
    path = new Path(GitServlet.GIT_URI + '/' + Status.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_STATUS, link);

    // add Git Index URI
    path = new Path(GitServlet.GIT_URI + '/' + Index.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_INDEX, link);

    // add Git Ignore URI
    path = new Path(GitServlet.GIT_URI + '/' + Ignore.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_IGNORE, link);

    // add Git HEAD URI
    path = new Path(GitServlet.GIT_URI + '/' + Commit.RESOURCE).append(Constants.HEAD).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_HEAD, link);

    // add Git Commit URI
    path = new Path(GitServlet.GIT_URI + '/' + Commit.RESOURCE).append(GitUtils.encode(branchName)).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_COMMIT, link);

    // add Git Remote URI
    path = new Path(GitServlet.GIT_URI + '/' + Remote.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_REMOTE, link);

    // add Git Clone Config URI
    path = new Path(GitServlet.GIT_URI + '/' + ConfigOption.RESOURCE + '/' + Clone.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_CONFIG, link);

    // add Git Default Remote Branch URI
    gitSection.put(GitConstants.KEY_DEFAULT_REMOTE_BRANCH, defaultRemoteBranch.getLocation());

    // add Git Tag URI
    path = new Path(GitServlet.GIT_URI + '/' + Tag.RESOURCE).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_TAG, link);

    // add Git Blame URI
    path = new Path(GitServlet.GIT_URI + '/' + Blame.RESOURCE).append(Constants.HEAD).append(targetPath);
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_BLAME, link);

    // add Git Clone URI
    gitSection.put(GitConstants.KEY_CLONE, cloneLocation);

    // add Git Tree URI
    IPath clonePath = new Path(cloneLocation.getPath()).removeFirstSegments(2);
    path = new Path(GitServlet.GIT_URI + '/' + Tree.RESOURCE).append(clonePath).append(Constants.HEAD)
        .append(targetPath.toPortableString().substring(clonePath.toPortableString().length()));
    link = new URI(location.getScheme(), location.getAuthority(), path.toString(), null, null);
    gitSection.put(GitConstants.KEY_TREE, link);

    representation.put(GitConstants.KEY_GIT, gitSection);
  }

  private Repository repositoryForPath(HttpServletRequest request, IPath targetPath) throws CoreException, IOException {
    IPath requestPath = targetPath;

    if (request.getContextPath().length() != 0) {
      IPath contextPath = new Path(request.getContextPath());
      if (contextPath.isPrefixOf(targetPath)) {
        requestPath = targetPath.removeFirstSegments(contextPath.segmentCount());
      }
    }

    File gitDir = GitUtils.getGitDir(requestPath);
    if (gitDir == null)
      return null;

    Repository db = FileRepositoryBuilder.create(gitDir);
    return db;
  }

  /**
   * If this server is configured to use git by default, then each project creation that is not already in a repository needs to have a git -init performed to
   * initialize the repository.
   */
  private void initGitRepository(HttpServletRequest request, IPath targetPath, JSONObject representation) {
    // project creation URL is of the form POST /workspace/<id>
    if (!(targetPath.segmentCount() == 2 && "workspace".equals(targetPath.segment(0)) && Method.POST.equals(Method.fromString(request.getMethod())))) //$NON-NLS-1$
      return;
    String scm = PreferenceHelper.getString(ServerConstants.CONFIG_FILE_DEFAULT_SCM, "").toLowerCase(); //$NON-NLS-1$
    if (!"git".equals(scm)) //$NON-NLS-1$
      return;
    try {
      ProjectInfo project = getProjectForLocation(representation.getString(ProtocolConstants.KEY_LOCATION));
      if (project == null)
        return;
      IFileStore store = project.getProjectStore();
      // create repository in each project if it doesn't already exist
      File localFile = store.toLocalFile(EFS.NONE, null);
      File gitDir = GitUtils.getGitDir(localFile);
      if (gitDir == null) {
        gitDir = new File(localFile, Constants.DOT_GIT);
        Repository repo = null;
        try {
          repo = FileRepositoryBuilder.create(gitDir);
          repo.create();
          // we need to perform an initial commit to workaround JGit bug 339610.
          Git git = new Git(repo);
          git.add().addFilepattern(".").call(); //$NON-NLS-1$
          git.commit().setMessage("Initial commit").call();
        } finally {
          if (repo != null) {
            repo.close();
          }
        }
      }
    } catch (Exception e) {
      // just log it - this is not the purpose of the file decorator
      LogHelper.log(e);
    }
  }

  /**
   * Returns the project for the given metadata location, or <code>null</code>.
   *
   * @throws CoreException
   */
  private ProjectInfo getProjectForLocation(String location) throws CoreException {
    // location is URI of the form protocol:/workspace/workspaceId/project/projectName
    IMetaStore store = OrionConfiguration.getMetaStore();
    return WorkspaceResourceHandler.projectForMetadataLocation(store, location);
  }
}
TOP

Related Classes of org.eclipse.orion.server.git.GitFileDecorator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.