package org.rubypeople.rdt.internal.ui.rdocexport;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.RubyUIMessages;
import org.rubypeople.rdt.internal.ui.dialogs.StatusInfo;
import org.rubypeople.rdt.launching.RubyRuntime;
/**
* A utility class which will generate RDoc for a resource. If teh resource is
* not a project, we will search up its hierarchy for a project. We then run
* rdoc on the project (if possible) or the selected resource).
*
* @author Chris
*/
public class RDocUtility {
static {
String generateRdocOption = Platform.getDebugOption(RubyPlugin.PLUGIN_ID + "/generaterdoc");
RDocUtility.setDebugging(generateRdocOption == null ? false : generateRdocOption.equalsIgnoreCase("true"));
}
private static Set<RdocListener> listeners = new HashSet<RdocListener>();
private static boolean isDebug = false;
public static void addRdocListener(RdocListener listener) {
listeners.add(listener);
}
public static void removeRdocListener(RdocListener listener) {
listeners.remove(listener);
}
public static void setDebugging(boolean isDebug) {
RDocUtility.isDebug = isDebug;
}
public static void generateDocumentation(IResource resource) {
RubyInvoker invoker = new RubyInvoker(resource);
invoker.invoke();
notifyListeners();
}
private static class RubyInvoker {
private IResource resource;
private RubyInvoker(IResource resource) {
this.resource = resource;
findParentProject(resource);
}
private void findParentProject(IResource resource) {
IResource project = resource;
while (!isProject(project)) {
project = project.getParent();
if (project == null) break;
}
if (project != null && isProject(project)) this.resource = project;
}
private boolean isProject(IResource resource) {
return (resource instanceof IProject);
}
private void log(String message) {
if (RDocUtility.isDebug) {
System.out.println(message);
}
}
public final void invoke() {
log("Generating RDoc for " + resource.getName());
File file = RubyRuntime.getRDoc();
// check the rdoc path for existence. It might have been
// unconfigured
// and set to the default value or the file could have been removed
// If we can't find it ourselves then display an error to the user
if (file == null || !file.exists() || !file.isFile()) {
MessageDialog.openError(RubyPlugin.getActiveWorkbenchShell(), RubyUIMessages.RDocPathErrorTitle, RubyUIMessages.RDocPathError);
return;
}
List<String> args = new ArrayList<String>();
args.add(file.getAbsolutePath());
args.add("-r");
args.add(resource.getLocation().toOSString());
String[] argArray= (String[]) args.toArray(new String[args.size()]);
try {
Process process= Runtime.getRuntime().exec(argArray);
if (process != null) {
handleOutput(process, args);
}
} catch (IOException e) {
RubyPlugin.log(e);
log(e.getMessage());
ErrorDialog.openError(RubyPlugin.getActiveWorkbenchShell(), RubyUIMessages.ErrorRunningRdocTitle, e.getMessage(), new StatusInfo(StatusInfo.ERROR, e.getMessage()));
}
}
/**
* Get a handle on the process' error stream and pipe it to our Plugin
* to log. Then wait for the process to finish and log a message that
* we're done generating the Rdoc.
*
* @param p
* The Process.
*/
private void handleOutput(Process p, List<String> cmdLine) {
BufferedReader reader = null;
String lastLine = null;
try {
reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = null;
while ((line = reader.readLine()) != null) {
log(line);
lastLine = line;
}
} catch (Exception e) {
log(e.getMessage());
}
try {
p.waitFor();
if (p.exitValue() != 0) {
String message = RubyUIMessages.getFormattedString(RubyUIMessages.RDocExecutionError, Integer.toString(p.exitValue())) ;
String additionalMessage = null;
if (lastLine != null) {
additionalMessage = RubyUIMessages.getFormattedString(RubyUIMessages.RDocExecutionErrorAdditionalMessageWithStderr, new String[] { cmdLine.toString(), lastLine });
} else {
additionalMessage = RubyUIMessages.getFormattedString(RubyUIMessages.RDocExecutionErrorAdditionalMessage, cmdLine.toString());
}
String title = RubyUIMessages.getFormattedString(RubyUIMessages.ErrorRunningRdocTitle, Integer.toString(p.exitValue())) ;
ErrorDialog.openError(RubyPlugin.getActiveWorkbenchShell(), title, message, new StatusInfo(StatusInfo.ERROR, additionalMessage));
}
} catch (InterruptedException e) {
log("InterruptedException while waiting for rdoc process to finish." + e.getMessage());
}
log("Done generating RDoc");
}
}
/**
* Notify registered listeners that the rdoc has changed
*
*/
public static void notifyListeners() {
for (Iterator<RdocListener> iter = listeners.iterator(); iter.hasNext();) {
RdocListener listener = (RdocListener) iter.next();
listener.rdocChanged();
}
}
}