aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Stocker2011-08-16 11:34:09 (EDT)
committerMatthias Sohn2011-08-16 11:35:10 (EDT)
commit7fbeca4c218d7712abd6198ca9551f3c15904343 (patch)
treeb22c8eced7ff904e11b4b23ed1d45fb5e22cf3e3
parente17df54ee93c101302350df01cc5f8b13495aac6 (diff)
downloadegit-7fbeca4c218d7712abd6198ca9551f3c15904343.zip
egit-7fbeca4c218d7712abd6198ca9551f3c15904343.tar.gz
egit-7fbeca4c218d7712abd6198ca9551f3c15904343.tar.bz2
Team project set supportrefs/changes/36/2936/16
This is based on the previous work by Mykola Nikishov in change I800dd9f23953ad903f20289c442707e2dde08f75 ("Import a project set file"). This change includes export support, unit tests, and can handle the situation where different branches of the same repository should be imported. A project reference string in the project set file looks like this: 1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit Based on an array of these reference strings, GitProjectSetCapability does the following when importing: - Clone a repository with CloneOperation for each combination of repository URL and branch name. - Import a project from each directory that is specified in the last part of the string ("." if the repository itself is the .project). - Add the repository to the Repositories View. - Connect the projects using ConnectProviderOperation. Due to Bug 244313, import and export of project set files requires the org.eclipse.core.runtime.compatibility plug-in. The dependency is in a separate optional feature, as proposed on the old change. It's required for Eclipse < 3.7. CQ: 5438 Bug: 296082 Change-Id: I1500cc376961117b39b8760e6de675a4885e5f72 Also-by: Mykola Nikishov <mn@mn.com.ua> Signed-off-by: Robin Stocker <robin@nibor.org> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r--egit.psf19
-rw-r--r--org.eclipse.egit-feature/feature.xml5
-rw-r--r--org.eclipse.egit-updatesite/site.xml3
-rw-r--r--org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/GitProjectSetCapabilityTest.java240
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java12
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/GitProjectSetCapability.java274
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties5
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/internal/GitRepositoryProviderType.java7
-rw-r--r--org.eclipse.egit.psf-feature/.gitignore1
-rw-r--r--org.eclipse.egit.psf-feature/.project17
-rw-r--r--org.eclipse.egit.psf-feature/build.properties4
-rw-r--r--org.eclipse.egit.psf-feature/epl-v10.html261
-rw-r--r--org.eclipse.egit.psf-feature/feature.properties159
-rw-r--r--org.eclipse.egit.psf-feature/feature.xml29
-rw-r--r--org.eclipse.egit.psf-feature/license.html108
-rw-r--r--org.eclipse.egit.psf-feature/pom.xml27
-rw-r--r--pom.xml2
17 files changed, 1173 insertions, 0 deletions
diff --git a/egit.psf b/egit.psf
new file mode 100644
index 0000000..320d294
--- /dev/null
+++ b/egit.psf
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<psf version="2.0">
+<provider id="org.eclipse.egit.core.GitProvider">
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.console"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.packaging/org.eclipse.jgit.feature"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.junit"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.pgm"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.test"/>
+<project reference="1.0,git://egit.eclipse.org/jgit.git,master,org.eclipse.jgit.ui"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit.core"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit.core.test"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit-feature"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit.ui"/>
+<project reference="1.0,git://egit.eclipse.org/egit.git,master,org.eclipse.egit-updatesite"/>
+</provider>
+</psf>
diff --git a/org.eclipse.egit-feature/feature.xml b/org.eclipse.egit-feature/feature.xml
index d6d4b6b..a3da961 100644
--- a/org.eclipse.egit-feature/feature.xml
+++ b/org.eclipse.egit-feature/feature.xml
@@ -23,6 +23,11 @@
<discovery label="%updateSiteName" url="http://download.eclipse.org/egit/updates"/>
</url>
+ <includes
+ id="org.eclipse.egit.psf"
+ version="0.0.0"
+ optional="true"/>
+
<requires>
<import plugin="org.eclipse.core.runtime" version="3.4" match="compatible"/>
<import plugin="org.eclipse.core.resources" version="3.4.0" match="compatible"/>
diff --git a/org.eclipse.egit-updatesite/site.xml b/org.eclipse.egit-updatesite/site.xml
index a8dcf59..cddb0fc 100644
--- a/org.eclipse.egit-updatesite/site.xml
+++ b/org.eclipse.egit-updatesite/site.xml
@@ -12,6 +12,9 @@
<feature url="features/org.eclipse.egit.mylyn_0.0.0.qualifier.jar" id="org.eclipse.egit.mylyn" version="0.0.0" patch="false">
<category name="Eclipse Git Team Provider"/>
</feature>
+ <feature url="features/org.eclipse.egit.psf_0.0.0.qualifier.jar" id="org.eclipse.egit.psf" version="0.0.0" patch="false">
+ <category name="Eclipse Git Team Provider"/>
+ </feature>
<feature url="features/org.eclipse.jgit_0.0.0.qualifier.jar" id="org.eclipse.jgit" version="0.0.0" patch="true">
<category name="JGit"/>
</feature>
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/GitProjectSetCapabilityTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/GitProjectSetCapabilityTest.java
new file mode 100644
index 0000000..78457c0
--- /dev/null
+++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/GitProjectSetCapabilityTest.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Robin Stocker <robin@nibor.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.core.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.egit.core.Activator;
+import org.eclipse.egit.core.GitProjectSetCapability;
+import org.eclipse.egit.core.op.ConnectProviderOperation;
+import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepository;
+import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.team.core.ProjectSetSerializationContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitProjectSetCapabilityTest {
+
+ private GitProjectSetCapability capability;
+
+ private List<IProject> createdProjects = new ArrayList<IProject>();
+ private List<File> pathsToClean = new ArrayList<File>();
+
+ @Before
+ public void setUp() {
+ Activator.getDefault().getRepositoryCache().clear();
+ capability = new GitProjectSetCapability();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Activator.getDefault().getRepositoryCache().clear();
+ for (IProject project : createdProjects)
+ if (project.exists())
+ project.delete(true, true, null);
+ for (File pathToClean : pathsToClean)
+ if (pathToClean.exists())
+ FileUtils.delete(pathToClean, FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
+
+ @Test
+ public void testExport() throws Exception {
+ IProject aProject = createProject("a");
+ File aRepo = createRepository(aProject.getLocation(), "http://example.org/repo-a", "master");
+ connectProject(aProject, aRepo);
+
+ IPath bPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().append("b");
+ File bRepo = createRepository(bPath, "http://example.org/repo-b", "master");
+ IProject baProject = createProject(bPath, "ba");
+ IProject bbProject = createProject(bPath, "bb");
+ connectProject(baProject, bRepo);
+ connectProject(bbProject, bRepo);
+ pathsToClean.add(bPath.toFile());
+
+ IProject cProject = createProject("c");
+ File cRepo = createRepository(cProject.getLocation(), "http://example.org/repo-c", "stable");
+ connectProject(cProject, cRepo);
+
+ IProject[] projects = new IProject[] { aProject, baProject, bbProject, cProject };
+ String[] references = capability.asReference(
+ projects, new ProjectSetSerializationContext(), new NullProgressMonitor());
+ assertEquals(4, references.length);
+ assertEquals("1.0,http://example.org/repo-a,master,.", references[0]);
+ assertEquals("1.0,http://example.org/repo-b,master,ba", references[1]);
+ assertEquals("1.0,http://example.org/repo-b,master,bb", references[2]);
+ assertEquals("1.0,http://example.org/repo-c,stable,.", references[3]);
+ }
+
+ @Test
+ public void testImport() throws Exception {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath reposPath = root.getLocation().append("repos");
+ pathsToClean.add(reposPath.toFile());
+
+ IPath aPath = reposPath.append("a");
+ IProject aProject = createProject(reposPath, "a");
+ createRepository(aPath, "notused", "master");
+ aProject.delete(false, true, null);
+
+ IPath bPath = reposPath.append("b");
+ IProject baProject = createProject(bPath, "ba");
+ IProject bbProject = createProject(bPath, "bb");
+ createRepository(bPath, "notused", "master");
+ baProject.delete(false, true, null);
+ bbProject.delete(false, true, null);
+
+ IPath cPath = reposPath.append("c");
+ IProject cProject = createProject(reposPath, "c");
+ createRepository(cPath, "notused", "stable");
+ cProject.delete(false, true, null);
+
+ String aReference = "1.0," + aPath.toFile().toURI().toString() + ",master,.";
+ String baReference = "1.0," + bPath.toFile().toURI().toString() + ",master,ba";
+ String bbReference = "1.0," + bPath.toFile().toURI().toString() + ",master,bb";
+ String cReference = "1.0," + cPath.toFile().toURI().toString() + ",stable,.";
+ String[] references = new String[] { aReference, baReference, bbReference, cReference };
+
+ capability.addToWorkspace(references,
+ new ProjectSetSerializationContext(),
+ new NullProgressMonitor());
+
+ pathsToClean.add(root.getLocation().append("b").toFile());
+
+ IProject aImported = root.getProject("a");
+ createdProjects.add(aImported);
+ assertTrue(aImported.exists());
+ assertNotNull(RepositoryMapping.getMapping(aImported));
+
+ IProject baImported = root.getProject("ba");
+ createdProjects.add(baImported);
+ assertTrue(baImported.exists());
+ assertEquals(root.getLocation().append("b/ba"), baImported.getLocation());
+ assertNotNull(RepositoryMapping.getMapping(baImported));
+
+ IProject bbImported = root.getProject("bb");
+ createdProjects.add(bbImported);
+ assertTrue(bbImported.exists());
+ assertEquals(root.getLocation().append("b/bb"), bbImported.getLocation());
+ assertNotNull(RepositoryMapping.getMapping(bbImported));
+
+ IProject cImported = root.getProject("c");
+ createdProjects.add(cImported);
+ assertTrue(cImported.exists());
+ RepositoryMapping cMapping = RepositoryMapping.getMapping(cImported);
+ assertNotNull(cMapping);
+ assertEquals("stable", cMapping.getRepository().getBranch());
+ }
+
+ @Test
+ public void testImportWithDifferentBranchesOfSameRepo() throws Exception {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath reposPath = root.getLocation().append("repos");
+ pathsToClean.add(reposPath.toFile());
+
+ IPath xPath = reposPath.append("x");
+ IProject xaProject = createProject(xPath, "xa");
+ IProject xbProject = createProject(xPath, "xb");
+ createRepository(xPath, "notused", "stable");
+ xaProject.delete(false, true, null);
+ xbProject.delete(false, true, null);
+
+ String xaMasterReference = "1.0," + xPath.toFile().toURI().toString() + ",master,xa";
+ String xbStableReference = "1.0," + xPath.toFile().toURI().toString() + ",stable,xb";
+ String[] references = new String[] { xaMasterReference, xbStableReference };
+
+ capability.addToWorkspace(references,
+ new ProjectSetSerializationContext(),
+ new NullProgressMonitor());
+
+ pathsToClean.add(root.getLocation().append("x").toFile());
+ pathsToClean.add(root.getLocation().append("x_stable").toFile());
+
+ IProject xaImported = root.getProject("xa");
+ createdProjects.add(xaImported);
+ assertTrue(xaImported.exists());
+ assertEquals(root.getLocation().append("x/xa"), xaImported.getLocation());
+ RepositoryMapping xaMapping = RepositoryMapping.getMapping(xaImported);
+ assertNotNull(xaMapping);
+ assertEquals("master", xaMapping.getRepository().getBranch());
+
+ IProject xbImported = root.getProject("xb");
+ createdProjects.add(xbImported);
+ assertTrue(xbImported.exists());
+ assertEquals(root.getLocation().append("x_stable/xb"), xbImported.getLocation());
+ RepositoryMapping xbMapping = RepositoryMapping.getMapping(xbImported);
+ assertNotNull(xbMapping);
+ assertEquals("stable", xbMapping.getRepository().getBranch());
+ }
+
+ private IProject createProject(String name) throws CoreException {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IProject p = root.getProject(name);
+ p.create(null);
+ p.open(null);
+
+ createdProjects.add(p);
+ return p;
+ }
+
+ private IProject createProject(IPath parentLocation, String name) throws CoreException {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ IProject p = root.getProject(name);
+ IProjectDescription projectDescription = ResourcesPlugin.getWorkspace().newProjectDescription(p.getName());
+ projectDescription.setLocation(parentLocation.append(name));
+ p.create(projectDescription, null);
+ p.open(null);
+
+ createdProjects.add(p);
+ return p;
+ }
+
+ private File createRepository(IPath location, String url, String branch) throws Exception {
+ File gitDirectory = new File(location.toFile(), Constants.DOT_GIT);
+ Repository repo = new FileRepository(gitDirectory);
+ repo.getConfig().setString(ConfigConstants.CONFIG_REMOTE_SECTION, "origin", ConfigConstants.CONFIG_KEY_URL, url);
+ repo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION, branch, ConfigConstants.CONFIG_KEY_REMOTE, "origin");
+ repo.create();
+ repo.close();
+
+ Git git = new Git(repo);
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("initial").call();
+ if (!branch.equals("master"))
+ git.checkout().setName(branch).setCreateBranch(true).call();
+
+ pathsToClean.add(gitDirectory);
+ return gitDirectory;
+ }
+
+ private void connectProject(IProject project, File gitDir) throws CoreException {
+ ConnectProviderOperation operation = new ConnectProviderOperation(
+ project.getProject(), gitDir);
+ operation.execute(null);
+ }
+}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
index 9bb557a..f827a68 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
@@ -276,6 +276,18 @@ public class CoreText extends NLS {
public static String OperationNotYetExecuted;
/** */
+ public static String GitProjectSetCapability_InvalidTokensCount;
+
+ /** */
+ public static String GitProjectSetCapability_CloneToExistingDirectory;
+
+ /** */
+ public static String GitProjectSetCapability_ExportCouldNotGetBranch;
+
+ /** */
+ public static String GitProjectSetCapability_ExportNoRemote;
+
+ /** */
public static String IgnoreOperation_error;
/** */
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/GitProjectSetCapability.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/GitProjectSetCapability.java
new file mode 100644
index 0000000..ff573fd
--- /dev/null
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/GitProjectSetCapability.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright (C) 2009, Mykola Nikishov <mn@mn.com.ua>
+ * Copyright (C) 2011, Robin Stocker <robin@nibor.org>
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.egit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.core.op.CloneOperation;
+import org.eclipse.egit.core.op.ConnectProviderOperation;
+import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.team.core.ProjectSetCapability;
+import org.eclipse.team.core.ProjectSetSerializationContext;
+import org.eclipse.team.core.TeamException;
+
+/**
+ * Capability for exporting and importing projects shared with Git as part of a
+ * team project set.
+ */
+public final class GitProjectSetCapability extends ProjectSetCapability {
+
+ private static final String SEPARATOR = ","; //$NON-NLS-1$
+ private static final String VERSION = "1.0"; //$NON-NLS-1$
+
+ private final class ProjectReferenceComparator implements
+ Comparator<ProjectReference> {
+ public int compare(ProjectReference o1, ProjectReference o2) {
+ final boolean reposEqual = o1.repository.equals(o2.repository);
+ final boolean branchesEqual = o1.branch
+ .equals(o2.branch);
+ final boolean projectDirsEqual = o1.projectDir
+ .equals(o2.projectDir);
+ return reposEqual && branchesEqual && projectDirsEqual ? 0 : 1;
+ }
+ }
+
+ final class ProjectReference {
+
+ private static final String DEFAULT_BRANCH = Constants.MASTER;
+
+ /**
+ * the version of the reference string
+ */
+ String version;
+
+ /**
+ * a relative path (from the repository root) to a project
+ */
+ String projectDir;
+
+ /**
+ * <code>repository</code> parameter
+ */
+ URIish repository;
+
+ /**
+ * the remote branch that will be checked out, see <code>--branch</code>
+ * option
+ */
+ String branch = DEFAULT_BRANCH;
+
+ /**
+ * use this name instead of using the remote name origin to keep track
+ * of the upstream repository, see <code>--origin</code> option.
+ */
+ String origin = Constants.DEFAULT_REMOTE_NAME;
+
+ @SuppressWarnings("boxing")
+ ProjectReference(final String reference) throws URISyntaxException, IllegalArgumentException {
+ final String[] tokens = reference.split(Pattern.quote(SEPARATOR));
+ if (tokens.length != 4)
+ throw new IllegalArgumentException(NLS.bind(
+ CoreText.GitProjectSetCapability_InvalidTokensCount, new Object[] {
+ 4, tokens.length, tokens }));
+
+ this.version = tokens[0];
+ this.repository = new URIish(tokens[1]);
+ if (!"".equals(tokens[2])) //$NON-NLS-1$
+ this.branch = tokens[2];
+ this.projectDir = tokens[3];
+ }
+ }
+
+ @Override
+ public String[] asReference(IProject[] projects,
+ ProjectSetSerializationContext context, IProgressMonitor monitor)
+ throws TeamException {
+ String[] references = new String[projects.length];
+ for (int i = 0; i < projects.length; i++)
+ references[i] = asReference(projects[i]);
+ return references;
+ }
+
+ private String asReference(IProject project) throws TeamException {
+ RepositoryMapping mapping = RepositoryMapping.getMapping(project);
+ String branch;
+ try {
+ branch = mapping.getRepository().getBranch();
+ } catch (IOException e) {
+ throw new TeamException(NLS.bind(
+ CoreText.GitProjectSetCapability_ExportCouldNotGetBranch,
+ project.getName()));
+ }
+ StoredConfig config = mapping.getRepository().getConfig();
+ String remote = config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
+ branch, ConfigConstants.CONFIG_KEY_REMOTE);
+ String url = config.getString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ remote, ConfigConstants.CONFIG_KEY_URL);
+ if (url == null)
+ throw new TeamException(NLS.bind(
+ CoreText.GitProjectSetCapability_ExportNoRemote,
+ project.getName()));
+
+ String projectPath = mapping.getRepoRelativePath(project);
+ if (projectPath.equals("")) //$NON-NLS-1$
+ projectPath = "."; //$NON-NLS-1$
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(VERSION);
+ sb.append(SEPARATOR);
+ sb.append(url);
+ sb.append(SEPARATOR);
+ sb.append(branch);
+ sb.append(SEPARATOR);
+ sb.append(projectPath);
+
+ return sb.toString();
+ }
+
+ @Override
+ public IProject[] addToWorkspace(final String[] referenceStrings,
+ final ProjectSetSerializationContext context,
+ final IProgressMonitor monitor) throws TeamException {
+ final Map<URIish, Map<String, Set<ProjectReference>>> repositories =
+ new LinkedHashMap<URIish, Map<String, Set<ProjectReference>>>();
+ for (final String reference : referenceStrings) {
+ try {
+ final ProjectReference projectReference = new ProjectReference(
+ reference);
+ Map<String, Set<ProjectReference>> repositoryBranches = repositories
+ .get(projectReference.repository);
+ if (repositoryBranches == null) {
+ repositoryBranches = new HashMap<String, Set<ProjectReference>>();
+ repositories.put(projectReference.repository,
+ repositoryBranches);
+ }
+ Set<ProjectReference> projectReferences = repositoryBranches.get(projectReference.branch);
+ if (projectReferences == null) {
+ projectReferences = new TreeSet<ProjectReference>(new ProjectReferenceComparator());
+ repositoryBranches.put(projectReference.branch, projectReferences);
+ }
+
+ projectReferences.add(projectReference);
+ } catch (final IllegalArgumentException e) {
+ throw new TeamException(reference, e);
+ } catch (final URISyntaxException e) {
+ throw new TeamException(reference, e);
+ }
+ }
+ final ArrayList<IProject> importedProjects = new ArrayList<IProject>();
+ for (final URIish gitUrl : repositories.keySet()) {
+ Map<String, Set<ProjectReference>> branches = repositories
+ .get(gitUrl);
+ for (final String branch : branches.keySet()) {
+ final Set<ProjectReference> projects = branches.get(branch);
+ try {
+ final IPath workDir = getWorkingDir(gitUrl, branch,
+ branches.keySet());
+ if (workDir.toFile().exists()) {
+ final Collection<String> projectNames = new LinkedList<String>();
+ for (final ProjectReference projectReference : projects)
+ projectNames.add(projectReference.projectDir);
+ throw new TeamException(NLS.bind(
+ CoreText.GitProjectSetCapability_CloneToExistingDirectory,
+ new Object[] { workDir, projectNames, gitUrl }));
+ }
+
+ int timeout = 60;
+ String refName = Constants.R_HEADS + branch;
+ final CloneOperation cloneOperation = new CloneOperation(
+ gitUrl, true, null, workDir.toFile(), refName,
+ Constants.DEFAULT_REMOTE_NAME, timeout);
+ cloneOperation.run(monitor);
+
+ final File repositoryPath = workDir.append(Constants.DOT_GIT_EXT).toFile();
+
+ Activator.getDefault().getRepositoryUtil().addConfiguredRepository(repositoryPath);
+
+ // import projects from the current repository to workspace
+ final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ final IWorkspaceRoot root = workspace.getRoot();
+ for (final ProjectReference projectToImport : projects) {
+ final IPath projectDir = workDir
+ .append(projectToImport.projectDir);
+ final IProjectDescription projectDescription = workspace
+ .loadProjectDescription(projectDir
+ .append(IProjectDescription.DESCRIPTION_FILE_NAME));
+ final IProject project = root
+ .getProject(projectDescription.getName());
+ project.create(projectDescription, monitor);
+ importedProjects.add(project);
+
+ project.open(monitor);
+ final ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation(
+ project, repositoryPath);
+ connectProviderOperation.execute(monitor);
+ }
+ } catch (final InvocationTargetException e) {
+ throw TeamException.asTeamException(e);
+ } catch (final CoreException e) {
+ throw TeamException.asTeamException(e);
+ } catch (final InterruptedException e) {
+ // was canceled by user
+ return new IProject[0];
+ }
+ }
+ }
+ final IProject[] result = importedProjects
+ .toArray(new IProject[importedProjects.size()]);
+ return result;
+ }
+
+ /**
+ * @param gitUrl
+ * @param branch the branch to check out
+ * @param allBranches all branches which should be checked out for this gitUrl
+ * @return the directory where the project should be checked out
+ */
+ private static IPath getWorkingDir(URIish gitUrl, String branch, Set<String> allBranches) {
+ final IPath workspaceLocation = ResourcesPlugin.getWorkspace()
+ .getRoot().getRawLocation();
+ final String humanishName = gitUrl.getHumanishName();
+ String extendedName;
+ if (allBranches.size() == 1 || branch.equals(Constants.MASTER))
+ extendedName = humanishName;
+ else
+ extendedName = humanishName + "_" + branch; //$NON-NLS-1$
+ final IPath workDir = workspaceLocation.append(extendedName);
+ return workDir;
+ }
+
+}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
index d57325c..6eba656 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
@@ -71,6 +71,11 @@ The resource cannot be moved, renamed or deleted due to an internal error.
Error_CanonicalFile=Unable to determine a canonical file path.
+GitProjectSetCapability_InvalidTokensCount={0} tokens expected in project reference but {1} had been found: {2}
+GitProjectSetCapability_CloneToExistingDirectory=Destination directory {0} exists. Don't clone {1} from {2} to prevent data loss.
+GitProjectSetCapability_ExportCouldNotGetBranch=Could not get current branch from repository of project {0}.
+GitProjectSetCapability_ExportNoRemote=No remote URL configured for current branch in repository of project {0}.
+
CloneOperation_checkingOutFiles=Checking out files
CloneOperation_initializingRepository=Initializing local repository
CloneOperation_title=Cloning from {0}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/GitRepositoryProviderType.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/GitRepositoryProviderType.java
index 4626dfc..97d550a 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/GitRepositoryProviderType.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/GitRepositoryProviderType.java
@@ -7,17 +7,20 @@
*
* Contributors:
* Chris Aniszczyk <caniszczyk@gmail.com> - initial API and implementation
+ * Robin Stocker <robin@nibor.org> - ProjectSetCapability
*******************************************************************************/
package org.eclipse.egit.core.internal;
import java.io.IOException;
import org.eclipse.egit.core.Activator;
+import org.eclipse.egit.core.GitProjectSetCapability;
import org.eclipse.egit.core.synchronize.GitResourceVariantTreeSubscriber;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.team.core.ProjectSetCapability;
import org.eclipse.team.core.RepositoryProviderType;
import org.eclipse.team.core.subscribers.Subscriber;
@@ -43,4 +46,8 @@ public class GitRepositoryProviderType extends RepositoryProviderType {
return new GitResourceVariantTreeSubscriber(set);
}
+ @Override
+ public ProjectSetCapability getProjectSetCapability() {
+ return new GitProjectSetCapability();
+ }
}
diff --git a/org.eclipse.egit.psf-feature/.gitignore b/org.eclipse.egit.psf-feature/.gitignore
new file mode 100644
index 0000000..2f7896d
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/org.eclipse.egit.psf-feature/.project b/org.eclipse.egit.psf-feature/.project
new file mode 100644
index 0000000..70d4c26
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.egit.psf-feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.egit.psf-feature/build.properties b/org.eclipse.egit.psf-feature/build.properties
new file mode 100644
index 0000000..c1d5701
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/build.properties
@@ -0,0 +1,4 @@
+bin.includes = feature.xml,\
+ feature.properties,\
+ epl-v10.html,\
+ license.html
diff --git a/org.eclipse.egit.psf-feature/epl-v10.html b/org.eclipse.egit.psf-feature/epl-v10.html
new file mode 100644
index 0000000..6d5bbe8
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/epl-v10.html
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Public License - Version 1.0</title>
+<style type="text/css">
+ body {
+ size: 8.5in 11.0in;
+ margin: 0.25in 0.5in 0.25in 0.5in;
+ tab-interval: 0.5in;
+ }
+ p {
+ margin-left: auto;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+ p.list {
+ margin-left: 0.5in;
+ margin-top: 0.05em;
+ margin-bottom: 0.05em;
+ }
+ </style>
+
+</head>
+
+<body lang="EN-US">
+
+<h2>Eclipse Public License - v 1.0</h2>
+
+<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.</p>
+
+<p><b>1. DEFINITIONS</b></p>
+
+<p>&quot;Contribution&quot; means:</p>
+
+<p class="list">a) in the case of the initial Contributor, the initial
+code and documentation distributed under this Agreement, and</p>
+<p class="list">b) in the case of each subsequent Contributor:</p>
+<p class="list">i) changes to the Program, and</p>
+<p class="list">ii) additions to the Program;</p>
+<p class="list">where such changes and/or additions to the Program
+originate from and are distributed by that particular Contributor. A
+Contribution 'originates' from a Contributor if it was added to the
+Program by such Contributor itself or anyone acting on such
+Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.</p>
+
+<p>&quot;Contributor&quot; means any person or entity that distributes
+the Program.</p>
+
+<p>&quot;Licensed Patents&quot; mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program.</p>
+
+<p>&quot;Program&quot; means the Contributions distributed in accordance
+with this Agreement.</p>
+
+<p>&quot;Recipient&quot; means anyone who receives the Program under
+this Agreement, including all Contributors.</p>
+
+<p><b>2. GRANT OF RIGHTS</b></p>
+
+<p class="list">a) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works
+of, publicly display, publicly perform, distribute and sublicense the
+Contribution of such Contributor, if any, and such derivative works, in
+source code and object code form.</p>
+
+<p class="list">b) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell,
+offer to sell, import and otherwise transfer the Contribution of such
+Contributor, if any, in source code and object code form. This patent
+license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to be covered
+by the Licensed Patents. The patent license shall not apply to any other
+combinations which include the Contribution. No hardware per se is
+licensed hereunder.</p>
+
+<p class="list">c) Recipient understands that although each Contributor
+grants the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe the
+patent or other intellectual property rights of any other entity. Each
+Contributor disclaims any liability to Recipient for claims brought by
+any other entity based on infringement of intellectual property rights
+or otherwise. As a condition to exercising the rights and licenses
+granted hereunder, each Recipient hereby assumes sole responsibility to
+secure any other intellectual property rights needed, if any. For
+example, if a third party patent license is required to allow Recipient
+to distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.</p>
+
+<p class="list">d) Each Contributor represents that to its knowledge it
+has sufficient copyright rights in its Contribution, if any, to grant
+the copyright license set forth in this Agreement.</p>
+
+<p><b>3. REQUIREMENTS</b></p>
+
+<p>A Contributor may choose to distribute the Program in object code
+form under its own license agreement, provided that:</p>
+
+<p class="list">a) it complies with the terms and conditions of this
+Agreement; and</p>
+
+<p class="list">b) its license agreement:</p>
+
+<p class="list">i) effectively disclaims on behalf of all Contributors
+all warranties and conditions, express and implied, including warranties
+or conditions of title and non-infringement, and implied warranties or
+conditions of merchantability and fitness for a particular purpose;</p>
+
+<p class="list">ii) effectively excludes on behalf of all Contributors
+all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;</p>
+
+<p class="list">iii) states that any provisions which differ from this
+Agreement are offered by that Contributor alone and not by any other
+party; and</p>
+
+<p class="list">iv) states that source code for the Program is available
+from such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for software
+exchange.</p>
+
+<p>When the Program is made available in source code form:</p>
+
+<p class="list">a) it must be made available under this Agreement; and</p>
+
+<p class="list">b) a copy of this Agreement must be included with each
+copy of the Program.</p>
+
+<p>Contributors may not remove or alter any copyright notices contained
+within the Program.</p>
+
+<p>Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.</p>
+
+<p><b>4. COMMERCIAL DISTRIBUTION</b></p>
+
+<p>Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+(&quot;Commercial Contributor&quot;) hereby agrees to defend and
+indemnify every other Contributor (&quot;Indemnified Contributor&quot;)
+against any losses, damages and costs (collectively &quot;Losses&quot;)
+arising from claims, lawsuits and other legal actions brought by a third
+party against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In
+order to qualify, an Indemnified Contributor must: a) promptly notify
+the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial
+Contributor in, the defense and any related settlement negotiations. The
+Indemnified Contributor may participate in any such claim at its own
+expense.</p>
+
+<p>For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any other
+Contributor to pay any damages as a result, the Commercial Contributor
+must pay those damages.</p>
+
+<p><b>5. NO WARRANTY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to
+the risks and costs of program errors, compliance with applicable laws,
+damage to or loss of data, programs or equipment, and unavailability or
+interruption of operations.</p>
+
+<p><b>6. DISCLAIMER OF LIABILITY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
+
+<p><b>7. GENERAL</b></p>
+
+<p>If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further action
+by the parties hereto, such provision shall be reformed to the minimum
+extent necessary to make such provision valid and enforceable.</p>
+
+<p>If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other
+software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the
+date such litigation is filed.</p>
+
+<p>All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time
+after becoming aware of such noncompliance. If all Recipient's rights
+under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive.</p>
+
+<p>Everyone is permitted to copy and distribute copies of this
+Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The
+Agreement Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other than the
+Agreement Steward has the right to modify this Agreement. The Eclipse
+Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a
+suitable separate entity. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version
+of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version. Except as
+expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+rights or licenses to the intellectual property of any Contributor under
+this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this
+Agreement are reserved.</p>
+
+<p>This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No party
+to this Agreement will bring a legal action under this Agreement more
+than one year after the cause of action arose. Each party waives its
+rights to a jury trial in any resulting litigation.</p>
+
+</body>
+
+</html>
diff --git a/org.eclipse.egit.psf-feature/feature.properties b/org.eclipse.egit.psf-feature/feature.properties
new file mode 100644
index 0000000..c49a9fa
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/feature.properties
@@ -0,0 +1,159 @@
+###############################################################################
+# Copyright (c) 2011 Robin Stocker 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
+###############################################################################
+
+featureName=EGit Project Set Support
+providerName=Eclipse EGit
+
+updateSiteName=Eclipse EGit Update Site
+
+# description property - text of the "Feature Description"
+description=\
+Project Set support for EGit for Eclipse 3.6 and earlier.\n
+################ end of description property ##################################
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2011 Robin Stocker and others.\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License v1.0\n\
+which accompanies this distribution, and is available at\n\
+http://www.eclipse.org/legal/epl-v10.html\n
+################ end of copyright property ####################################
+
+# "licenseURL" property - URL of the "Feature License"
+# do not translate value - just change to point to a locale-specific HTML page
+licenseURL=license.html
+
+# "license" property - text of the "Feature Update License"
+# should be plain text version of license agreement pointed to be "licenseURL"
+license=\
+Eclipse Foundation Software User Agreement\n\
+February 1, 2011\n\
+\n\
+Usage Of Content\n\
+\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
+OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
+USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
+AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
+NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU\n\
+AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
+AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
+OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+\n\
+Applicable Licenses\n\
+\n\
+Unless otherwise indicated, all Content made available by the\n\
+Eclipse Foundation is provided to you under the terms and conditions of\n\
+the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
+provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
+For purposes of the EPL, "Program" will mean the Content.\n\
+\n\
+Content includes, but is not limited to, source code, object code,\n\
+documentation and other files maintained in the Eclipse Foundation source code\n\
+repository ("Repository") in software modules ("Modules") and made available\n\
+as downloadable archives ("Downloads").\n\
+\n\
+ - Content may be structured and packaged into modules to facilitate delivering,\n\
+ extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
+ plug-in fragments ("Fragments"), and features ("Features").\n\
+ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
+ in a directory named "plugins".\n\
+ - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
+ Each Feature may be packaged as a sub-directory in a directory named "features".\n\
+ Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
+ numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
+ - Features may also include other Features ("Included Features"). Within a Feature, files\n\
+ named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+\n\
+The terms and conditions governing Plug-ins and Fragments should be\n\
+contained in files named "about.html" ("Abouts"). The terms and\n\
+conditions governing Features and Included Features should be contained\n\
+in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
+Licenses may be located in any directory of a Download or Module\n\
+including, but not limited to the following locations:\n\
+\n\
+ - The top-level (root) directory\n\
+ - Plug-in and Fragment directories\n\
+ - Inside Plug-ins and Fragments packaged as JARs\n\
+ - Sub-directories of the directory named "src" of certain Plug-ins\n\
+ - Feature directories\n\
+\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
+Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
+Update License") during the installation process. If the Feature contains\n\
+Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform\n\
+you where you can locate them. Feature Update Licenses may be found in\n\
+the "license" property of files named "feature.properties" found within a Feature.\n\
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
+terms and conditions (or references to such terms and conditions) that\n\
+govern your use of the associated Content in that directory.\n\
+\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
+SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+\n\
+ - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+ - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
+ - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
+ - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
+ - Metro Link Public License 1.00 (available at http://www.opengroup.org/openmotif/supporters/metrolink/license.html)\n\
+ - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
+TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
+is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
+govern that particular Content.\n\
+\n\
+\n\Use of Provisioning Technology\n\
+\n\
+The Eclipse Foundation makes available provisioning software, examples of which include,\n\
+but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
+the purpose of allowing users to install software, documentation, information and/or\n\
+other materials (collectively "Installable Software"). This capability is provided with\n\
+the intent of allowing such users to install, extend and update Eclipse-based products.\n\
+Information about packaging Installable Software is available at\n\
+http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
+\n\
+You may use Provisioning Technology to allow other parties to install Installable Software.\n\
+You shall be responsible for enabling the applicable license agreements relating to the\n\
+Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
+in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
+making it available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the following:\n\
+\n\
+ 1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
+ the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
+ extending or updating the functionality of an Eclipse-based product.\n\
+ 2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
+ Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
+ 3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
+ govern the use of the Installable Software ("Installable Software Agreement") and such\n\
+ Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
+ with the Specification. Such Installable Software Agreement must inform the user of the\n\
+ terms and conditions that govern the Installable Software and must solicit acceptance by\n\
+ the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
+ indication of agreement by the user, the provisioning Technology will complete installation\n\
+ of the Installable Software.\n\
+\n\
+Cryptography\n\
+\n\
+Content may contain encryption software. The country in which you are\n\
+currently may have restrictions on the import, possession, and use,\n\
+and/or re-export to another country, of encryption software. BEFORE\n\
+using any encryption software, please check the country's laws,\n\
+regulations and policies concerning the import, possession, or use, and\n\
+re-export of encryption software, to see if this is permitted.\n\
+\n\
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
+########### end of license property ##########################################
+
diff --git a/org.eclipse.egit.psf-feature/feature.xml b/org.eclipse.egit.psf-feature/feature.xml
new file mode 100644
index 0000000..41c3c10
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/feature.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.egit.psf"
+ label="%featureName"
+ version="1.1.0.qualifier"
+ provider-name="%providerName">
+
+ <description>
+ %description
+ </description>
+
+ <copyright>
+ %copyright
+ </copyright>
+
+ <license url="%licenseURL">
+ %license
+ </license>
+
+ <url>
+ <update label="%updateSiteName" url="http://download.eclipse.org/egit/updates"/>
+ </url>
+
+ <requires>
+ <import plugin="org.eclipse.core.runtime.compatibility" version="3.2.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.egit.core" version="1.1.0" match="equivalent"/>
+ </requires>
+
+</feature>
diff --git a/org.eclipse.egit.psf-feature/license.html b/org.eclipse.egit.psf-feature/license.html
new file mode 100644
index 0000000..f19c483
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/license.html
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ (&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+ <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+ <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+ <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.</li>
+ <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+ <li>The top-level (root) directory</li>
+ <li>Plug-in and Fragment directories</li>
+ <li>Inside Plug-ins and Fragments packaged as JARs</li>
+ <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+ <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+ <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+ <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+ <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+ <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+ <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+ <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+ (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+ <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+ on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.</li>
+ <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.</li>
+ <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html>
diff --git a/org.eclipse.egit.psf-feature/pom.xml b/org.eclipse.egit.psf-feature/pom.xml
new file mode 100644
index 0000000..9ed02e1
--- /dev/null
+++ b/org.eclipse.egit.psf-feature/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Mykola Nikishov <mn@mn.com.ua>
+
+ 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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.egit</groupId>
+ <artifactId>egit-parent</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.egit.psf</artifactId>
+ <packaging>eclipse-feature</packaging>
+
+ <name>EGit Team Project Set Support</name>
+
+</project>
diff --git a/pom.xml b/pom.xml
index 28e9879..e0cf9e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,6 +143,8 @@
<module>org.eclipse.egit.mylyn.ui</module>
<module>org.eclipse.egit.mylyn-feature</module>
+ <module>org.eclipse.egit.psf-feature</module>
+
<module>org.eclipse.egit.doc</module>
<module>org.eclipse.egit-feature</module>
<module>org.eclipse.egit-updatesite</module>