aboutsummaryrefslogtreecommitdiff
path: root/src/context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/context.cpp')
-rw-r--r--src/context.cpp524
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>
25using namespace Bu;
26
27Context::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
45Context::~Context()
46{
47}
48
49void 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
57void Context::addRule( Rule *pRule )
58{
59 hRule.insert( pRule->getName(), pRule );
60}
61
62void Context::addFunction( Function *pFunction )
63{
64 pFunction->setContext( this );
65 hFunction.insert( pFunction->getName(), pFunction );
66}
67
68void 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
82void Context::addAction( Action *pAction )
83{
84 hAction.insert( pAction->getName(), pAction );
85}
86
87Action *Context::getAction( const Bu::FString &sName )
88{
89 return hAction.get( sName );
90}
91
92void 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
101void 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
109TargetList &Context::getTag( const Bu::FString &sTag )
110{
111 return hTag.get( sTag );
112}
113
114Variable &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
126void 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
137void Context::pushScope()
138{
139 VarHash h;
140 if( !sVars.isEmpty() )
141 h = sVars.peek();
142 sVars.push( h );
143}
144
145void 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
159VarHash &Context::getScope()
160{
161 return sVars.first();
162}
163
164void Context::popScope()
165{
166 sVars.pop();
167}
168
169Variable 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>
180using namespace Bu;
181Bu::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
256Target *Context::getTarget( const Bu::FString &sOutput )
257{
258 return hTarget.get( sOutput );
259}
260
261TargetList 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
272void 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
345void 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
420void 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
431void 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
447void 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
478void Context::setView( View *pNewView )
479{
480 delete pView;
481 pView = pNewView;
482}
483
484View *Context::getView()
485{
486 return pView;
487}
488
489Bu::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
498void 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