In progress: [ Issue 40 ] Add support for import resolution across multiple folders https://code.google.com/p/protobuf-dt/issues/detail?id=40
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java new file mode 100644 index 0000000..73a3305 --- /dev/null +++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Google Inc. + * + * 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 com.google.eclipse.protobuf.ui.scoping; + +import static org.eclipse.emf.common.util.URI.createURI; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.*; + +import com.google.eclipse.protobuf.junit.core.XtextRule; +import com.google.eclipse.protobuf.scoping.IFileUriResolver; +import com.google.inject.*; + +/** + * Tests for <code>{@link FileUriResolver#resolveUri(String, Resource)}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class FileUriResolver_resolveUri_Test { + + @Rule public XtextRule xtext = new XtextRule(); + + private URI resourceUri; + private ResourcesStub resources; + private FileUriResolver resolver; + + @Before public void setUp() { + resources = new ResourcesStub(); + resources.resourceShouldAlwaysExist = true; + Module module = new Module() { + public void configure(Binder binder) { + binder.bind(Resources.class).toInstance(resources); + binder.bind(IFileUriResolver.class).to(FileUriResolver.class); + } + }; + Injector injector = xtext.injector().createChildInjector(module); + resourceUri = createURI("platform:/resource/src/proto/person.proto"); + resolver = (FileUriResolver) injector.getInstance(IFileUriResolver.class); + } + + @Test public void should_resolve_import_URI_if_missing_scheme() { + resolver.resolveUri("folder1/address.proto", null); +// String uri = resolver.resolveUri("folder1/address.proto", resourceUri); +// assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto")); + } +// +// @Test public void should_not_resolve_import_URI_if_not_missing_scheme() { +// String originalUri = "platform:/resource/src/proto/folder1/address.proto"; +// String uri = resolver.resolveUri(originalUri, resourceUri, resources); +// assertThat(uri, equalTo(originalUri)); +// } +// +// @Test public void should_resolve_import_URI_even_if_overlapping_folders_with_resource_URI() { +// String uri = resolver.resolveUri("src/proto/folder1/address.proto", resourceUri); +// assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto")); +// } +// +// @Test public void should_resolve_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() { +// String uri = resolver.resolveUri("src/proto/read-only/address.proto", resourceUri); +// assertThat(uri, equalTo("platform:/resource/src/proto/read-only/address.proto")); +// } +// + private static class ResourcesStub extends Resources { + boolean resourceShouldAlwaysExist; + + @Override public boolean fileExists(URI uri) { + return resourceShouldAlwaysExist; + } + } +}
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java deleted file mode 100644 index 4cf9927..0000000 --- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java +++ /dev/null
@@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. - * - * 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 com.google.eclipse.protobuf.ui.scoping; - -import static org.eclipse.emf.common.util.URI.createURI; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import org.eclipse.emf.common.util.URI; -import org.junit.Before; -import org.junit.Test; - -import com.google.eclipse.protobuf.scoping.ResourceChecker; - -/** - * Tests for <code>{@link ProtobufImportUriFixer#fixUri(String, URI, ResourceChecker)}</code>. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class ProtobufImportUriFixer_fixUri_Test { - - private URI resourceUri; - private ResourceCheckerStub resourceChecker; - private ProtobufImportUriFixer fixer; - - @Before public void setUp() { - resourceUri = createURI("platform:/resource/src/proto/person.proto"); - resourceChecker = new ResourceCheckerStub(); - resourceChecker.resourceShouldAlwaysExist = true; - fixer = new ProtobufImportUriFixer(); - } - - @Test public void should_fix_import_URI_if_missing_scheme() { - String uri = fixer.fixUri("folder1/address.proto", resourceUri, resourceChecker); - assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto")); - } - - @Test public void should_not_fix_import_URI_if_not_missing_scheme() { - String originalUri = "platform:/resource/src/proto/folder1/address.proto"; - String uri = fixer.fixUri(originalUri, resourceUri, resourceChecker); - assertThat(uri, equalTo(originalUri)); - } - - @Test public void should_fix_import_URI_even_if_overlapping_folders_with_resource_URI() { - String uri = fixer.fixUri("src/proto/folder1/address.proto", resourceUri, resourceChecker); - assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto")); - } - - @Test public void should_fix_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() { - String uri = fixer.fixUri("src/proto/read-only/address.proto", resourceUri, resourceChecker); - assertThat(uri, equalTo("platform:/resource/src/proto/read-only/address.proto")); - } - - private static class ResourceCheckerStub extends ResourceChecker { - boolean resourceShouldAlwaysExist; - - ResourceCheckerStub() { - super(null); - } - - @Override public boolean resourceExists(String uri) { - return resourceShouldAlwaysExist; - } - } -}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java index 322cdcc..5396011 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -16,13 +16,13 @@ import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution; import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; -import com.google.eclipse.protobuf.scoping.ImportUriFixer; +import com.google.eclipse.protobuf.scoping.IFileUriResolver; import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback; import com.google.eclipse.protobuf.ui.outline.LinkWithEditor; import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage; import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencesInitializer; import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferencesInitializer; -import com.google.eclipse.protobuf.ui.scoping.ProtobufImportUriFixer; +import com.google.eclipse.protobuf.ui.scoping.FileUriResolver; import com.google.inject.Binder; /** @@ -64,7 +64,7 @@ binder.bind(IPreferenceStoreInitializer.class).annotatedWith(named(name)).to(initializerType); } - public void configureImportUriResolver(Binder binder) { - binder.bind(ImportUriFixer.class).to(ProtobufImportUriFixer.class); + public void configureFileUriResolver(Binder binder) { + binder.bind(IFileUriResolver.class).to(FileUriResolver.class); } }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java similarity index 73% rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java index c0692f0..5249e26 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
@@ -15,26 +15,24 @@ import java.util.ArrayList; import java.util.List; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; import org.eclipse.xtext.util.Pair; -import com.google.eclipse.protobuf.scoping.ImportUriFixer; -import com.google.eclipse.protobuf.scoping.ResourceChecker; +import com.google.eclipse.protobuf.scoping.IFileUriResolver; import com.google.eclipse.protobuf.ui.preferences.paths.Preferences; import com.google.inject.Inject; /** * @author alruiz@google.com (Alex Ruiz) */ -public class ProtobufImportUriFixer implements ImportUriFixer { +public class FileUriResolver implements IFileUriResolver { private static final String SEPARATOR = "/"; @Inject private IPreferenceStoreAccess access; + @Inject private Resources resources; /* * The import URI is relative to the file where the import is. Protoc works fine, but the editor doesn't. @@ -51,32 +49,26 @@ * If we import "folder/proto2.proto" into proto1.proto, proto1.proto will compile fine, but the editor will complain. * We need to have the import URI as "platform:/resource/protobuf-test/folder/proto2.proto" for the editor to see it. */ - public String fixUri(String importUri, URI resourceUri, ResourceChecker checker) { + public String resolveUri(String importUri, Resource declaringResource) { if (importUri.startsWith(PREFIX)) return importUri; Pair<String, List<String>> importUriPair = pair(importUri, createURI(importUri).segmentsList()); - Preferences preferences = Preferences.loadPreferences(access, projectFrom(resourceUri)); - String fixed = fixUri(importUriPair, resourceUri, checker, preferences); + URI resourceUri = declaringResource.getURI(); + Preferences preferences = Preferences.loadPreferences(access, resources.project(resourceUri)); + String fixed = fixUri(importUriPair, resourceUri, preferences); System.out.println(resourceUri + " : " + importUri + " : " + fixed); if (fixed == null) return importUri; return fixed; } - - private static IProject projectFrom(URI resourceUri) { - IPath resourcePath = new Path(resourceUri.toPlatformString(true)); - IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(resourcePath); - return resource.getProject(); - } - private String fixUri(Pair<String, List<String>> importUri, URI resourceUri, ResourceChecker checker, - Preferences preferences) { + private String fixUri(Pair<String, List<String>> importUri, URI resourceUri, Preferences preferences) { List<String> segments = removeFirstAndLast(resourceUri.segmentsList()); if (preferences.fileResolutionType.equals(SINGLE_FOLDER)) { - return fixUri(importUri, segments, checker); + return fixUri(importUri, segments); } List<String> folderNames = preferences.folderNames; for (String folderName : folderNames) { segments.set(1, folderName); - String fixed = fixUri(importUri, segments, checker); + String fixed = fixUri(importUri, segments); if (fixed != null) return fixed; } return null; @@ -90,17 +82,17 @@ return newList; } - private String fixUri(Pair<String, List<String>> importUri, List<String> resourceUri, ResourceChecker checker) { + private String fixUri(Pair<String, List<String>> importUri, List<String> resourceUri) { StringBuilder prefix = new StringBuilder(); - prefix.append(PREFIX); + // prefix.append(PREFIX); String firstSegment = importUri.getSecond().get(0); for (String segment : resourceUri) { if (segment.equals(firstSegment)) break; prefix.append(SEPARATOR).append(segment); } prefix.append(SEPARATOR); - String fixed = prefix.toString() + importUri.getFirst(); - if (checker.resourceExists(fixed)) return fixed; + String fixed = PREFIX + prefix.toString() + importUri.getFirst(); + if (resources.fileExists(createURI(fixed))) return fixed; return null; } }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java new file mode 100644 index 0000000..b252395 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java
@@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Google Inc. + * + * 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 com.google.eclipse.protobuf.ui.scoping; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.util.URI; + +/** + * Utility methods related to resources (e.g. files, directories.) + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class Resources { + + /** + * Returns the project that contains the resource at the given URI. + * @param fileUri the URI of a resource. + * @return the project that contains the resource at the given URI. + */ + public IProject project(URI fileUri) { + return file(fileUri).getProject(); + } + + /** + * Indicates whether the given URI belongs to an existing file. + * @param fileUri the URI to check, as a {@code String}. + * @return {@code true} if the given URI belongs to an existing file, {@code false} otherwise. + */ + public boolean fileExists(URI fileUri) { + return file(fileUri).exists(); + } + + private IFile file(URI uri) { + IPath resourcePath = new Path(uri.toPlatformString(true)); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + return root.getFile(resourcePath); + } +}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java new file mode 100644 index 0000000..044a1a2 --- /dev/null +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Google Inc. + * + * 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 com.google.eclipse.protobuf.scoping; + +import org.eclipse.emf.ecore.resource.Resource; + +import com.google.eclipse.protobuf.scoping.IFileUriResolver.NullFileUriResolver; +import com.google.inject.ImplementedBy; + +/** + * Resolves partial URIs converting them to full ones belonging to existing files. + * + * @author alruiz@google.com (Alex Ruiz) + */ +@ImplementedBy(NullFileUriResolver.class) +public interface IFileUriResolver { + + /** Prefix present in resolved URIs. */ + String PREFIX = "platform:/resource"; + + /** + * Resolves the given partial URI. + * @param importUri the partial URI (comes from a {@code Import}.) + * @param declaringResource the resource declaring the import. + * @return the resolved URI. + */ + String resolveUri(String importUri, Resource declaringResource); + + public static class NullFileUriResolver implements IFileUriResolver { + + public String resolveUri(String importUri, Resource declaringResource) { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java deleted file mode 100644 index 5337acd..0000000 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java +++ /dev/null
@@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. - * - * 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 com.google.eclipse.protobuf.scoping; - -import org.eclipse.emf.common.util.URI; - -import com.google.eclipse.protobuf.protobuf.Import; - -/** - * Fixes partial URIs in <code>{@link Import}</code>s by resolving them to existing files with matching URIs. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public interface ImportUriFixer { - - /** - * Prefix present in complete import URIs. - */ - String PREFIX = "platform:/resource"; - - /** - * Returns a "fixed" full URI based on the given partial URI. - * @param importUri the partial URI (comes from a {@code Import}.) - * @param resourceUri the URI of the resource declaring the import. - * @param checker indicates whether the resolved URI belongs to an existing file. - * @return the "fixed" full URI. - */ - String fixUri(String importUri, URI resourceUri, ResourceChecker checker); -} \ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java index 4f4f764..3be0863 100644 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java +++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java
@@ -8,7 +8,7 @@ */ package com.google.eclipse.protobuf.scoping; -import static com.google.eclipse.protobuf.scoping.ImportUriFixer.PREFIX; +import static com.google.eclipse.protobuf.scoping.IFileUriResolver.PREFIX; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; @@ -18,7 +18,7 @@ import com.google.inject.Inject; /** - * Resolves URIs. This implementation mimics how protoc understands imported file URIs. For example, the URI + * This implementation mimics how protoc understands URIs of imported files. For example, the URI * "platform:/resource/proto1.proto" is understood by EMF but not by protoc. The URI in the proto file needs to be * simply "proto1.proto" for protoc to understand it. * <p> @@ -30,7 +30,7 @@ */ public class ProtobufImportUriResolver extends ImportUriResolver { - @Inject private ImportUriFixer uriFixer; + @Inject private IFileUriResolver delegate; /** * Prefix used by EMF for resource URIs: "platform:/resource/". @@ -50,8 +50,7 @@ private void fixUri(Import anImport) { Resource resource = anImport.eResource(); - ResourceChecker resourceChecker = new ResourceChecker(resource.getResourceSet()); - String fixed = uriFixer.fixUri(anImport.getImportURI(), resource.getURI(), resourceChecker); + String fixed = delegate.resolveUri(anImport.getImportURI(), resource); anImport.setImportURI(fixed); } }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java deleted file mode 100644 index 5231cd3..0000000 --- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java +++ /dev/null
@@ -1,38 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. - * - * 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 com.google.eclipse.protobuf.scoping; - -import static org.eclipse.emf.common.util.URI.createURI; - -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; - -/** - * Verifies that resources exist. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class ResourceChecker { - - private final ResourceSet resourceSet; - - public ResourceChecker(ResourceSet resourceSet) { - this.resourceSet = resourceSet; - } - - /** - * Indicates whether the given URI belongs to an existing resource. - * @param uri the URI to check, as a {@code String}. - * @return {@code true} if the given URI belongs to an existing resource, {@code false} otherwise. - */ - public boolean resourceExists(String uri) { - Resource resource = resourceSet.getResource(createURI(uri), true); - return resource != null && resource.getErrors().isEmpty(); - } -}