{"thread":{"id":"18789","subject":"[EGIT PATCH 3/4] Use explicit bundle name in UIText to aid IDE integration","startedAt":"2009-04-08T15:51:28Z","lastAt":"2009-04-08T15:51:31Z","messageCount":4,"participants":["Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"110843","messageId":"1239205891-28236-1-git-send-email-robin.rosenberg@dewire.com","threadId":"18789","inReplyTo":null,"subject":"[EGIT PATCH 1/4] Add actual test for success to ConnectOperationTest","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2009-04-08T15:51:28Z","receivedAt":"2009-04-08T15:51:28Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Also remove a few obsolete lines (irrelevant asserts)\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../op/T0001_ConnectProviderOperationTest.java     |   16 +++-------------\n 1 files changed, 3 insertions(+), 13 deletions(-)\n\ndiff --git a/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java b/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\nindex 092c048..1d332a3 100644\n--- a/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\n+++ b/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\n@@ -89,19 +89,6 @@ public void testNewUnsharedFile() throws CoreException, IOException,\n \t\tlck.setNewObjectId(id);\n \t\tassertEquals(RefUpdate.Result.NEW, lck.forceUpdate());\n \n-\t\t// helper asserts, this is not what we are really testing\n-\t\tassertTrue(\"blob missing\", new File(gitDir,\n-\t\t\t\t\"objects/2e/2439c32d01f0ef39644d561945e8f4b2239489\").exists());\n-\n-\t\tassertTrue(\"tree missing\", new File(gitDir,\n-\t\t\t\t\"objects/87/a105cc4bc0a79885d07ec560c3eee49438acf0\").exists());\n-\t\tassertTrue(\"tree missing\", new File(gitDir,\n-\t\t\t\t\"objects/08/ccc3d91a14d337a45f355d3d63bd97fd5e4db9\").exists());\n-\t\tassertTrue(\"tree missing\", new File(gitDir,\n-\t\t\t\t\"objects/9d/aeec817090098f05eeca858e3a552d78b0a346\").exists());\n-\t\tassertTrue(\"commit missing\", new File(gitDir,\n-\t\t\t\t\"objects/09/6f1a84091b90b6d9fb12f95848da69496305c1\").exists());\n-\n \t\tConnectProviderOperation operation = new ConnectProviderOperation(\n \t\t\t\tproject.getProject(), null);\n \t\toperation.run(null);\n@@ -125,5 +112,8 @@ protected IStatus run(IProgressMonitor monitor) {\n \t\t\tThread.sleep(1000);\n \t\t}\n \t\tSystem.out.println(\"DONE\");\n+\n+\t\tassertNotNull(RepositoryProvider.getProvider(project.getProject()));\n+\n \t}\n }\n-- \n1.6.2.2.446.gfbdc0\n"},{"id":"110841","messageId":"1239205891-28236-2-git-send-email-robin.rosenberg@dewire.com","threadId":"18789","inReplyTo":"1239205891-28236-1-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 2/4] Add a method to RepositoryMapping to get the directory for not-yet-mapped projects","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2009-04-08T15:51:29Z","receivedAt":"2009-04-08T15:51:29Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Usually a RepositoryMapping has an associated Repository. Not so when it is returned\nfrom the RepositoryFinded.\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../egit/core/project/RepositoryMapping.java       |    7 +++++++\n 1 files changed, 7 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.egit.core/src/org/spearce/egit/core/project/RepositoryMapping.java b/org.spearce.egit.core/src/org/spearce/egit/core/project/RepositoryMapping.java\nindex e9df630..b49f380 100644\n--- a/org.spearce.egit.core/src/org/spearce/egit/core/project/RepositoryMapping.java\n+++ b/org.spearce.egit.core/src/org/spearce/egit/core/project/RepositoryMapping.java\n@@ -234,4 +234,11 @@ public static RepositoryMapping getMapping(final IResource resource) {\n \n \t\treturn ((GitProvider)rp).getData().getRepositoryMapping(resource);\n \t}\n+\n+\t/**\n+\t * @return the name of the .git directory\n+\t */\n+\tpublic String getGitDir() {\n+\t\treturn gitdirPath;\n+\t}\n }\n-- \n1.6.2.2.446.gfbdc0\n"},{"id":"110840","messageId":"1239205891-28236-3-git-send-email-robin.rosenberg@dewire.com","threadId":"18789","inReplyTo":"1239205891-28236-2-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 3/4] Use explicit bundle name in UIText to aid IDE integration","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2009-04-08T15:51:30Z","receivedAt":"2009-04-08T15:51:30Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"When the bundle name is specified as a raw string Eclipse will pick up\nthe location of the uitext.properties file and display the actual string\nvalue when hovering over UIText declarations. It also allows direct\nnavigation to the uitext.properties string from a declaration.\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../src/org/spearce/egit/core/CoreText.java        |    3 +--\n 1 files changed, 1 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java b/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\nindex d81a008..46a7ef6 100644\n--- a/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\n+++ b/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\n@@ -106,7 +106,6 @@\n \tpublic static String PushOperation_taskNameNormalRun;\n \n \tstatic {\n-\t\tfinal Class c = CoreText.class;\n-\t\tinitializeMessages(c.getPackage().getName() + \".coretext\", c);\n+\t\tinitializeMessages(\"org.spearce.egit.core.coretext\", CoreText.class);\n \t}\n }\n-- \n1.6.2.2.446.gfbdc0\n"},{"id":"110842","messageId":"1239205891-28236-4-git-send-email-robin.rosenberg@dewire.com","threadId":"18789","inReplyTo":"1239205891-28236-3-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 4/4] Multi-project connect to Git provider","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2009-04-08T15:51:31Z","receivedAt":"2009-04-08T15:51:31Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Eclipse supports connecting multiple projects to a repository. This\npatch implements this for Git.\n\nThe sharing Wizard has been rewritten and create support moved out\nof the ConnectOperation class to the wizard.\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../core/T0003_AdaptableFileTreeIteratorTest.java  |    2 +-\n .../egit/core/internal/mapping/T0002_history.java  |    2 +-\n .../op/T0001_ConnectProviderOperationTest.java     |   11 +-\n .../src/org/spearce/egit/core/CoreText.java        |    8 +-\n .../src/org/spearce/egit/core/coretext.properties  |    4 +-\n .../egit/core/op/ConnectProviderOperation.java     |  112 ++++------\n .../src/org/spearce/egit/ui/UIText.java            |   17 +-\n .../ui/internal/clone/GitProjectsImportPage.java   |    2 +-\n .../ui/internal/sharing/ExistingOrNewPage.java     |  235 ++++++++++++++++----\n .../egit/ui/internal/sharing/SharingWizard.java    |   53 ++---\n .../src/org/spearce/egit/ui/uitext.properties      |   11 +-\n 11 files changed, 283 insertions(+), 174 deletions(-)\n\ndiff --git a/org.spearce.egit.core.test/src/org/spearce/egit/core/T0003_AdaptableFileTreeIteratorTest.java b/org.spearce.egit.core.test/src/org/spearce/egit/core/T0003_AdaptableFileTreeIteratorTest.java\nindex 1e2fe03..63e0798 100644\n--- a/org.spearce.egit.core.test/src/org/spearce/egit/core/T0003_AdaptableFileTreeIteratorTest.java\n+++ b/org.spearce.egit.core.test/src/org/spearce/egit/core/T0003_AdaptableFileTreeIteratorTest.java\n@@ -44,7 +44,7 @@ protected void setUp() throws Exception {\n \t\tfileWriter.close();\n \n \t\tfinal ConnectProviderOperation operation = new ConnectProviderOperation(\n-\t\t\t\tproject.getProject(), null);\n+\t\t\t\tproject.getProject());\n \t\toperation.run(null);\n \t}\n \ndiff --git a/org.spearce.egit.core.test/src/org/spearce/egit/core/internal/mapping/T0002_history.java b/org.spearce.egit.core.test/src/org/spearce/egit/core/internal/mapping/T0002_history.java\nindex 148e61e..735540e 100644\n--- a/org.spearce.egit.core.test/src/org/spearce/egit/core/internal/mapping/T0002_history.java\n+++ b/org.spearce.egit.core.test/src/org/spearce/egit/core/internal/mapping/T0002_history.java\n@@ -78,7 +78,7 @@ protected void setUp() throws Exception {\n \t\tassertEquals(RefUpdate.Result.NEW, lck.forceUpdate());\n \n \t\tConnectProviderOperation operation = new ConnectProviderOperation(\n-\t\t\t\tproject.getProject(), null);\n+\t\t\t\tproject.getProject());\n \t\toperation.run(null);\n \t}\n \ndiff --git a/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java b/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\nindex 1d332a3..f891262 100644\n--- a/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\n+++ b/org.spearce.egit.core.test/src/org/spearce/egit/core/op/T0001_ConnectProviderOperationTest.java\n@@ -35,7 +35,7 @@\n \tpublic void testNoRepository() throws CoreException {\n \n \t\tConnectProviderOperation operation = new ConnectProviderOperation(\n-\t\t\t\tproject.getProject(), null);\n+\t\t\t\tproject.getProject());\n \t\toperation.run(null);\n \n \t\t// We are shared because we declared as shared\n@@ -43,12 +43,15 @@ public void testNoRepository() throws CoreException {\n \t\tassertTrue(!gitDir.exists());\n \t}\n \n-\tpublic void testNewRepository() throws CoreException {\n+\tpublic void testNewRepository() throws CoreException, IOException {\n \n \t\tFile gitDir = new File(project.getProject().getWorkspace().getRoot()\n \t\t\t\t.getRawLocation().toFile(), \".git\");\n+\t\tRepository repository = new Repository(gitDir);\n+\t\trepository.create();\n+\t\trepository.close();\n \t\tConnectProviderOperation operation = new ConnectProviderOperation(\n-\t\t\t\tproject.getProject(), gitDir);\n+\t\t\t\tproject.getProject());\n \t\toperation.run(null);\n \n \t\tassertTrue(RepositoryProvider.isShared(project.getProject()));\n@@ -90,7 +93,7 @@ public void testNewUnsharedFile() throws CoreException, IOException,\n \t\tassertEquals(RefUpdate.Result.NEW, lck.forceUpdate());\n \n \t\tConnectProviderOperation operation = new ConnectProviderOperation(\n-\t\t\t\tproject.getProject(), null);\n+\t\t\t\tproject.getProject());\n \t\toperation.run(null);\n \n \t\tfinal boolean f[] = new boolean[1];\ndiff --git a/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java b/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\nindex 46a7ef6..6b2627b 100644\n--- a/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\n+++ b/org.spearce.egit.core/src/org/spearce/egit/core/CoreText.java\n@@ -28,13 +28,7 @@\n \tpublic static String ConnectProviderOperation_connecting;\n \n \t/** */\n-\tpublic static String ConnectProviderOperation_creating;\n-\n-\t/** */\n-\tpublic static String ConnectProviderOperation_recordingMapping;\n-\n-\t/** */\n-\tpublic static String ConnectProviderOperation_updatingCache;\n+\tpublic static String ConnectProviderOperation_ConnectingProject;\n \n \t/** */\n \tpublic static String DisconnectProviderOperation_disconnecting;\ndiff --git a/org.spearce.egit.core/src/org/spearce/egit/core/coretext.properties b/org.spearce.egit.core/src/org/spearce/egit/core/coretext.properties\nindex a911889..663c996 100644\n--- a/org.spearce.egit.core/src/org/spearce/egit/core/coretext.properties\n+++ b/org.spearce.egit.core/src/org/spearce/egit/core/coretext.properties\n@@ -16,9 +16,7 @@\n ##\n \n ConnectProviderOperation_connecting=Connecting Git team provider.\n-ConnectProviderOperation_creating=Creating new Git repository.\n-ConnectProviderOperation_recordingMapping=Saving repository mappings.\n-ConnectProviderOperation_updatingCache=Updating workspace cache.\n+ConnectProviderOperation_ConnectingProject=Connecting project {0}\n \n DisconnectProviderOperation_disconnecting=Disconnecting Git team provider.\n \ndiff --git a/org.spearce.egit.core/src/org/spearce/egit/core/op/ConnectProviderOperation.java b/org.spearce.egit.core/src/org/spearce/egit/core/op/ConnectProviderOperation.java\nindex 7fc82ec..274fabb 100644\n--- a/org.spearce.egit.core/src/org/spearce/egit/core/op/ConnectProviderOperation.java\n+++ b/org.spearce.egit.core/src/org/spearce/egit/core/op/ConnectProviderOperation.java\n@@ -8,8 +8,6 @@\n  *******************************************************************************/\n package org.spearce.egit.core.op;\n \n-import java.io.File;\n-import java.util.ArrayList;\n import java.util.Collection;\n \n import org.eclipse.core.resources.IProject;\n@@ -19,6 +17,7 @@\n import org.eclipse.core.runtime.IProgressMonitor;\n import org.eclipse.core.runtime.NullProgressMonitor;\n import org.eclipse.core.runtime.SubProgressMonitor;\n+import org.eclipse.osgi.util.NLS;\n import org.eclipse.team.core.RepositoryProvider;\n import org.spearce.egit.core.Activator;\n import org.spearce.egit.core.CoreText;\n@@ -26,29 +25,31 @@\n import org.spearce.egit.core.project.GitProjectData;\n import org.spearce.egit.core.project.RepositoryFinder;\n import org.spearce.egit.core.project.RepositoryMapping;\n-import org.spearce.jgit.lib.Repository;\n \n /**\n- * Connects Eclipse to an existing Git repository, or creates a new one.\n+ * Connects Eclipse to an existing Git repository\n  */\n public class ConnectProviderOperation implements IWorkspaceRunnable {\n-\tprivate final IProject project;\n-\n-\tprivate final File newGitDir;\n+\tprivate final IProject[] projects;\n \n \t/**\n \t * Create a new connection operation to execute within the workspace.\n \t * \n \t * @param proj\n \t *            the project to connect to the Git team provider.\n-\t * @param newdir\n-\t *            git repository to create if the user requested a new\n-\t *            repository be constructed for this project; null to scan for\n-\t *            an existing repository and connect to that.\n \t */\n-\tpublic ConnectProviderOperation(final IProject proj, final File newdir) {\n-\t\tproject = proj;\n-\t\tnewGitDir = newdir;\n+\tpublic ConnectProviderOperation(final IProject proj) {\n+\t\tthis(new IProject[] { proj });\n+\t}\n+\n+\t/**\n+\t * Create a new connection operation to execute within the workspace.\n+\t *\n+\t * @param projects\n+\t *            the projects to connect to the Git team provider.\n+\t */\n+\tpublic ConnectProviderOperation(final IProject[] projects) {\n+\t\tthis.projects = projects;\n \t}\n \n \tpublic void run(IProgressMonitor m) throws CoreException {\n@@ -56,63 +57,42 @@ public void run(IProgressMonitor m) throws CoreException {\n \t\t\tm = new NullProgressMonitor();\n \t\t}\n \n-\t\tm.beginTask(CoreText.ConnectProviderOperation_connecting, 100);\n+\t\tm.beginTask(CoreText.ConnectProviderOperation_connecting,\n+\t\t\t\t100 * projects.length);\n \t\ttry {\n-\t\t\tfinal Collection<RepositoryMapping> repos = new ArrayList<RepositoryMapping>();\n-\n-\t\t\tif (newGitDir != null) {\n-\t\t\t\ttry {\n-\t\t\t\t\tfinal Repository db;\n-\n-\t\t\t\t\tm.subTask(CoreText.ConnectProviderOperation_creating);\n-\t\t\t\t\tActivator.trace(\"Creating repository \" + newGitDir);\n-\n-\t\t\t\t\tdb = new Repository(newGitDir);\n-\t\t\t\t\tdb.create();\n-\t\t\t\t\trepos.add(new RepositoryMapping(project, db.getDirectory()));\n-\t\t\t\t\tdb.close();\n-\n-\t\t\t\t\t// If we don't refresh the project directory right\n-\t\t\t\t\t// now we won't later know that a .git directory\n-\t\t\t\t\t// exists within it and we won't mark the .git\n-\t\t\t\t\t// directory as a team-private member. Failure\n-\t\t\t\t\t// to do so might allow someone to delete\n-\t\t\t\t\t// the .git directory without us stopping them.\n-\t\t\t\t\t//\n-\t\t\t\t\tproject.refreshLocal(IResource.DEPTH_ONE,\n-\t\t\t\t\t\t\tnew SubProgressMonitor(m, 10));\n \n+\t\t\tfor (IProject project : projects) {\n+\t\t\t\tm.setTaskName(NLS.bind(\n+\t\t\t\t\t\tCoreText.ConnectProviderOperation_ConnectingProject,\n+\t\t\t\t\t\tproject.getName()));\n+\t\t\t\tActivator.trace(\"Locating repository for \" + project); //$NON-NLS-1$\n+\t\t\t\tCollection<RepositoryMapping> repos = new RepositoryFinder(\n+\t\t\t\t\t\tproject).find(new SubProgressMonitor(m, 40));\n+\t\t\t\tif (repos.size() == 1) {\n+\t\t\t\t\tGitProjectData projectData = new GitProjectData(project);\n+\t\t\t\t\ttry {\n+\t\t\t\t\t\tprojectData.setRepositoryMappings(repos);\n+\t\t\t\t\t\tprojectData.store();\n+\t\t\t\t\t} catch (CoreException ce) {\n+\t\t\t\t\t\tGitProjectData.delete(project);\n+\t\t\t\t\t\tthrow ce;\n+\t\t\t\t\t} catch (RuntimeException ce) {\n+\t\t\t\t\t\tGitProjectData.delete(project);\n+\t\t\t\t\t\tthrow ce;\n+\t\t\t\t\t}\n+\t\t\t\t\tRepositoryProvider\n+\t\t\t\t\t\t\t.map(project, GitProvider.class.getName());\n+\t\t\t\t\tprojectData = GitProjectData.get(project);\n+\t\t\t\t\tproject.refreshLocal(IResource.DEPTH_INFINITE,\n+\t\t\t\t\t\t\tnew SubProgressMonitor(m, 50));\n \t\t\t\t\tm.worked(10);\n-\t\t\t\t} catch (Throwable err) {\n-\t\t\t\t\tthrow Activator.error(\n-\t\t\t\t\t\t\tCoreText.ConnectProviderOperation_creating, err);\n+\t\t\t\t} else {\n+\t\t\t\t\tActivator\n+\t\t\t\t\t\t\t.trace(\"Attempted to share project without repository ignored :\" //$NON-NLS-1$\n+\t\t\t\t\t\t\t\t\t+ project);\n+\t\t\t\t\tm.worked(60);\n \t\t\t\t}\n-\t\t\t} else {\n-\t\t\t\tActivator.trace(\"Finding existing repositories.\");\n-\t\t\t\trepos.addAll(new RepositoryFinder(project)\n-\t\t\t\t\t\t.find(new SubProgressMonitor(m, 20)));\n \t\t\t}\n-\n-\t\t\tm.subTask(CoreText.ConnectProviderOperation_recordingMapping);\n-\t\t\tGitProjectData projectData = new GitProjectData(project);\n-\t\t\tprojectData.setRepositoryMappings(repos);\n-\t\t\tprojectData.store();\n-\n-\t\t\ttry {\n-\t\t\t\tRepositoryProvider.map(project, GitProvider.class.getName());\n-\t\t\t} catch (CoreException ce) {\n-\t\t\t\tGitProjectData.delete(project);\n-\t\t\t\tthrow ce;\n-\t\t\t} catch (RuntimeException ce) {\n-\t\t\t\tGitProjectData.delete(project);\n-\t\t\t\tthrow ce;\n-\t\t\t}\n-\n-\t\t\tprojectData = GitProjectData.get(project);\n-\t\t\tproject.refreshLocal(IResource.DEPTH_INFINITE,\n-\t\t\t\t\tnew SubProgressMonitor(m, 50));\n-\n-\t\t\tm.subTask(CoreText.ConnectProviderOperation_updatingCache);\n \t\t} finally {\n \t\t\tm.done();\n \t\t}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\nindex f14eada..654e155 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\n@@ -68,22 +68,31 @@\n \tpublic static String GenericOperationFailed;\n \n \t/** */\n+\tpublic static String ExistingOrNewPage_CreateButton;\n+\n+\t/** */\n \tpublic static String ExistingOrNewPage_title;\n \n \t/** */\n \tpublic static String ExistingOrNewPage_description;\n \n \t/** */\n-\tpublic static String ExistingOrNewPage_groupHeader;\n+\tpublic static String ExistingOrNewPage_ErrorFailedToCreateRepository;\n+\n+\t/** */\n+\tpublic static String ExistingOrNewPage_ErrorFailedToRefreshRepository;\n+\n+\t/** */\n+\tpublic static String ExistingOrNewPage_HeaderPath;\n \n \t/** */\n-\tpublic static String ExistingOrNewPage_useExisting;\n+\tpublic static String ExistingOrNewPage_HeaderProject;\n \n \t/** */\n-\tpublic static String ExistingOrNewPage_createNew;\n+\tpublic static String ExistingOrNewPage_HeaderRepository;\n \n \t/** */\n-\tpublic static String ExistingOrNewPage_createInParent;\n+\tpublic static String ExistingOrNewPage_SymbolicValueEmptyMapping;\n \n \t/** */\n \tpublic static String GitCloneWizard_title;\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java\nindex 5d82edc..8e02cd1 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java\n@@ -711,7 +711,7 @@ private boolean createExistingProject(final ProjectRecord record,\n \t\t\t\t\tmonitor, openTicks));\n \t\t\tif (share) {\n \t\t\t\tConnectProviderOperation connectProviderOperation = new ConnectProviderOperation(\n-\t\t\t\t\t\tproject, null);\n+\t\t\t\t\t\tproject);\n \t\t\t\tconnectProviderOperation\n \t\t\t\t\t\t.run(new SubProgressMonitor(monitor, 20));\n \t\t\t}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/ExistingOrNewPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/ExistingOrNewPage.java\nindex b3ea769..8676f0a 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/ExistingOrNewPage.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/ExistingOrNewPage.java\n@@ -1,5 +1,5 @@\n /*******************************************************************************\n- * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, Robin Rosenberg\n  *\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@@ -7,80 +7,221 @@\n  *******************************************************************************/\n package org.spearce.egit.ui.internal.sharing;\n \n+import java.io.File;\n+import java.io.IOException;\n+import java.util.Collection;\n+import java.util.Iterator;\n+\n+import org.eclipse.core.resources.IProject;\n+import org.eclipse.core.resources.IResource;\n+import org.eclipse.core.runtime.CoreException;\n+import org.eclipse.core.runtime.IPath;\n+import org.eclipse.core.runtime.NullProgressMonitor;\n+import org.eclipse.core.runtime.Path;\n+import org.eclipse.jface.dialogs.MessageDialog;\n+import org.eclipse.jface.layout.GridDataFactory;\n import org.eclipse.jface.wizard.WizardPage;\n import org.eclipse.swt.SWT;\n import org.eclipse.swt.events.SelectionEvent;\n import org.eclipse.swt.events.SelectionListener;\n-import org.eclipse.swt.layout.RowLayout;\n+import org.eclipse.swt.layout.GridLayout;\n import org.eclipse.swt.widgets.Button;\n import org.eclipse.swt.widgets.Composite;\n+import org.eclipse.swt.widgets.Event;\n import org.eclipse.swt.widgets.Group;\n+import org.eclipse.swt.widgets.Listener;\n+import org.eclipse.swt.widgets.Text;\n+import org.eclipse.swt.widgets.Tree;\n+import org.eclipse.swt.widgets.TreeColumn;\n+import org.eclipse.swt.widgets.TreeItem;\n+import org.spearce.egit.core.Activator;\n+import org.spearce.egit.core.project.RepositoryFinder;\n+import org.spearce.egit.core.project.RepositoryMapping;\n import org.spearce.egit.ui.UIIcons;\n import org.spearce.egit.ui.UIText;\n+import org.spearce.jgit.lib.Repository;\n \n+/**\n+ * Wizard page for connecting projects to Git repositories.\n+ */\n class ExistingOrNewPage extends WizardPage {\n-\tfinal SharingWizard myWizard;\n-\tprivate Button createInParent;\n \n-\tExistingOrNewPage(final SharingWizard w) {\n+\tprivate final SharingWizard myWizard;\n+\tprivate Button button;\n+\tprivate Tree tree;\n+\tprivate Text repositoryToCreate;\n+\tprivate IPath minumumPath;\n+\n+\tExistingOrNewPage(SharingWizard w) {\n \t\tsuper(ExistingOrNewPage.class.getName());\n \t\tsetTitle(UIText.ExistingOrNewPage_title);\n \t\tsetDescription(UIText.ExistingOrNewPage_description);\n \t\tsetImageDescriptor(UIIcons.WIZBAN_CONNECT_REPO);\n-\t\tmyWizard = w;\n+\t\tthis.myWizard = w;\n \t}\n \n-\tpublic void createControl(final Composite parent) {\n-\t\tfinal Group g;\n-\t\tfinal Button useExisting;\n-\t\tfinal Button createNew;\n-\n-\t\tg = new Group(parent, SWT.NONE);\n-\t\tg.setText(UIText.ExistingOrNewPage_groupHeader);\n-\t\tg.setLayout(new RowLayout(SWT.VERTICAL));\n-\n-\t\tuseExisting = new Button(g, SWT.RADIO);\n-\t\tuseExisting.setText(UIText.ExistingOrNewPage_useExisting);\n-\t\tuseExisting.addSelectionListener(new SelectionListener() {\n-\t\t\tpublic void widgetDefaultSelected(final SelectionEvent e) {\n-\t\t\t\twidgetSelected(e);\n+\tpublic void createControl(Composite parent) {\n+\t\tGroup g = new Group(parent, SWT.NONE);\n+\t\tg.setLayout(new GridLayout(3,false));\n+\t\tg.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());\n+\t\ttree = new Tree(g, SWT.BORDER|SWT.MULTI);\n+\t\ttree.setHeaderVisible(true);\n+\t\ttree.setLayout(new GridLayout());\n+\t\ttree.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).span(3,1).create());\n+\t\tTreeColumn c1 = new TreeColumn(tree,SWT.NONE);\n+\t\tc1.setText(UIText.ExistingOrNewPage_HeaderProject);\n+\t\tc1.setWidth(100);\n+\t\tTreeColumn c2 = new TreeColumn(tree,SWT.NONE);\n+\t\tc2.setText(UIText.ExistingOrNewPage_HeaderPath);\n+\t\tc2.setWidth(400);\n+\t\tTreeColumn c3 = new TreeColumn(tree,SWT.NONE);\n+\t\tc3.setText(UIText.ExistingOrNewPage_HeaderRepository);\n+\t\tc3.setWidth(200);\n+\t\tfor (IProject project : myWizard.projects) {\n+\t\t\tTreeItem treeItem = new TreeItem(tree, SWT.NONE);\n+\t\t\ttreeItem.setData(project);\n+\t\t\ttreeItem.setText(0, project.getName());\n+\t\t\ttreeItem.setText(1, project.getLocation().toOSString());\n+\t\t\tRepositoryFinder repositoryFinder = new RepositoryFinder(project);\n+\t\t\tCollection<RepositoryMapping> find;\n+\t\t\ttry {\n+\t\t\t\tfind = repositoryFinder.find(new NullProgressMonitor());\n+\t\t\t\tif (find.size() == 0)\n+\t\t\t\t\ttreeItem.setText(2, \"\"); //$NON-NLS-1$\n+\t\t\t\telse {\n+\t\t\t\t\tIterator<RepositoryMapping> mi = find.iterator();\n+\t\t\t\t\tRepositoryMapping m = mi.next();\n+\t\t\t\t\tif (m.getGitDir() == null)\n+\t\t\t\t\t\ttreeItem.setText(2,UIText.ExistingOrNewPage_SymbolicValueEmptyMapping);\n+\t\t\t\t\telse\n+\t\t\t\t\t\ttreeItem.setText(2, m.getGitDir());\n+\t\t\t\t\twhile (mi.hasNext()) {\n+\t\t\t\t\t\tTreeItem treeItem2 = new TreeItem(treeItem, SWT.NONE);\n+\t\t\t\t\t\tif (m.getGitDir() == null)\n+\t\t\t\t\t\t\ttreeItem2.setText(2,UIText.ExistingOrNewPage_SymbolicValueEmptyMapping);\n+\t\t\t\t\t\telse\n+\t\t\t\t\t\t\ttreeItem2.setText(2,m.getGitDir());\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t} catch (CoreException e) {\n+\t\t\t\tTreeItem treeItem2 = new TreeItem(treeItem, SWT.BOLD|SWT.ITALIC);\n+\t\t\t\ttreeItem2.setText(e.getMessage());\n \t\t\t}\n+\t\t}\n \n-\t\t\tpublic void widgetSelected(final SelectionEvent e) {\n-\t\t\t\tmyWizard.setUseExisting();\n-\t\t\t\tcreateInParent.setEnabled(false);\n+\t\tbutton = new Button(g, SWT.PUSH);\n+\t\tbutton.setLayoutData(GridDataFactory.fillDefaults().create());\n+\t\tbutton.setText(UIText.ExistingOrNewPage_CreateButton);\n+\t\tbutton.addSelectionListener(new SelectionListener() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tFile gitDir = new File(repositoryToCreate.getText(),\".git\");\n+\t\t\t\ttry {\n+\t\t\t\t\tRepository repository = new Repository(gitDir);\n+\t\t\t\t\trepository.create();\n+\t\t\t\t\tfor (IProject project : getProjects()) {\n+\t\t\t\t\t\t// If we don't refresh the project directories right\n+\t\t\t\t\t\t// now we won't later know that a .git directory\n+\t\t\t\t\t\t// exists within it and we won't mark the .git\n+\t\t\t\t\t\t// directory as a team-private member. Failure\n+\t\t\t\t\t\t// to do so might allow someone to delete\n+\t\t\t\t\t\t// the .git directory without us stopping them.\n+\t\t\t\t\t\t// (Half lie, we should optimize so we do not\n+\t\t\t\t\t\t// refresh when the .git is not within the project)\n+\t\t\t\t\t\t//\n+\t\t\t\t\t\tif (!gitDir.toString().contains(\"..\")) //$NON-NLS-1$\n+\t\t\t\t\t\t\tproject.refreshLocal(IResource.DEPTH_ONE,\n+\t\t\t\t\t\t\t\t\tnew NullProgressMonitor());\n+\t\t\t\t\t}\n+\t\t\t\t} catch (IOException e1) {\n+\t\t\t\t\tMessageDialog.openError(getShell(), UIText.ExistingOrNewPage_ErrorFailedToCreateRepository, gitDir.toString() + \":\\n\" + e1.getMessage());\n+\t\t\t\t\tActivator.logError(\"Failed to create repository at \" + gitDir, e1); //$NON-NLS-1$\n+\t\t\t\t} catch (CoreException e2) {\n+\t\t\t\t\tActivator.logError(UIText.ExistingOrNewPage_ErrorFailedToRefreshRepository + gitDir, e2);\n+\t\t\t\t}\n+\t\t\t\tfor (TreeItem ti : tree.getSelection()) {\n+\t\t\t\t\tti.setText(2, gitDir.toString());\n+\t\t\t\t}\n+\t\t\t\tupdateCreateOptions();\n+\t\t\t\tgetContainer().updateButtons();\n+\t\t\t}\n+\t\t\tpublic void widgetDefaultSelected(SelectionEvent e) {\n \t\t\t}\n \t\t});\n-\t\tuseExisting.setSelection(true);\n-\n-\t\tcreateNew = new Button(g, SWT.RADIO);\n-\t\tcreateNew.setEnabled(myWizard.canCreateNew());\n-\t\tcreateNew.setText(UIText.ExistingOrNewPage_createNew);\n-\t\tcreateNew.addSelectionListener(new SelectionListener() {\n-\t\t\tpublic void widgetDefaultSelected(final SelectionEvent e) {\n-\t\t\t\twidgetSelected(e);\n+\t\trepositoryToCreate = new Text(g, SWT.SINGLE | SWT.BORDER);\n+\t\trepositoryToCreate.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(1,1).create());\n+\t\trepositoryToCreate.addListener(SWT.Modify, new Listener() {\n+\t\t\tpublic void handleEvent(Event e) {\n+\t\t\t\tif (e.text == null)\n+\t\t\t\t\treturn;\n+\t\t\t\tIPath fromOSString = Path.fromOSString(e.text);\n+\t\t\t\tbutton.setEnabled(minumumPath\n+\t\t\t\t\t\t.matchingFirstSegments(fromOSString) == fromOSString\n+\t\t\t\t\t\t.segmentCount());\n \t\t\t}\n-\n-\t\t\tpublic void widgetSelected(final SelectionEvent e) {\n-\t\t\t\tmyWizard.setCreateNew();\n-\t\t\t\tcreateInParent.setEnabled(true);\n+\t\t});\n+\t\tText l = new Text(g,SWT.NONE);\n+\t\tl.setEnabled(false);\n+\t\tl.setEditable(false);\n+\t\tl.setText(File.separatorChar + \".git\"); //$NON-NLS-1$\n+\t\tl.setLayoutData(GridDataFactory.fillDefaults().create());\n+\t\ttree.addSelectionListener(new SelectionListener() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tupdateCreateOptions();\n+\t\t\t}\n+\t\t\tpublic void widgetDefaultSelected(SelectionEvent e) {\n+\t\t\t\t// Empty\n \t\t\t}\n \t\t});\n+\t\tupdateCreateOptions();\n+\t\tsetControl(g);\n+\t}\n \n-\t\tcreateInParent = new Button(g, SWT.CHECK);\n-\t\tcreateInParent.setEnabled(createNew.getSelection());\n-\t\tcreateInParent.setText(UIText.ExistingOrNewPage_createInParent);\n-\t\tcreateInParent.addSelectionListener(new SelectionListener() {\n-\t\t\tpublic void widgetDefaultSelected(SelectionEvent e) {\n-\t\t\t\twidgetSelected(e);\n+\tprivate void updateCreateOptions() {\n+\t\tminumumPath = null;\n+\t\tIPath p = null;\n+\t\tfor (TreeItem ti : tree.getSelection()) {\n+\t\t\tString path = ti.getText(2);\n+\t\t\tif (!path.equals(\"\")) { //$NON-NLS-1$\n+\t\t\t\tp = null;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tString gitDirParentCandidate = ti.getText(1);\n+\t\t\tIPath thisPath = Path.fromOSString(gitDirParentCandidate);\n+\t\t\tif (p == null)\n+\t\t\t\tp = thisPath;\n+\t\t\telse {\n+\t\t\t\tint n = p.matchingFirstSegments(thisPath);\n+\t\t\t\tp = p.removeLastSegments(p.segmentCount() - n);\n \t\t\t}\n+\t\t}\n+\t\tminumumPath = p;\n+\t\tif (p != null) {\n+\t\t\trepositoryToCreate.setText(p.toOSString());\n+\t\t} else {\n+\t\t\trepositoryToCreate.setText(\"\"); //$NON-NLS-1$\n+\t\t}\n+\t\tbutton.setEnabled(p != null);\n+\t\trepositoryToCreate.setEnabled(p != null);\n+\t\tgetContainer().updateButtons();\n+\t}\n \n-\t\t\tpublic void widgetSelected(SelectionEvent e) {\n-\t\t\t\tmyWizard.setUseParent(createInParent.getSelection());\n+\t@Override\n+\tpublic boolean isPageComplete() {\n+\t\tif (tree.getSelectionCount() == 0)\n+\t\t\treturn false;\n+\t\tfor (TreeItem ti : tree.getSelection()) {\n+\t\t\tString path = ti.getText(2);\n+\t\t\tif (path.equals(\"\")) { //$NON-NLS-1$\n+\t\t\t\treturn false;\n \t\t\t}\n-\t\t});\n-\t\tcreateInParent.setSelection(true);\n-\t\tmyWizard.setUseParent(createInParent.getSelection());\n-\t\tsetControl(g);\n+\t\t}\n+\t\treturn true;\n+\t}\n+\n+\tpublic IProject[] getProjects() {\n+\t\tIProject[] ret = new IProject[tree.getSelection().length];\n+\t\tfor (int i = 0; i < ret.length; ++i)\n+\t\t\tret[i] = (IProject)tree.getSelection()[i].getData();\n+\t\treturn ret;\n \t}\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/SharingWizard.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/SharingWizard.java\nindex 292baf2..1e89ab2 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/SharingWizard.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/sharing/SharingWizard.java\n@@ -8,7 +8,6 @@\n  *******************************************************************************/\n package org.spearce.egit.ui.internal.sharing;\n \n-import java.io.File;\n import java.lang.reflect.InvocationTargetException;\n \n import org.eclipse.core.resources.IProject;\n@@ -20,6 +19,7 @@\n import org.eclipse.jface.operation.IRunnableWithProgress;\n import org.eclipse.jface.wizard.Wizard;\n import org.eclipse.team.ui.IConfigurationWizard;\n+import org.eclipse.team.ui.IConfigurationWizardExtension;\n import org.eclipse.ui.IWorkbench;\n import org.spearce.egit.core.op.ConnectProviderOperation;\n import org.spearce.egit.ui.Activator;\n@@ -27,16 +27,13 @@\n \n /**\n  * The dialog used for activating Team>Share, i.e. to create a new\n- * Git repository or associate a project with one.\n+ * Git repository or associate projects with one.\n  */\n-public class SharingWizard extends Wizard implements IConfigurationWizard {\n-\tprivate IProject project;\n+public class SharingWizard extends Wizard implements IConfigurationWizard,\n+\t\tIConfigurationWizardExtension {\n+\tIProject[] projects;\n \n-\tprivate boolean create;\n-\n-\tprivate File newGitDir;\n-\n-\tprivate boolean useParent;\n+\tprivate ExistingOrNewPage existingPage;\n \n \t/**\n \t * Construct the Git Sharing Wizard for connecting Git project to Eclipse\n@@ -46,39 +43,23 @@ public SharingWizard() {\n \t\tsetNeedsProgressMonitor(true);\n \t}\n \n-\tpublic void init(final IWorkbench workbench, final IProject p) {\n-\t\tproject = p;\n-\t\tcalculateNewGitDir();\n+\tpublic void init(IWorkbench workbench, IProject[] p) {\n+\t\tthis.projects = new IProject[p.length];\n+\t\tSystem.arraycopy(p, 0, this.projects, 0, p.length);\n \t}\n \n-\tprivate void calculateNewGitDir() {\n-\t\tFile pdir = project.getLocation().toFile();\n-\t\tif (useParent)\n-\t\t\tpdir = pdir.getParentFile();\n-\t\tnewGitDir = new File(pdir, \".git\");\n+\tpublic void init(final IWorkbench workbench, final IProject p) {\n+\t\tprojects = new IProject[] { p };\n \t}\n \n \tpublic void addPages() {\n-\t\taddPage(new ExistingOrNewPage(this));\n-\t}\n-\n-\tboolean canCreateNew() {\n-\t\treturn !newGitDir.exists();\n-\t}\n-\n-\tvoid setCreateNew() {\n-\t\tif (canCreateNew()) {\n-\t\t\tcreate = true;\n-\t\t}\n-\t}\n-\n-\tvoid setUseExisting() {\n-\t\tcreate = false;\n+\t\texistingPage = new ExistingOrNewPage(this);\n+\t\taddPage(existingPage);\n \t}\n \n \tpublic boolean performFinish() {\n \t\tfinal ConnectProviderOperation op = new ConnectProviderOperation(\n-\t\t\t\tproject, create ? newGitDir : null);\n+\t\t\t\texistingPage.getProjects());\n \t\ttry {\n \t\t\tgetContainer().run(true, false, new IRunnableWithProgress() {\n \t\t\t\tpublic void run(final IProgressMonitor monitor)\n@@ -110,8 +91,8 @@ public void run(final IProgressMonitor monitor)\n \t\t}\n \t}\n \n-\tvoid setUseParent(boolean selection) {\n-\t\tuseParent = selection;\n-\t\tcalculateNewGitDir();\n+\t@Override\n+\tpublic boolean canFinish() {\n+\t\treturn existingPage.isPageComplete();\n \t}\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\nindex 1e1a29d..1d21c81 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\n@@ -35,12 +35,15 @@ SharingWizard_failed=Failed to initialize Git team provider.\n \n GenericOperationFailed={0} Failed\n \n+ExistingOrNewPage_CreateButton=&Create...\n ExistingOrNewPage_title=Configure Git Repository\n ExistingOrNewPage_description=Select Git Repository Location\n-ExistingOrNewPage_groupHeader=Repository Location\n-ExistingOrNewPage_useExisting=Search for existing Git repositories\n-ExistingOrNewPage_createNew=Create a new Git repository for this project\n-ExistingOrNewPage_createInParent=Create repository in project's parent directory\n+ExistingOrNewPage_ErrorFailedToCreateRepository=Failed to create repository\n+ExistingOrNewPage_ErrorFailedToRefreshRepository=Failed to refresh project after creating repo at\n+ExistingOrNewPage_HeaderPath=Path\n+ExistingOrNewPage_HeaderProject=Project\n+ExistingOrNewPage_HeaderRepository=Repository\n+ExistingOrNewPage_SymbolicValueEmptyMapping=<empty repository mapping>\n \n GitCloneWizard_title=Import Git Repository\n GitCloneWizard_jobName=Cloning from {0}\n-- \n1.6.2.2.446.gfbdc0\n"}]}