/******************************************************************************* * Copyright (c) 2005, 2016 IBM Corporation and others. * 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 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()]); } }