diff options
Diffstat (limited to 'plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBSession.java')
-rw-r--r-- | plugins/org.yocto.bc.ui/src/org/yocto/bc/bitbake/BBSession.java | 739 |
1 files changed, 739 insertions, 0 deletions
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 | } | ||