blob: 822a8a89e9e0a77e06cabc5410f30b79326e5cca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.compare.git.pgm.internal.args;
import static org.eclipse.emf.compare.git.pgm.internal.Messages.CAN_T_FIND_GIT_REPOSITORY_MESSAGE;
import static org.eclipse.emf.compare.git.pgm.internal.exception.Die.DeathType.FATAL;
import com.google.common.base.Preconditions;
import java.io.File;
import java.io.IOException;
import org.eclipse.emf.compare.git.pgm.internal.exception.Die;
import org.eclipse.emf.compare.git.pgm.internal.exception.Die.DeathType;
import org.eclipse.emf.compare.git.pgm.internal.exception.Die.DiesOn;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.kohsuke.args4j.CmdLineParser;
/**
* CmdLineParser that is aware of a git repository. Some {@link org.kohsuke.args4j.spi.OptionHandler}s might
* need it for validation.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
public final class CmdLineParserRepositoryBuilder extends CmdLineParser {
/**
* Functional interface used to build a {@link Repository}.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
public interface RepoBuilder {
/**
* Build the repository represented by the given directory.
*
* @param gitDir
* the repository to build.
* @return a {@link Repository}.
* @throws Die
* e
*/
Repository buildRepository(String gitDir) throws Die;
}
/**
* {@link Repository} builder that uses pure JGit code.
*/
private static RepoBuilder jgitRepoBuilder = new JGitRepoBuilder();
/**
* {@link Repository} builder that uses pure EGit code.
* <p>
* This builder creates the repository and add it the RepositoryCache of EGit
* </p>
*/
private static RepoBuilder egitRepoBuilder = new EGitRepoBuilder();
/**
* Git directory.
*/
private String gitDir;
/**
* Git repository.
*/
private Repository repository;
/**
* {@link Repository} builder.
*/
private final RepoBuilder builder;
/**
* Constructor.
* <p>
* The git repository will be buit during argument parsing
* </p>
*
* @param bean
* instance of a class annotated by Option and Argument.
* @param builder
* the Repository builder.
*/
private CmdLineParserRepositoryBuilder(Object bean, RepoBuilder builder) {
super(bean);
this.builder = builder;
}
/**
* Creates a new {@link CmdLineParser} that will build the {@link Repository} using pure JGit methods.
* <p>
* Using this method calling {@link #setGitDir(String)} is optional.
* </p>
*
* @param bean
* instance of a class annotated by Option and Argument.
* @return a new {@link CmdLineParser}.
*/
public static CmdLineParserRepositoryBuilder newJGitRepoBuilderCmdParser(Object bean) {
return new CmdLineParserRepositoryBuilder(bean, jgitRepoBuilder);
}
/**
* Creates a new {@link CmdLineParser} that will build the {@link Repository} using EGit methods (creates
* the repository and add it to the cache).
* <p>
* With this implementation the method {@link #setGitDir(String)} needs to be called before the  
* {@link #getRepo()} since EGit needs the path to the git dir to build the repository
* </p>
*
* @param bean
* instance of a class annotated by Option and Argument.
* @return a new {@link CmdLineParser}.
*/
public static CmdLineParserRepositoryBuilder newEGitRepoBuilderCmdParser(Object bean) {
return new CmdLineParserRepositoryBuilder(bean, egitRepoBuilder);
}
/**
* Get the git {@link Repository}.
* <p>
* The first time this method is called it may build the repository and so laucn a {@link Die} exception
* <p>
*
* @return the git {@link Repository}.
* @throws Die
* e
*/
public Repository getRepo() throws Die {
if (repository == null) {
repository = builder.buildRepository(gitDir);
}
return repository;
}
/**
* Sets the path to the git dir repository.
* <p>
* This method does not need to be called if the command has been run inside the git repository. However
* if it's used it needs to be called before the first call of the {@link #getRepo()} method.
* </p>
*
* @param gitDir
* the path to the git dir repository.
*/
public void setGitDir(String gitDir) {
// The gitDir argument should be provided before the repository is built
Preconditions.checkArgument(repository == null);
this.gitDir = gitDir;
}
/**
* {@link Repository} builder that uses pure EGit code.
* <p>
* This builder creates the repository and add it the RepositoryCache of EGit
* </p>
*/
private static final class EGitRepoBuilder implements RepoBuilder {
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.git.pgm.internal.args.CmdLineParserRepositoryBuilder.RepoBuilder#buildRepository(java.lang.String)
*/
public Repository buildRepository(String aGitdir) throws Die {
Preconditions.checkNotNull(aGitdir);
File myGitDir = new File(aGitdir);
if (!myGitDir.exists()) {
throw new DiesOn(DeathType.FATAL).displaying(
"Can't build git repository: " + aGitdir + "does not exist").ready();
}
try {
Repository myRepo = org.eclipse.egit.core.Activator.getDefault().getRepositoryCache()
.lookupRepository(myGitDir);
if (myRepo == null) {
throw new DiesOn(DeathType.FATAL).displaying("Can't build repository " + aGitdir).ready();
}
return myRepo;
} catch (IOException e1) {
throw new DiesOn(DeathType.FATAL).duedTo(e1).displaying("Can't build repository " + aGitdir)
.ready();
}
}
}
/**
* {@link Repository} builder that uses pure JGit code.
*/
private static final class JGitRepoBuilder implements RepoBuilder {
/**
* {@inheritDoc}.
*/
public Repository buildRepository(String aGitdir) throws Die {
/** The current repository directory. */
final File myGitDir;
/** The current repository. */
final Repository myRepo;
if (aGitdir == null) {
myGitDir = null;
} else {
myGitDir = new File(aGitdir);
}
RepositoryBuilder rb = new RepositoryBuilder().setGitDir(myGitDir).readEnvironment()
.setMustExist(true).findGitDir();
if (rb.getGitDir() == null) {
throw new DiesOn(FATAL).displaying(CAN_T_FIND_GIT_REPOSITORY_MESSAGE).ready();
}
try {
myRepo = rb.build();
} catch (RepositoryNotFoundException e) {
throw new DiesOn(FATAL).displaying(CAN_T_FIND_GIT_REPOSITORY_MESSAGE).ready();
} catch (IOException e) {
throw new DiesOn(FATAL).duedTo(e).displaying("Cannot build the git repository").ready();
}
return myRepo;
}
}
}