playRepository.SVNRepository.java Source code

Java tutorial

Introduction

Here is the source code for playRepository.SVNRepository.java

Source

/**
 * Yobi, Project Hosting SW
 *
 * Copyright 2012 NAVER Corp.
 * http://yobi.io
 *
 * @Author Ahn Hyeok Jun
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package playRepository;

import controllers.UserApp;
import controllers.routes;
import models.Project;
import models.User;
import models.enumeration.ResourceType;
import models.resource.Resource;
import org.apache.commons.io.FileUtils;
import org.apache.tika.Tika;
import org.codehaus.jackson.node.ObjectNode;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.RawText;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.tigris.subversion.javahl.ClientException;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import play.libs.Json;
import utils.FileUtil;
import utils.GravatarUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class SVNRepository implements PlayRepository {

    private static String repoPrefix = "repo/svn/";

    public static String getRepoPrefix() {
        return repoPrefix;
    }

    public static void setRepoPrefix(String repoPrefix) {
        SVNRepository.repoPrefix = repoPrefix;
    }

    private final String projectName;

    private final String ownerName;

    public SVNRepository(final String userName, String projectName) {
        this.ownerName = userName;
        this.projectName = projectName;
    }

    @Override
    public byte[] getRawFile(String revision, String path) throws SVNException {
        Long revId = (revision.equals("HEAD") ? -1l : Long.parseLong(revision));
        org.tmatesoft.svn.core.io.SVNRepository repository = getSVNRepository();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        repository.getFile(path, revId, null, baos); // revId=-1l
        return baos.toByteArray();
    }

    @Override
    public ObjectNode getMetaDataFromPath(String path) throws SVNException, IOException {
        org.tmatesoft.svn.core.io.SVNRepository repository = getSVNRepository();

        SVNNodeKind nodeKind = repository.checkPath(path, -1);

        if (nodeKind == SVNNodeKind.DIR) {
            ObjectNode result = Json.newObject();
            ObjectNode listData = Json.newObject();
            SVNProperties prop = new SVNProperties();
            Collection<SVNDirEntry> entries = repository.getDir(path, -1, prop, SVNDirEntry.DIRENT_ALL,
                    (Collection) null);

            result.put("type", "folder");

            for (SVNDirEntry entry : entries) {
                ObjectNode data = Json.newObject();
                String author = entry.getAuthor();
                User user = User.findByLoginId(author);
                Long commitTime = entry.getDate().getTime();

                data.put("type", entry.getKind() == SVNNodeKind.DIR ? "folder" : "file");
                data.put("msg", entry.getCommitMessage());
                data.put("author", author);
                data.put("avatar", getAvatar(user));
                data.put("userName", user.name);
                data.put("userLoginId", user.loginId);
                data.put("createdDate", commitTime);
                data.put("commitMessage", entry.getCommitMessage());
                data.put("commiter", author);
                data.put("commitDate", commitTime);
                data.put("commitId", entry.getRevision());
                data.put("size", entry.getSize());

                listData.put(entry.getName(), data);
            }
            result.put("data", listData);

            return result;

        } else if (nodeKind == SVNNodeKind.FILE) {
            return fileAsJson(path, repository);
        } else {
            return null;
        }
    }

    private static String getAvatar(User user) {
        if (user.isAnonymous() || user.avatarUrl().equals(UserApp.DEFAULT_AVATAR_URL)) {
            String defaultImageUrl = "http://ko.gravatar.com/userimage/53495145/0eaeeb47c620542ad089f17377298af6.png";
            return GravatarUtil.getAvatar(user.email, 34, defaultImageUrl);
        } else {
            return user.avatarUrl();
        }
    }

    @Override
    public ObjectNode getMetaDataFromPath(String branch, String path) throws IOException, SVNException {
        List<String> branches = getBranchNames();
        if (!branches.contains(branch)) {
            return null;
        }

        org.tmatesoft.svn.core.io.SVNRepository repository = getSVNRepository();

        SVNNodeKind nodeKind = repository.checkPath(path, -1);

        if (nodeKind == SVNNodeKind.DIR) {
            ObjectNode result = Json.newObject();
            ObjectNode listData = Json.newObject();
            SVNProperties prop = new SVNProperties();
            Collection<SVNDirEntry> entries = repository.getDir(path, -1, prop, SVNDirEntry.DIRENT_ALL,
                    (Collection) null);

            result.put("type", "folder");

            for (SVNDirEntry entry : entries) {
                ObjectNode data = Json.newObject();
                String author = entry.getAuthor();
                User user = User.findByLoginId(author);
                Long commitTime = entry.getDate().getTime();

                data.put("type", entry.getKind() == SVNNodeKind.DIR ? "folder" : "file");
                data.put("msg", entry.getCommitMessage());
                data.put("author", author);
                data.put("avatar", getAvatar(user));
                data.put("userName", user.name);
                data.put("userLoginId", user.loginId);
                data.put("createdDate", commitTime);
                data.put("commitMessage", entry.getCommitMessage());
                data.put("commiter", author);
                data.put("commitDate", commitTime);
                data.put("commitId", entry.getRevision());
                data.put("commitUrl", routes.CodeHistoryApp
                        .show(ownerName, projectName, String.valueOf(entry.getRevision())).url());
                data.put("size", entry.getSize());

                listData.put(entry.getName(), data);
            }
            result.put("data", listData);

            return result;
        } else if (nodeKind == SVNNodeKind.FILE) {
            return fileAsJson(path, repository);
        } else {
            return null;
        }
    }

    private ObjectNode fileAsJson(String path, org.tmatesoft.svn.core.io.SVNRepository repository)
            throws SVNException, IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        SVNProperties prop = new SVNProperties();
        repository.getFile(path, -1l, prop, baos);
        SVNDirEntry entry = repository.info(path, -1l);
        long size = entry.getSize();
        boolean isBinary;
        String mimeType;
        String data = null;

        if (size > MAX_FILE_SIZE_CAN_BE_VIEWED) {
            isBinary = true;
            mimeType = "application/octet-stream";
        } else {
            byte[] bytes = baos.toByteArray();
            isBinary = RawText.isBinary(bytes);
            if (!isBinary) {
                data = new String(bytes, FileUtil.detectCharset(bytes));
            }
            mimeType = new Tika().detect(bytes, path);
        }

        String author = prop.getStringValue(SVNProperty.LAST_AUTHOR);
        User user = User.findByLoginId(author);

        String commitDate = prop.getStringValue(SVNProperty.COMMITTED_DATE);
        DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTime();
        Long commitTime = dateFormatter.parseMillis(commitDate);

        ObjectNode result = Json.newObject();
        result.put("type", "file");
        result.put("revisionNo", prop.getStringValue(SVNProperty.COMMITTED_REVISION));
        result.put("author", author);
        result.put("avatar", getAvatar(user));
        result.put("userName", user.name);
        result.put("userLoginId", user.loginId);
        result.put("createdDate", commitTime);
        result.put("commitMessage", entry.getCommitMessage());
        result.put("commiter", author);
        result.put("size", size);
        result.put("isBinary", isBinary);
        result.put("mimeType", mimeType);
        result.put("data", data);

        return result;
    }

    @Override
    public void create() throws ClientException {
        String svnPath = new File(SVNRepository.getRepoPrefix() + ownerName + "/" + projectName).getAbsolutePath();
        new org.tigris.subversion.javahl.SVNAdmin().create(svnPath, false, false, null, "fsfs");
    }

    @Override
    public void delete() {
        FileUtil.rm_rf(new File(getRepoPrefix() + ownerName + "/" + projectName));
    }

    @Override
    public String getPatch(String commitId) throws SVNException {
        long rev = Integer.parseInt(commitId);
        return getPatch(rev - 1, rev);
    }

    @Override
    public String getPatch(String revA, String revB) throws SVNException {
        return getPatch(Long.parseLong(revA), Long.parseLong(revB));
    }

    private String getPatch(long revA, long revB) throws SVNException {
        // Prepare required arguments.
        SVNURL svnURL = SVNURL.fromFile(new File(getRepoPrefix() + ownerName + "/" + projectName));

        // Get diffClient.
        SVNClientManager clientManager = SVNClientManager.newInstance();
        SVNDiffClient diffClient = clientManager.getDiffClient();

        // Using diffClient, write the changes by commitId into
        // byteArrayOutputStream, as unified format.
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        diffClient.doDiff(svnURL, null, SVNRevision.create(revA), SVNRevision.create(revB), SVNDepth.INFINITY, true,
                byteArrayOutputStream);

        return byteArrayOutputStream.toString();
    }

    @Override
    public List<FileDiff> getDiff(String commitId) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<FileDiff> getDiff(String revA, String revB) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Commit> getHistory(int page, int limit, String until, String path)
            throws IOException, GitAPIException, SVNException {
        // Get the repository
        SVNURL svnURL = SVNURL.fromFile(new File(repoPrefix + ownerName + "/" + projectName));
        org.tmatesoft.svn.core.io.SVNRepository repository = SVNRepositoryFactory.create(svnURL);

        // path to get log
        String[] paths = { "/" };
        if (path != null) {
            paths[0] = "/" + path;
        }

        // Determine revisions
        long startRevision = repository.getLatestRevision() - page * limit;
        long endRevision = startRevision - limit;
        if (endRevision < 1) {
            endRevision = 1;
        }

        // No log to return.
        if (startRevision < endRevision) {
            return new ArrayList<>();
        }

        // Get the logs
        List<Commit> result = new ArrayList<>();
        for (Object entry : repository.log(paths, null, startRevision, endRevision, false, false)) {
            result.add(new SvnCommit((SVNLogEntry) entry));
        }

        return result;
    }

    @Override
    public Commit getCommit(String revNumber) throws IOException, SVNException {
        long rev = Integer.parseInt(revNumber);
        String[] paths = { "/" };
        SVNURL svnURL = SVNURL.fromFile(new File(getRepoPrefix() + ownerName + "/" + projectName));
        org.tmatesoft.svn.core.io.SVNRepository repository = SVNRepositoryFactory.create(svnURL);

        for (Object entry : repository.log(paths, null, rev, rev, false, false)) {
            return new SvnCommit((SVNLogEntry) entry);
        }

        return null;
    }

    @Override
    public List<String> getBranchNames() {
        ArrayList<String> branches = new ArrayList<>();
        branches.add(SVNRevision.HEAD.getName());
        return branches;
    }

    @Override
    public Resource asResource() {
        return new Resource() {
            @Override
            public String getId() {
                return null;
            }

            @Override
            public Project getProject() {
                return Project.findByOwnerAndProjectName(ownerName, projectName);
            }

            @Override
            public ResourceType getType() {
                return ResourceType.CODE;
            }

        };
    }

    private org.tmatesoft.svn.core.io.SVNRepository getSVNRepository() throws SVNException {
        SVNURL svnURL = SVNURL.fromFile(new File(getRepoPrefix() + ownerName + "/" + projectName));

        return SVNRepositoryFactory.create(svnURL);
    }

    public boolean isFile(String path, long rev) throws SVNException {
        return getSVNRepository().checkPath(path, rev) == SVNNodeKind.FILE;
    }

    @Override
    public boolean isFile(String path) throws SVNException, IOException {
        return isFile(path, getSVNRepository().getLatestRevision());
    }

    @Override
    public boolean isFile(String path, String revStr) throws SVNException {
        return isFile(path, Long.valueOf(revStr));
    }

    @Override
    public boolean renameTo(String projectName) {
        return move(this.ownerName, this.projectName, this.ownerName, projectName);
    }

    @Override
    public String getDefaultBranch() throws IOException {
        return "HEAD";
    }

    @Override
    public void setDefaultBranch(String target) throws IOException {
    }

    @Override
    public Commit getParentCommitOf(String revNumber) {
        Long rev = Long.parseLong(revNumber) - 1;
        try {
            return getCommit(rev.toString());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean isEmpty() {
        SVNURL svnURL;
        org.tmatesoft.svn.core.io.SVNRepository repository = null;
        try {
            svnURL = SVNURL.fromFile(new File(repoPrefix + ownerName + "/" + projectName));
            repository = SVNRepositoryFactory.create(svnURL);
            return repository.getLatestRevision() == 0;
        } catch (SVNException e) {
            throw new RuntimeException(e);
        } finally {
            if (repository != null) {
                repository.closeSession();
            }
        }
    }

    public boolean move(String srcProjectOwner, String srcProjectName, String desrProjectOwner,
            String destProjectName) {
        File src = new File(getRepoPrefix() + srcProjectOwner + "/" + srcProjectName);
        File dest = new File(getRepoPrefix() + desrProjectOwner + "/" + destProjectName);
        src.setWritable(true);

        try {
            if (src.exists()) {
                FileUtils.moveDirectory(src, dest);
            }
            return true;
        } catch (IOException e) {
            play.Logger.error("Move Failed", e);
            return false;
        }
    }

    @Override
    public File getDirectory() {
        return new File(getRepoPrefix() + ownerName + "/" + projectName);
    }
}