DiffCommand.java

package org.docascode.api;

import org.docascode.api.core.DocAsCodeRepository;
import org.docascode.api.core.errors.DocAsCodeException;
import org.docascode.api.diff.DocxDifferencer;
import org.docascode.api.event.Event;
import org.docascode.api.retrieve.GitRetriever;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.version.Version;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.awt.Desktop;

public class DiffCommand extends DocAsCodeCommand<File>{
    private String oldRevision;

    public DiffCommand setOldRevision(String oldRevision){
        this.oldRevision = oldRevision;
        return this;
    }

    private String newRevision;

    public DiffCommand setNewRevision(String newRevision){
        this.newRevision = newRevision;
        return this;
    }

    private String revision;

    public DiffCommand setRevision(String revision){
        this.revision = revision;
        return this;
    }

    private File toFile;

    public DiffCommand toFile(File toFile){
        this.toFile = toFile;
        return this;
    }

    private File file;

    public DiffCommand setFile(File file){
        this.file = file;
        return this;
    }

    public DiffCommand(DocAsCodeRepository repo) {
        super(repo);
    }

    private boolean openAtEnd = false;

    public DiffCommand openAtEnd(boolean openAtEnd){
        this.openAtEnd = openAtEnd;
        return this;
    }

    private File resolve(String revision) throws DocAsCodeException {
        String path = getRepository().relativize(file);
        Map<String, org.eclipse.aether.artifact.Artifact> artifactMap =
                ((DocAsCodeRepository) getRepository().addListener(this)).chrono().toArtifacts(null);
        if (artifactMap.keySet().contains(path)){
            org.eclipse.aether.artifact.Artifact artifact = artifactMap.get(path);
            List<Version> listVersion = getRepository().mvn().getVersionRange(artifact,
                    getRepository().mvn().getRemoteRepositories(null));
            List<String> listVersionString = new ArrayList<>();
            for (Version v : listVersion){
                listVersionString.add(v.toString());
            }
            if (listVersionString.contains(revision) ||
                    (!listVersionString.isEmpty() && revision.equals("LATEST")) ){
                artifact = artifact.setVersion(revision);
                ArtifactResult artifactResult = getRepository().mvn().resolve(artifact,
                        getRepository().mvn().getRemoteRepositories(null));
                return artifactResult.getArtifact().getFile();
            }
        }
        RevWalk revWalk = new RevWalk(getRepository().git());
        try {
            ObjectId revisionId = getRepository().git().resolve(revision);
            if (revisionId!= null){
                RevCommit commit = revWalk.parseCommit(revisionId);
                return new GitRetriever()
                        .setCommit(commit)
                        .setPath(path)
                        .setRepository(getRepository().git())
                        .toDir(new File(
                                getRepository().getTmpDir().getAbsolutePath(),
                                commit.getName()))
                        .call();
            } else {
                Event e = new Event(this);
                e.setMessage(String.format(
                        "File '%s' not found at revision '%s'...",
                        path,
                        revision));
                fireEvent(e);
                return null;
            }
        } catch (IOException e) {
            throw new DocAsCodeException(
                String.format(
                    "Revision '%s' not found in git repository",
                    revision),
                e
            );
        }
    }

    @Override
    public File call() throws DocAsCodeException {
        File newFile;
        if (newRevision == null){
            newFile = file;
            newRevision = "WorkTree";
        } else {
            newFile = resolve(newRevision);
        }
        if (revision==null){
            revision = oldRevision+":"+newRevision;
        }
        File oldFile = resolve(oldRevision);
        toFile.getParentFile().mkdirs();
        try {
            if(toFile.delete() || !toFile.createNewFile()){
                throw new DocAsCodeException(
                    String.format(
                        "Unable to create file '%s'",
                         toFile));
            }
        } catch (IOException e) {
            throw new DocAsCodeException(
                    String.format(
                            "Unable to create file '%s'",
                            toFile));
        }
        DocxDifferencer diff = (DocxDifferencer) new DocxDifferencer().addListener(this);
        diff.setBaseFile(oldFile)
                .setRevisedFile(newFile)
                .setRevision(this.revision)
                .setTargetFile(toFile)
                .diff();
        if (openAtEnd){
            Desktop desktop;
            if (Desktop.isDesktopSupported()) {
                desktop = Desktop.getDesktop();
                try {
                    Event e = new Event(this);
                    e.setMessage(
                        String.format(
                            "Opening diff of file '%s' from '%s' to '%s'.",
                            file,
                            oldRevision,
                            newRevision));
                    e.setLevel(Event.Level.SUCESS);
                    fireEvent(e);
                    desktop.open(toFile);
                } catch (IOException e) {
                    throw new DocAsCodeException(
                            String.format(
                                "Unable to open file '%s",
                                    toFile),e);
                }
            }
        }
        return toFile;
    }
}