/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.web.git.operation;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.RawParseUtils;
import org.flowerplatform.common.CommonPlugin;
import org.flowerplatform.communication.CommunicationPlugin;
import org.flowerplatform.communication.channel.CommunicationChannel;
import org.flowerplatform.communication.command.DisplaySimpleMessageClientCommand;
import org.flowerplatform.communication.progress_monitor.ProgressMonitor;
import org.flowerplatform.web.entity.User;
import org.flowerplatform.web.git.GitPlugin;
import org.flowerplatform.web.git.remote.dto.CommitPageDto;
import org.flowerplatform.web.git.remote.dto.CommitResourceDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Cristina Constantinescu
*/
public class CommitOperation {
private static Logger logger = LoggerFactory.getLogger(CommitOperation.class);
private CommunicationChannel channel;
private List<File> selection;
private Repository repository;
public CommitOperation(CommunicationChannel channel) {
this.channel = channel;
}
public CommitOperation(CommunicationChannel channel, List<File> selection) {
this(channel);
this.selection = selection;
}
private void includeList(Set<String> added, Set<String> files) {
for (String filename : added) {
if (!files.contains(filename)) {
files.add(filename);
}
}
}
private String getMergeResolveMessage(Repository mergeRepository) {
File mergeMsg = new File(mergeRepository.getDirectory(),
Constants.MERGE_MSG);
FileReader reader;
try {
reader = new FileReader(mergeMsg);
BufferedReader br = new BufferedReader(reader);
try {
StringBuilder message = new StringBuilder();
String s;
String newLine = newLine();
while ((s = br.readLine()) != null)
message.append(s).append(newLine);
return message.toString();
} catch (IOException e) {
throw new IllegalStateException(e);
} finally {
try {
br.close();
} catch (IOException e) {
// Empty
}
}
} catch (FileNotFoundException e) {
return null;
}
}
private String newLine() {
return System.getProperty("line.separator");
}
private String getCherryPickOriginalAuthor(Repository mergeRepository) {
try {
ObjectId cherryPickHead = mergeRepository.readCherryPickHead();
PersonIdent author = new RevWalk(mergeRepository).parseCommit(cherryPickHead).getAuthorIdent();
return author.getName() + " <" + author.getEmailAddress() + ">";
} catch (IOException e) {
return null;
}
}
private Repository getRepository(List<File> files) {
Repository repo = null;
for (File file : files) {
if (repo == null) {
repo = GitPlugin.getInstance().getUtils().getRepository(file);
} else if (!repo.equals(GitPlugin.getInstance().getUtils().getRepository(file))) {
return null;
}
}
return repo;
}
public CommitPageDto getPageDto() {
try {
repository = getRepository(selection);
if (repository == null) {
channel.appendOrSendCommand(new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
GitPlugin.getInstance().getMessage("git.commit.errorDifferentRepositories"),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return null;
}
RepositoryState state = repository.getRepositoryState();
if (!state.canCommit()) {
channel.appendOrSendCommand(new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
GitPlugin.getInstance().getMessage("git.commit.repositoryState", new Object[] {state.getDescription()}),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return null;
}
boolean isMergedResolved = false;
boolean isCherryPickResolved = false;
if (state.equals(RepositoryState.MERGING_RESOLVED)) {
isMergedResolved = true;
} else if (state.equals(RepositoryState.CHERRY_PICKING_RESOLVED)) {
isCherryPickResolved = true;
}
User user = (User) CommunicationPlugin.tlCurrentPrincipal.get().getUser();
String committer = user.getName() + " <" + user.getEmail() + ">";
String author = user.getName() + " <" + user.getEmail() + ">";
if (isCherryPickResolved) {
author = getCherryPickOriginalAuthor(repository);
}
if (author == null) {
author = user.getName() + " <" + user.getEmail() + ">";
}
String message = null;
if (isMergedResolved || isCherryPickResolved) {
message = getMergeResolveMessage(repository);
}
org.eclipse.jgit.api.Status repoStatus = new Git(repository).status().call();
Set<String> files = new HashSet<String>();
includeList(repoStatus.getAdded(), files);
includeList(repoStatus.getChanged(), files);
includeList(repoStatus.getRemoved(), files);
includeList(repoStatus.getMissing(), files);
includeList(repoStatus.getModified(), files);
includeList(repoStatus.getUntracked(), files);
List<CommitResourceDto> commitResources = new ArrayList<CommitResourceDto>();
for (String path : files) {
CommitResourceDto commitDto = new CommitResourceDto();
commitDto.setLabel(path);
commitDto.setPath(path);
commitDto.setImage("images/file.gif");
if (repoStatus.getUntracked().contains(path)) {
commitDto.setState(CommitResourceDto.UNTRACKED);
}
commitResources.add(commitDto);
}
CommitPageDto dto = new CommitPageDto();
dto.setCommitResources(commitResources);
dto.setAuthor(author);
dto.setCommitter(committer);
dto.setMessage(message);
dto.setRepository(repository.getDirectory().getAbsolutePath());
return dto;
} catch (Exception e) {
logger.debug(GitPlugin.getInstance().getMessage("git.commit.error"), e);
channel.appendOrSendCommand(new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
GitPlugin.getInstance().getMessage("git.commit.error"),
e.getMessage(),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return null;
}
}
private void addUntracked(Collection<String> notTracked, Repository repo) throws Exception {
if (notTracked == null || notTracked.size() == 0)
return;
AddCommand addCommand = new Git(repo).add();
for (String path : notTracked) {
addCommand.addFilepattern(path);
}
addCommand.call();
}
public boolean commit(String repositoryLocation, List<CommitResourceDto> files, String author, String committer, String message, boolean amending) {
ProgressMonitor monitor = ProgressMonitor.create(GitPlugin.getInstance().getMessage("git.commit.monitor.title"), channel);
try {
Repository repo = GitPlugin.getInstance().getUtils().getRepository(new File(repositoryLocation));
Collection<String> notTracked = new HashSet<String>();
Collection<String> resources = new HashSet<String>();
for (CommitResourceDto file : files) {
resources.add(file.getPath());
if (file.getState() == CommitResourceDto.UNTRACKED) {
notTracked.add(file.getPath());
}
}
monitor.beginTask(GitPlugin.getInstance().getMessage("git.commit.monitor.message"), 10);
addUntracked(notTracked, repo);
monitor.worked(1);
CommitCommand commitCommand = new Git(repo).commit();
commitCommand.setAmend(amending).setMessage(message);
for (String path : resources) {
commitCommand.setOnly(path);
}
Date commitDate = new Date();
TimeZone timeZone = TimeZone.getDefault();
PersonIdent enteredAuthor = RawParseUtils.parsePersonIdent(author);
PersonIdent enteredCommitter = RawParseUtils.parsePersonIdent(committer);
if (enteredAuthor == null) {
channel.appendOrSendCommand(
new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
GitPlugin.getInstance().getMessage("git.commit.errorParsingPersonIdent", new Object[] {author}),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return false;
}
if (enteredCommitter == null) {
channel.appendOrSendCommand(
new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
GitPlugin.getInstance().getMessage("git.commit.errorParsingPersonIdent", new Object[] {committer}),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return false;
}
PersonIdent authorIdent = new PersonIdent(enteredAuthor, commitDate, timeZone);
PersonIdent committerIdent = new PersonIdent(enteredCommitter, commitDate, timeZone);
if (amending) {
RevCommit headCommit = GitPlugin.getInstance().getUtils().getHeadCommit(repo);
if (headCommit != null) {
PersonIdent headAuthor = headCommit.getAuthorIdent();
authorIdent = new PersonIdent(enteredAuthor, headAuthor.getWhen(), headAuthor.getTimeZone());
}
}
commitCommand.setAuthor(authorIdent);
commitCommand.setCommitter(committerIdent);
monitor.worked(1);
commitCommand.call();
if (monitor.isCanceled()) {
return false;
}
monitor.worked(8);
// GitLightweightDecorator.refresh();
//
// updateDispatcher.dispatchContentUpdate(null, repo, GitTreeUpdateDispatcher.COMMIT, null);
return true;
} catch (Exception e) {
logger.debug(GitPlugin.getInstance().getMessage("git.commit.error"), e);
channel.appendOrSendCommand(
new DisplaySimpleMessageClientCommand(
CommonPlugin.getInstance().getMessage("error"),
e.getMessage(),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return false;
} finally {
monitor.done();
}
}
}