/* 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(); } } }