blob: 4b6fd3f9128c7ef3b3f79a9882e8f8748c72165c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2016 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.ruby.internal.launching;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.environment.IDeployment;
import org.eclipse.dltk.core.environment.IExecutionEnvironment;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.launching.AbstractInterpreterInstall;
import org.eclipse.dltk.launching.IInterpreterInstallType;
import org.eclipse.dltk.launching.IInterpreterRunner;
import org.eclipse.dltk.launching.InterpreterConfig;
import org.eclipse.dltk.launching.ScriptLaunchUtil;
import org.eclipse.dltk.launching.model.InterpreterGeneratedContent;
import org.eclipse.dltk.launching.model.LaunchingModel;
import org.eclipse.dltk.launching.model.LaunchingModelFactory;
import org.eclipse.dltk.launching.model.util.GeneratedContentPredicate;
import org.eclipse.dltk.ruby.core.RubyNature;
import org.eclipse.dltk.ruby.launching.RubyLaunchingPlugin;
import org.eclipse.emf.ecore.util.EcoreUtil;
public class RubyGenericInstall extends AbstractInterpreterInstall {
public class BuiltinsHelper {
private static final int CACHE_LIFETIME = 24 * 60 * 60 * 1000;
private static final String SCRIPT_NAME = "scripts/builtin.rb"; //$NON-NLS-1$
private static final String PREFIX = "#### DLTK RUBY BUILTINS ####"; //$NON-NLS-1$
private Map<String, String> sources;
private List<String> generateLines() throws IOException, CoreException {
IExecutionEnvironment exeEnv = getExecEnvironment();
IDeployment deployment = exeEnv.createDeployment();
if (deployment == null) {
return null;
}
final IPath builder = deployment.add(RubyLaunchingPlugin
.getDefault().getBundle(), SCRIPT_NAME);
final List<String> lines = new ArrayList<String>();
IFileHandle builderFile = deployment.getFile(builder);
InterpreterConfig config = ScriptLaunchUtil
.createInterpreterConfig(exeEnv, builderFile, builderFile
.getParent());
config.removeEnvVar("RUBYOPT"); //$NON-NLS-1$
// config.addInterpreterArg("-KU"); //$NON-NLS-1$
final Process process = ScriptLaunchUtil.runScriptWithInterpreter(
exeEnv, RubyGenericInstall.this.getInstallLocation()
.toOSString(), config);
Thread readerThread = new Thread(new Runnable() {
@Override
public void run() {
BufferedReader input = null;
try {
input = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null;
try {
while ((line = input.readLine()) != null) {
lines.add(line);
}
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
}
}
});
try {
readerThread.start();
readerThread.join(10000);
} catch (InterruptedException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
deployment.dispose();
return lines;
}
private void parseLines(List<String> lines) {
String fileName = null;
StringBuffer sb = new StringBuffer();
for (String line : lines) {
int index = line.indexOf(PREFIX);
if (index != -1) {
if (fileName != null) {
String old = sources.get(fileName);
if (old == null)
sources.put(fileName, sb.toString());
else
sources.put(fileName, old + "\n\n" + sb.toString()); //$NON-NLS-1$
sb.setLength(0);
}
fileName = line.substring(index + PREFIX.length());
} else {
sb.append(line);
sb.append("\n"); //$NON-NLS-1$
}
}
}
public synchronized Map<String, String> getSources() {
if (sources == null) {
sources = new HashMap<String, String>();
load();
}
return sources;
}
private void load() {
InterpreterGeneratedContent content = (InterpreterGeneratedContent) LaunchingModel
.getInstance().find(RubyGenericInstall.this,
new GeneratedContentPredicate(SCRIPT_NAME));
if (content != null
&& content.getValue() != null
&& content.getLastModified() != null
&& content.getInterpreterLastModified() != null
&& content.getInterpreterLastModified().getTime() == getInstallLocation()
.lastModified()) {
if (content.getFetchedAt() != null
&& content.getFetchedAt().getTime() + CACHE_LIFETIME > System
.currentTimeMillis()) {
parseLines(content.getValue());
lastModified = content.getLastModified().getTime();
return;
}
} else {
content = null;
}
try {
final List<String> lines = generateLines();
if (lines != null) {
parseLines(lines);
if (content != null) {
content = EcoreUtil.copy(content);
content.setFetchedAt(new Date());
if (!lines.equals(content.getValue())) {
content.getValue().clear();
content.getValue().addAll(lines);
content.setLastModified(content.getFetchedAt());
}
} else {
content = LaunchingModelFactory.eINSTANCE
.createInterpreterGeneratedContent();
content.setKey(SCRIPT_NAME);
content.setFetchedAt(new Date());
content.setLastModified(content.getFetchedAt());
content.getValue().clear();
content.getValue().addAll(lines);
content.setInterpreterLastModified(new Date(
getInstallLocation().lastModified()));
}
LaunchingModel.getInstance()
.save(RubyGenericInstall.this,
new GeneratedContentPredicate(SCRIPT_NAME),
content);
lastModified = content.getLastModified().getTime();
}
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
}
long lastModified;
}
private BuiltinsHelper helper = new BuiltinsHelper();
public RubyGenericInstall(IInterpreterInstallType type, String id) {
super(type, id);
}
@Override
public IInterpreterRunner getInterpreterRunner(String mode) {
final IInterpreterRunner runner = super.getInterpreterRunner(mode);
if (runner != null) {
return runner;
}
if (mode.equals(ILaunchManager.RUN_MODE)) {
return new RubyInterpreterRunner(this);
}
return null;
}
@Override
public String getNatureId() {
return RubyNature.NATURE_ID;
}
// Builtins
@Override
public String getBuiltinModuleContent(String name) {
final Map<String, String> sources = helper.getSources();
return sources.get(name);
}
@Override
public long lastModified() {
helper.getSources();
return helper.lastModified;
}
@Override
public String[] getBuiltinModules() {
final Map<String, String> sources = helper.getSources();
return sources.keySet().toArray(new String[sources.size()]);
}
}