Major cleanup of protoc-invocation-related code.
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder_findRootOf_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder_findRootOf_Test.java
deleted file mode 100644
index 81f8409..0000000
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder_findRootOf_Test.java
+++ /dev/null
@@ -1,50 +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.builder.protoc;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.*;
-import static org.junit.rules.ExpectedException.none;
-
-import org.junit.*;
-import org.junit.rules.ExpectedException;
-
-/**
- * Tests for <code>{@link ProtoDescriptorPathFinder#findRootOf(String)}</code>.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class ProtoDescriptorPathFinder_findRootOf_Test {
- private static ProtoDescriptorPathFinder finder;
-
- @BeforeClass public static void setUpOnce() {
- finder = new ProtoDescriptorPathFinder("/");
- }
-
- @Rule public ExpectedException thrown = none();
-
- @Test public void should_return_null_if_path_is_null() {
- assertNull(finder.findRootOf(null));
- }
-
- @Test public void should_return_null_if_path_is_empty() {
- assertNull(finder.findRootOf(""));
- }
-
- @Test public void should_throw_error_if_path_does_not_contain_descriptor_FQN() {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Path '/usr/local/include' does not contain '/google/protobuf/descriptor.proto'");
- finder.findRootOf("/usr/local/include");
- }
-
- @Test public void should_find_import_root_of_descriptor() {
- String filePath = "/usr/local/include/google/protobuf/descriptor.proto";
- assertThat(finder.findRootOf(filePath), equalTo("/usr/local/include"));
- }
-}
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption_appendOptionToCommand_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption_appendOptionToCommand_Test.java
new file mode 100644
index 0000000..8bba92d
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption_appendOptionToCommand_Test.java
@@ -0,0 +1,70 @@
+/*
+ * 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.builder.protoc.command;
+
+import static org.junit.rules.ExpectedException.none;
+import static org.mockito.Mockito.*;
+
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import com.google.eclipse.protobuf.ui.preferences.StringPreference;
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+
+/**
+ * Tests for <code>{@link DescriptorPathProtocOption#appendOptionToCommand(ProtocCommand)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class DescriptorPathProtocOption_appendOptionToCommand_Test {
+ @Rule public ExpectedException thrown = none();
+
+ private StringPreference descriptorPath;
+ private CompilerPreferences preferences;
+ private ProtocCommand command;
+ private DescriptorPathProtocOption option;
+
+ @Before public void setUp() {
+ descriptorPath = mock(StringPreference.class);
+ preferences = mock(CompilerPreferences.class);
+ command = mock(ProtocCommand.class);
+ option = new DescriptorPathProtocOption(preferences, "/");
+ }
+
+ @Test public void should_not_append_to_command_if_descriptor_path_is_null() {
+ expectDescriptorPathToBeEqualTo(null);
+ option.appendOptionToCommand(command);
+ verifyZeroInteractions(command);
+ }
+
+ @Test public void should_not_append_to_command_if_descriptor_path_is_empty() {
+ expectDescriptorPathToBeEqualTo("");
+ option.appendOptionToCommand(command);
+ verifyZeroInteractions(command);
+ }
+
+ @Test public void should_throw_error_if_descriptor_path_does_not_contain_descriptor_FQN() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Path '/usr/local/include' does not contain '/google/protobuf/descriptor.proto'");
+ expectDescriptorPathToBeEqualTo("/usr/local/include");
+ option.appendOptionToCommand(command);
+ verifyZeroInteractions(command);
+ }
+
+ @Test public void should_append_path_of_descriptor_to_command() {
+ expectDescriptorPathToBeEqualTo("/usr/local/include/google/protobuf/descriptor.proto");
+ option.appendOptionToCommand(command);
+ verify(command).appendOption("proto_path", "/usr/local/include");
+ }
+
+ private void expectDescriptorPathToBeEqualTo(String value) {
+ when(preferences.descriptorPath()).thenReturn(descriptorPath);
+ when(descriptorPath.getValue()).thenReturn(value);
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java
similarity index 97%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java
index b0f3228..d5ede0c 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser_parseAndAddMarkerIfNecessary_Test.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static org.mockito.Mockito.*;
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory_createErrorIfNecessary_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory_createErrorIfNecessary_Test.java
similarity index 97%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory_createErrorIfNecessary_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory_createErrorIfNecessary_Test.java
index 0e21e1c..b798fe7 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory_createErrorIfNecessary_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory_createErrorIfNecessary_Test.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static com.google.eclipse.protobuf.junit.stubs.resources.MarkerStub.error;
import static com.google.eclipse.protobuf.ui.validation.ProtobufResourceUIValidatorExtension.EDITOR_CHECK;
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java
similarity index 95%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java
index 841cbb8..793a984 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withLineNumber_Test.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static org.mockito.Mockito.*;
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java
similarity index 95%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java
index 7602ba6..31153fa 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser_parseAndAddMarkerIfNecessary_withoutLineNumber_Test.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static org.mockito.Mockito.*;
diff --git a/com.google.eclipse.protobuf.ui/plugin.xml b/com.google.eclipse.protobuf.ui/plugin.xml
index 54a8999..ae19672 100644
--- a/com.google.eclipse.protobuf.ui/plugin.xml
+++ b/com.google.eclipse.protobuf.ui/plugin.xml
@@ -248,7 +248,7 @@
</extension>
<extension point="org.eclipse.xtext.builder.participant">
<participant
- class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.builder.protoc.ProtobufBuildParticipant">
+ class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.builder.protoc.core.ProtobufBuildParticipant">
</participant>
</extension>
<extension
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectories.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectories.java
deleted file mode 100644
index c42cec6..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectories.java
+++ /dev/null
@@ -1,42 +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.builder.protoc;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-
-import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class OutputDirectories {
- private final OutputDirectory java;
- private final OutputDirectory cpp;
- private final OutputDirectory python;
-
- OutputDirectories(IProject project, CompilerPreferences preferences) throws CoreException {
- java = new OutputDirectory(project, preferences.javaCodeGenerationEnabled(), preferences.javaOutputDirectory());
- cpp = new OutputDirectory(project, preferences.cppCodeGenerationEnabled(), preferences.cppOutputDirectory());
- python = new OutputDirectory(project, preferences.pythonCodeGenerationEnabled(),
- preferences.pythonOutputDirectory());
- }
-
- OutputDirectory java() {
- return java;
- }
-
- OutputDirectory cpp() {
- return cpp;
- }
-
- OutputDirectory python() {
- return python;
- }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java
deleted file mode 100644
index 75cd929..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java
+++ /dev/null
@@ -1,57 +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.builder.protoc;
-
-import static com.google.eclipse.protobuf.ui.util.Paths.segmentsOf;
-import static org.eclipse.core.runtime.IPath.SEPARATOR;
-
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
-
-import com.google.eclipse.protobuf.ui.preferences.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class OutputDirectory {
- private static final NullProgressMonitor NO_MONITOR = new NullProgressMonitor();
-
- private final boolean enabled;
- private final IFolder location;
-
- OutputDirectory(IProject project, BooleanPreference codeGenerationEnabled, StringPreference outputDirectory)
- throws CoreException {
- enabled = codeGenerationEnabled.getValue();
- location = findOrCreateLocation(project, outputDirectory.getValue());
- }
-
- private IFolder findOrCreateLocation(IProject project, String directoryName) throws CoreException {
- IFolder directory = null;
- if (enabled) {
- StringBuilder path = new StringBuilder();
- for (String segment : segmentsOf(directoryName)) {
- path.append(segment);
- directory = project.getFolder(path.toString());
- if (!directory.exists()) {
- directory.create(true, true, NO_MONITOR);
- }
- path.append(SEPARATOR);
- }
- }
- return directory;
- }
-
- boolean isEnabled() {
- return enabled;
- }
-
- IFolder getLocation() {
- return location;
- }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder.java
deleted file mode 100644
index 21262e1..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtoDescriptorPathFinder.java
+++ /dev/null
@@ -1,43 +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.builder.protoc;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static java.io.File.separator;
-import static org.eclipse.xtext.util.Strings.*;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.inject.Singleton;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-@Singleton class ProtoDescriptorPathFinder {
- private final String descriptorFqn;
-
- ProtoDescriptorPathFinder() {
- this(separator);
- }
-
- @VisibleForTesting ProtoDescriptorPathFinder(String fileSeparator) {
- descriptorFqn = concat(fileSeparator, newArrayList("", "google", "protobuf", "descriptor.proto"));
- }
-
- String findRootOf(String descriptorFilePath) {
- if (isEmpty(descriptorFilePath)) {
- return null;
- }
- int indexOfDescriptorFqn = descriptorFilePath.indexOf(descriptorFqn);
- if (indexOfDescriptorFqn == -1) {
- String format = "Path '%s' does not contain '%s'";
- throw new IllegalArgumentException(String.format(format, descriptorFilePath, descriptorFqn));
- }
- return descriptorFilePath.substring(0, indexOfDescriptorFqn);
- }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtobufBuildParticipant.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtobufBuildParticipant.java
deleted file mode 100644
index ed4e295..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtobufBuildParticipant.java
+++ /dev/null
@@ -1,193 +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.builder.protoc;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.io.Closeables.closeQuietly;
-import static com.google.eclipse.protobuf.ui.builder.protoc.ConsolePrinter.createAndDisplayConsole;
-import static com.google.eclipse.protobuf.ui.exception.CoreExceptions.error;
-import static com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences.compilerPreferences;
-import static com.google.eclipse.protobuf.ui.util.CommaSeparatedValues.splitCsv;
-import static java.util.Collections.*;
-import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
-
-import java.io.*;
-import java.util.List;
-
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.xtext.builder.IXtextBuilderParticipant;
-import org.eclipse.xtext.resource.IResourceDescription;
-import org.eclipse.xtext.resource.IResourceDescription.Delta;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
-
-import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
-import com.google.eclipse.protobuf.ui.preferences.paths.core.DirectoryPath;
-import com.google.eclipse.protobuf.ui.preferences.paths.core.PathsPreferences;
-import com.google.inject.Inject;
-
-/**
- * Calls protoc to generate Java, C++ or Python code from .proto files.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class ProtobufBuildParticipant implements IXtextBuilderParticipant {
- @Inject private ProtocCommandFactory commandFactory;
- @Inject private ProtocOutputParser outputParser;
- @Inject private ProtoDescriptorPathFinder protoDescriptorPathFinder;
- @Inject private IPreferenceStoreAccess storeAccess;
-
- @Override public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
- IProject project = context.getBuiltProject();
- CompilerPreferences preferences = compilerPreferences(storeAccess, project);
- if (!preferences.compileProtoFiles().getValue()) {
- return;
- }
- List<Delta> deltas = context.getDeltas();
- if (deltas.isEmpty()) {
- return;
- }
- OutputDirectories outputDirectories = new OutputDirectories(project, preferences);
- String descriptorPath = descriptorPath(preferences);
- List<String> importRoots = importRoots(project);
- for (Delta d : deltas) {
- IFile source = protoFile(d.getNew(), project);
- if (source == null) {
- continue;
- }
- if (importRoots.isEmpty()) {
- importRoots = singleImportRoot(source);
- }
- generateSingleProto(source, protocPath(preferences), importRoots, descriptorPath, outputDirectories);
- }
- if (preferences.refreshResources().getValue()) {
- boolean refreshProject = preferences.refreshProject().getValue();
- refresh(project, outputDirectories, refreshProject, monitor);
- }
- }
-
- private String descriptorPath(CompilerPreferences preferences) {
- return protoDescriptorPathFinder.findRootOf(preferences.descriptorPath().getValue());
- }
-
- private List<String> importRoots(IProject project) {
- List<String> paths = newArrayList();
- PathsPreferences preferences = new PathsPreferences(storeAccess, project);
- if (preferences.filesInMultipleDirectories().getValue()) {
- String directoryPaths = preferences.directoryPaths().getValue();
- for (String importRoot : splitCsv(directoryPaths)) {
- DirectoryPath path = DirectoryPath.parse(importRoot, project);
- String location = path.absolutePathInFileSystem();
- if (location != null) {
- paths.add(location);
- }
- }
- return unmodifiableList(paths);
- }
- return emptyList();
- }
-
- private IFile protoFile(IResourceDescription resource, IProject project) {
- String path = filePathIfIsProtoFile(resource);
- return (path == null) ? null : project.getWorkspace().getRoot().getFile(new Path(path));
- }
-
- private String filePathIfIsProtoFile(IResourceDescription resource) {
- if (resource == null) {
- return null;
- }
- URI uri = resource.getURI();
- if (!uri.fileExtension().equals("proto"))
- {
- return null;
- }
- if (uri.scheme() == null) {
- return uri.toFileString();
- }
- StringBuilder b = new StringBuilder();
- int segmentCount = uri.segmentCount();
- for (int i = 1; i < segmentCount; i++)
- {
- b.append("/").append(uri.segment(i));
- }
- return b.length() == 0 ? null : b.toString();
- }
-
- private List<String> singleImportRoot(IFile source) {
- IProject project = source.getProject();
- File projectFile = project.getLocation().toFile();
- File current = source.getLocation().toFile();
- while (!current.getParentFile().equals(projectFile)) {
- current = current.getParentFile();
- }
- return singletonList(current.toString());
- }
-
- String protocPath(CompilerPreferences preferences) {
- if (preferences.useProtocInSystemPath().getValue()) {
- return "protoc";
- }
- return preferences.protocPath().getValue();
- }
-
- private void generateSingleProto(IFile source, String protocPath, List<String> importRoots, String descriptorPath,
- OutputDirectories outputDirectories) throws CoreException {
- String command = commandFactory.protocCommand(source, protocPath, importRoots, descriptorPath, outputDirectories);
- ConsolePrinter console = null;
- try {
- console = createAndDisplayConsole();
- console.printCommand(command);
- Process process = Runtime.getRuntime().exec(command);
- processStream(process.getErrorStream(), source, console);
- process.destroy();
- } catch (Throwable e) {
- e.printStackTrace();
- throw error(e);
- } finally {
- if (console != null) {
- console.close();
- }
- }
- }
-
- private void processStream(InputStream stream, IFile source, ConsolePrinter console) throws Throwable {
- InputStreamReader reader = null;
- try {
- reader = new InputStreamReader(stream);
- BufferedReader bufferedReader = new BufferedReader(reader);
- String line = null;
- ProtocMarkerFactory markerFactory = new ProtocMarkerFactory(source);
- while ((line = bufferedReader.readLine()) != null) {
- outputParser.parseAndAddMarkerIfNecessary(line, markerFactory);
- console.printProtocOutput(line);
- }
- } finally {
- closeQuietly(reader);
- }
- }
-
- private void refresh(IProject project, OutputDirectories outputDirectories, boolean refreshProject,
- IProgressMonitor monitor) throws CoreException {
- if (refreshProject) {
- project.refreshLocal(DEPTH_INFINITE, monitor);
- return;
- }
- refresh(outputDirectories.java(), monitor);
- refresh(outputDirectories.cpp(), monitor);
- refresh(outputDirectories.python(), monitor);
- }
-
- private void refresh(OutputDirectory directory, IProgressMonitor monitor) throws CoreException {
- if (directory.isEnabled()) {
- IFolder location = directory.getLocation();
- location.refreshLocal(DEPTH_INFINITE, monitor);
- }
- }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocCommandFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocCommandFactory.java
deleted file mode 100644
index fa53cb4..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocCommandFactory.java
+++ /dev/null
@@ -1,47 +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.builder.protoc;
-
-import static com.google.eclipse.protobuf.util.CommonWords.space;
-import static org.eclipse.xtext.util.Strings.isEmpty;
-
-import java.util.List;
-
-import org.eclipse.core.resources.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class ProtocCommandFactory {
- String protocCommand(IFile protoFile, String protocPath, List<String> importRoots, String descriptorPath,
- OutputDirectories outputDirectories) {
- StringBuilder command = new StringBuilder();
- command.append(protocPath).append(space());
- for (String importRoot : importRoots) {
- command.append("-I=").append(importRoot).append(space());
- }
- if (!isEmpty(descriptorPath)) {
- command.append("--proto_path=").append(descriptorPath).append(space());
- }
- addOutputDirectory(outputDirectories.java(), "java", command);
- addOutputDirectory(outputDirectories.cpp(), "cpp", command);
- addOutputDirectory(outputDirectories.python(), "python", command);
- command.append(protoFile.getLocation().toOSString());
- return command.toString();
- }
-
- private void addOutputDirectory(OutputDirectory outputDirectory, String code, StringBuilder command) {
- if (!outputDirectory.isEnabled()) {
- return;
- }
- command.append("--").append(code).append("_out=");
- IFolder directory = outputDirectory.getLocation();
- command.append(directory.getLocation().toOSString()).append(space());
- }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocOutputParser.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocOutputParser.java
deleted file mode 100644
index 7b16351..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocOutputParser.java
+++ /dev/null
@@ -1,21 +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.builder.protoc;
-
-import org.eclipse.core.runtime.CoreException;
-
-import com.google.inject.ImplementedBy;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-@ImplementedBy(CompositeOutputParser.class)
-interface ProtocOutputParser {
- boolean parseAndAddMarkerIfNecessary(String line, ProtocMarkerFactory markerFactory) throws CoreException;
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/CppProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/CppProtocOption.java
new file mode 100644
index 0000000..83bc3ff
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/CppProtocOption.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.eclipse.protobuf.ui.builder.protoc.command.IResources.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class CppProtocOption implements OutputDirectoryProtocOption {
+ private final CompilerPreferences preferences;
+ private final IProject project;
+
+ private boolean initialized;
+ private boolean enabled;
+ private IFolder outputDirectory;
+ private String outputDirectoryLocation;
+
+ CppProtocOption(CompilerPreferences preferences, IProject project) {
+ this.preferences = preferences;
+ this.project = project;
+ }
+
+ @Override public void appendOptionToCommand(ProtocCommand command) throws CoreException {
+ ensureIsInitialized();
+ if (enabled) {
+ command.appendOption("cpp_out", outputDirectoryLocation);
+ }
+ }
+
+ @Override public IFolder outputDirectory() throws CoreException {
+ ensureIsInitialized();
+ return outputDirectory;
+ }
+
+ private void ensureIsInitialized() throws CoreException {
+ if (!initialized) {
+ initialize();
+ }
+ }
+
+ private void initialize() throws CoreException {
+ initialized = true;
+ enabled = preferences.cppCodeGenerationEnabled().getValue();
+ if (enabled) {
+ String directoryName = preferences.cppOutputDirectory().getValue();
+ outputDirectory = findOrCreateDirectory(directoryName, project);
+ outputDirectoryLocation = locationOf(outputDirectory);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption.java
new file mode 100644
index 0000000..95e86e9
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/DescriptorPathProtocOption.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.io.File.separator;
+import static org.eclipse.xtext.util.Strings.*;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class DescriptorPathProtocOption implements ProtocOption {
+ private final CompilerPreferences preferences;
+ private final String descriptorFqn;
+
+ private boolean initialized;
+ private String descriptorPath;
+
+ DescriptorPathProtocOption(CompilerPreferences preferences) {
+ this(preferences, separator);
+ }
+
+ @VisibleForTesting DescriptorPathProtocOption(CompilerPreferences preferences, String pathSeparator) {
+ this.preferences = preferences;
+ descriptorFqn = concat(pathSeparator, newArrayList("", "google", "protobuf", "descriptor.proto"));
+ }
+
+ @Override public void appendOptionToCommand(ProtocCommand command) {
+ if (!initialized) {
+ initialize();
+ }
+ if (!isEmpty(descriptorPath)) {
+ command.appendOption("proto_path", descriptorPath);
+ }
+ }
+
+ private void initialize() {
+ initialized = true;
+ String fullPath = preferences.descriptorPath().getValue();
+ if (!isEmpty(fullPath)) {
+ int indexOfDescriptorFqn = fullPath.indexOf(descriptorFqn);
+ if (indexOfDescriptorFqn == -1) {
+ String format = "Path '%s' does not contain '%s'";
+ throw new IllegalArgumentException(String.format(format, fullPath, descriptorFqn));
+ }
+ descriptorPath = fullPath.substring(0, indexOfDescriptorFqn);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/IResources.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/IResources.java
new file mode 100644
index 0000000..83340ae
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/IResources.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.eclipse.protobuf.ui.util.Paths.segmentsOf;
+import static org.eclipse.core.runtime.IPath.SEPARATOR;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+final class IResources {
+ private static final NullProgressMonitor NO_MONITOR = new NullProgressMonitor();
+
+ static String locationOf(IFolder directory) {
+ return directory.getLocation().toOSString();
+ }
+
+ static IFolder findOrCreateDirectory(String directoryName, IProject project) throws CoreException {
+ IFolder directory = null;
+ StringBuilder path = new StringBuilder();
+ for (String segment : segmentsOf(directoryName)) {
+ path.append(segment);
+ directory = project.getFolder(path.toString());
+ if (!directory.exists()) {
+ directory.create(true, true, NO_MONITOR);
+ }
+ path.append(SEPARATOR);
+ }
+ return directory;
+ }
+
+ private IResources() {}
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ImportRootsProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ImportRootsProtocOption.java
new file mode 100644
index 0000000..902e799
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ImportRootsProtocOption.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.eclipse.protobuf.ui.preferences.paths.core.DirectoryPath.parse;
+import static com.google.eclipse.protobuf.ui.util.CommaSeparatedValues.splitCsv;
+import static java.util.Collections.emptyList;
+import static org.eclipse.xtext.util.Strings.isEmpty;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.core.resources.*;
+
+import com.google.eclipse.protobuf.ui.preferences.paths.core.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ImportRootsProtocOption {
+ private final PathsPreferences preferences;
+ private final IProject project;
+
+ private boolean initialized;
+ private List<String> importRoots;
+
+ ImportRootsProtocOption(PathsPreferences preferences, IProject project) {
+ this.preferences = preferences;
+ this.project = project;
+ }
+
+ public void appendOptionToCommand(ProtocCommand command, IFile protoFile) {
+ if (!initialized) {
+ initialize();
+ }
+ if (!importRoots.isEmpty()) {
+ for (String importRoot : importRoots) {
+ appendToCommand(command, importRoot);
+ }
+ return;
+ }
+ appendToCommand(command, singleImportRoot(protoFile));
+ }
+
+ private void initialize() {
+ initialized = true;
+ if (!preferences.filesInMultipleDirectories().getValue()) {
+ importRoots = emptyList();
+ return;
+ }
+ importRoots = newArrayList();
+ String directoryPaths = preferences.directoryPaths().getValue();
+ for (String importRoot : splitCsv(directoryPaths)) {
+ DirectoryPath path = parse(importRoot, project);
+ String location = path.absolutePathInFileSystem();
+ if (!isEmpty(location)) {
+ importRoots.add(location);
+ }
+ }
+ }
+
+ private String singleImportRoot(IFile protoFile) {
+ File projectFile = toFile(project);
+ File currentFile = toFile(protoFile);
+ while (!currentFile.getParentFile().equals(projectFile)) {
+ currentFile = currentFile.getParentFile();
+ }
+ return currentFile.toString();
+ }
+
+ private File toFile(IResource resource) {
+ return resource.getLocation().toFile();
+ }
+
+ private void appendToCommand(ProtocCommand command, String importRoot) {
+ command.appendOption("proto_path", importRoot);
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/JavaProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/JavaProtocOption.java
new file mode 100644
index 0000000..9b276de
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/JavaProtocOption.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.eclipse.protobuf.ui.builder.protoc.command.IResources.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class JavaProtocOption implements OutputDirectoryProtocOption {
+ private final CompilerPreferences preferences;
+ private final IProject project;
+
+ private boolean initialized;
+ private boolean enabled;
+ private IFolder outputDirectory;
+ private String outputDirectoryLocation;
+
+ JavaProtocOption(CompilerPreferences preferences, IProject project) {
+ this.preferences = preferences;
+ this.project = project;
+ }
+
+ @Override public void appendOptionToCommand(ProtocCommand command) throws CoreException {
+ ensureIsInitialized();
+ if (enabled) {
+ command.appendOption("java_out", outputDirectoryLocation);
+ }
+ }
+
+ @Override public IFolder outputDirectory() throws CoreException {
+ ensureIsInitialized();
+ return outputDirectory;
+ }
+
+ private void ensureIsInitialized() throws CoreException {
+ if (!initialized) {
+ initialize();
+ }
+ }
+
+ private void initialize() throws CoreException {
+ initialized = true;
+ enabled = preferences.javaCodeGenerationEnabled().getValue();
+ if (enabled) {
+ String directoryName = preferences.javaOutputDirectory().getValue();
+ outputDirectory = findOrCreateDirectory(directoryName, project);
+ outputDirectoryLocation = locationOf(outputDirectory);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/OutputDirectoryProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/OutputDirectoryProtocOption.java
new file mode 100644
index 0000000..3f8b965
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/OutputDirectoryProtocOption.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public interface OutputDirectoryProtocOption extends ProtocOption {
+ IFolder outputDirectory() throws CoreException;
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommand.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommand.java
new file mode 100644
index 0000000..f44d26b
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.eclipse.protobuf.util.CommonWords.space;
+
+/**
+ * The command used to call protoc to compile a single .proto file.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class ProtocCommand {
+ private final StringBuilder content = new StringBuilder();
+
+ ProtocCommand(String protocPath) {
+ content.append(protocPath).append(space());
+ }
+
+ /**
+ * Appends the given option name and value to the command. So far, the best description of protoc options is
+ * <a href="http://www.discursive.com/books/cjcook/reference/proto-sect-compiling"> this one</a>.
+ * @param name the given option name.
+ * @param value the given option value.
+ */
+ void appendOption(String name, String value) {
+ content.append("--").append(name).append("=").append(value).append(space());
+ }
+
+ @Override public String toString() {
+ return content.toString();
+ };
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommandBuilder.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommandBuilder.java
new file mode 100644
index 0000000..9bf1921
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocCommandBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.List;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+import com.google.eclipse.protobuf.ui.preferences.paths.core.PathsPreferences;
+
+/**
+ * Builds the command to call protoc to compile a single .proto file.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtocCommandBuilder {
+ private final List<ProtocOption> options = newArrayList();
+
+ private final String protocPath;
+ private final ImportRootsProtocOption importRootsProtocOption;
+
+ public ProtocCommandBuilder(CompilerPreferences compilerPreferences, PathsPreferences pathsPreferences,
+ IProject project) {
+ boolean useProtocInSystemPath = compilerPreferences.useProtocInSystemPath().getValue();
+ protocPath = useProtocInSystemPath ? "protoc" : compilerPreferences.protocPath().getValue();
+ options.add(new DescriptorPathProtocOption(compilerPreferences));
+ options.add(new JavaProtocOption(compilerPreferences, project));
+ options.add(new CppProtocOption(compilerPreferences, project));
+ options.add(new PythonProtocOption(compilerPreferences, project));
+ importRootsProtocOption = new ImportRootsProtocOption(pathsPreferences, project);
+ }
+
+ /**
+ * Builds the command to call protoc to compile a single .proto file.
+ * @param protoFile the .proto file.
+ * @return the built command.
+ * @throws CoreException if something goes wrong.
+ */
+ public String buildCommand(IFile protoFile) throws CoreException {
+ ProtocCommand command = new ProtocCommand(protocPath);
+ importRootsProtocOption.appendOptionToCommand(command, protoFile);
+ for (ProtocOption option : options) {
+ option.appendOptionToCommand(command);
+ }
+ return command.toString();
+ }
+
+ /**
+ * Returns the output directories where generated code is stored.
+ * @return the output directories where generated code is stored.
+ * @throws CoreException if something goes wrong.
+ */
+ public List<IFolder> outputDirectories() throws CoreException {
+ List<IFolder> outputDirectories = newArrayList();
+ for (ProtocOption option : options) {
+ if (option instanceof OutputDirectoryProtocOption) {
+ IFolder outputDirectory = ((OutputDirectoryProtocOption) option).outputDirectory();
+ outputDirectories.add(outputDirectory);
+ }
+ }
+ return unmodifiableList(outputDirectories);
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocOption.java
new file mode 100644
index 0000000..ec2675e
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/ProtocOption.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface ProtocOption {
+ void appendOptionToCommand(ProtocCommand command) throws CoreException;
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/PythonProtocOption.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/PythonProtocOption.java
new file mode 100644
index 0000000..e31b9e5
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/command/PythonProtocOption.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 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.builder.protoc.command;
+
+import static com.google.eclipse.protobuf.ui.builder.protoc.command.IResources.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class PythonProtocOption implements OutputDirectoryProtocOption {
+ private final CompilerPreferences preferences;
+ private final IProject project;
+
+ private boolean initialized;
+ private boolean enabled;
+ private IFolder outputDirectory;
+ private String outputDirectoryLocation;
+
+ PythonProtocOption(CompilerPreferences preferences, IProject project) {
+ this.preferences = preferences;
+ this.project = project;
+ }
+
+ @Override public void appendOptionToCommand(ProtocCommand command) throws CoreException {
+ ensureIsInitialized();
+ if (enabled) {
+ command.appendOption("python_out", outputDirectoryLocation);
+ }
+ }
+
+ @Override public IFolder outputDirectory() throws CoreException {
+ ensureIsInitialized();
+ return outputDirectory;
+ }
+
+ private void ensureIsInitialized() throws CoreException {
+ if (!initialized) {
+ initialize();
+ }
+ }
+ private void initialize() throws CoreException {
+ initialized = true;
+ enabled = preferences.pythonCodeGenerationEnabled().getValue();
+ if (enabled) {
+ String directoryName = preferences.pythonOutputDirectory().getValue();
+ outputDirectory = findOrCreateDirectory(directoryName, project);
+ outputDirectoryLocation = locationOf(outputDirectory);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ConsolePrinter.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ConsolePrinter.java
similarity index 96%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ConsolePrinter.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ConsolePrinter.java
index beacffd..8e684d1 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ConsolePrinter.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ConsolePrinter.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.core;
import static com.google.common.io.Closeables.closeQuietly;
import static com.google.eclipse.protobuf.ui.util.Workbenches.activeWorkbenchPage;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ProtobufBuildParticipant.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ProtobufBuildParticipant.java
new file mode 100644
index 0000000..13ce5bb
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/core/ProtobufBuildParticipant.java
@@ -0,0 +1,138 @@
+/*
+ * 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.builder.protoc.core;
+
+import static com.google.common.io.Closeables.closeQuietly;
+import static com.google.eclipse.protobuf.ui.builder.protoc.core.ConsolePrinter.createAndDisplayConsole;
+import static com.google.eclipse.protobuf.ui.exception.CoreExceptions.error;
+import static com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences.compilerPreferences;
+import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
+
+import java.io.*;
+import java.util.List;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.builder.IXtextBuilderParticipant;
+import org.eclipse.xtext.resource.*;
+import org.eclipse.xtext.resource.IResourceDescription.Delta;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+
+import com.google.eclipse.protobuf.ui.builder.protoc.command.ProtocCommandBuilder;
+import com.google.eclipse.protobuf.ui.builder.protoc.output.*;
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+import com.google.eclipse.protobuf.ui.preferences.paths.core.PathsPreferences;
+import com.google.inject.Inject;
+
+/**
+ * Calls protoc to generate Java, C++ or Python code from .proto files.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtobufBuildParticipant implements IXtextBuilderParticipant {
+ @Inject private ProtocOutputParser outputParser;
+ @Inject private IPreferenceStoreAccess storeAccess;
+
+ @Override public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
+ List<Delta> deltas = context.getDeltas();
+ if (deltas.isEmpty()) {
+ return;
+ }
+ IProject project = context.getBuiltProject();
+ CompilerPreferences compilerPreferences = compilerPreferences(storeAccess, project);
+ if (!compilerPreferences.compileProtoFiles().getValue()) {
+ return;
+ }
+ PathsPreferences pathsPreferences = new PathsPreferences(storeAccess, project);
+ ProtocCommandBuilder commandBuilder = new ProtocCommandBuilder(compilerPreferences, pathsPreferences, project);
+ for (Delta d : deltas) {
+ IFile protoFile = protoFile(d.getNew(), project);
+ if (protoFile == null) {
+ continue;
+ }
+ generateSingleProto(commandBuilder.buildCommand(protoFile), protoFile);
+ }
+ if (compilerPreferences.refreshResources().getValue()) {
+ boolean refreshProject = compilerPreferences.refreshProject().getValue();
+ refresh(project, commandBuilder.outputDirectories(), refreshProject, monitor);
+ }
+ }
+
+ private IFile protoFile(IResourceDescription resource, IProject project) {
+ String path = filePathIfIsProtoFile(resource);
+ return (path == null) ? null : project.getWorkspace().getRoot().getFile(new Path(path));
+ }
+
+ private String filePathIfIsProtoFile(IResourceDescription resource) {
+ if (resource == null) {
+ return null;
+ }
+ URI uri = resource.getURI();
+ if (!uri.fileExtension().equals("proto"))
+ {
+ return null;
+ }
+ if (uri.scheme() == null) {
+ return uri.toFileString();
+ }
+ StringBuilder b = new StringBuilder();
+ int segmentCount = uri.segmentCount();
+ for (int i = 1; i < segmentCount; i++)
+ {
+ b.append("/").append(uri.segment(i));
+ }
+ return b.length() == 0 ? null : b.toString();
+ }
+
+ private void generateSingleProto(String command, IFile protoFile) throws CoreException {
+ ConsolePrinter console = null;
+ try {
+ console = createAndDisplayConsole();
+ console.printCommand(command);
+ Process process = Runtime.getRuntime().exec(command);
+ processStream(process.getErrorStream(), protoFile, console);
+ process.destroy();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw error(e);
+ } finally {
+ if (console != null) {
+ console.close();
+ }
+ }
+ }
+
+ private void processStream(InputStream stream, IFile protoFile, ConsolePrinter console) throws Throwable {
+ InputStreamReader reader = null;
+ try {
+ reader = new InputStreamReader(stream);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = null;
+ ProtocMarkerFactory markerFactory = new ProtocMarkerFactory(protoFile);
+ while ((line = bufferedReader.readLine()) != null) {
+ outputParser.parseAndAddMarkerIfNecessary(line, markerFactory);
+ console.printProtocOutput(line);
+ }
+ } finally {
+ closeQuietly(reader);
+ }
+ }
+
+ private void refresh(IProject project, List<IFolder> outputDirectories, boolean refreshProject,
+ IProgressMonitor monitor) throws CoreException {
+ if (refreshProject) {
+ project.refreshLocal(DEPTH_INFINITE, monitor);
+ return;
+ }
+ for (IFolder outputDirectory : outputDirectories) {
+ outputDirectory.refreshLocal(DEPTH_INFINITE, monitor);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser.java
similarity index 96%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser.java
index bd004e7..66f382c 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/CompositeOutputParser.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/CompositeOutputParser.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static com.google.common.collect.Lists.newArrayList;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory.java
similarity index 60%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory.java
index 1969bc2..a447056 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/ProtocMarkerFactory.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocMarkerFactory.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static com.google.eclipse.protobuf.ui.validation.ProtobufResourceUIValidatorExtension.EDITOR_CHECK;
import static org.eclipse.core.resources.IMarker.*;
@@ -20,24 +20,31 @@
*
* @author alruiz@google.com (Alex Ruiz)
*/
-class ProtocMarkerFactory {
+public class ProtocMarkerFactory {
private static final String PROTOC_CHECK = "com.google.eclipse.protobuf.ui.protocMarker";
- private final IFile file;
+ private final IFile protoFile;
private final IMarker[] markers;
- ProtocMarkerFactory(IFile file) throws CoreException {
- this.file = file;
- file.deleteMarkers(PROTOC_CHECK, true, DEPTH_INFINITE);
- markers = file.findMarkers(EDITOR_CHECK, true, DEPTH_INFINITE);
+ public ProtocMarkerFactory(IFile protoFile) throws CoreException {
+ this.protoFile = protoFile;
+ protoFile.deleteMarkers(PROTOC_CHECK, true, DEPTH_INFINITE);
+ markers = protoFile.findMarkers(EDITOR_CHECK, true, DEPTH_INFINITE);
}
- void createErrorIfNecessary(String fileName, int lineNumber, String message) throws CoreException {
- String location = file.getLocation().toOSString();
+ /**
+ * Creates a new editor marker if the given file name matches the one in this factory.
+ * @param fileName the name of the proto file, obtained from protoc output.
+ * @param lineNumber the line number where to create the editor marker.
+ * @param message the message for the editor marker.
+ * @throws CoreException if something goes wrong.
+ */
+ public void createErrorIfNecessary(String fileName, int lineNumber, String message) throws CoreException {
+ String location = protoFile.getLocation().toOSString();
if (!location.endsWith(fileName) || containsMarker(message, lineNumber)) {
return;
}
- IMarker marker = file.createMarker(PROTOC_CHECK);
+ IMarker marker = protoFile.createMarker(PROTOC_CHECK);
marker.setAttribute(SEVERITY, SEVERITY_ERROR);
marker.setAttribute(MESSAGE, message);
marker.setAttribute(LINE_NUMBER, lineNumber);
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocOutputParser.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocOutputParser.java
new file mode 100644
index 0000000..b58ec02
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/ProtocOutputParser.java
@@ -0,0 +1,30 @@
+/*
+ * 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.builder.protoc.output;
+
+import org.eclipse.core.runtime.CoreException;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Parser of protoc output.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@ImplementedBy(CompositeOutputParser.class)
+public interface ProtocOutputParser {
+ /**
+ * Parses a single line of protoc output. It may create an editor marker.
+ * @param line the line to process.
+ * @param markerFactory the factory of editor markers.
+ * @return {@code true} if the given line was parsed, {@code false} otherwise.
+ * @throws CoreException if something wrong happens.
+ */
+ boolean parseAndAddMarkerIfNecessary(String line, ProtocMarkerFactory markerFactory) throws CoreException;
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser.java
similarity index 96%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser.java
index ec35892..7e063e8 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/RegexOutputParser.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/output/RegexOutputParser.java
@@ -6,7 +6,7 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.ui.builder.protoc;
+package com.google.eclipse.protobuf.ui.builder.protoc.output;
import static java.lang.Integer.parseInt;