Package playRepository

Source Code of playRepository.BareCommit$RefHeadFileLock

/**
* Yobi, Project Hosting SW
*
* Copyright 2014 NAVER Corp.
* http://yobi.io
*
* @Author Suwon Chae
*
* 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 models.Project;
import models.User;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;

import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static utils.LineEnding.*;
import static playRepository.BareRepository.*;

public class BareCommit {
    private PersonIdent personIdent;
    private Repository repository;
    private String commitMessage;
    private ObjectInserter objectInserter;

    private File file;
    private String refName;
    private ObjectId headObjectId;

    public BareCommit(Project project, User user) {
        this.repository = BareRepository.getRepository(project);
        this.personIdent = new PersonIdent(user.name, user.email);
    }

    /**
     * Commit to bare repository with filename and text contents
     *
     * @param fileNameWithPath
     * @param contents
     * @param message
     */
    public void commitTextFile(String fileNameWithPath, String contents, String message) throws IOException {
        this.file = new File(fileNameWithPath);
        setCommitMessage(message);
        if (this.refName == null) {
            setRefName(HEAD);
        }

        RefHeadFileLock refHeadFileLock = new RefHeadFileLock().invoke(this.refName);
        try {
            this.objectInserter = this.repository.newObjectInserter();
            contents = addEOL(changeLineEnding(contents, findFileLineEnding(repository, fileNameWithPath)));
            refUpdate(createCommitWithNewTree(createGitObjectWithText(contents)), refName);
        } catch (OverlappingFileLockException e) {
            play.Logger.error("Overlapping File Lock Error: " + e.getMessage());
        } finally {
            objectInserter.release();
            repository.close();
            refHeadFileLock.release();
        }
    }

    private boolean noHeadRef() {
        if(this.headObjectId == null) {
            return true;
        }
        return this.headObjectId.equals(ObjectId.zeroId());
    }

    private ObjectId createCommitWithNewTree(ObjectId targetTextFileObjectId) throws IOException {
        return objectInserter.insert(buildCommitWith(file.getName(), targetTextFileObjectId));
    }

    private CommitBuilder buildCommitWith(String fileName, ObjectId fileObjectId) throws IOException {
        CommitBuilder commit = new CommitBuilder();
        commit.setTreeId(createTreeWith(fileName, fileObjectId));
        if (!noHeadRef()) {
            commit.setParentId(this.headObjectId);
        }
        commit.setAuthor(getPersonIdent());
        commit.setCommitter(getPersonIdent());
        commit.setMessage(getCommitMessage());
        return commit;
    }

    private ObjectId createTreeWith(String fileName, ObjectId fileObjectId) throws IOException {
        if (noHeadRef()){
            return objectInserter.insert(newTreeWith(fileName, fileObjectId));
        } else {
            return objectInserter.insert(rebuildExistingTreeWith(fileName, fileObjectId));
        }
    }

    private TreeFormatter newTreeWith(String fileName, ObjectId fileObjectId) {
        TreeFormatter formatter = new TreeFormatter();
        formatter.append(fileName, FileMode.REGULAR_FILE, fileObjectId);
        return formatter;
    }

    private TreeFormatter rebuildExistingTreeWith(String fileName, ObjectId fileObjectId) throws IOException {
        TreeFormatter formatter = new TreeFormatter();
        CanonicalTreeParser treeParser = getCanonicalTreeParser(this.repository);

        boolean isInsertedInTree = false;
        while(!treeParser.eof()){
            String entryName = new String(treeParser.getEntryPathBuffer(), 0, treeParser.getEntryPathLength());
            String nameForComparison = entryName;

            if (treeParser.getEntryFileMode() == FileMode.TREE){
                nameForComparison = entryName.concat("/"); //for tree ordering comparison
            }
            if (nameForComparison.compareTo(fileName) == 0 && isInsertedInTree == false){
                formatter.append(fileName, FileMode.REGULAR_FILE, fileObjectId);
                isInsertedInTree = true;
            } else if (nameForComparison.compareTo(fileName) > 0 && isInsertedInTree == false) {
                formatter.append(fileName, FileMode.REGULAR_FILE, fileObjectId);
                formatter.append(entryName.getBytes()
                        , treeParser.getEntryFileMode()
                        , treeParser.getEntryObjectId());
                isInsertedInTree = true;
            } else {
                formatter.append(entryName.getBytes()
                        , treeParser.getEntryFileMode()
                        , treeParser.getEntryObjectId());
            }

            treeParser = treeParser.next();
        }
        if(!isInsertedInTree){
            formatter.append(fileName, FileMode.REGULAR_FILE, fileObjectId);
        }
        return formatter;
    }

    private CanonicalTreeParser getCanonicalTreeParser(Repository repository) throws IOException {
        RevWalk revWalk = new RevWalk(repository);
        RevCommit commit = revWalk.parseCommit(this.headObjectId);
        return new CanonicalTreeParser(new byte[]{}, revWalk.getObjectReader(), commit.getTree().getId());
    }

    private ObjectId createGitObjectWithText(String contents) throws IOException {
        return objectInserter.insert(OBJ_BLOB, contents.getBytes(), 0, contents.getBytes().length);
    }

    private void refUpdate(ObjectId commitId, String refName) throws IOException {
        RefUpdate ru = this.repository.updateRef(refName);
        ru.setForceUpdate(false);
        ru.setRefLogIdent(getPersonIdent());
        ru.setNewObjectId(commitId);
        if(hasOldCommit(refName)){
            ru.setExpectedOldObjectId(getCurrentMomentHeadObjectId());
        }
        ru.setRefLogMessage(getCommitMessage(), false);
        ru.update();
    }

    private boolean hasOldCommit(String refName) throws IOException {
        return this.repository.getRef(refName).getObjectId() != null;
    }

    private PersonIdent getPersonIdent() {
        if (this.personIdent == null) {
            this.personIdent = new PersonIdent(this.repository);
        }
        return personIdent;
    }

    private String getCommitMessage() {
        if(this.commitMessage == null){
            return "Update " + this.file.getName();
        }
        return commitMessage;
    }

    public void setCommitMessage(String commitMessage) {
        this.commitMessage = commitMessage;
    }

    public void setHeadObjectId(String refName) throws IOException {
        if(this.repository.getRef(refName).getObjectId() == null){
            this.headObjectId = ObjectId.zeroId();
        } else {
            this.headObjectId = this.repository.getRef(refName).getObjectId();
        }
    }

    public ObjectId getCurrentMomentHeadObjectId() throws IOException {
        if( this.repository.getRef(refName).getObjectId() == null ){
            return ObjectId.zeroId();
        } else {
            return this.repository.getRef(refName).getObjectId();
        }
    }

    public void setRefName(String refName){
        this.refName = refName;
    }

    private class RefHeadFileLock {
        private FileChannel channel;
        private FileLock lock;
        private File refHeadFile;

        public RefHeadFileLock invoke(String refName) throws IOException {
            refHeadFile = new File(repository.getDirectory().getPath(),
                    repository.getRef(refName).getLeaf().getName());
            if(refHeadFile.exists()){
                channel = new RandomAccessFile(refHeadFile, "rw").getChannel();
                lock = channel.lock();
            }
            setHeadObjectId(refName);
            return this;
        }

        public void release() {
            try {
                if(refHeadFile.exists()) {
                    if(lock != null) lock.release();
                    if(channel != null) channel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                play.Logger.error(e.getMessage());
            }
        }
    }
}
TOP

Related Classes of playRepository.BareCommit$RefHeadFileLock

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.