/**
* Copyright (c) 2016 committers of YAKINDU and others.
* 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:
* committers of YAKINDU - initial API and implementation
*
*/
package org.yakindu.sct.examples.wizard.service.git;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.TrackingRefUpdate;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
import org.yakindu.sct.examples.wizard.ExampleActivator;
import org.yakindu.sct.examples.wizard.preferences.ExamplesPreferenceConstants;
import org.yakindu.sct.examples.wizard.service.ExampleData;
import org.yakindu.sct.examples.wizard.service.IExampleService;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
*
* @author t00manysecretss
* @author andreas muelder - let GitRepositoryExampleService implement
* {@link IExampleService} interface
*
*/
@Singleton
public class GitRepositoryExampleService implements IExampleService {
private static final String METADATA_JSON = "metadata.json";
@Inject
private IExampleDataReader reader;
protected java.nio.file.Path getStorageLocation() {
return java.nio.file.Paths.get(ExampleActivator.getDefault().getPreferenceStore()
.getString(ExamplesPreferenceConstants.STORAGE_LOCATION));
}
@Override
public boolean exists() {
return Files.exists(getStorageLocation()) && hasMetaData(getStorageLocation());
}
@Override
public IStatus fetchAllExamples(IProgressMonitor monitor) {
if (!exists()) {
java.nio.file.Path storageLocation = getStorageLocation();
try {
Files.createDirectories(storageLocation);
} catch (IOException e1) {
return new Status(IStatus.ERROR, ExampleActivator.PLUGIN_ID,
"Unable to create folder " + storageLocation.getFileName());
}
return cloneRepository(monitor);
} else {
return updateRepository(monitor);
}
}
protected IStatus updateRepository(IProgressMonitor monitor) {
String repoURL = getPreference(ExamplesPreferenceConstants.REMOTE_LOCATION);
try {
java.nio.file.Path storageLocation = getStorageLocation();
PullResult result = Git.open(storageLocation.toFile()).pull()
.setProgressMonitor(new EclipseGitProgressTransformer(monitor)).call();
if (!result.isSuccessful()) {
return new Status(IStatus.ERROR, ExampleActivator.PLUGIN_ID,
"Unable to update repository " + repoURL + "!");
}
} catch (GitAPIException | IOException e) {
return new Status(IStatus.ERROR, ExampleActivator.PLUGIN_ID,
"Unable to update repository " + repoURL + "!");
}
return Status.OK_STATUS;
}
protected String getPreference(String constant){
return ExampleActivator.getDefault().getPreferenceStore().getString(constant);
}
protected IStatus cloneRepository(IProgressMonitor monitor) {
String repoURL = getPreference(ExamplesPreferenceConstants.REMOTE_LOCATION);
String remoteBranch = getPreference(ExamplesPreferenceConstants.REMOTE_BRANCH);
Git call = null;
java.nio.file.Path storageLocation = getStorageLocation();
try {
call = Git.cloneRepository().setURI(repoURL).setDirectory(storageLocation.toFile())
.setProgressMonitor(new EclipseGitProgressTransformer(monitor)).setBranch(remoteBranch).call();
} catch (GitAPIException e) {
try {
deleteFolder(storageLocation);
} catch (IOException ex) {
ex.printStackTrace();
}
return new Status(IStatus.ERROR, ExampleActivator.PLUGIN_ID,
"Unable to clone repository " + repoURL + "!");
} finally {
if (call != null)
call.close();
if (monitor.isCanceled()) {
try {
deleteFolder(storageLocation);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return Status.OK_STATUS;
}
@Override
public List<ExampleData> getExamples(IProgressMonitor monitor) {
java.nio.file.Path storageLocation = getStorageLocation();
List<java.nio.file.Path> projects = new ArrayList<>();
findMetaData(projects, storageLocation);
List<ExampleData> result = reader.parse(projects);
Collections.sort(result);
return result;
}
protected void findMetaData(List<java.nio.file.Path> result, java.nio.file.Path root) {
try (DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(root)) {
for (java.nio.file.Path entry : stream) {
if (Files.isDirectory(entry)) {
findMetaData(result, entry);
} else if (entry.getFileName().toString().equals(METADATA_JSON)) {
result.add(entry);
}
}
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
protected boolean hasMetaData(java.nio.file.Path root) {
List<java.nio.file.Path> result = new ArrayList<>();
findMetaData(result, root);
return !result.isEmpty();
}
@Override
public void importExample(ExampleData edata, IProgressMonitor monitor) {
try {
IProjectDescription original = ResourcesPlugin.getWorkspace()
.loadProjectDescription(new Path(edata.getProjectDir().getAbsolutePath()).append("/.project"));
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(edata.getProjectDir().getName());
IProjectDescription clone = ResourcesPlugin.getWorkspace()
.newProjectDescription(original.getName());
clone.setBuildSpec(original.getBuildSpec());
clone.setComment(original.getComment());
clone.setDynamicReferences(original
.getDynamicReferences());
clone.setNatureIds(original.getNatureIds());
clone.setReferencedProjects(original
.getReferencedProjects());
if(project.exists()){
return;
}
project.create(clone, monitor);
project.open(monitor);
@SuppressWarnings("unchecked")
List<IFile> filesToImport = FileSystemStructureProvider.INSTANCE.getChildren(edata.getProjectDir());
ImportOperation io = new ImportOperation(project.getFullPath(), edata.getProjectDir(),
FileSystemStructureProvider.INSTANCE, new IOverwriteQuery() {
@Override
public String queryOverwrite(String pathString) {
return IOverwriteQuery.ALL;
}
}, filesToImport);
io.setOverwriteResources(true);
io.setCreateContainerStructure(false);
io.run(monitor);
project.refreshLocal(IProject.DEPTH_INFINITE, monitor);
} catch (Exception e) {
e.printStackTrace();
}
}
public void deleteFolder(java.nio.file.Path path) throws IOException {
if (!Files.exists(path))
return;
Files.walkFileTree(path, new SimpleFileVisitor<java.nio.file.Path>() {
@Override
public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
@Override
public boolean isUpToDate(IProgressMonitor monitor) {
java.nio.file.Path storageLocation = getStorageLocation();
try {
FetchCommand fetch = Git.open(storageLocation.toFile()).fetch();
FetchResult result = fetch.setProgressMonitor(new EclipseGitProgressTransformer(monitor)).setDryRun(true)
.call();
Collection<TrackingRefUpdate> trackingRefUpdates = result.getTrackingRefUpdates();
return trackingRefUpdates.size() == 0;
} catch (RepositoryNotFoundException ex) {
// This is the case when the examples are imported manually
return true;
} catch (Exception ex) {
ex.printStackTrace();
return true;
}
}
}