diff options
Diffstat (limited to 'src/context.cpp')
-rw-r--r-- | src/context.cpp | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/src/context.cpp b/src/context.cpp new file mode 100644 index 0000000..c257a75 --- /dev/null +++ b/src/context.cpp | |||
@@ -0,0 +1,524 @@ | |||
1 | #include "context.h" | ||
2 | #include "target.h" | ||
3 | #include "rule.h" | ||
4 | #include "function.h" | ||
5 | #include "runner.h" | ||
6 | #include "action.h" | ||
7 | #include "profile.h" | ||
8 | #include "view.h" | ||
9 | |||
10 | #include "functionreplace.h" | ||
11 | #include "functionexists.h" | ||
12 | #include "functionfiles.h" | ||
13 | #include "functionexecute.h" | ||
14 | #include "functionmatches.h" | ||
15 | #include "functiontostring.h" | ||
16 | #include "functionunlink.h" | ||
17 | #include "functiontargets.h" | ||
18 | #include "functiondirs.h" | ||
19 | #include "functiongetmakedeps.h" | ||
20 | #include "functionfilename.h" | ||
21 | #include "functiondirname.h" | ||
22 | |||
23 | #include <bu/process.h> | ||
24 | #include <bu/sio.h> | ||
25 | using namespace Bu; | ||
26 | |||
27 | Context::Context() : | ||
28 | pView( NULL ) | ||
29 | { | ||
30 | addFunction( new FunctionReplace() ); | ||
31 | addFunction( new FunctionExists() ); | ||
32 | addFunction( new FunctionFiles() ); | ||
33 | addFunction( new FunctionExecute() ); | ||
34 | addFunction( new FunctionMatches() ); | ||
35 | addFunction( new FunctionToString() ); | ||
36 | addFunction( new FunctionUnlink() ); | ||
37 | addFunction( new FunctionTargets() ); | ||
38 | addFunction( new FunctionDirs() ); | ||
39 | addFunction( new FunctionGetMakeDeps() ); | ||
40 | addFunction( new FunctionFileName() ); | ||
41 | addFunction( new FunctionDirName() ); | ||
42 | pushScope(); | ||
43 | } | ||
44 | |||
45 | Context::~Context() | ||
46 | { | ||
47 | } | ||
48 | |||
49 | void Context::addTarget( Target *pTarget ) | ||
50 | { | ||
51 | for( StrList::const_iterator i = pTarget->getOutputList().begin(); i; i++ ) | ||
52 | { | ||
53 | hTarget.insert( (*i).getStr(), pTarget ); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | void Context::addRule( Rule *pRule ) | ||
58 | { | ||
59 | hRule.insert( pRule->getName(), pRule ); | ||
60 | } | ||
61 | |||
62 | void Context::addFunction( Function *pFunction ) | ||
63 | { | ||
64 | pFunction->setContext( this ); | ||
65 | hFunction.insert( pFunction->getName(), pFunction ); | ||
66 | } | ||
67 | |||
68 | void Context::addVariable( const Bu::FString &sName, const Variable &vValue ) | ||
69 | { | ||
70 | for( ScopeStack::iterator i = sVars.begin(); i; i++ ) | ||
71 | { | ||
72 | if( (*i).has( sName ) ) | ||
73 | { | ||
74 | // sio << "Replacing higher scope variable \"" << sName << "\" with value \"" << (*i).get( sName ) << "\" with new value \"" << vValue << "\"" << sio.nl; | ||
75 | (*i).insert( sName, vValue ); | ||
76 | return; | ||
77 | } | ||
78 | } | ||
79 | sVars.first().insert( sName, vValue ); | ||
80 | } | ||
81 | |||
82 | void Context::addAction( Action *pAction ) | ||
83 | { | ||
84 | hAction.insert( pAction->getName(), pAction ); | ||
85 | } | ||
86 | |||
87 | Action *Context::getAction( const Bu::FString &sName ) | ||
88 | { | ||
89 | return hAction.get( sName ); | ||
90 | } | ||
91 | |||
92 | void Context::addTargetToTag( Target *pTarget, const Bu::FString &sTag ) | ||
93 | { | ||
94 | if( !hTag.has( sTag ) ) | ||
95 | { | ||
96 | hTag.insert( sTag, TargetList() ); | ||
97 | } | ||
98 | hTag.get( sTag ).append( pTarget ); | ||
99 | } | ||
100 | |||
101 | void Context::addTargetToTags( Target *pTarget, const StrList &sTags ) | ||
102 | { | ||
103 | for( StrList::const_iterator i = sTags.begin(); i; i++ ) | ||
104 | { | ||
105 | addTargetToTag( pTarget, *i ); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | TargetList &Context::getTag( const Bu::FString &sTag ) | ||
110 | { | ||
111 | return hTag.get( sTag ); | ||
112 | } | ||
113 | |||
114 | Variable &Context::getVariable( const Bu::FString &sName ) | ||
115 | { | ||
116 | for( ScopeStack::iterator i = sVars.begin(); i; i++ ) | ||
117 | { | ||
118 | if( (*i).has( sName ) ) | ||
119 | { | ||
120 | return (*i).get( sName ); | ||
121 | } | ||
122 | } | ||
123 | throw Bu::ExceptionBase("No such variable."); | ||
124 | } | ||
125 | |||
126 | void Context::delVariable( const Bu::FString &sName ) | ||
127 | { | ||
128 | for( ScopeStack::iterator i = sVars.begin(); i; i++ ) | ||
129 | { | ||
130 | if( (*i).has( sName ) ) | ||
131 | { | ||
132 | (*i).erase( sName ); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | void Context::pushScope() | ||
138 | { | ||
139 | VarHash h; | ||
140 | if( !sVars.isEmpty() ) | ||
141 | h = sVars.peek(); | ||
142 | sVars.push( h ); | ||
143 | } | ||
144 | |||
145 | void Context::pushScope( const VarHash &hNewVars ) | ||
146 | { | ||
147 | VarHash h = hNewVars; | ||
148 | if( !sVars.isEmpty() ) | ||
149 | { | ||
150 | for( VarHash::iterator i = sVars.peek().begin(); i; i++ ) | ||
151 | { | ||
152 | if( !h.has( i.getKey() ) ) | ||
153 | h.insert( i.getKey(), i.getValue() ); | ||
154 | } | ||
155 | } | ||
156 | sVars.push( h ); | ||
157 | } | ||
158 | |||
159 | VarHash &Context::getScope() | ||
160 | { | ||
161 | return sVars.first(); | ||
162 | } | ||
163 | |||
164 | void Context::popScope() | ||
165 | { | ||
166 | sVars.pop(); | ||
167 | } | ||
168 | |||
169 | Variable Context::call( const Bu::FString &sName, Variable &input, | ||
170 | VarList lParams ) | ||
171 | { | ||
172 | if( !hFunction.has( sName ) ) | ||
173 | { | ||
174 | throw Bu::ExceptionBase("Unknown function called: %s", sName.getStr() ); | ||
175 | } | ||
176 | return hFunction.get( sName )->call( input, lParams ); | ||
177 | } | ||
178 | |||
179 | #include <bu/sio.h> | ||
180 | using namespace Bu; | ||
181 | Bu::FString Context::expand( const Bu::FString &sInS ) | ||
182 | { | ||
183 | Bu::FString sRet; | ||
184 | Bu::FString sIn = sInS; | ||
185 | |||
186 | for( int iPass = 0; iPass < 2; iPass++ ) | ||
187 | { | ||
188 | Bu::FString::const_iterator b = sIn.begin(); | ||
189 | sRet.clear(); | ||
190 | for(;;) | ||
191 | { | ||
192 | Bu::FString::const_iterator e = b.find('$'); | ||
193 | if( !e ) | ||
194 | { | ||
195 | sRet.append( b ); | ||
196 | break; | ||
197 | } | ||
198 | sRet.append( b, e ); | ||
199 | b = e+1; | ||
200 | if( !b ) | ||
201 | { | ||
202 | sRet.append('$'); | ||
203 | } | ||
204 | else if( *b == '{' ) | ||
205 | { | ||
206 | b++; | ||
207 | e = b.find('}'); | ||
208 | Bu::FString sVar( b, e ); | ||
209 | try | ||
210 | { | ||
211 | sRet.append( getVariable( sVar ).toString() ); | ||
212 | } catch(...) | ||
213 | { | ||
214 | // TODO: This may be handy debugging later... | ||
215 | //sio << "No variable named " << sVar << sio.nl; | ||
216 | //sio << "Vars: " << sVars << sio.nl << sio.nl; | ||
217 | } | ||
218 | b = e+1; | ||
219 | } | ||
220 | else if( *b == '(' && iPass == 1 ) | ||
221 | { | ||
222 | b++; | ||
223 | e = b.find(')'); | ||
224 | Bu::FString sCmd( b, e ); | ||
225 | Bu::FString sBuf; | ||
226 | try | ||
227 | { | ||
228 | //sio << "Executing command: >>>" << sCmd << "<<<" << sio.nl; | ||
229 | Process p( Process::StdOut, "/bin/bash", "/bin/bash", "-c", sCmd.getStr(), NULL ); | ||
230 | while( p.isRunning() ) | ||
231 | { | ||
232 | char buf[4096]; | ||
233 | sBuf.append( buf, p.read( buf, 4096 ) ); | ||
234 | } | ||
235 | sRet.append( sBuf ); | ||
236 | } catch(...) | ||
237 | { | ||
238 | // TODO: This may be handy debugging later... | ||
239 | //sio << "No variable named " << sVar << sio.nl; | ||
240 | //sio << "Vars: " << sVars << sio.nl << sio.nl; | ||
241 | } | ||
242 | b = e+1; | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | // Not a match, uh, just output the $ for now... | ||
247 | sRet.append('$'); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | sIn = sRet; | ||
252 | } | ||
253 | return sRet; | ||
254 | } | ||
255 | |||
256 | Target *Context::getTarget( const Bu::FString &sOutput ) | ||
257 | { | ||
258 | return hTarget.get( sOutput ); | ||
259 | } | ||
260 | |||
261 | TargetList Context::getExplicitTargets() | ||
262 | { | ||
263 | TargetList lRet; | ||
264 | for( TargetHash::iterator i = hTarget.begin(); i; i++ ) | ||
265 | { | ||
266 | if( (*i)->isExplicit() ) | ||
267 | lRet.append( *i ); | ||
268 | } | ||
269 | return lRet; | ||
270 | } | ||
271 | |||
272 | void Context::buildTargetTree( Runner &r ) | ||
273 | { | ||
274 | TargetList lTargets = hTarget.getValues(); | ||
275 | |||
276 | for( TargetList::iterator i = lTargets.begin(); i; i++ ) | ||
277 | { | ||
278 | // I believe we only want to autogenerate targets for explicit targets | ||
279 | // that have rules defined. | ||
280 | if( !(*i)->isExplicit() || !(*i)->hasRule() ) | ||
281 | continue; | ||
282 | |||
283 | StrList lNewIns; // The new "changed" inputs for this target | ||
284 | |||
285 | Rule *pMaster = hRule.get( (*i)->getRule() ); | ||
286 | |||
287 | for( StrList::const_iterator j = (*i)->getInputList().begin(); j; j++ ) | ||
288 | { | ||
289 | if( pMaster->ruleMatches( r, *j ) ) | ||
290 | { | ||
291 | lNewIns.append( *j ); | ||
292 | } | ||
293 | |||
294 | if( hTarget.has( *j ) ) | ||
295 | { | ||
296 | // Find the existing dependancy | ||
297 | lNewIns.append( *j ); | ||
298 | } | ||
299 | //else | ||
300 | //{ | ||
301 | buildTargetTree( r, *i, *j, pMaster, lNewIns ); | ||
302 | //} | ||
303 | } | ||
304 | |||
305 | pMaster->prepTarget( *i ); | ||
306 | (*i)->resetInputList( lNewIns ); | ||
307 | } | ||
308 | //sio << "Building dependancies: " << Fmt(3) << 0 << "%\r" << sio.flush; | ||
309 | //int iSize = hTarget.getSize(), iCur = 0; | ||
310 | for( TargetHash::iterator i = hTarget.begin(); i; i++ ) | ||
311 | { | ||
312 | // Before we can take a look at the requirements, we need to build | ||
313 | // them... | ||
314 | // (*i)->buildRequires( r ); | ||
315 | |||
316 | // For every target we have to examine both it's inputs and it's | ||
317 | // additional requirements. Inputs first | ||
318 | StrList lDeps( (*i)->getInputList() ); | ||
319 | lDeps += (*i)->getRequiresList(); | ||
320 | for( StrList::const_iterator j = lDeps.begin(); j; j++ ) | ||
321 | { | ||
322 | try | ||
323 | { | ||
324 | (*i)->addDep( hTarget.get( *j ) ); | ||
325 | } | ||
326 | catch(...) | ||
327 | { | ||
328 | } | ||
329 | } | ||
330 | //iCur++; | ||
331 | // sio << "Building dependancies: " << Fmt(3) << (iCur*100/iSize) << "%\r" << sio.flush; | ||
332 | (*i)->collapseDeps(); | ||
333 | } | ||
334 | // sio << sio.nl; | ||
335 | |||
336 | for( TargetHash::iterator i = hTarget.begin(); i; i++ ) | ||
337 | { | ||
338 | if( !(*i)->isExplicit() ) | ||
339 | continue; | ||
340 | (*i)->setDepCount(); | ||
341 | (*i)->resetRun( false ); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | void Context::buildTargetTree( class Runner &r, class Target * /*pTarget*/, const Bu::FString &sInput, Rule *pMaster, StrList &lNewIns ) | ||
346 | { | ||
347 | Target *pNewTarget = NULL; | ||
348 | for( RuleHash::iterator i = hRule.begin(); i; i++ ) | ||
349 | { | ||
350 | if( (*i)->hasOutputs() && (*i)->ruleMatches( r, sInput ) ) | ||
351 | { | ||
352 | pNewTarget = (*i)->createTarget( r, sInput ); | ||
353 | |||
354 | Bu::Hash<ptrdiff_t, bool> hDone; | ||
355 | for( StrList::const_iterator oi = | ||
356 | pNewTarget->getOutputList().begin(); oi; oi++ ) | ||
357 | { | ||
358 | try | ||
359 | { | ||
360 | Target *pOver = hTarget.get( *oi ); | ||
361 | if( hDone.has( (ptrdiff_t)pOver ) ) | ||
362 | continue; | ||
363 | hDone.insert( (ptrdiff_t)pOver, true ); | ||
364 | if( !pOver->isExplicit() ) | ||
365 | { | ||
366 | delete pNewTarget; | ||
367 | pNewTarget = pOver; | ||
368 | break; | ||
369 | } | ||
370 | pOver->mergeUnder( pNewTarget ); | ||
371 | delete pNewTarget; | ||
372 | // sio << "Delete: " << Fmt::ptr() << (ptrdiff_t)pNewTarget << sio.nl; | ||
373 | pNewTarget = pOver; | ||
374 | break; | ||
375 | } | ||
376 | catch(...) | ||
377 | { | ||
378 | } | ||
379 | } | ||
380 | |||
381 | // We actually want to add this either way, if the merge added new | ||
382 | // outputs, then we need to take them into account. | ||
383 | addTarget( pNewTarget ); | ||
384 | addTargetToTags( pNewTarget, (*i)->getTagList() ); | ||
385 | |||
386 | // We have created a new target (or not, either way, we need to | ||
387 | // check if it matches.) | ||
388 | for( StrList::const_iterator m = | ||
389 | pNewTarget->getOutputList().begin(); m; m++ ) | ||
390 | { | ||
391 | // Does the new output match the master rule? | ||
392 | if( pMaster->ruleMatches( r, (*m) ) ) | ||
393 | { | ||
394 | lNewIns.append( (*m) ); | ||
395 | |||
396 | // sio << "What?" << sio.nl; | ||
397 | // These relationships are difficult to pick up on except | ||
398 | // that one target was created by the other, I suppose. | ||
399 | // Anyway, that means that we need to add this while we | ||
400 | // can. | ||
401 | // pTarget->addDep( pNewTarget ); | ||
402 | } | ||
403 | // else | ||
404 | // { | ||
405 | buildTargetTree( r, pNewTarget, *m, pMaster, lNewIns ); | ||
406 | // } | ||
407 | } | ||
408 | |||
409 | return; | ||
410 | } | ||
411 | } | ||
412 | if( !pNewTarget ) | ||
413 | { | ||
414 | //sio << "Incomplete tree created, trying to find purpose for \"" | ||
415 | // << sInput << "\"." << sio.nl; | ||
416 | return; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | void Context::attachDefaults() | ||
421 | { | ||
422 | for( TargetHash::iterator i = hTarget.begin(); i; i++ ) | ||
423 | { | ||
424 | if( !(*i)->hasProfile("clean") ) | ||
425 | { | ||
426 | (*i)->addProfile( Profile::genDefaultClean() ); | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | |||
431 | void Context::genDefaultActions() | ||
432 | { | ||
433 | if( !hAction.has("all") ) | ||
434 | { | ||
435 | addAction( Action::genDefaultAll() ); | ||
436 | } | ||
437 | if( !hAction.has("clean") ) | ||
438 | { | ||
439 | addAction( Action::genDefaultClean() ); | ||
440 | } | ||
441 | if( !hAction.has("default") ) | ||
442 | { | ||
443 | addAction( Action::genDefaultDefault() ); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | void Context::writeTargetDot() | ||
448 | { | ||
449 | Bu::Hash<ptrdiff_t, bool> hDone; | ||
450 | sio << "digraph {" << sio.nl | ||
451 | << "\trankdir=LR;" << sio.nl; | ||
452 | for( TargetHash::iterator i = hTarget.begin(); i; i++ ) | ||
453 | { | ||
454 | if( hDone.has( (ptrdiff_t)*i ) ) | ||
455 | continue; | ||
456 | hDone.insert( (ptrdiff_t)*i, true ); | ||
457 | for( StrList::const_iterator l = (*i)->getOutputList().begin(); | ||
458 | l; l++ ) | ||
459 | { | ||
460 | for( StrList::const_iterator k = (*i)->getInputList().begin(); | ||
461 | k; k++ ) | ||
462 | { | ||
463 | sio << "\t\"" << *k << "\" -> \"" | ||
464 | << *l << "\";" << sio.nl; | ||
465 | } | ||
466 | for( StrList::const_iterator k = (*i)->getRequiresList().begin(); | ||
467 | k; k++ ) | ||
468 | { | ||
469 | sio << "\t\"" << *k << "\" -> \"" | ||
470 | << *l << "\" [color=red];" << sio.nl; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | } | ||
475 | sio << "}" << sio.nl; | ||
476 | } | ||
477 | |||
478 | void Context::setView( View *pNewView ) | ||
479 | { | ||
480 | delete pView; | ||
481 | pView = pNewView; | ||
482 | } | ||
483 | |||
484 | View *Context::getView() | ||
485 | { | ||
486 | return pView; | ||
487 | } | ||
488 | |||
489 | Bu::Formatter &operator<<( Bu::Formatter &f, const Context &c ) | ||
490 | { | ||
491 | f << "Variables: " << c.sVars << f.nl; | ||
492 | f << "Targets: " << c.hTarget << f.nl; | ||
493 | f << "Rules: " << c.hRule << f.nl; | ||
494 | |||
495 | return f; | ||
496 | } | ||
497 | |||
498 | void Context::printBasicInfo() | ||
499 | { | ||
500 | sio << "Available actions:" << sio.nl << "\t"; | ||
501 | for( ActionHash::iterator i = hAction.begin(); i; i++ ) | ||
502 | { | ||
503 | if( i != hAction.begin() ) | ||
504 | sio << ", "; | ||
505 | sio << i.getKey(); | ||
506 | } | ||
507 | |||
508 | TargetList lTargets = getExplicitTargets(); | ||
509 | sio << sio.nl << sio.nl << "Available targets:" << sio.nl << "\t"; | ||
510 | for( TargetList::iterator i = lTargets.begin(); i; i++ ) | ||
511 | { | ||
512 | if( i != lTargets.begin() ) | ||
513 | sio << ", "; | ||
514 | for( StrList::const_iterator j = (*i)->getOutputList().begin(); j; j++ ) | ||
515 | { | ||
516 | if( j != (*i)->getOutputList().begin() ) | ||
517 | sio << ", "; | ||
518 | sio << (*j); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | sio << sio.nl << sio.nl; | ||
523 | } | ||
524 | |||