/******************************************************************************* * Copyright (c) 2015 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.tests.performance.git; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.mapping.IModelProviderDescriptor; import org.eclipse.core.resources.mapping.ModelProvider; import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.resources.mapping.ResourceMappingContext; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.egit.core.op.ConnectProviderOperation; import org.eclipse.egit.core.synchronize.GitResourceVariantTreeSubscriber; import org.eclipse.egit.core.synchronize.GitSubscriberMergeContext; import org.eclipse.egit.core.synchronize.GitSubscriberResourceMappingContext; import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData; import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; import org.eclipse.jgit.lib.Repository; import org.eclipse.team.core.subscribers.Subscriber; import org.eclipse.team.core.subscribers.SubscriberScopeManager; import com.google.common.base.Throwables; /** * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a> */ @SuppressWarnings("restriction") public final class GitUtil { /** * This will unzip the repository contained in the given zip location in the given destination. * * @param zipLocation * the zip (that contains the repository) location. * @param destination * the destination * @param monitor * {@link IProgressMonitor} that will be used to monitor the operation. */ public static void unzipRepo(URL zipLocation, String destination, IProgressMonitor monitor) { try { final ZipInputStream zipFileStream = new ZipInputStream(zipLocation.openStream()); ZipEntry zipEntry = zipFileStream.getNextEntry(); while (zipEntry != null) { // We will construct the new file but we will strip off the project // directory from the beginning of the path because we have already // created the destination project for this zip. final File file = new File(destination, zipEntry.getName()); if (!zipEntry.isDirectory()) { /* * Copy files (and make sure parent directory exist) */ final File parentFile = file.getParentFile(); if (null != parentFile && !parentFile.exists()) { parentFile.mkdirs(); } OutputStream os = null; try { os = new FileOutputStream(file); final int bufferSize = 102400; final byte[] buffer = new byte[bufferSize]; while (true) { final int len = zipFileStream.read(buffer); if (zipFileStream.available() == 0) { break; } os.write(buffer, 0, len); } } finally { if (null != os) { os.close(); } } } zipFileStream.closeEntry(); zipEntry = zipFileStream.getNextEntry(); } } catch (final IOException e) { Throwables.propagate(e); } } /** * Delete the repository (and all files contained in). * * @param repository * the File representing the repository. */ public static void deleteRepo(File repository) { if (repository.exists()) { File[] files = repository.listFiles(); if (null != files) { for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteRepo(files[i]); } else { files[i].delete(); } } } repository.delete(); } } /** * Import the project from the given repository. * * @param repository * the given repository. * @param projectFilePath * the path containing the project in the repository. * @return the imported project, or null if import step fails. */ public static IProject importProjectFromRepo(File repository, String projectFilePath) { try { IProjectDescription description = ResourcesPlugin.getWorkspace().loadProjectDescription( new Path(repository.getPath() + File.separator + projectFilePath)); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(description.getName()); project.create(description, new NullProgressMonitor()); project.open(new NullProgressMonitor()); return project; } catch (CoreException e) { Throwables.propagate(e); } return null; } /** * Import all projects contain in the given repository. * * @param repository * the given repository. */ public static Collection<IProject> importProjectsFromRepo(File repository) { Collection<IProject> projects = new ArrayList<IProject>(); try { Collection<File> projectsFromRepo = getProjectsFromRepo(repository); for (File file : projectsFromRepo) { IProjectDescription description = ResourcesPlugin.getWorkspace() .loadProjectDescription(new Path(file.getPath())); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(description.getName()); project.create(description, new NullProgressMonitor()); project.open(new NullProgressMonitor()); projects.add(project); } } catch (CoreException e) { Throwables.propagate(e); } return projects; } /** * Get the ".projects" files from the given repository. * * @param repository * the given repository. * @return the ".projects" files from the given repository. */ public static Collection<File> getProjectsFromRepo(File repository) { List<File> projects = new ArrayList<File>(); if (repository.exists()) { File[] files = repository.listFiles(); if (null != files) { for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { projects.addAll(getProjectsFromRepo(files[i])); } else if (files[i].getName().endsWith(IProjectDescription.DESCRIPTION_FILE_NAME)) { projects.add(files[i]); } } } } return projects; } /** * Connect given projects to the given repository. * * @param repository * the given repository. * @param projects * the given projects. */ public static void connectProjectsToRepo(Repository repository, Collection<IProject> projects) { for (IProject project : projects) { try { ConnectProviderOperation op = new ConnectProviderOperation(project, repository.getDirectory()); op.execute(new NullProgressMonitor()); } catch (CoreException e) { Throwables.propagate(e); } } } /** * Simulate a comparison between the two given references and returns back the subscriber that can provide * all computed synchronization information. * * @param sourceRef * Source reference (i.e. "left" side of the comparison). * @param targetRef * Target reference (i.e. "right" side of the comparison). * @param comparedFile * The file we are comparing (that would be the file right-clicked into the workspace). * @return The created subscriber. */ public static Subscriber createSubscriberForComparison(Repository repository, String sourceRef, String targetRef, IFile comparedFile, List<Runnable> disposers) throws IOException { final GitSynchronizeData data = new GitSynchronizeData(repository, sourceRef, targetRef, false); final GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); final ResourceMapping[] mappings = getResourceMappings(comparedFile); final GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber(dataSet); subscriber.init(new NullProgressMonitor()); final RemoteResourceMappingContext remoteContext = new GitSubscriberResourceMappingContext(subscriber, dataSet); final SubscriberScopeManager manager = new SubscriberScopeManager(subscriber.getName(), mappings, subscriber, remoteContext, true); final GitSubscriberMergeContext context = new GitSubscriberMergeContext(subscriber, manager, dataSet); disposers.add(new Runnable() { public void run() { manager.dispose(); context.dispose(); subscriber.dispose(); } }); return context.getSubscriber(); } /** * This will query all model providers for those that are enabled on the given file and list all mappings * available for that file. * * @param file * The file for which we need the associated resource mappings. * @return All mappings available for that file. */ private static ResourceMapping[] getResourceMappings(IFile file) { final IModelProviderDescriptor[] modelDescriptors = ModelProvider.getModelProviderDescriptors(); final Set<ResourceMapping> mappings = new LinkedHashSet<ResourceMapping>(); for (IModelProviderDescriptor candidate : modelDescriptors) { try { final IResource[] resources = candidate.getMatchingResources(new IResource[] {file, }); if (resources.length > 0) { // get mappings from model provider if there are matching resources final ModelProvider model = candidate.getModelProvider(); final ResourceMapping[] modelMappings = model.getMappings(file, ResourceMappingContext.LOCAL_CONTEXT, null); for (ResourceMapping mapping : modelMappings) { mappings.add(mapping); } } } catch (CoreException e) { Throwables.propagate(e); } } return mappings.toArray(new ResourceMapping[mappings.size()]); } }