From 8dd79b7b5a0309f9bc1185019a4af16b3b52aece Mon Sep 17 00:00:00 2001
From: Mike Buland <eichlan@xagasoft.com>
Date: Sat, 5 Aug 2006 00:04:34 +0000
Subject: Build now uses a cachefile for all of it's requires that are
 generated from other means (running other programs).  It's really fast, and
 seems to work pretty well.

---
 src/builder.cpp    | 113 ++++++++++++++++++++++++-----------------------------
 src/builder.h      |   9 ++++-
 src/cache.cpp      |  78 ++++++++++++++++++++++++++++++++++++
 src/cache.h        |  33 ++++++++++++++++
 src/filetarget.cpp |   5 ++-
 src/main.cpp       |  27 +++++++++----
 6 files changed, 193 insertions(+), 72 deletions(-)
 create mode 100644 src/cache.cpp
 create mode 100644 src/cache.h

diff --git a/src/builder.cpp b/src/builder.cpp
index d3cb2c0..a21bc99 100644
--- a/src/builder.cpp
+++ b/src/builder.cpp
@@ -7,6 +7,8 @@
 #include "build.tab.h"
 #include "rule.h"
 #include "viewer.h"
+#include "cache.h"
+#include "serializerbinary.h"
 
 subExceptionDef( BuildException )
 
@@ -21,6 +23,18 @@ Builder::Builder( Viewer &rView ) :
 
 Builder::~Builder()
 {
+	if( sCacheFile.getLength() > 0 )
+	{
+		try
+		{
+			SerializerBinary ar( sCacheFile, Serializer::save );
+
+			ar << cRequires;
+		}
+		catch( ExceptionBase &e )
+		{
+		}
+	}
 }
 
 void yyparse( Builder &bld );
@@ -53,6 +67,21 @@ void Builder::build( const char *sAct )
 	rView.endAction();
 }
 
+void Builder::setCache( const std::string &sFile )
+{
+	sCacheFile = sFile.c_str();
+
+	try
+	{
+		SerializerBinary ar( sCacheFile, Serializer::load );
+
+		ar >> cRequires;
+	}
+	catch( ExceptionBase &e )
+	{
+	}
+}
+
 void Builder::execute( Action *pAct )
 {
 	pAct->execute( *this );
@@ -247,75 +276,31 @@ void Builder::processRequires( std::list<std::string> &lInput )
 		}
 	}
 
-	// These are only done on request now, they were too expensive
-	/*
-	for( regreqlist::iterator i = lRequiresRegexpCommand.begin();
-		 i != lRequiresRegexpCommand.end(); i++ )
+}
+
+void Builder::genRequiresFor( const char *sName, time_t tNewTime )
+{
+	Cache::Entry *ent = cRequires.get( sName );
+	if( ent && tNewTime > 0 )
 	{
-		RegExp *re = (*i).first;
-		for( std::list<std::string>::iterator j = lInput.begin();
-			 j != lInput.end(); j++ )
+		if( ent->tCreated >= tNewTime )
 		{
-			if( re->execute( (*j).c_str() ) )
+			for( std::list<std::string>::iterator i = ent->lData.begin();
+				 i != ent->lData.end(); i++ )
 			{
-				varmap *revars = regexVars( re );
-				std::string s = varRepl( (*i).second.c_str(), "", revars );
-				FILE *fcmd = popen( s.c_str(), "r" );
-				std::string rhs;
-				bool bHeader = true;
-				for(;;)
-				{
-					if( feof( fcmd ) )
-						break;
-					int cc = fgetc( fcmd );
-					if( cc == EOF )
-						break;
-					unsigned char c = cc;
-					if( bHeader )
-					{
-						if( c == ':' )
-							bHeader = false;
-					}
-					else
-					{
-						if( c == ' ' || c == '\t' )
-						{
-							if( rhs != "" )
-							{
-								requiresNormal(
-									(*j).c_str(),
-									rhs.c_str()
-									);
-								rhs = "";
-							}
-						}
-						else
-						{
-							if( c == '\\' )
-								c = fgetc( fcmd );
-							if( c != '\n' )
-								rhs += c;
-						}
-					}
-				}
-				if( rhs != "" )
-				{
-					requiresNormal(
-						(*j).c_str(),
-						rhs.c_str()
-						);
-					rhs = "";
-				}
-				pclose( fcmd );
-				delete revars;
+				requiresNormal(
+					sName,
+					(*i).c_str()
+					);
 			}
+
+			return;
 		}
 	}
-	*/
-}
 
-void Builder::genRequiresFor( const char *sName )
-{
+	ent = new Cache::Entry;
+	ent->tCreated = tNewTime;
+
 	for( regreqlist::iterator i = lRequiresRegexpCommand.begin();
 		 i != lRequiresRegexpCommand.end(); i++ )
 	{
@@ -352,6 +337,7 @@ void Builder::genRequiresFor( const char *sName )
 								sName,
 								rhs.c_str()
 								);
+							ent->lData.push_back( rhs );
 							rhs = "";
 						}
 					}
@@ -370,6 +356,7 @@ void Builder::genRequiresFor( const char *sName )
 					sName,
 					rhs.c_str()
 					);
+				ent->lData.push_back( rhs );
 				rhs = "";
 			}
 			pclose( fcmd );
@@ -377,6 +364,8 @@ void Builder::genRequiresFor( const char *sName )
 			rView.endExtraRequiresCheck();
 		}
 	}
+
+	cRequires.put( sName, ent );
 }
 
 std::map<std::string, std::string> *Builder::regexVars( RegExp *re )
diff --git a/src/builder.h b/src/builder.h
index 06e84f3..56a7b07 100644
--- a/src/builder.h
+++ b/src/builder.h
@@ -8,6 +8,7 @@
 #include "exceptionbase.h"
 #include "staticstring.h"
 #include "regexp.h"
+#include "cache.h"
 
 subExceptionDecl( BuildException )
 
@@ -17,6 +18,7 @@ class Command;
 class Rule;
 class Target;
 class Viewer;
+class Cache;
 
 #define YY_DECL int yylex( YYSTYPE *yylval_param, YYLTYPE *yylloc_param, Builder &bld )
 YY_DECL;
@@ -48,6 +50,8 @@ public:
 	{
 		return rView;
 	}
+
+	void setCache( const std::string &sFile );
 	void add( Action *pAct );
 	void add( Command *pCmd );
 	void add( Rule *pRule );
@@ -59,7 +63,7 @@ public:
 	void processRequires( std::list<std::string> &lInput );
 	void requires( const char *sBase, const char *sReq );
 	void requiresFromCommand( const char *sBase, const char *sReq );
-	void genRequiresFor( const char *sName );
+	void genRequiresFor( const char *sName, time_t tNewTime );
 	void requiresRegexp( bool on )
 	{
 		bReqRegexp = on;
@@ -152,6 +156,9 @@ private:
 	bool bReqRegexp;
 
 	Viewer &rView;
+
+	StaticString sCacheFile;
+	class Cache cRequires;
 };
 
 void cleanList( std::list<std::string> &lst );
diff --git a/src/cache.cpp b/src/cache.cpp
new file mode 100644
index 0000000..43e69dc
--- /dev/null
+++ b/src/cache.cpp
@@ -0,0 +1,78 @@
+#include "cache.h"
+#include "serializer.h"
+
+Cache::Cache()
+{
+}
+
+Cache::~Cache()
+{
+	for( std::map<std::string, Entry *>::iterator i = mCache.begin();
+		 i != mCache.end(); i++ )
+	{
+		delete (*i).second;
+	}
+}
+
+void Cache::serialize( class Serializer &ar )
+{
+	if( ar.isLoading() )
+	{
+		int sCache, sData;
+		ar >> sCache;
+		std::string sTmp;
+
+		for( int i = 0; i < sCache; i++ )
+		{
+			Entry *e = new Entry;
+			ar >> e->tCreated;
+			ar >> sData;
+			std::list<std::string> &lData = e->lData;
+			for( int j = 0; j < sData; j++ )
+			{
+				ar >> sTmp;
+				lData.push_back( sTmp );
+			}
+			ar >> sTmp;
+			mCache[sTmp] = e;
+		}
+	}
+	else
+	{
+		ar << mCache.size();
+		for( std::map<std::string, Entry *>::iterator i = mCache.begin();
+			 i != mCache.end(); i++ )
+		{
+			ar << (*i).second->tCreated;
+			std::list<std::string> &lData = (*i).second->lData;
+			ar << lData.size();
+			for( std::list<std::string>::iterator j = lData.begin();
+				 j != lData.end(); j++ )
+			{
+				ar << (*j);
+			}
+
+			std::string str = (*i).first;
+			ar << str;
+		}
+	}
+}
+
+Cache::Entry *Cache::get( const std::string &id )
+{
+	std::map<std::string, Entry *>::iterator i = mCache.find( id );
+	if( i != mCache.end() )
+		return (*i).second;
+
+	return NULL;
+}
+
+void Cache::put( const std::string &id, Entry *data )
+{
+	std::map<std::string, Entry *>::iterator i = mCache.find( id );
+	if( i != mCache.end() )
+		delete (*i).second;
+
+	mCache[id] = data;
+}
+
diff --git a/src/cache.h b/src/cache.h
new file mode 100644
index 0000000..944aa24
--- /dev/null
+++ b/src/cache.h
@@ -0,0 +1,33 @@
+#ifndef CACHE_H
+#define CACHE_H
+
+#include <stdint.h>
+#include <time.h>
+#include "serializable.h"
+#include <list>
+#include <map>
+#include <string>
+
+class Cache : public Serializable
+{
+public:
+	Cache();
+	virtual ~Cache();
+
+	virtual void serialize( class Serializer &ar );
+
+	class Entry
+	{
+	public:
+		int tCreated;
+		std::list<std::string> lData;
+	};
+
+	Entry *get( const std::string &id );
+	void put( const std::string &id, Entry *data );
+
+private:
+	std::map<std::string, Entry *> mCache;
+};
+
+#endif
diff --git a/src/filetarget.cpp b/src/filetarget.cpp
index e89cd5f..7a714a5 100644
--- a/src/filetarget.cpp
+++ b/src/filetarget.cpp
@@ -98,7 +98,8 @@ void FileTarget::check( Builder &bld )
 		for( std::list<std::string>::iterator j = lReqs->begin();
 			 j != lReqs->end(); j++ )
 		{
-			if( getTime( bld, *j ) > target )
+			time_t srcfile = getTime( bld, *j );
+			if( srcfile > target )
 			{
 				bld.view().beginExecute();
 				(*i)->execute( bld );
@@ -113,7 +114,7 @@ void FileTarget::check( Builder &bld )
 				if( k == lReqs->end() )
 				{
 					bExtraReqs = true;
-					bld.genRequiresFor( (*i)->getTarget() );
+					bld.genRequiresFor( (*i)->getTarget(), srcfile );
 				}
 			}
 		}
diff --git a/src/main.cpp b/src/main.cpp
index 70a3ffc..009aac5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,13 +8,18 @@ class Param : public ParamProc
 {
 public:
 	Param() :
-		sFile("build.conf")
+		sFile("build.conf"),
+		sCache("build.cache")
 	{
 		addHelpBanner("Build r?\n\n");
 		addParam("file", 'f', &sFile, 
 				"Set the input script, default: build.conf");
 		addParam('p', mkproc(Param::procViewPercent),
 				"Switch to percent view.");
+		addParam("cache", &sCache,
+				"Set an alternative cache file." );
+		addParam('d', &bDebug,
+				"Print out a debug dump of the read build.conf", "true" );
 		addParam("help", mkproc(ParamProc::help),
 				"This help");
 		pViewer = new ViewerPlain;
@@ -42,9 +47,11 @@ public:
 		pViewer = new ViewerPercent;
 	}
 
+	std::string sCache;
 	std::string sFile;
 	StaticString sAction;
 	Viewer *pViewer;
+	bool bDebug;
 
 private:
 };
@@ -56,14 +63,20 @@ int main( int argc, char *argv[] )
 
 	Builder bld( *prm.pViewer );
 
+	bld.setCache( prm.sCache );
 	bld.load( prm.sFile.c_str() );
 
-	if( prm.sAction > 0 )
-		bld.build( prm.sAction );
+	if( prm.bDebug )
+	{
+		printf("\n\n----------\nDebug dump\n----------\n");
+		bld.debug();
+	}
 	else
-		bld.build();
-/*
-	printf("\n\n----------\nDebug dump\n----------\n");
-	bld.debug();*/
+	{
+		if( prm.sAction > 0 )
+			bld.build( prm.sAction );
+		else
+			bld.build();
+	}
 }
 
-- 
cgit v1.2.3