diff options
author | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 13:36:50 +0100 |
---|---|---|
committer | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 15:25:03 +0100 |
commit | 41ac47d732eed8392d60d0f6773e5a279d49b999 (patch) | |
tree | cf19d099db9cfdb8d73aa21c31e7aa1cc86ff860 /plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake | |
download | eclipse-poky-juno-master.tar.gz |
Migrated from the internal git server on the dora-enea branch
Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
Diffstat (limited to 'plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake')
8 files changed, 1261 insertions, 0 deletions
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBCommonVars.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBCommonVars.java new file mode 100644 index 0000000..d905e50 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBCommonVars.java | |||
@@ -0,0 +1,24 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | /** | ||
14 | * Constants for commonly used bitbake variables. | ||
15 | * @author kgilmer | ||
16 | * | ||
17 | */ | ||
18 | public class BBCommonVars { | ||
19 | public final static String WORKDIR = "WORKDIR"; | ||
20 | public static final String PN = "PN"; | ||
21 | public static final String S = "S"; | ||
22 | public static final String PV = "PV"; | ||
23 | |||
24 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBLanguageHelper.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBLanguageHelper.java new file mode 100644 index 0000000..8ebe134 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBLanguageHelper.java | |||
@@ -0,0 +1,62 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | * Lianhao Lu (Intel) - add more bitbake keywords and functions | ||
11 | *******************************************************************************/ | ||
12 | package org.yocto.bc.bitbake; | ||
13 | |||
14 | import java.util.Comparator; | ||
15 | import java.util.Map; | ||
16 | import java.util.TreeMap; | ||
17 | |||
18 | /** | ||
19 | * Here is where all BitBake-related information is centralized. | ||
20 | * @author kgilmer | ||
21 | * | ||
22 | */ | ||
23 | public class BBLanguageHelper { | ||
24 | |||
25 | public static final String[] BITBAKE_KEYWORDS = new String[] { "inherit", "require", "export", "addtask", "python", "include", "fakeroot", "addhandler", "def"}; | ||
26 | 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"}; | ||
27 | public static final String[] BITBAKE_STANDARD_FUNCTIONS = new String[] { "fetch", "unpack", "patch", "configure", "compile", "install", "populate_sysroot", "package"}; | ||
28 | public static final String BITBAKE_RECIPE_FILE_EXTENSION = "bb"; | ||
29 | |||
30 | /** | ||
31 | * @return A map of names and descriptions of commonly used BitBake variables. | ||
32 | */ | ||
33 | public static Map<String, String> getCommonBitbakeVariables() { | ||
34 | Map<String, String> m = new TreeMap<String, String>(new Comparator<Object>() { | ||
35 | |||
36 | public int compare(Object o1, Object o2) { | ||
37 | |||
38 | return ((String) o1).compareTo(((String) o2)); | ||
39 | } | ||
40 | |||
41 | }); | ||
42 | |||
43 | m.put("SECTION", "Category of package"); | ||
44 | m.put("PR", "Package Release Number"); | ||
45 | m.put("SRC_URI", "Location of package sources"); | ||
46 | m.put("DESCRIPTION", "Description of package"); | ||
47 | m.put("EXTRA_OEMAKE", "Extra flags to pass to the package makefile"); | ||
48 | m.put("EXTRA_OECONF", "Extra configuration flags for the package makefile"); | ||
49 | m.put("DEPENDS", "The set of build-time dependent packages"); | ||
50 | m.put("RDEPENDS", "The set of run-time dependent packages"); | ||
51 | m.put("HOMEPAGE", "Homepage of the package"); | ||
52 | m.put("LICENSE", "License of the package"); | ||
53 | m.put("FILES_${PN}", "Full file path of files on target."); | ||
54 | m.put("S", "Package source directory"); | ||
55 | m.put("PV", "Package version"); | ||
56 | m.put("AUTHOR", "Author or maintainer of package"); | ||
57 | m.put("PRIORITY", "Priority of package"); | ||
58 | |||
59 | return m; | ||
60 | } | ||
61 | |||
62 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBRecipe.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBRecipe.java new file mode 100644 index 0000000..2b355ba --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBRecipe.java | |||
@@ -0,0 +1,50 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | import java.io.IOException; | ||
14 | |||
15 | import org.eclipse.jface.preference.JFacePreferences; | ||
16 | import org.eclipse.jface.resource.JFaceResources; | ||
17 | import org.eclipse.swt.widgets.Display; | ||
18 | import org.eclipse.ui.console.ConsolePlugin; | ||
19 | import org.eclipse.ui.console.IConsole; | ||
20 | import org.eclipse.ui.console.MessageConsole; | ||
21 | import org.eclipse.ui.console.MessageConsoleStream; | ||
22 | |||
23 | /** | ||
24 | * Represents the bitbake environment of a recipe package. | ||
25 | * @author kgilmer | ||
26 | * | ||
27 | */ | ||
28 | public class BBRecipe extends BBSession { | ||
29 | private final BBSession session; | ||
30 | private final String filePath; | ||
31 | |||
32 | public BBRecipe(BBSession session, String filePath) throws IOException { | ||
33 | super(session.shell, session.pinfo.getRootPath()); | ||
34 | this.session = session; | ||
35 | this.filePath = filePath; | ||
36 | this.parsingCmd = "DISABLE_SANITY_CHECKS=1 bitbake -e -b " + filePath; | ||
37 | } | ||
38 | |||
39 | @Override | ||
40 | public void initialize() throws Exception { | ||
41 | if (this.size() == 0) { | ||
42 | //System.out.println("Failed to parse " + filePath); | ||
43 | //throw new IOException("Failed to parse " + filePath); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | protected String getDefaultDepends() { | ||
48 | return this.filePath; | ||
49 | } | ||
50 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBSession.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBSession.java new file mode 100644 index 0000000..e998bcd --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBSession.java | |||
@@ -0,0 +1,739 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | import java.io.BufferedReader; | ||
14 | import java.io.File; | ||
15 | import java.io.FileFilter; | ||
16 | import java.io.IOException; | ||
17 | import java.io.StringReader; | ||
18 | import java.util.ArrayList; | ||
19 | import java.util.Arrays; | ||
20 | import java.util.Collection; | ||
21 | import java.util.Hashtable; | ||
22 | import java.util.Iterator; | ||
23 | import java.util.List; | ||
24 | import java.util.Map; | ||
25 | import java.util.Set; | ||
26 | import java.util.Stack; | ||
27 | import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
28 | import java.util.concurrent.locks.Lock; | ||
29 | |||
30 | import org.eclipse.core.resources.IFile; | ||
31 | import org.eclipse.core.resources.IProject; | ||
32 | import org.eclipse.core.resources.IResource; | ||
33 | import org.eclipse.core.runtime.IProgressMonitor; | ||
34 | import org.eclipse.core.runtime.IStatus; | ||
35 | import org.eclipse.core.runtime.Status; | ||
36 | import org.eclipse.jface.preference.JFacePreferences; | ||
37 | import org.eclipse.jface.resource.JFaceResources; | ||
38 | import org.eclipse.ui.console.ConsolePlugin; | ||
39 | import org.eclipse.ui.console.IConsole; | ||
40 | import org.eclipse.ui.console.IConsoleManager; | ||
41 | import org.eclipse.ui.console.MessageConsole; | ||
42 | import org.eclipse.ui.console.MessageConsoleStream; | ||
43 | import org.eclipse.ui.progress.WorkbenchJob; | ||
44 | |||
45 | import org.yocto.bc.ui.model.IModelElement; | ||
46 | import org.yocto.bc.ui.model.ProjectInfo; | ||
47 | |||
48 | /** | ||
49 | * BBSession encapsulates a global bitbake configuration and is the primary interface | ||
50 | * for actions against a BitBake installation. | ||
51 | * | ||
52 | * @author kgilmer | ||
53 | * | ||
54 | */ | ||
55 | public class BBSession implements IBBSessionListener, IModelElement, Map { | ||
56 | public static final int TYPE_VARIABLE_ASSIGNMENT = 1; | ||
57 | public static final int TYPE_UNKNOWN = 2; | ||
58 | public static final int TYPE_STATEMENT = 3; | ||
59 | public static final int TYPE_FLAG = 4; | ||
60 | |||
61 | public static final String BUILDDIR_INDICATORS [] = { | ||
62 | File.separatorChar + "conf" + File.separatorChar + "local.conf", | ||
63 | File.separatorChar + "conf" + File.separatorChar + "bblayers.conf", | ||
64 | }; | ||
65 | |||
66 | protected final ProjectInfo pinfo; | ||
67 | protected final ShellSession shell; | ||
68 | protected Map properties = null; | ||
69 | protected List <String> depends = null; | ||
70 | protected boolean initialized = false; | ||
71 | protected MessageConsole sessionConsole; | ||
72 | private final ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock(); | ||
73 | private final Lock rlock = rwlock.readLock(); | ||
74 | private final Lock wlock = rwlock.writeLock(); | ||
75 | protected String parsingCmd; | ||
76 | private boolean silent = false; | ||
77 | |||
78 | public BBSession(ShellSession ssession, String projectRoot) throws IOException { | ||
79 | shell = ssession; | ||
80 | this.pinfo = new ProjectInfo(); | ||
81 | pinfo.setLocation(projectRoot); | ||
82 | pinfo.setInitScriptPath(ProjectInfoHelper.getInitScriptPath(projectRoot)); | ||
83 | this.parsingCmd = "DISABLE_SANITY_CHECKS=1 bitbake -e"; | ||
84 | } | ||
85 | |||
86 | public BBSession(ShellSession ssession, String projectRoot, boolean silent) throws IOException { | ||
87 | this(ssession, projectRoot); | ||
88 | this.silent = silent; | ||
89 | } | ||
90 | |||
91 | private Collection adapttoIPath(List<File> asList, IProject project) { | ||
92 | |||
93 | List pathList = new ArrayList(); | ||
94 | |||
95 | for (Iterator i = asList.iterator(); i.hasNext();) { | ||
96 | File f = (File) i.next(); | ||
97 | IFile ff = project.getFile(stripLeading(f.toString(), project.getLocationURI().getPath())); | ||
98 | if (ff.exists()) { | ||
99 | pathList.add(ff); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | return pathList; | ||
104 | } | ||
105 | |||
106 | private String appendAll(String[] elems, int st) { | ||
107 | StringBuffer sb = new StringBuffer(); | ||
108 | |||
109 | for (int i = st; i < elems.length; ++i) { | ||
110 | sb.append(elems[i]); | ||
111 | } | ||
112 | |||
113 | return sb.toString(); | ||
114 | } | ||
115 | |||
116 | private int charCount(String trimmed, char c) { | ||
117 | int i = 0; | ||
118 | int p = 0; | ||
119 | |||
120 | while ((p = trimmed.indexOf(c, p)) > -1) { | ||
121 | i++; | ||
122 | p++; | ||
123 | } | ||
124 | |||
125 | return i; | ||
126 | } | ||
127 | |||
128 | public void clear() { | ||
129 | throw new RuntimeException("BB configuration is read-only."); | ||
130 | } | ||
131 | |||
132 | public boolean containsKey(Object arg0) { | ||
133 | try { | ||
134 | checkValidAndLock(true); | ||
135 | return properties.containsKey(arg0); | ||
136 | } catch (Exception e) { | ||
137 | e.printStackTrace(); | ||
138 | return false; | ||
139 | }finally { | ||
140 | rlock.unlock(); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | public boolean containsValue(Object arg0) { | ||
145 | try { | ||
146 | checkValidAndLock(true); | ||
147 | return properties.containsValue(arg0); | ||
148 | } catch (Exception e) { | ||
149 | e.printStackTrace(); | ||
150 | return false; | ||
151 | }finally { | ||
152 | rlock.unlock(); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | public Set entrySet() { | ||
157 | try { | ||
158 | checkValidAndLock(true); | ||
159 | return properties.entrySet(); | ||
160 | } catch (Exception e) { | ||
161 | e.printStackTrace(); | ||
162 | return null; | ||
163 | }finally { | ||
164 | rlock.unlock(); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | @Override | ||
169 | public boolean equals(Object arg0) { | ||
170 | try { | ||
171 | checkValidAndLock(true); | ||
172 | return properties.equals(arg0); | ||
173 | } catch (Exception e) { | ||
174 | e.printStackTrace(); | ||
175 | return false; | ||
176 | }finally { | ||
177 | rlock.unlock(); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | public ShellSession getShell() { | ||
182 | return shell; | ||
183 | } | ||
184 | |||
185 | public String getProjInfoRoot() { | ||
186 | return pinfo.getRootPath(); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * Recursively generate list of Recipe files from a root directory. | ||
191 | * | ||
192 | * @param rootDir | ||
193 | * @param recipes | ||
194 | * @param fileExtension | ||
195 | * @param project | ||
196 | */ | ||
197 | private void findRecipes(File rootDir, List recipes, final String fileExtension, IProject project) { | ||
198 | File[] children = rootDir.listFiles(new FileFilter() { | ||
199 | |||
200 | public boolean accept(File pathname) { | ||
201 | return pathname.isFile() && pathname.getName().endsWith(fileExtension); | ||
202 | } | ||
203 | |||
204 | }); | ||
205 | |||
206 | if (children != null && children.length > 0) { | ||
207 | recipes.addAll(adapttoIPath(Arrays.asList(children), project)); | ||
208 | } | ||
209 | |||
210 | File[] childDirs = rootDir.listFiles(new FileFilter() { | ||
211 | |||
212 | public boolean accept(File pathname) { | ||
213 | return pathname.isDirectory(); | ||
214 | } | ||
215 | |||
216 | }); | ||
217 | |||
218 | if (childDirs != null && childDirs.length > 0) { | ||
219 | for (int i = 0; i < childDirs.length; ++i) { | ||
220 | findRecipes(childDirs[i], recipes, fileExtension, project); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | private Collection findRecipes(List paths, IProject project) { | ||
226 | List recipes = new ArrayList(); | ||
227 | |||
228 | for (Iterator i = paths.iterator(); i.hasNext();) { | ||
229 | String rawPath = (String) i.next(); | ||
230 | String[] elems = rawPath.split("\\*/\\*"); | ||
231 | |||
232 | if (elems.length == 2) { | ||
233 | |||
234 | File rootDir = new File(elems[0]); | ||
235 | |||
236 | findRecipes(rootDir, recipes, elems[1], project); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | return recipes; | ||
241 | } | ||
242 | |||
243 | public Object get(Object arg0) { | ||
244 | try { | ||
245 | checkValidAndLock(true); | ||
246 | return properties.get(arg0); | ||
247 | } catch (Exception e) { | ||
248 | e.printStackTrace(); | ||
249 | return null; | ||
250 | }finally { | ||
251 | rlock.unlock(); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | private List getBitBakeKeywords() { | ||
256 | return Arrays.asList(BBLanguageHelper.BITBAKE_KEYWORDS); | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * @return A MessageConsole for this BB session. | ||
261 | */ | ||
262 | public MessageConsole getConsole() { | ||
263 | if (sessionConsole == null) { | ||
264 | String cName = ProjectInfoHelper.getProjectName(pinfo.getRootPath()) + " Console"; | ||
265 | IConsoleManager conMan = ConsolePlugin.getDefault().getConsoleManager(); | ||
266 | IConsole[] existing = conMan.getConsoles(); | ||
267 | for (int i = 0; i < existing.length; i++) | ||
268 | if (cName.equals(existing[i].getName())) { | ||
269 | sessionConsole = (MessageConsole) existing[i]; | ||
270 | break; | ||
271 | } | ||
272 | if (sessionConsole == null) { | ||
273 | sessionConsole = new MessageConsole(cName, null); | ||
274 | conMan.addConsoles(new IConsole[] { sessionConsole }); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | ConsolePlugin.getDefault().getConsoleManager().showConsoleView(sessionConsole); | ||
279 | |||
280 | return sessionConsole; | ||
281 | } | ||
282 | |||
283 | private int getLineType(String line) { | ||
284 | |||
285 | if (line.contains("=")) { | ||
286 | return TYPE_VARIABLE_ASSIGNMENT; | ||
287 | } | ||
288 | |||
289 | for (Iterator i = getBitBakeKeywords().iterator(); i.hasNext();) { | ||
290 | if (line.startsWith((String) i.next())) { | ||
291 | return TYPE_STATEMENT; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | if (line.contains(":")) { | ||
296 | return TYPE_FLAG; | ||
297 | } | ||
298 | |||
299 | return TYPE_UNKNOWN; | ||
300 | } | ||
301 | |||
302 | public Collection getRecipeFiles(IProject project) { | ||
303 | try { | ||
304 | checkValidAndLock(true); | ||
305 | if (!initialized) { | ||
306 | throw new RuntimeException(this.getClass().getName() + " is not initialized."); | ||
307 | } | ||
308 | String bbfiles = (String) this.properties.get("BBFILES"); | ||
309 | List paths = parseBBFiles(bbfiles); | ||
310 | return findRecipes(paths, project); | ||
311 | } catch (Exception e) { | ||
312 | return null; | ||
313 | } | ||
314 | finally { | ||
315 | rlock.unlock(); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | @Override | ||
320 | public int hashCode() { | ||
321 | try { | ||
322 | checkValidAndLock(true); | ||
323 | return properties.hashCode(); | ||
324 | } catch (Exception e) { | ||
325 | e.printStackTrace(); | ||
326 | return 0; | ||
327 | }finally { | ||
328 | rlock.unlock(); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | protected int checkExecuteError(String result, int code) { | ||
333 | String recipe = getDefaultDepends(); | ||
334 | String text = "Parsing " + ((recipe != null) ? ("recipe " + recipe) : "base configurations"); | ||
335 | if (code != 0) { | ||
336 | text = text + " ERROR!\n" + result; | ||
337 | }else { | ||
338 | text = text + " SUCCESS.\n"; | ||
339 | } | ||
340 | if(!silent) { | ||
341 | displayInConsole(text, code, false); | ||
342 | } | ||
343 | return code; | ||
344 | } | ||
345 | |||
346 | protected void displayInConsole(final String result, final int code, boolean clear) { | ||
347 | MessageConsole console = getConsole(); | ||
348 | final MessageConsoleStream info = console.newMessageStream(); | ||
349 | if(clear) | ||
350 | console.clearConsole(); | ||
351 | new WorkbenchJob("Display parsing result") { | ||
352 | public IStatus runInUIThread(IProgressMonitor monitor) { | ||
353 | if(code != 0) { | ||
354 | info.setColor(JFaceResources.getColorRegistry().get(JFacePreferences.ERROR_COLOR)); | ||
355 | } | ||
356 | try { | ||
357 | info.println(result); | ||
358 | info.close(); | ||
359 | }catch (Exception e) { | ||
360 | e.printStackTrace(); | ||
361 | } | ||
362 | return Status.OK_STATUS; | ||
363 | } | ||
364 | }.schedule(); | ||
365 | } | ||
366 | |||
367 | private void checkValidAndLock(boolean rdlck) throws Exception { | ||
368 | if(rdlck) | ||
369 | rlock.lock(); | ||
370 | else | ||
371 | wlock.lock(); | ||
372 | if(!initialized) { | ||
373 | //upgrade lock manually | ||
374 | if(rdlck) { | ||
375 | rlock.unlock(); | ||
376 | wlock.lock(); | ||
377 | } | ||
378 | try { | ||
379 | if(!initialized) { //recheck | ||
380 | int [] codes = {-1}; | ||
381 | String result = shell.execute(parsingCmd, codes); | ||
382 | if(checkExecuteError(result, codes[0]) == 0) { | ||
383 | properties = parseBBEnvironment(result); | ||
384 | } else { | ||
385 | properties = parseBBEnvironment(""); | ||
386 | } | ||
387 | initialized = true; | ||
388 | } | ||
389 | } finally { | ||
390 | //downgrade lock | ||
391 | if(rdlck) { | ||
392 | rlock.lock(); | ||
393 | wlock.unlock(); | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | //not release lock | ||
398 | } | ||
399 | |||
400 | public void initialize() throws Exception { | ||
401 | try { | ||
402 | checkValidAndLock(false); | ||
403 | }finally { | ||
404 | wlock.unlock(); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | private boolean isBlockEnd(String trimmed) { | ||
409 | return charCount(trimmed, '}') > charCount(trimmed, '{'); | ||
410 | // return trimmed.indexOf('}') > -1 && trimmed.indexOf('{') == -1; | ||
411 | } | ||
412 | |||
413 | private boolean isBlockStart(String trimmed) { | ||
414 | return charCount(trimmed, '{') > charCount(trimmed, '}'); | ||
415 | // return trimmed.indexOf('{') > -1 && trimmed.indexOf('}') == -1; | ||
416 | } | ||
417 | |||
418 | public boolean isEmpty() { | ||
419 | try { | ||
420 | checkValidAndLock(true); | ||
421 | return properties.isEmpty(); | ||
422 | } catch (Exception e) { | ||
423 | e.printStackTrace(); | ||
424 | return true; | ||
425 | }finally { | ||
426 | rlock.unlock(); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | public Set keySet() { | ||
431 | try { | ||
432 | checkValidAndLock(true); | ||
433 | return properties.keySet(); | ||
434 | } catch (Exception e) { | ||
435 | e.printStackTrace(); | ||
436 | return null; | ||
437 | }finally { | ||
438 | rlock.unlock(); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | protected void parse(String content, Map outMap) throws Exception { | ||
443 | BufferedReader reader = new BufferedReader(new StringReader(content)); | ||
444 | String line; | ||
445 | boolean inLine = false; | ||
446 | StringBuffer sb = null; | ||
447 | Stack blockStack = new Stack(); | ||
448 | |||
449 | while ((line = reader.readLine()) != null) { | ||
450 | String trimmed = line.trim(); | ||
451 | if (trimmed.length() == 0 || line.startsWith("#")) { | ||
452 | // weed out the blank and comment lines | ||
453 | continue; | ||
454 | } | ||
455 | // Now we look for block start ends, and ignore all code within | ||
456 | // blocks. | ||
457 | if (isBlockStart(trimmed)) { | ||
458 | blockStack.push(trimmed); | ||
459 | } else if (isBlockEnd(trimmed)) { | ||
460 | blockStack.pop(); | ||
461 | |||
462 | } | ||
463 | |||
464 | if (!blockStack.isEmpty()) { | ||
465 | // we are in a code block, continue until we break into global | ||
466 | // scope. | ||
467 | continue; | ||
468 | } | ||
469 | if (trimmed.endsWith("\\")) { | ||
470 | if (!inLine) { | ||
471 | inLine = true; | ||
472 | sb = new StringBuffer(trimmed.substring(0, trimmed.length() - 1)); | ||
473 | } else { | ||
474 | sb.append(trimmed.substring(0, trimmed.length() - 1)); | ||
475 | } | ||
476 | // Only parse the line when we have the complete contents. | ||
477 | continue; | ||
478 | } else if (inLine) { | ||
479 | inLine = false; | ||
480 | line = sb.toString(); | ||
481 | } | ||
482 | |||
483 | parseLine(line, outMap); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | private void parseAdditiveAssignment(String line, String operator, Map mo) throws Exception { | ||
488 | String[] elems = splitAssignment(line, "\\+="); | ||
489 | |||
490 | if (elems.length != 2) { | ||
491 | throw new Exception("Unable to parse additive variable assignment in line: " + line); | ||
492 | } | ||
493 | |||
494 | if (!mo.containsKey(elems[0])) { | ||
495 | mo.put(elems[0].trim(), elems[1]); | ||
496 | } else { | ||
497 | String existing = (String) mo.get(elems[0]); | ||
498 | if (operator.equals("+=")) { | ||
499 | mo.put(elems[0], existing + elems[1]); | ||
500 | } else { | ||
501 | mo.put(elems[0], elems[1] + existing); | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | |||
506 | protected String getDefaultDepends() { | ||
507 | return null; | ||
508 | } | ||
509 | |||
510 | protected Map parseBBEnvironment(String bbOut) throws Exception { | ||
511 | Map env = new Hashtable(); | ||
512 | this.depends = new ArrayList<String>(); | ||
513 | |||
514 | parse(bbOut, env); | ||
515 | |||
516 | String included = (String) env.get("BBINCLUDED"); | ||
517 | if(getDefaultDepends() != null) { | ||
518 | this.depends.add(getDefaultDepends()); | ||
519 | } | ||
520 | if(included != null) { | ||
521 | this.depends.addAll(Arrays.asList(included.split(" "))); | ||
522 | } | ||
523 | |||
524 | return env; | ||
525 | } | ||
526 | |||
527 | |||
528 | private List parseBBFiles(String bbfiles) { | ||
529 | return Arrays.asList(bbfiles.split(" ")); | ||
530 | } | ||
531 | |||
532 | //Map delegate methods | ||
533 | |||
534 | private void parseConditionalAssignment(String line, Map mo) throws Exception { | ||
535 | String[] elems = splitAssignment(line, "\\?="); | ||
536 | |||
537 | if (elems.length != 2) { | ||
538 | throw new Exception("Unable to parse conditional variable assignment in line: " + line); | ||
539 | } | ||
540 | |||
541 | if (!mo.containsKey(elems[0].trim())) { | ||
542 | mo.put(elems[0].trim(), elems[1].trim()); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | private void parseImmediateAssignment(String line, String delimiter, Map mo) throws Exception { | ||
547 | String[] elems = splitAssignment(line, delimiter); | ||
548 | |||
549 | mo.put(elems[0], substitute(elems[1], mo)); | ||
550 | } | ||
551 | |||
552 | private void parseKeyValue(String line, String delimiter, Map mo) throws Exception { | ||
553 | String[] elems = splitAssignment(line, delimiter); | ||
554 | |||
555 | mo.put(elems[0], elems[1]); | ||
556 | } | ||
557 | |||
558 | private void parseLine(String line, Map mo) throws Exception { | ||
559 | |||
560 | switch (getLineType(line)) { | ||
561 | case TYPE_VARIABLE_ASSIGNMENT: | ||
562 | parseVariableAssignment(line, mo); | ||
563 | break; | ||
564 | case TYPE_STATEMENT: | ||
565 | case TYPE_FLAG: | ||
566 | // for now ignore statements | ||
567 | break; | ||
568 | case TYPE_UNKNOWN: | ||
569 | // we'll gloss over unknown lines as well; | ||
570 | break; | ||
571 | default: | ||
572 | throw new Exception("Unable to parse line: " + line); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | private void parseVariableAssignment(String line, Map mo) throws Exception { | ||
577 | if (line.contains("?=")) { | ||
578 | parseConditionalAssignment(line, mo); | ||
579 | } else if (line.contains("+=")) { | ||
580 | parseAdditiveAssignment(line, "+=", mo); | ||
581 | } else if (line.contains("=+")) { | ||
582 | parseAdditiveAssignment(line, "=+", mo); | ||
583 | } else if (line.contains(":=")) { | ||
584 | parseImmediateAssignment(line, ":=", mo); | ||
585 | } else { | ||
586 | parseKeyValue(line, "=", mo); | ||
587 | } | ||
588 | |||
589 | } | ||
590 | |||
591 | private List parseVars(String line) { | ||
592 | List l = new ArrayList(); | ||
593 | |||
594 | int i = 0; | ||
595 | |||
596 | while ((i = line.indexOf("${", i)) > -1) { | ||
597 | int i2 = line.indexOf("}", i); | ||
598 | |||
599 | l.add(line.subSequence(i + 2, i2)); | ||
600 | i++; | ||
601 | } | ||
602 | |||
603 | return l; | ||
604 | } | ||
605 | |||
606 | public Object put(Object arg0, Object arg1) { | ||
607 | throw new RuntimeException("BB configuration is read-only."); | ||
608 | } | ||
609 | |||
610 | public void putAll(Map arg0) { | ||
611 | throw new RuntimeException("BB configuration is read-only."); | ||
612 | } | ||
613 | |||
614 | public Object remove(Object arg0) { | ||
615 | throw new RuntimeException("BB configuration is read-only."); | ||
616 | } | ||
617 | |||
618 | private String removeQuotes(String line) { | ||
619 | line = line.trim(); | ||
620 | |||
621 | if (line.startsWith("\"")) { | ||
622 | line = line.substring(1); | ||
623 | } | ||
624 | |||
625 | if (line.endsWith("\"")) { | ||
626 | line = line.substring(0, line.length() - 1); | ||
627 | } | ||
628 | |||
629 | return line; | ||
630 | } | ||
631 | |||
632 | public int size() { | ||
633 | try { | ||
634 | checkValidAndLock(true); | ||
635 | return properties.size(); | ||
636 | }catch (Exception e) { | ||
637 | e.printStackTrace(); | ||
638 | return 0; | ||
639 | }finally { | ||
640 | rlock.unlock(); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | private String[] splitAssignment(String line, String seperator) throws Exception { | ||
645 | String[] elems = line.split(seperator); | ||
646 | |||
647 | if (elems.length < 2) { | ||
648 | throw new Exception("Unable to parse assignment in line: " + line); | ||
649 | } else if (elems.length == 2) { | ||
650 | |||
651 | elems[0] = elems[0].trim(); // Clean up trailing or leading spaces. | ||
652 | if (elems[0].startsWith("export ")) { | ||
653 | elems[0] = elems[0].substring("export ".length()).trim(); | ||
654 | } | ||
655 | elems[1] = removeQuotes(elems[1]); // Evaluate variables | ||
656 | |||
657 | return elems; | ||
658 | } else { | ||
659 | String[] retVal = new String[2]; | ||
660 | |||
661 | retVal[0] = elems[0]; | ||
662 | if (retVal[0].startsWith("export ")) { | ||
663 | retVal[0] = retVal[0].substring("export ".length()).trim(); | ||
664 | } | ||
665 | retVal[1] = appendAll(elems, 1); | ||
666 | |||
667 | return retVal; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | private String stripLeading(String target, String leading) { | ||
672 | if (target.startsWith(leading)) { | ||
673 | target = target.substring(leading.length()); | ||
674 | } | ||
675 | |||
676 | return target; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * Return a string with variable substitutions in place. | ||
681 | * | ||
682 | * @param expression | ||
683 | * @return Input string with any substitutions from this file. | ||
684 | */ | ||
685 | public String substitute(String expression, Map mo) { | ||
686 | |||
687 | List vars = parseVars(expression); | ||
688 | |||
689 | for (Iterator i = vars.iterator(); i.hasNext();) { | ||
690 | String varName = (String) i.next(); | ||
691 | String varToken = "${" + varName + "}"; | ||
692 | |||
693 | if (mo.containsKey(varName)) { | ||
694 | expression = expression.replace(varToken, (String) mo.get(varName)); | ||
695 | } else if (System.getProperty(varName) != null) { | ||
696 | expression = expression.replace(varToken, System.getProperty(varName)); | ||
697 | } else if (varName.toUpperCase().equals("HOME")) { | ||
698 | expression = expression.replace(varToken, System.getProperty("user.home")); | ||
699 | } | ||
700 | } | ||
701 | |||
702 | return expression; | ||
703 | } | ||
704 | |||
705 | public Collection values() { | ||
706 | try { | ||
707 | checkValidAndLock(true); | ||
708 | return properties.values(); | ||
709 | } catch (Exception e) { | ||
710 | e.printStackTrace(); | ||
711 | return null; | ||
712 | }finally { | ||
713 | rlock.unlock(); | ||
714 | } | ||
715 | } | ||
716 | |||
717 | public void changeNotified(IResource[] added, IResource[] removed, IResource[] changed) { | ||
718 | wlock.lock(); | ||
719 | try { | ||
720 | if (initialized && (removed != null || changed != null)) { | ||
721 | for(int i=0;removed != null && i<removed.length;i++) { | ||
722 | if (this.depends.contains(removed[i].getLocation().toString())) { | ||
723 | initialized = false; | ||
724 | return; | ||
725 | } | ||
726 | } | ||
727 | for(int i=0;changed != null && i<changed.length;i++) { | ||
728 | if (this.depends.contains(changed[i].getLocation().toString())) { | ||
729 | initialized = false; | ||
730 | return; | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | finally { | ||
736 | wlock.unlock(); | ||
737 | } | ||
738 | } | ||
739 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/IBBSessionListener.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/IBBSessionListener.java new file mode 100644 index 0000000..4d0054f --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/IBBSessionListener.java | |||
@@ -0,0 +1,18 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2012 Intel Corporation. | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Intel - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | |||
12 | package org.yocto.bc.bitbake; | ||
13 | |||
14 | import org.eclipse.core.resources.IResource; | ||
15 | |||
16 | public interface IBBSessionListener { | ||
17 | public void changeNotified(IResource[] added, IResource[] removed, IResource[] changed); | ||
18 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ICommandResponseHandler.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ICommandResponseHandler.java new file mode 100644 index 0000000..4c44352 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ICommandResponseHandler.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | public interface ICommandResponseHandler { | ||
14 | public void response(String line, boolean isError); | ||
15 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ProjectInfoHelper.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ProjectInfoHelper.java new file mode 100644 index 0000000..25dac97 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ProjectInfoHelper.java | |||
@@ -0,0 +1,105 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | import java.io.BufferedReader; | ||
14 | import java.io.File; | ||
15 | import java.io.FileOutputStream; | ||
16 | import java.io.FileReader; | ||
17 | import java.io.IOException; | ||
18 | |||
19 | import org.eclipse.core.resources.IProject; | ||
20 | import org.eclipse.core.resources.ResourcesPlugin; | ||
21 | |||
22 | import org.yocto.bc.ui.model.ProjectInfo; | ||
23 | |||
24 | /** | ||
25 | * A helper class for ProjectInfo related tasks. | ||
26 | * | ||
27 | * @author kgilmer | ||
28 | * | ||
29 | */ | ||
30 | public class ProjectInfoHelper { | ||
31 | |||
32 | protected static final String DEFAULT_INIT_SCRIPT = "oe-init-build-env"; | ||
33 | /** | ||
34 | * @param path | ||
35 | * @return The path to bitbake init script | ||
36 | * @throws IOException | ||
37 | */ | ||
38 | public static String getInitScriptPath(String path) throws IOException { | ||
39 | String val = path + File.separator + DEFAULT_INIT_SCRIPT; | ||
40 | |||
41 | File inFile = new File(path, ".eclipse-data"); | ||
42 | if(inFile.exists()) { | ||
43 | BufferedReader br = new BufferedReader(new FileReader(inFile)); | ||
44 | val = br.readLine(); | ||
45 | br.close(); | ||
46 | } | ||
47 | |||
48 | return val; | ||
49 | } | ||
50 | |||
51 | public static String getInitScript(String path) throws IOException { | ||
52 | File inFile = new File(path); | ||
53 | BufferedReader br = new BufferedReader(new FileReader(inFile)); | ||
54 | StringBuffer sb = new StringBuffer(); | ||
55 | String line = null; | ||
56 | |||
57 | while ((line = br.readLine()) != null) { | ||
58 | sb.append(line); | ||
59 | } | ||
60 | |||
61 | br.close(); | ||
62 | |||
63 | return sb.toString(); | ||
64 | } | ||
65 | |||
66 | public static String getProjectName(String projectRoot) { | ||
67 | IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); | ||
68 | for (int i = 0; i < projects.length; ++i) { | ||
69 | try { | ||
70 | if (projects[i].getLocationURI().getPath().equals(projectRoot)) { | ||
71 | return projects[i].getName(); | ||
72 | } | ||
73 | |||
74 | } catch (Exception e) { | ||
75 | // TODO Auto-generated catch block | ||
76 | e.printStackTrace(); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | return null; | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * This method will store the path to the bitbake init script for future | ||
85 | * reference. | ||
86 | * | ||
87 | * @param path | ||
88 | * @param projInfo | ||
89 | * @throws IOException | ||
90 | */ | ||
91 | public static void store(String path, ProjectInfo projInfo) throws IOException { | ||
92 | writeToFile(path, projInfo.getInitScriptPath()); | ||
93 | } | ||
94 | |||
95 | private static void writeToFile(String path, String init) throws IOException { | ||
96 | File outFile = new File(path, ".eclipse-data"); | ||
97 | FileOutputStream fos = new FileOutputStream(outFile); | ||
98 | |||
99 | fos.write(init.getBytes()); | ||
100 | |||
101 | fos.flush(); | ||
102 | fos.close(); | ||
103 | } | ||
104 | |||
105 | } | ||
diff --git a/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ShellSession.java b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ShellSession.java new file mode 100644 index 0000000..4719865 --- /dev/null +++ b/plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/ShellSession.java | |||
@@ -0,0 +1,248 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright (c) 2009 Ken Gilmer | ||
3 | * All rights reserved. This program and the accompanying materials | ||
4 | * are made available under the terms of the Eclipse Public License v1.0 | ||
5 | * which accompanies this distribution, and is available at | ||
6 | * http://www.eclipse.org/legal/epl-v10.html | ||
7 | * | ||
8 | * Contributors: | ||
9 | * Ken Gilmer - initial API and implementation | ||
10 | *******************************************************************************/ | ||
11 | package org.yocto.bc.bitbake; | ||
12 | |||
13 | import java.io.BufferedReader; | ||
14 | import java.io.File; | ||
15 | import java.io.IOException; | ||
16 | import java.io.InputStream; | ||
17 | import java.io.InputStreamReader; | ||
18 | import java.io.OutputStream; | ||
19 | import java.io.Writer; | ||
20 | |||
21 | /** | ||
22 | * A class for Linux shell sessions. | ||
23 | * @author kgilmer | ||
24 | * | ||
25 | */ | ||
26 | public class ShellSession { | ||
27 | /** | ||
28 | * Bash shell | ||
29 | */ | ||
30 | public static final int SHELL_TYPE_BASH = 1; | ||
31 | /** | ||
32 | * sh shell | ||
33 | */ | ||
34 | public static final int SHELL_TYPE_SH = 2; | ||
35 | private volatile boolean interrupt = false; | ||
36 | /** | ||
37 | * String used to isolate command execution | ||
38 | */ | ||
39 | public static final String TERMINATOR = "#234o987dsfkcqiuwey18837032843259d"; | ||
40 | public static final String LT = System.getProperty("line.separator"); | ||
41 | |||
42 | public static String getFilePath(String file) throws IOException { | ||
43 | File f = new File(file); | ||
44 | |||
45 | if (!f.exists() || f.isDirectory()) { | ||
46 | throw new IOException("Path passed is not a file: " + file); | ||
47 | } | ||
48 | |||
49 | StringBuffer sb = new StringBuffer(); | ||
50 | |||
51 | String elems[] = file.split(File.separator); | ||
52 | |||
53 | for (int i = 0; i < elems.length - 1; ++i) { | ||
54 | sb.append(elems[i]); | ||
55 | sb.append(File.separator); | ||
56 | } | ||
57 | |||
58 | return sb.toString(); | ||
59 | } | ||
60 | private Process process; | ||
61 | |||
62 | private OutputStream pos = null; | ||
63 | //private File initFile = null; | ||
64 | private String shellPath = null; | ||
65 | private final String initCmd; | ||
66 | private final File root; | ||
67 | private final Writer out; | ||
68 | |||
69 | |||
70 | public ShellSession(int shellType, File root, String initCmd, Writer out) throws IOException { | ||
71 | this.root = root; | ||
72 | this.initCmd = initCmd; | ||
73 | if (out == null) { | ||
74 | this.out = new NullWriter(); | ||
75 | } else { | ||
76 | this.out = out; | ||
77 | } | ||
78 | if (shellType == SHELL_TYPE_SH) { | ||
79 | shellPath = "/bin/sh"; | ||
80 | } | ||
81 | shellPath = "/bin/bash"; | ||
82 | |||
83 | initializeShell(); | ||
84 | } | ||
85 | |||
86 | private void initializeShell() throws IOException { | ||
87 | process = Runtime.getRuntime().exec(shellPath); | ||
88 | pos = process.getOutputStream(); | ||
89 | |||
90 | if (root != null) { | ||
91 | out.write(execute("cd " + root.getAbsolutePath())); | ||
92 | } | ||
93 | |||
94 | if (initCmd != null) { | ||
95 | out.write(execute("source " + initCmd)); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | synchronized | ||
100 | public String execute(String command) throws IOException { | ||
101 | return execute(command, (int [])null); | ||
102 | } | ||
103 | |||
104 | synchronized | ||
105 | public String execute(String command, int[] retCode) throws IOException { | ||
106 | String errorMessage = null; | ||
107 | interrupt = false; | ||
108 | out.write(command); | ||
109 | out.write(LT); | ||
110 | |||
111 | sendToProcessAndTerminate(command); | ||
112 | |||
113 | if (process.getErrorStream().available() > 0) { | ||
114 | byte[] msg = new byte[process.getErrorStream().available()]; | ||
115 | |||
116 | process.getErrorStream().read(msg, 0, msg.length); | ||
117 | out.write(new String(msg)); | ||
118 | out.write(LT); | ||
119 | errorMessage = "Error while executing: " + command + LT + new String(msg); | ||
120 | } | ||
121 | |||
122 | BufferedReader br = new BufferedReader(new InputStreamReader(process | ||
123 | .getInputStream())); | ||
124 | |||
125 | StringBuffer sb = new StringBuffer(); | ||
126 | String line = null; | ||
127 | |||
128 | while (((line = br.readLine()) != null) && !line.endsWith(TERMINATOR) && !interrupt) { | ||
129 | sb.append(line); | ||
130 | sb.append(LT); | ||
131 | out.write(line); | ||
132 | out.write(LT); | ||
133 | } | ||
134 | |||
135 | if (interrupt) { | ||
136 | process.destroy(); | ||
137 | initializeShell(); | ||
138 | interrupt = false; | ||
139 | }else if (line != null && retCode != null) { | ||
140 | try { | ||
141 | retCode[0]=Integer.parseInt(line.substring(0,line.lastIndexOf(TERMINATOR))); | ||
142 | }catch (NumberFormatException e) { | ||
143 | throw new IOException("Can NOT get return code" + command + LT + line); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | if (errorMessage != null) { | ||
148 | throw new IOException(errorMessage); | ||
149 | } | ||
150 | |||
151 | return sb.toString(); | ||
152 | } | ||
153 | |||
154 | synchronized | ||
155 | public void execute(String command, ICommandResponseHandler handler) throws IOException { | ||
156 | System.out.println(command); | ||
157 | execute(command, TERMINATOR, handler); | ||
158 | } | ||
159 | |||
160 | synchronized | ||
161 | public void execute(String command, String terminator, ICommandResponseHandler handler) throws IOException { | ||
162 | interrupt = false; | ||
163 | InputStream errIs = process.getErrorStream(); | ||
164 | if (errIs.available() > 0) { | ||
165 | clearErrorStream(errIs); | ||
166 | } | ||
167 | sendToProcessAndTerminate(command); | ||
168 | |||
169 | BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); | ||
170 | String std = null; | ||
171 | |||
172 | do { | ||
173 | if (errIs.available() > 0) { | ||
174 | byte[] msg = new byte[errIs.available()]; | ||
175 | |||
176 | errIs.read(msg, 0, msg.length); | ||
177 | out.write(new String(msg)); | ||
178 | handler.response(new String(msg), true); | ||
179 | } | ||
180 | |||
181 | std = br.readLine(); | ||
182 | |||
183 | if (std != null && !std.endsWith(terminator)) { | ||
184 | out.write(std); | ||
185 | handler.response(std, false); | ||
186 | } | ||
187 | |||
188 | } while (std != null && !std.endsWith(terminator) && !interrupt); | ||
189 | |||
190 | if (interrupt) { | ||
191 | process.destroy(); | ||
192 | initializeShell(); | ||
193 | interrupt = false; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | private void clearErrorStream(InputStream is) { | ||
198 | |||
199 | try { | ||
200 | byte b[] = new byte[is.available()]; | ||
201 | is.read(b); | ||
202 | System.out.println("clearing: " + new String(b)); | ||
203 | } catch (IOException e) { | ||
204 | e.printStackTrace(); | ||
205 | //Ignore any error | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * Send command string to shell process and add special terminator string so | ||
211 | * reader knows when output is complete. | ||
212 | * | ||
213 | * @param command | ||
214 | * @throws IOException | ||
215 | */ | ||
216 | private void sendToProcessAndTerminate(String command) throws IOException { | ||
217 | pos.write(command.getBytes()); | ||
218 | pos.write(LT.getBytes()); | ||
219 | pos.flush(); | ||
220 | pos.write("echo $?".getBytes()); | ||
221 | pos.write(TERMINATOR.getBytes()); | ||
222 | pos.write(LT.getBytes()); | ||
223 | pos.flush(); | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * Interrupt any running processes. | ||
228 | */ | ||
229 | public void interrupt() { | ||
230 | interrupt = true; | ||
231 | } | ||
232 | |||
233 | private class NullWriter extends Writer { | ||
234 | |||
235 | @Override | ||
236 | public void close() throws IOException { | ||
237 | } | ||
238 | |||
239 | @Override | ||
240 | public void flush() throws IOException { | ||
241 | } | ||
242 | |||
243 | @Override | ||
244 | public void write(char[] cbuf, int off, int len) throws IOException { | ||
245 | } | ||
246 | |||
247 | } | ||
248 | } | ||