aboutsummaryrefslogtreecommitdiffstats
path: root/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake
diff options
context:
space:
mode:
Diffstat (limited to 'org.openembedded.bc.ui/src/org/openembedded/bc/bitbake')
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBCommonVars.java24
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBLanguageHelper.java61
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBRecipe.java45
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBSession.java513
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ICommandResponseHandler.java15
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ProjectInfoHelper.java102
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellSession.java233
-rw-r--r--org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellTest2.java111
8 files changed, 1104 insertions, 0 deletions
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBCommonVars.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBCommonVars.java
new file mode 100644
index 0000000..0bd1a44
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBCommonVars.java
@@ -0,0 +1,24 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+/**
+ * Constants for commonly used bitbake variables.
+ * @author kgilmer
+ *
+ */
+public class BBCommonVars {
+ public final static String WORKDIR = "WORKDIR";
+ public static final String PN = "PN";
+ public static final String S = "S";
+ public static final String PV = "PV";
+
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBLanguageHelper.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBLanguageHelper.java
new file mode 100644
index 0000000..249bdee
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBLanguageHelper.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Here is where all BitBake-related information is centralized.
+ * @author kgilmer
+ *
+ */
+public class BBLanguageHelper {
+
+ public static final String[] BITBAKE_KEYWORDS = new String[] { "inherit", "require", "export", "addtask", "python", "include"};
+ public static final String[] SHELL_KEYWORDS = new String[] { "while", "do", "if", "fi", "ln", "export", "install", "oe_libinstall", "for", "in", "done", "echo", "then", "cat", "rm", "rmdir", "mkdir", "printf", "exit", "test", "cd", "cp"};
+ public static final String[] BITBAKE_STANDARD_FUNCTIONS = new String[] { "stage", "configure", "compile", "install" };
+ public static final String BITBAKE_RECIPE_FILE_EXTENSION = "bb";
+
+ /**
+ * @return A map of names and descriptions of commonly used BitBake variables.
+ */
+ public static Map getCommonBitbakeVariables() {
+ Map m = new TreeMap(new Comparator() {
+
+ public int compare(Object o1, Object o2) {
+
+ return ((String) o1).compareTo(((String) o2));
+ }
+
+ });
+
+ m.put("SECTION", "Category of package");
+ m.put("PR", "Package Release Number");
+ m.put("SRC_URI", "Location of package sources");
+ m.put("DESCRIPTION", "Description of package");
+ m.put("EXTRA_OEMAKE", "Extra flags to pass to the package makefile");
+ m.put("EXTRA_OECONF", "Extra configuration flags for the package makefile");
+ m.put("DEPENDS", "The set of build-time dependent packages");
+ m.put("RDEPENDS", "The set of run-time dependent packages");
+ m.put("HOMEPAGE", "Homepage of the package");
+ m.put("LICENSE", "License of the package");
+ m.put("FILES_${PN}", "Full file path of files on target.");
+ m.put("S", "Package source directory");
+ m.put("PV", "Package version");
+ m.put("AUTHOR", "Author or maintainer of package");
+ m.put("PRIORITY", "Priority of package");
+
+ return m;
+ }
+
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBRecipe.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBRecipe.java
new file mode 100644
index 0000000..3321abd
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBRecipe.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+import java.io.IOException;
+
+/**
+ * Represents the bitbake environment of a recipe package.
+ * @author kgilmer
+ *
+ */
+public class BBRecipe extends BBSession {
+ private final BBSession session;
+ private final String filePath;
+
+ public BBRecipe(BBSession session, String filePath) throws IOException {
+ super(session.shell, session.pinfo.getRootPath());
+ this.session = session;
+ this.filePath = filePath;
+ }
+
+ @Override
+ public void initialize() throws Exception {
+ if (initialized) {
+ return;
+ }
+
+ String ret = shell.execute("bitbake -e -b " + filePath);
+ properties = parseBBEnvironment(ret);
+
+ if (ret == null || properties.size() == 0) {
+ throw new IOException("Failed to parse " + filePath);
+ }
+
+ initialized = true;
+ }
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBSession.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBSession.java
new file mode 100644
index 0000000..87b3f53
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/BBSession.java
@@ -0,0 +1,513 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.MessageConsole;
+import org.openembedded.bc.ui.model.IModelElement;
+import org.openembedded.bc.ui.model.ProjectInfo;
+
+
+/**
+ * BBSession encapsulates a global bitbake configuration and is the primary interface
+ * for actions against a BitBake installation.
+ *
+ * @author kgilmer
+ *
+ */
+public class BBSession implements IModelElement, Map {
+ public static final int TYPE_VARIABLE_ASSIGNMENT = 1;
+ public static final int TYPE_UNKNOWN = 2;
+ public static final int TYPE_STATEMENT = 3;
+ public static final int TYPE_FLAG = 4;
+
+ protected final ProjectInfo pinfo;
+ protected final ShellSession shell;
+ protected Map properties = null;
+ protected boolean initialized = false;
+ private MessageConsole sessionConsole;
+
+ public BBSession(ShellSession ssession, String projectRoot) throws IOException {
+ shell = ssession;
+ this.pinfo = new ProjectInfo();
+ pinfo.setLocation(projectRoot);
+ pinfo.setInitScriptPath(ProjectInfoHelper.getInitScriptPath(projectRoot));
+ }
+
+ private Collection adapttoIPath(List<File> asList, IProject project) {
+
+ List pathList = new ArrayList();
+
+ for (Iterator i = asList.iterator(); i.hasNext();) {
+ File f = (File) i.next();
+ IFile ff = project.getFile(stripLeading(f.toString(), project.getLocationURI().getPath()));
+ if (ff.exists()) {
+ pathList.add(ff);
+ }
+ }
+
+ return pathList;
+ }
+
+ private String appendAll(String[] elems, int st) {
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = st; i < elems.length; ++i) {
+ sb.append(elems[i]);
+ }
+
+ return sb.toString();
+ }
+
+ private int charCount(String trimmed, char c) {
+ int i = 0;
+ int p = 0;
+
+ while ((p = trimmed.indexOf(c, p)) > -1) {
+ i++;
+ p++;
+ }
+
+ return i;
+ }
+
+ public void clear() {
+ throw new RuntimeException("BB configuration is read-only.");
+ }
+
+ public boolean containsKey(Object arg0) {
+ return properties.containsKey(arg0);
+ }
+
+ public boolean containsValue(Object arg0) {
+ return properties.containsValue(arg0);
+ }
+
+ public Set entrySet() {
+ return properties.entrySet();
+ }
+
+ @Override
+ public boolean equals(Object arg0) {
+ return properties.equals(arg0);
+ }
+
+ public ShellSession getShell() {
+ return shell;
+ }
+
+ /**
+ * Recursively generate list of Recipe files from a root directory.
+ *
+ * @param rootDir
+ * @param recipes
+ * @param fileExtension
+ * @param project
+ */
+ private void findRecipes(File rootDir, List recipes, final String fileExtension, IProject project) {
+ File[] children = rootDir.listFiles(new FileFilter() {
+
+ public boolean accept(File pathname) {
+ return pathname.isFile() && pathname.getName().endsWith(fileExtension);
+ }
+
+ });
+
+ if (children != null && children.length > 0) {
+ recipes.addAll(adapttoIPath(Arrays.asList(children), project));
+ }
+
+ File[] childDirs = rootDir.listFiles(new FileFilter() {
+
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+
+ });
+
+ if (childDirs != null && childDirs.length > 0) {
+ for (int i = 0; i < childDirs.length; ++i) {
+ findRecipes(childDirs[i], recipes, fileExtension, project);
+ }
+ }
+ }
+
+ private Collection findRecipes(List paths, IProject project) {
+ List recipes = new ArrayList();
+
+ for (Iterator i = paths.iterator(); i.hasNext();) {
+ String rawPath = (String) i.next();
+ String[] elems = rawPath.split("\\*/\\*");
+
+ if (elems.length == 2) {
+
+ File rootDir = new File(elems[0]);
+
+ findRecipes(rootDir, recipes, elems[1], project);
+ }
+ }
+
+ return recipes;
+ }
+
+ public Object get(Object arg0) {
+ return properties.get(arg0);
+ }
+
+ private List getBitBakeKeywords() {
+ return Arrays.asList(BBLanguageHelper.BITBAKE_KEYWORDS);
+ }
+
+ /**
+ * @return A MessageConsole for this BB session.
+ */
+ public MessageConsole getConsole() {
+ if (sessionConsole == null) {
+ String cName = ProjectInfoHelper.getProjectName(pinfo.getRootPath()) + " Console";
+ sessionConsole = new MessageConsole(cName, null);
+ ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { sessionConsole });
+ }
+
+ ConsolePlugin.getDefault().getConsoleManager().showConsoleView(sessionConsole);
+
+ return sessionConsole;
+ }
+
+ private int getLineType(String line) {
+
+ if (line.contains("=")) {
+ return TYPE_VARIABLE_ASSIGNMENT;
+ }
+
+ for (Iterator i = getBitBakeKeywords().iterator(); i.hasNext();) {
+ if (line.startsWith((String) i.next())) {
+ return TYPE_STATEMENT;
+ }
+ }
+
+ if (line.contains(":")) {
+ return TYPE_FLAG;
+ }
+
+ return TYPE_UNKNOWN;
+ }
+
+ public Collection getRecipeFiles(IProject project) {
+ if (!initialized) {
+ throw new RuntimeException(this.getClass().getName() + " is not initialized.");
+ }
+ String bbfiles = (String) this.properties.get("BBFILES");
+
+ List paths = parseBBFiles(bbfiles);
+
+ return findRecipes(paths, project);
+ }
+
+ @Override
+ public int hashCode() {
+ return properties.hashCode();
+ }
+
+ public void initialize() throws Exception {
+ if (initialized) {
+ return;
+ }
+
+ properties = parseBBEnvironment(shell.execute("bitbake -e"));
+ initialized = true;
+ }
+
+ private boolean isBlockEnd(String trimmed) {
+ return charCount(trimmed, '}') > charCount(trimmed, '{');
+ // return trimmed.indexOf('}') > -1 && trimmed.indexOf('{') == -1;
+ }
+
+ private boolean isBlockStart(String trimmed) {
+ return charCount(trimmed, '{') > charCount(trimmed, '}');
+ // return trimmed.indexOf('{') > -1 && trimmed.indexOf('}') == -1;
+ }
+
+ public boolean isEmpty() {
+ return properties.isEmpty();
+ }
+
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ public Set keySet() {
+ return properties.keySet();
+ }
+
+ protected void parse(String content, Map outMap) throws Exception {
+ BufferedReader reader = new BufferedReader(new StringReader(content));
+ String line;
+ boolean inLine = false;
+ StringBuffer sb = null;
+ Stack blockStack = new Stack();
+
+ while ((line = reader.readLine()) != null) {
+ String trimmed = line.trim();
+ if (trimmed.length() == 0 || line.startsWith("#")) {
+ // weed out the blank and comment lines
+ continue;
+ }
+ // Now we look for block start ends, and ignore all code within
+ // blocks.
+ if (isBlockStart(trimmed)) {
+ blockStack.push(trimmed);
+ } else if (isBlockEnd(trimmed)) {
+ blockStack.pop();
+
+ }
+
+ if (!blockStack.isEmpty()) {
+ // we are in a code block, continue until we break into global
+ // scope.
+ continue;
+ }
+ if (trimmed.endsWith("\\")) {
+ if (!inLine) {
+ inLine = true;
+ sb = new StringBuffer(trimmed.substring(0, trimmed.length() - 1));
+ } else {
+ sb.append(trimmed.substring(0, trimmed.length() - 1));
+ }
+ // Only parse the line when we have the complete contents.
+ continue;
+ } else if (inLine) {
+ inLine = false;
+ line = sb.toString();
+ }
+
+ parseLine(line, outMap);
+ }
+ }
+
+ private void parseAdditiveAssignment(String line, String operator, Map mo) throws Exception {
+ String[] elems = splitAssignment(line, "\\+=");
+
+ if (elems.length != 2) {
+ throw new Exception("Unable to parse additive variable assignment in line: " + line);
+ }
+
+ if (!mo.containsKey(elems[0])) {
+ mo.put(elems[0].trim(), elems[1]);
+ } else {
+ String existing = (String) mo.get(elems[0]);
+ if (operator.equals("+=")) {
+ mo.put(elems[0], existing + elems[1]);
+ } else {
+ mo.put(elems[0], elems[1] + existing);
+ }
+ }
+ }
+
+ protected Map parseBBEnvironment(String bbOut) throws Exception {
+ Map env = new Hashtable();
+
+ parse(bbOut, env);
+
+ return env;
+ }
+
+
+ private List parseBBFiles(String bbfiles) {
+ return Arrays.asList(bbfiles.split(" "));
+ }
+
+ //Map delegate methods
+
+ private void parseConditionalAssignment(String line, Map mo) throws Exception {
+ String[] elems = splitAssignment(line, "\\?=");
+
+ if (elems.length != 2) {
+ throw new Exception("Unable to parse conditional variable assignment in line: " + line);
+ }
+
+ if (!mo.containsKey(elems[0].trim())) {
+ mo.put(elems[0].trim(), elems[1].trim());
+ }
+ }
+
+ private void parseImmediateAssignment(String line, String delimiter, Map mo) throws Exception {
+ String[] elems = splitAssignment(line, delimiter);
+
+ mo.put(elems[0], substitute(elems[1], mo));
+ }
+
+ private void parseKeyValue(String line, String delimiter, Map mo) throws Exception {
+ String[] elems = splitAssignment(line, delimiter);
+
+ mo.put(elems[0], elems[1]);
+ }
+
+ private void parseLine(String line, Map mo) throws Exception {
+
+ switch (getLineType(line)) {
+ case TYPE_VARIABLE_ASSIGNMENT:
+ parseVariableAssignment(line, mo);
+ break;
+ case TYPE_STATEMENT:
+ case TYPE_FLAG:
+ // for now ignore statements
+ break;
+ case TYPE_UNKNOWN:
+ // we'll gloss over unknown lines as well;
+ break;
+ default:
+ throw new Exception("Unable to parse line: " + line);
+ }
+ }
+
+ private void parseVariableAssignment(String line, Map mo) throws Exception {
+ if (line.contains("?=")) {
+ parseConditionalAssignment(line, mo);
+ } else if (line.contains("+=")) {
+ parseAdditiveAssignment(line, "+=", mo);
+ } else if (line.contains("=+")) {
+ parseAdditiveAssignment(line, "=+", mo);
+ } else if (line.contains(":=")) {
+ parseImmediateAssignment(line, ":=", mo);
+ } else {
+ parseKeyValue(line, "=", mo);
+ }
+
+ }
+
+ private List parseVars(String line) {
+ List l = new ArrayList();
+
+ int i = 0;
+
+ while ((i = line.indexOf("${", i)) > -1) {
+ int i2 = line.indexOf("}", i);
+
+ l.add(line.subSequence(i + 2, i2));
+ i++;
+ }
+
+ return l;
+ }
+
+ public Object put(Object arg0, Object arg1) {
+ throw new RuntimeException("BB configuration is read-only.");
+ }
+
+ public void putAll(Map arg0) {
+ throw new RuntimeException("BB configuration is read-only.");
+ }
+
+ public Object remove(Object arg0) {
+ throw new RuntimeException("BB configuration is read-only.");
+ }
+
+ private String removeQuotes(String line) {
+ line = line.trim();
+
+ if (line.startsWith("\"")) {
+ line = line.substring(1);
+ }
+
+ if (line.endsWith("\"")) {
+ line = line.substring(0, line.length() - 1);
+ }
+
+ return line;
+ }
+
+ public int size() {
+ return properties.size();
+ }
+
+ private String[] splitAssignment(String line, String seperator) throws Exception {
+ String[] elems = line.split(seperator);
+
+ if (elems.length < 2) {
+ throw new Exception("Unable to parse assignment in line: " + line);
+ } else if (elems.length == 2) {
+
+ elems[0] = elems[0].trim(); // Clean up trailing or leading spaces.
+ if (elems[0].startsWith("export ")) {
+ elems[0] = elems[0].substring("export ".length()).trim();
+ }
+ elems[1] = removeQuotes(elems[1]); // Evaluate variables
+
+ return elems;
+ } else {
+ String[] retVal = new String[2];
+
+ retVal[0] = elems[0];
+ if (retVal[0].startsWith("export ")) {
+ retVal[0] = retVal[0].substring("export ".length()).trim();
+ }
+ retVal[1] = appendAll(elems, 1);
+
+ return retVal;
+ }
+ }
+
+ private String stripLeading(String target, String leading) {
+ if (target.startsWith(leading)) {
+ target = target.substring(leading.length());
+ }
+
+ return target;
+ }
+
+ /**
+ * Return a string with variable substitutions in place.
+ *
+ * @param expression
+ * @return Input string with any substitutions from this file.
+ */
+ public String substitute(String expression, Map mo) {
+
+ List vars = parseVars(expression);
+
+ for (Iterator i = vars.iterator(); i.hasNext();) {
+ String varName = (String) i.next();
+ String varToken = "${" + varName + "}";
+
+ if (mo.containsKey(varName)) {
+ expression = expression.replace(varToken, (String) mo.get(varName));
+ } else if (System.getProperty(varName) != null) {
+ expression = expression.replace(varToken, System.getProperty(varName));
+ } else if (varName.toUpperCase().equals("HOME")) {
+ expression = expression.replace(varToken, System.getProperty("user.home"));
+ }
+ }
+
+ return expression;
+ }
+
+ public Collection values() {
+ return properties.values();
+ }
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ICommandResponseHandler.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ICommandResponseHandler.java
new file mode 100644
index 0000000..bc32895
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ICommandResponseHandler.java
@@ -0,0 +1,15 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+public interface ICommandResponseHandler {
+ public void response(String line, boolean isError);
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ProjectInfoHelper.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ProjectInfoHelper.java
new file mode 100644
index 0000000..37cc28b
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ProjectInfoHelper.java
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.openembedded.bc.ui.model.ProjectInfo;
+
+
+/**
+ * A helper class for ProjectInfo related tasks.
+ *
+ * @author kgilmer
+ *
+ */
+public class ProjectInfoHelper {
+
+ /**
+ * @param path
+ * @return The path to bitbake init script
+ * @throws IOException
+ */
+ public static String getInitScriptPath(String path) throws IOException {
+ File inFile = new File(path, ".eclipse-data");
+ BufferedReader br = new BufferedReader(new FileReader(inFile));
+
+ String val = br.readLine();
+
+ br.close();
+
+ return val;
+ }
+
+ public static String getInitScript(String path) throws IOException {
+ File inFile = new File(path);
+ BufferedReader br = new BufferedReader(new FileReader(inFile));
+ StringBuffer sb = new StringBuffer();
+ String line = null;
+
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+
+ br.close();
+
+ return sb.toString();
+ }
+
+ public static String getProjectName(String projectRoot) {
+ IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ for (int i = 0; i < projects.length; ++i) {
+ try {
+ if (projects[i].getLocationURI().getPath().equals(projectRoot)) {
+ return projects[i].getName();
+ }
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * This method will store the path to the bitbake init script for future
+ * reference.
+ *
+ * @param path
+ * @param projInfo
+ * @throws IOException
+ */
+ public static void store(String path, ProjectInfo projInfo) throws IOException {
+ writeToFile(path, projInfo.getInitScriptPath());
+ }
+
+ private static void writeToFile(String path, String init) throws IOException {
+ File outFile = new File(path, ".eclipse-data");
+ FileOutputStream fos = new FileOutputStream(outFile);
+
+ fos.write(init.getBytes());
+
+ fos.flush();
+ fos.close();
+ }
+
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellSession.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellSession.java
new file mode 100644
index 0000000..37f478f
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellSession.java
@@ -0,0 +1,233 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Ken Gilmer
+ * 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
+ *
+ * Contributors:
+ * Ken Gilmer - initial API and implementation
+ *******************************************************************************/
+package org.openembedded.bc.bitbake;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * A class for Linux shell sessions.
+ * @author kgilmer
+ *
+ */
+public class ShellSession {
+ /**
+ * Bash shell
+ */
+ public static final int SHELL_TYPE_BASH = 1;
+ /**
+ * sh shell
+ */
+ public static final int SHELL_TYPE_SH = 2;
+ private volatile boolean interrupt = false;
+ /**
+ * String used to isolate command execution
+ */
+ public static final String TERMINATOR = "234o987dsfkcqiuwey18837032843259d";
+ public static final String LT = System.getProperty("line.separator");
+
+ public static String getFilePath(String file) throws IOException {
+ File f = new File(file);
+
+ if (!f.exists() || f.isDirectory()) {
+ throw new IOException("Path passed is not a file: " + file);
+ }
+
+ StringBuffer sb = new StringBuffer();
+
+ String elems[] = file.split(File.separator);
+
+ for (int i = 0; i < elems.length - 1; ++i) {
+ sb.append(elems[i]);
+ sb.append(File.separator);
+ }
+
+ return sb.toString();
+ }
+ private Process process;
+
+ private OutputStream pos = null;
+ //private File initFile = null;
+ private String shellPath = null;
+ private final String initCmd;
+ private final File root;
+ private final Writer out;
+
+
+ public ShellSession(int shellType, File root, String initCmd, Writer out) throws IOException {
+ this.root = root;
+ this.initCmd = initCmd;
+ if (out == null) {
+ this.out = new NullWriter();
+ } else {
+ this.out = out;
+ }
+ if (shellType == SHELL_TYPE_SH) {
+ shellPath = "/bin/sh";
+ }
+ shellPath = "/bin/bash";
+
+ initializeShell();
+ }
+
+ private void initializeShell() throws IOException {
+ process = Runtime.getRuntime().exec(shellPath);
+ pos = process.getOutputStream();
+
+ if (root != null) {
+ out.write(execute("cd " + root.getAbsolutePath()));
+ }
+
+ if (initCmd != null) {
+ out.write(execute("source " + initCmd));
+ }
+ }
+
+ synchronized public String execute(String command) throws IOException {
+ String errorMessage = null;
+ interrupt = false;
+ out.write(command);
+ out.write(LT);
+
+ sendToProcessAndTerminate(command);
+
+ if (process.getErrorStream().available() > 0) {
+ byte[] msg = new byte[process.getErrorStream().available()];
+
+ process.getErrorStream().read(msg, 0, msg.length);
+ out.write(new String(msg));
+ out.write(LT);
+ errorMessage = "Error while executing: " + command + LT + new String(msg);
+ }
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(process
+ .getInputStream()));
+
+ StringBuffer sb = new StringBuffer();
+ String line = null;
+
+ while (((line = br.readLine()) != null) && !line.equals(TERMINATOR) && !interrupt) {
+ sb.append(line);
+ sb.append(LT);
+ out.write(line);
+ out.write(LT);
+ }
+
+ if (interrupt) {
+ process.destroy();
+ initializeShell();
+ interrupt = false;
+ }
+
+ if (errorMessage != null) {
+ throw new IOException(errorMessage);
+ }
+
+ return sb.toString();
+ }
+
+ synchronized public void execute(String command, ICommandResponseHandler handler) throws IOException {
+ execute(command, TERMINATOR, handler);
+ }
+
+ synchronized public void execute(String command, String terminator, ICommandResponseHandler handler) throws IOException {
+ interrupt = false;
+ InputStream errIs = process.getErrorStream();
+ if (errIs.available() > 0) {
+ clearErrorStream(errIs);
+ }
+ sendToProcessAndTerminate(command);
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ String std = null;
+
+ do {
+ if (errIs.available() > 0) {
+ byte[] msg = new byte[errIs.available()];
+
+ errIs.read(msg, 0, msg.length);
+ out.write(new String(msg));
+ handler.response(new String(msg), true);
+ }
+
+ std = br.readLine();
+
+ if (std != null && !std.equals(terminator)) {
+ out.write(std);
+ handler.response(std, false);
+ }
+
+ } while (std != null && !std.equals(terminator) && !interrupt);
+
+ if (interrupt) {
+ process.destroy();
+ initializeShell();
+ interrupt = false;
+ }
+ }
+
+ private void clearErrorStream(InputStream is) {
+
+ try {
+ byte b[] = new byte[is.available()];
+ is.read(b);
+ //System.out.println("clearing: " + new String(b));
+ } catch (IOException e) {
+ e.printStackTrace();
+ //Ignore any error
+ }
+ }
+
+ /**
+ * Send command string to shell process and add special terminator string so
+ * reader knows when output is complete.
+ *
+ * @param command
+ * @throws IOException
+ */
+ private void sendToProcessAndTerminate(String command) throws IOException {
+ pos.write(command.getBytes());
+ pos.write(LT.getBytes());
+ pos.flush();
+ pos.write("echo ".getBytes());
+ pos.write(TERMINATOR.getBytes());
+ pos.write(LT.getBytes());
+ pos.flush();
+ }
+
+ /**
+ * Interrupt any running processes.
+ */
+ public void interrupt() {
+ interrupt = true;
+ }
+
+ private class NullWriter extends Writer {
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ }
+
+ }
+}
diff --git a/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellTest2.java b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellTest2.java
new file mode 100644
index 0000000..8ef5ef5
--- /dev/null
+++ b/org.openembedded.bc.ui/src/org/openembedded/bc/bitbake/ShellTest2.java
@@ -0,0 +1,111 @@
+package org.openembedded.bc.bitbake;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * Tests for ShellSession.
+ *
+ * @author kgilmer
+ *
+ */
+public class ShellTest2 {
+ public static void main(String[] args) {
+ ShellTest2 st = new ShellTest2();
+
+ //testSimpleCommands();
+
+ testStreamResponse();
+ }
+
+ private static void streamOut(InputStream executeIS) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(executeIS));
+
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ System.out.println(line);
+ }
+ }
+
+ private static void testSimpleCommands() {
+ try {
+ ShellSession ss = new ShellSession(ShellSession.SHELL_TYPE_BASH, null, null, null);
+ System.out.println(ss.execute("echo \"bo is $boo\""));
+
+ System.out.println(ss.execute("export boo=asdf"));
+
+ System.out.println(ss.execute("echo \"bo is $boo\""));
+
+ System.out.println(ss.execute("cd /home/kgilmer/dev/workspaces/com.buglabs.build.oe"));
+ System.out.println(ss.execute("source reinstate-build-env"));
+ System.out.println(ss.execute("echo $BBPATH"));
+ System.out.println(ss.execute("bitbake -e"));
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private static void testStreamResponse() {
+ try {
+ final ShellSession ss = new ShellSession(ShellSession.SHELL_TYPE_BASH, null, null, null);
+
+ ss.execute("./loop.sh", ShellSession.TERMINATOR, new ICommandResponseHandler() {
+
+ public void response(String line, boolean isError) {
+ if (isError) {
+ System.out.println("ERROR: " + line);
+ } else {
+ System.out.println(line);
+ ss.interrupt();
+ }
+
+ }
+ });
+
+ ss.execute("ls /home", ShellSession.TERMINATOR, new ICommandResponseHandler() {
+
+ public void response(String line, boolean isError) {
+ if (isError) {
+ System.err.println("ERROR: " + line);
+ } else {
+ System.out.println(line);
+ }
+ }
+ });
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+/* *//**
+ * A reader that will terminate upon reading a specific line. Prevents reader from blocking.
+ *
+ * @author kgilmer
+ *//*
+ private class LineTerminatingReader extends BufferedReader {
+
+ private final String terminator;
+
+ public LineTerminatingReader(Reader in, String terminator) {
+ super(in);
+ this.terminator = terminator;
+ }
+
+ public String readLine() throws IOException {
+ String line = null;
+
+ while (((line = this.readLine()) != null) && !line.equals(terminator)) {
+ return line;
+ }
+
+ return null;
+ }
+
+ }*/
+}