package com.aptana.rdt.internal.launching;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.rubypeople.rdt.core.LoadpathVariableInitializer;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.util.Util;
import org.rubypeople.rdt.internal.launching.LaunchingPlugin;
import org.rubypeople.rdt.launching.IVMInstall;
import org.rubypeople.rdt.launching.IVMInstallChangedListener;
import org.rubypeople.rdt.launching.PropertyChangeEvent;
import org.rubypeople.rdt.launching.RubyRuntime;
import com.aptana.rdt.AptanaRDTPlugin;
import com.aptana.rdt.core.gems.IGemManager;
import com.aptana.rdt.launching.IGemRuntime;
public class GemLoadpathVariablesInitializer extends
LoadpathVariableInitializer implements IVMInstallChangedListener {
private static final String LEOPARD_GEM_PATH_1 = "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems";
private static final String LEOPARD_GEM_PATH_2 = "/Library/Ruby/Gems/1.8/gems";
private IProgressMonitor fMonitor;
public GemLoadpathVariablesInitializer() {
RubyRuntime.addVMInstallChangedListener(this);
}
@Override
public void initialize(final String variable) {
if (!variable.equals(IGemRuntime.GEMLIB_VARIABLE))
return;
IVMInstall vmInstall = RubyRuntime.getDefaultVMInstall();
if (vmInstall == null)
return;
// Return a "quick 'n dirty" guess, then run a job that sets the real
// value later
setQuickNDirtyPaths(variable, vmInstall);
Job realJob = new Job("") {
@Override
protected IStatus run(IProgressMonitor monitor) {
IGemManager gemManager = AptanaRDTPlugin.getDefault()
.getGemManager();
List<IPath> gemPaths = null;
int tries = 3; // Try to grab install path up to 3 times
while (tries > 0) {
gemPaths = gemManager.getGemInstallPaths();
if (gemPaths != null)
break;
tries--;
}
if (gemPaths == null) {
gemPaths = loadCachedValue();
} else {
saveValue(gemPaths);
}
if (gemPaths == null) {
return new Status(Status.ERROR, AptanaRDTPlugin.PLUGIN_ID,
-1, "Unable to retrieve gem install paths", null);
}
IPath[] paths = new IPath[gemPaths.size()];
int i = 0;
for (IPath path : gemPaths) {
paths[i++] = path.append("gems");
}
// Fix this for cygwin (need to resolve location to actual
// filesystem)
if (RubyRuntime.currentVMIsCygwin()) {
File home = RubyRuntime.getDefaultVMInstall()
.getInstallLocation();
for (int x = 0; x < paths.length; x++) {
// if starts with /usr/lib, convert to lib
// TODO Run "mount" to figure out mappings?
String portablePath = paths[x].toOSString();
if (portablePath.startsWith("\\usr\\lib")) {
portablePath = portablePath.substring(4);
}
String cygwinConverted = home.getAbsolutePath()
+ portablePath;
IPath path = new Path(cygwinConverted);
paths[x] = path;
}
}
setVariable(variable, paths);
return Status.OK_STATUS;
}
private void saveValue(List<IPath> gemPaths) {
File file = getCacheFile();
FileWriter writer = null;
try {
if (!file.exists())
file.createNewFile();
writer = new FileWriter(file);
for (IPath gemPath : gemPaths) {
writer.write(gemPath.toPortableString() + "\n");
}
} catch (IOException e) {
AptanaRDTPlugin.log(e);
} finally {
try {
if (writer != null)
writer.close();
} catch (IOException e) {
// ignore
}
}
}
private File getCacheFile() {
IPath path = AptanaRDTPlugin.getDefault().getStateLocation()
.append(
RubyRuntime.getDefaultVMInstall().getId()
+ "_gem_install_paths.txt");
return path.toFile();
}
private List<IPath> loadCachedValue() {
List<IPath> paths = new ArrayList<IPath>();
try {
String contents = new String(Util.getFileCharContent(
getCacheFile(), null));
String[] rawPaths = contents.split("\n");
for (int i = 0; i < rawPaths.length; i++) {
paths.add(Path.fromPortableString(rawPaths[i]));
}
} catch (IOException e) {
AptanaRDTPlugin.log(e);
}
return paths;
}
};
realJob.setSystem(true);
realJob.setPriority(Job.LONG);
realJob.schedule();
}
private void setQuickNDirtyPaths(final String variable, IVMInstall vmInstall) {
if (Platform.getOS().equals(Platform.OS_MACOSX)
&& !RubyRuntime.currentVMIsJRuby()) { // Special quick and dirty
// paths for Mac OSX
// Leopard!
File dir = new File(LEOPARD_GEM_PATH_2);
if (dir.exists()) {
setVariable(variable, new IPath[] {
new Path(LEOPARD_GEM_PATH_1),
new Path(LEOPARD_GEM_PATH_2) });
return;
}
}
IPath quickNDirty = new Path(vmInstall.getInstallLocation()
.getAbsolutePath()).append("lib").append("ruby").append("gems")
.append("1.8").append("gems");
setVariable(variable, new IPath[] { quickNDirty });
}
private void setVariable(String variable, IPath newPath[]) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription wsDescription = workspace.getDescription();
boolean wasAutobuild = wsDescription.isAutoBuilding();
try {
setAutobuild(workspace, false);
setRubyVMVariable(newPath, variable);
} catch (CoreException ce) {
LaunchingPlugin.log(ce);
return;
} finally {
try {
setAutobuild(workspace, wasAutobuild);
} catch (CoreException ce) {
LaunchingPlugin.log(ce);
}
}
}
private void setRubyVMVariable(IPath[] newPath, String var)
throws CoreException {
RubyCore.setLoadpathVariable(var, newPath, getMonitor());
}
private boolean setAutobuild(IWorkspace ws, boolean newState)
throws CoreException {
IWorkspaceDescription wsDescription = ws.getDescription();
boolean oldState = wsDescription.isAutoBuilding();
if (oldState != newState) {
wsDescription.setAutoBuilding(newState);
ws.setDescription(wsDescription);
}
return oldState;
}
protected IProgressMonitor getMonitor() {
if (fMonitor == null) {
return new NullProgressMonitor();
}
return fMonitor;
}
public void defaultVMInstallChanged(IVMInstall previous, IVMInstall current) {
initialize(IGemRuntime.GEMLIB_VARIABLE);
}
public void vmAdded(IVMInstall newVm) {
}
public void vmChanged(PropertyChangeEvent event) {
}
public void vmRemoved(IVMInstall removedVm) {
}
}