Beispiel #1
0
/*
 * Get a filename in cache for given md5sum.
 */
const char *filecache_getfilename(TARGET *t, MD5SUM sum, const char* extension)
{
	BUFFER buff;
	size_t pos;
	const char *cachedir;
	const char* result;

	cachedir = filecache_getpath(t);
	/* if no cachedir, no cachefiles */
	if (cachedir==NULL) {
		return NULL;
	}

	/* put the cachedir in front of buffer */
	buffer_init(&buff);
	buffer_addstring(&buff, cachedir, strlen(cachedir));
	buffer_addchar(&buff, '/');

	pos = buffer_pos(&buff);
	buffer_addstring(&buff, "000/", 4);

	/* add use md5 as filename */
	buffer_addstring(&buff, md5tostring(sum), 32);
	if (extension)
		buffer_addstring(&buff, extension, strlen(extension));
	buffer_addchar(&buff, 0);

	buffer_setpos(&buff, pos);
	buffer_putstring(&buff, buffer_ptr(&buff) + pos + 4, 3);

	result = newstr(buffer_ptr(&buff));
	buffer_free(&buff);
	return result;
}
Beispiel #2
0
void checksum_update(TARGET *t, MD5SUM buildmd5sum)
{
	CHECKSUMDATA cachedata, *c = &cachedata;
	char buildmd5sumstring[33];

	/* If the buildmd5sum is empty, then the file doesn't exist. */
	if (ismd5empty(buildmd5sum))
		return;

	/* if the target is available in the cache */
	strcpy(buildmd5sumstring, md5tostring(buildmd5sum));
	c->boundname = buildmd5sumstring;

	/* Search for the appropriate .link file that matches the target. */
	if (!hashcheck(checksumhash, (HASHDATA **)&c)) {
		if (hashenter(checksumhash, (HASHDATA **)&c)) {
			c->boundname = newstr( c->boundname );
			c->next = checksumdatalist;
			checksumdatalist = c;
		}
	}

	memcpy(&c->contentmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE);
	c->mtime = 1;
	c->age = 0;
	checksumsdirty = 1;
}
Beispiel #3
0
int checksum_retrieve(TARGET *t, MD5SUM buildmd5sum)
{
	CHECKSUMDATA cachedata, *c = &cachedata;
	char buildmd5sumstring[33];

	checksums_readfile();

	strcpy(buildmd5sumstring, md5tostring(buildmd5sum));
	c->boundname = buildmd5sumstring;

	if (!hashcheck(checksumhash, (HASHDATA **)&c)) {
		return 0;
	}

	getcachedmd5sum(t, 0);

	if (t->contentchecksum  &&  t->contentchecksum->mtime != 0  &&  memcmp( c->contentmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE ) == 0 )
	{
		time_t time;
#ifdef _MSC_VER
		_utime(t->boundname, NULL);
#else
		utime(t->boundname, NULL);
#endif
		file_time(t->boundname, &time);
		t->contentchecksum->mtime = time;
		t->contentchecksum->age = 0;
		checksumsdirty = 1;

		//printf("JAMDEBUG: %s is already the proper cached target.\n", t->name);
		return 1;
	}
	else
	{
		memset(&c->contentmd5sum, 0, MD5_SUMSIZE);
	}

	return 0;
}
Beispiel #4
0
/*
 * Get cached md5sum of a file. If none found, or not up to date, if the file is source
 * try to recalculate the sum. If not, then return empty sum (all zeroes).
 */
int getcachedmd5sum( TARGET *t, int source )
{
	HCACHEDATA cachedata, *c = &cachedata;
	int  use_cache = 1;
	HCACHEFILE *file;
	const char *target = t->boundname;
# ifdef DOWNSHIFT_PATHS
	char path[ MAXJPATH ];
	char *p;
#endif

	if ( t->contentmd5sum_calculated )
		return t->contentmd5sum_changed;

	if (!source) {
		memset(&t->buildmd5sum, 0, sizeof(t->buildmd5sum));
		memset(&t->contentmd5sum, 0, sizeof(t->contentmd5sum));
		t->contentmd5sum_calculated = 1;
		t->contentmd5sum_changed = 0;
		return t->contentmd5sum_changed;
	}

	file = hcachefile_get( t );

	++queries;

# ifdef DOWNSHIFT_PATHS
	p = path;

	do *p++ = (char)tolower( *target );
	while( *target++ );

	target = path;
# endif

	c->boundname = target;

	if( hashcheck( file->hcachehash, (HASHDATA **) &c ) )
	{
		if ( t->time == 0 ) {
			/* This file was generated.  Grab its timestamp. */
			file_time( c->boundname, &c->mtime );
		} else if( c->mtime != t->time )
			use_cache = 0;

		if ( use_cache ) {
			use_cache = memcmp(md5sumempty, &c->contentmd5sum, sizeof(c->contentmd5sum)) != 0;
		}

		if( use_cache ) {
			if( DEBUG_MD5HASH )
				printf( "- content md5: %s (%s)\n", t->boundname, md5tostring(c->contentmd5sum));
			c->age = 0; /* The entry has been used, its young again */
			++hits;
			t->contentmd5sum_changed = 0;
			memcpy(&t->contentmd5sum, &c->contentmd5sum, sizeof(t->contentmd5sum));
			t->contentmd5sum_calculated = 1;
			return t->contentmd5sum_changed;
		}
		else {
			if( DEBUG_MD5HASH )
				printf( "md5 cache out of date for %s (time %d, md5time %d)\n", t->boundname , (int)t->time, (int)c->mtime );
		}
	} else {
		if( hashenter( file->hcachehash, (HASHDATA **)&c ) ) {
			c->boundname = newstr( c->boundname );
			c->next = file->hcachelist;
			file->hcachelist = c;
			c->time = 0;
			c->includes = NULL;
			c->hdrscan = NULL;
		}
	}

	file->dirty = 1;

	/* 'c' points at the cache entry.  Its out of date. */

	{
		MD5SUM origmd5sum;
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
		LIST *md5callback;
#endif

		memcpy( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) );
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
		pushsettings( t->settings );
		md5callback = var_get( "MD5CALLBACK" );
		popsettings( t->settings );

		if ( md5callback )
		{
			luahelper_md5callback(t->boundname, c->contentmd5sum, md5callback->string);
		}
		else
		{
#endif
			md5file( t->boundname, c->contentmd5sum );
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
		}
#endif
		t->contentmd5sum_changed = memcmp( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) ) != 0;
	}
	if( DEBUG_MD5HASH )
		printf( "- content md5: %s (%s)\n", t->boundname, md5tostring(c->contentmd5sum));

	c->mtime = t->time;
	if ( c->mtime == 0 ) {
		/* This file was generated.  Grab its timestamp. */
		file_time( c->boundname, &c->mtime );
	}
	c->age = 0;
	memcpy(&t->contentmd5sum, &c->contentmd5sum, sizeof(t->contentmd5sum));
	t->contentmd5sum_calculated = (char)(memcmp(md5sumempty, &t->contentmd5sum, sizeof(t->contentmd5sum)) != 0);
	memset(&t->buildmd5sum, 0, sizeof(t->buildmd5sum));

	return t->contentmd5sum_changed;
}
Beispiel #5
0
void filecache_update(TARGET *t)
{
	MD5SUM blobmd5sum;
	int haveblobmd5sum = 0;
	const char *cachedname;
	const char *blobname;
	int cacheerror;

	if (!t->filecache_generate)
		return;

	/* If the buildmd5sum is empty, then the file doesn't exist. */
	cacheerror = ismd5empty(t->buildmd5sum);
	if (cacheerror)
		return;

	haveblobmd5sum = 0;
	cachedname = filecache_getfilename(t, t->buildmd5sum, NULL);
	if (!cachedname)
		return;

	/* Search for the appropriate .link file that matches the target. */
	haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum);

	/* If we weren't able to determine the target md5sum, do it now. */
	if (!haveblobmd5sum)
	{
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
		LIST *md5callback;

		pushsettings( t->settings );
		md5callback = var_get( "MD5CALLBACK" );
		popsettings( t->settings );

		if ( md5callback )
		{
			luahelper_md5callback(t->boundname, blobmd5sum, md5callback->string);
		}
		else
		{
#endif
			md5file(t->boundname, blobmd5sum);
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
		}
#endif
		memcpy(t->contentmd5sum, blobmd5sum, sizeof(MD5SUM));
		if (ismd5empty(t->contentmd5sum))
			return;
	}

	{
		/* Is the blob already there? */
		time_t blobtime;
		blobname = filecache_getfilename(t, blobmd5sum, ".blob");
		if (file_time(blobname, &blobtime) == -1)
		{
			time_t blobpartialtime;
			const char *blobpartialname;

			if(DEBUG_MD5HASH)
				printf("Caching %s as %s\n", t->name, cachedname);
			else
				printf("Caching %s\n", t->name);

			/* Write the new .blob to the cache. */
			blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial");
			if (file_time(blobpartialname, &blobpartialtime) == -1)
			{
				if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0  ||
					rename(blobpartialname, blobname) != 0)
				{
					printf("** Unable to write %s to cache.\n", t->name, cachedname);
					filecache_disable(t);
					return;
				}
			}
		}
	}

	/* Write the new .link file to the cache. */
	{
		FILE *file;
		BUFFER linknamebuff;
		buffer_init(&linknamebuff);
		buffer_addstring(&linknamebuff, cachedname, strlen(cachedname));
		buffer_addchar(&linknamebuff, '-');
		buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32);
		buffer_addstring(&linknamebuff, ".link", 5);
		buffer_addchar(&linknamebuff, 0);

		file_mkdir(buffer_ptr(&linknamebuff));
		file = fopen(buffer_ptr(&linknamebuff), "wb");
		if (file)
		{
			write_md5sum(file, blobmd5sum);
			write_string(file, t->name);
			fclose(file);
		}

		buffer_free(&linknamebuff);
	}
}
Beispiel #6
0
static CMD *
make1cmds( ACTIONS *a0 )
#endif
{
	CMD *cmds = 0;
	LIST *shell = var_get( "JAMSHELL" );	/* shell is per-target */

	/* Step through actions */
	/* Actions may be shared with other targets or grouped with */
	/* RULE_TOGETHER, so actions already seen are skipped. */

	for( ; a0; a0 = a0->next )
	{
	    RULE    *rule = a0->action->rule;
	    SETTINGS *boundvars;
	    LIST    *nt, *ns;
	    ACTIONS *a1;
	    int	    start, chunk, length, maxline;
		TARGETS *autosettingsreverse = 0;
		TARGETS *autot;

#ifdef OPT_MULTIPASS_EXT
	    if ( a0->action->pass != actionpass )
		continue;
#endif

	    /* Only do rules with commands to execute. */
	    /* If this action has already been executed, use saved status */

#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	    if (DEBUG_MAKE1) {
		printf( "make1cmds\t--\t%s (actions %s, running %s)\n" ,
			rule->name,
			rule->actions ? "yes" : "no",
			a0->action->running ? "yes" : "no" );
	    }
#endif
	    if( !rule->actions || a0->action->running )
		continue;

#ifdef OPT_REMOVE_EMPTY_DIRS_EXT
		if ( rule->flags & RULE_REMOVEEMPTYDIRS ) {
			for( a1 = a0; a1; a1 = a1->next ) {
				TARGETS* sources;
				for ( sources = a1->action->sources; sources; sources = sources->next ) {
					emptydirtargets = list_new( emptydirtargets, sources->target->name, 1 );
				}
			}
		}
#endif

		for ( autot = a0->action->autosettings; autot; autot = autot->next ) {
			if ( autot->target != t )
				pushsettings( autot->target->settings );
			autosettingsreverse = targetentryhead( autosettingsreverse, autot->target, 0 );
		}
		pushsettings( t->settings );
	    a0->action->running = 1;
#ifdef OPT_ACTIONS_WAIT_FIX
	    a0->action->run_tgt = t;
#endif

	    /* Make LISTS of targets and sources */
	    /* If `execute together` has been specified for this rule, tack */
	    /* on sources from each instance of this rule for this target. */
#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	    if (DEBUG_MAKE1) {
		LIST *list = make1list(L0, a0->action->targets, 0);
		printf("make1cmds\t--\ttargets: ");
		list_print(list);
		list_free(list);
		printf("\n");
		list = make1list(L0, a0->action->sources, 0);
		printf("make1cmds\t--\tsources: ");
		list_print(list);
		list_free(list);
		printf("\n");
	    }
#endif

#ifdef OPT_BUILTIN_MD5CACHE_EXT
	    if (t->filecache_generate  ||  t->filecache_use)
	    {
		LIST* targets = make1list_unbound( L0, a0->action->targets, 0 );
		LIST* sources = make1list_unbound( L0, a0->action->sources, rule->flags );

		nt = L0;
		ns = L0;

		if ( strncmp( rule->name, "batched_", 8 ) == 0 )
		{
		    int anycacheable = 0;
		    for( ; targets; targets = targets->next, sources = ( sources == NULL ? sources : sources->next ) )
		    {
			TARGET *t = bindtarget(targets->string);
			TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL;

			/* if this target could be cacheable */
			if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate  ||  t->filecache_use) ) {
			    /* find its final md5sum */
			    MD5_CTX context;
			    MD5SUM buildsumorg;
			    anycacheable = 1;
			    memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum));
			    MD5Init( &context );
			    MD5Update( &context, t->buildmd5sum, sizeof( t->buildmd5sum ) );
			    {
				TARGET *outt = bindtarget( t->boundname );
				outt->flags |= T_FLAG_USEFILECACHE;
				MD5Final( outt->buildmd5sum, &context );
				memcpy(&t->buildmd5sum, &outt->buildmd5sum, sizeof(t->buildmd5sum));
			    }
			    if (DEBUG_MD5HASH) {
				printf( "Cacheable: %s buildmd5: %s org: %s\n",
				    t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) );
			    }

			    /* if using cache is allowed */
			    if (t->filecache_use) {
				const char *cachedname;

				/* if the target is available in the cache */
				cachedname = filecache_getfilename(t, t->buildmd5sum, ".doesntwork");
				if (cachedname!=NULL) {
				    time_t cachedtime;
				    if ( file_time( cachedname, &cachedtime ) == 0 )
				    {
					/* try to get it from the cache */
					if (copyfile(t->boundname, cachedname, NULL)) {
					    printf( "Using cached %s\n", t->name );
					    continue;
					} else {
					    printf( "Cannot retrieve %s from cache (will build normally)\n", t->name );
					}
				    } else {
					if( DEBUG_MD5HASH) {
					    printf( "Cannot find %s in cache as %s\n", t->name, cachedname );
					}
				    }
				}
			    }
			    /* Build new lists */

			    nt = list_new( nt, t->boundname, 1 );
			    if (s)
				ns = list_new( ns, s->boundname, 1 );
			}
		    }

		    if ( !anycacheable ) {
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
		    }
		}
		else
		{
		    int allcached = 1;
		    popsettings( t->settings );
		    for( ; targets; targets = list_next(targets) )
		    {
			TARGET *t = bindtarget(targets->string);
//			TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL;
			TARGETS *c;
			TARGET *outt;
			LIST *filecache = 0;

			if ( t->flags & T_FLAG_USEFILECACHE )
			{
			    pushsettings( t->settings );
			    filecache = filecache_fillvalues( t );
			    popsettings( t->settings );
			}

			/* if this target could be cacheable */
			if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate  ||  t->filecache_use) ) {
			    /* find its final md5sum */
			    MD5_CTX context;

			    if( DEBUG_MD5HASH ) {
				printf( "------------------------------------------------\n" );
				printf( "------------------------------------------------\n" );
				printf( "------------------------------------------------\n" );
			    }

			    /* sort all dependents by name, so we can make reliable md5sums */
			    t->depends = make0sortbyname( t->depends );

			    MD5Init( &context );

			    /* add the path of the file to the sum - it is significant because one command can create more than one file */
			    MD5Update( &context, (unsigned char*)t->name, (unsigned int)strlen( t->name ) );

			    /* add in the COMMANDLINE */
			    if ( t->flags & T_FLAG_USECOMMANDLINE )
			    {
				SETTINGS *vars;
				for ( vars = t->settings; vars; vars = vars->next )
				{
				    if ( vars->symbol[0] == 'C'  &&  strcmp( vars->symbol, "COMMANDLINE" ) == 0 )
				    {
					LIST *list;
					for ( list = vars->value; list; list = list->next )
					{
					    MD5Update( &context, (unsigned char*)list->string, (unsigned int)strlen( list->string ) );
					    if( DEBUG_MD5HASH )
						printf( "\t\tCOMMANDLINE: %s\n", list->string );
					}

					break;
				    }
				}
			    }

			    /* for each dependencies */
			    for( c = t->depends; c; c = c->next )
			    {
				/* If this is a "Needs" dependency, don't care about its contents. */
				if (c->needs)
				{
				    continue;
				}

				/* add name of the dependency and its contents */
				make0calcmd5sum( c->target, 1 );
				if ( c->target->buildmd5sum_calculated )
				{
				    MD5Update( &context, (unsigned char*)c->target->name, (unsigned int)strlen( c->target->name ) );
				    MD5Update( &context, c->target->buildmd5sum, sizeof( c->target->buildmd5sum ) );
				}
			    }

			    outt = bindtarget( t->boundname );
			    outt->flags |= T_FLAG_USEFILECACHE;
			    outt->filecache_generate = t->filecache_generate;
			    outt->filecache_use = t->filecache_use;
			    outt->settings = addsettings( outt->settings, VAR_SET, "FILECACHE", list_new( L0, filecache->string, 1 ) );
			    MD5Final( outt->buildmd5sum, &context );
			    if (DEBUG_MD5HASH)
			    {
				printf( "Cacheable: %s buildmd5: %s\n", t->boundname, md5tostring(outt->buildmd5sum) );
			    }

			    /* if using cache is allowed */
			    if ( t->filecache_use  &&  allcached )
			    {
				allcached = filecache_retrieve( t, outt->buildmd5sum );
			    }
			    else
			    {
				allcached = 0;
			    }
			}
			else
			{
			    allcached = 0;
			}
		    }
		    pushsettings( t->settings );

		    if ( !allcached ) {
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
		    }
		}
		list_free( targets );
		list_free( sources );

		/* if no targets survived (all were retrieved from the cache)
		or no sources survived (all are up to date) */
		if (nt==NULL) { // || ns==NULL) {
		    /* skip this action */
		    list_free(ns);
			popsettings( t->settings );
			for ( autot = autosettingsreverse; autot; autot = autot->next ) {
				if ( autot->target != t )
					pushsettings( autot->target->settings );
			}
		    continue;
		}
	    }
	    else
	    {
#if 0
		if ( strncmp( rule->name, "batched_", 8 ) == 0 )
		{
			TARGETS* targets = a0->action->targets;
			TARGETS* sources = a0->action->sources;
		    int anycacheable = 0;

			nt = L0;
			ns = L0;

			/* walk sources and targets simultaneously */
			for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) )
			{
				TARGET *t = targets->target;
				TARGET *s = sources!=NULL ? sources->target : NULL;

				/* Sources to 'actions existing' are never in the dependency */
				/* graph (if they were, they'd get built and 'existing' would */
				/* be superfluous, so throttle warning message about independent */
				/* targets. */

				if( t->binding == T_BIND_UNBOUND )
					make1bind( t, 0 );
				if( s!=NULL) {
					if ( s->binding == T_BIND_UNBOUND )
						make1bind( s, !( rule->flags & RULE_EXISTING ) );
					if ( s->binding == T_BIND_UNBOUND )
						printf("Warning using unbound source %s for batched action.\n", s->name);
				}


				if( ( rule->flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS )
					continue;

				if( t->fate < T_FATE_BUILD )
					continue;

				/* Build new lists */

				nt = list_new( nt, t->boundname, 1 );
				if (s!=NULL) {
					ns = list_new( ns, s->boundname, 1 );
				}
			}

			if (sources!=NULL) {
				printf("warning: more sources than targets in a batched action!\n");
			}

		} else {
#endif
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
#if 0
	    }
#endif
		}
#else
	    nt = make1list( L0, a0->action->targets, 0 );
	    ns = make1list( L0, a0->action->sources, rule->flags );
#endif

	    if( rule->flags & RULE_TOGETHER )
		for( a1 = a0->next; a1; a1 = a1->next )
#ifdef OPT_MULTIPASS_EXT
		    if( a1->action->pass == actionpass && a1->action->rule == rule && !a1->action->running )
#else
		    if( a1->action->rule == rule && !a1->action->running )
#endif
	    {
		ns = make1list( ns, a1->action->sources, rule->flags );
		a1->action->running = 1;
#ifdef OPT_ACTIONS_WAIT_FIX
		a1->action->run_tgt = t;
#endif
	    }

	    /* If doing only updated (or existing) sources, but none have */
	    /* been updated (or exist), skip this action. */

	    if( !ns && ( rule->flags & ( RULE_UPDATED | RULE_EXISTING ) ) )
	    {
		list_free( nt );
#ifdef OPT_DEBUG_MAKE1_LOG_EXT
		if (DEBUG_MAKE1) {
		    const char* desc = 0;
		    if ((rule->flags & (RULE_UPDATED | RULE_EXISTING))
			== (RULE_UPDATED | RULE_EXISTING)) {
			desc = "updated/existing";
		    } else if (rule->flags & RULE_UPDATED) {
			desc = "updated";
		    } else if (rule->flags & RULE_EXISTING) {
			desc = "existing";
		    }
		    printf( "make1cmds\t--\t%s (skipping actions by %s)\n" ,
			    rule->name, desc );
		}
#endif /* OPT_DEBUG_MAKE1_LOG_EXT */
			popsettings( t->settings );
			for ( autot = autosettingsreverse; autot; autot = autot->next ) {
				if ( autot->target != t )
					pushsettings( autot->target->settings );
			}
		continue;
	    }

	    /* If we had 'actions xxx bind vars' we bind the vars now */

	    boundvars = make1settings( rule->bindlist );
	    pushsettings( boundvars );

	    /*
	     * Build command, starting with all source args.
	     *
	     * If cmd_new returns 0, it's because the resulting command
	     * length is > MAXLINE.  In this case, we'll slowly reduce
	     * the number of source arguments presented until it does
	     * fit.  This only applies to actions that allow PIECEMEAL
	     * commands.
	     *
	     * While reducing slowly takes a bit of compute time to get
	     * things just right, it's worth it to get as close to MAXLINE
	     * as possible, because launching the commands we're executing
	     * is likely to be much more compute intensive!
	     *
	     * Note we loop through at least once, for sourceless actions.
	     *
	     * Max line length is the action specific maxline or, if not
	     * given or bigger than MAXLINE, MAXLINE.
	     */

	    start = 0;
	    chunk = length = list_length( ns );
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
	    maxline = rule->maxline;
/* commented so jamgram.y can compile #else
	    maxline = rule->flags / RULE_MAXLINE;
#endif */
#ifdef OPT_PIECEMEAL_PUNT_EXT
	    maxline = maxline && maxline < CMDBUF ? maxline : CMDBUF;
#else
	    maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE;
#endif

	    do
	    {
		/* Build cmd: cmd_new consumes its lists. */
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
		int thischunk = rule->maxtargets != 0 ? (chunk < rule->maxtargets ? chunk : rule->maxtargets) : chunk;

		CMD *cmd = cmd_new( rule,
			list_copy( L0, nt ),
			list_sublist( ns, start, thischunk ),
			list_copy( L0, shell ),
			maxline );
/* commented so jamgram.y can compile #else
		CMD *cmd = cmd_new( rule,
			list_copy( L0, nt ),
			list_sublist( ns, start, chunk ),
			list_copy( L0, shell ),
			maxline );
#endif */

		if( cmd )
		{
		    /* It fit: chain it up. */

		    if( !cmds ) cmds = cmd;
		    else cmds->tail->next = cmd;
		    cmds->tail = cmd;
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
		    start += thischunk;
/* commented out so jamgram.y can compile #else
		    start += chunk;
#endif */
		}
		else if( ( rule->flags & RULE_PIECEMEAL ) && chunk > 1 )
		{
		    /* Reduce chunk size slowly. */

		    chunk = chunk * 9 / 10;
		}
		else
		{
		    /* Too long and not splittable. */

#ifdef OPT_PIECEMEAL_PUNT_EXT
		    if (maxline < CMDBUF) {
			maxline = CMDBUF;
			continue;
		    }
#endif
		    printf( "%s actions too long (max %d)!\n",
			rule->name, maxline );
		    exit( EXITBAD );
		}
	    }
	    while( start < length );

	    /* These were always copied when used. */

	    list_free( nt );
	    list_free( ns );

	    /* Free the variables whose values were bound by */
	    /* 'actions xxx bind vars' */

	    popsettings( boundvars );
	    freesettings( boundvars );

		popsettings( t->settings );
		for ( autot = autosettingsreverse; autot; autot = autot->next ) {
			if ( autot->target != t )
				pushsettings( autot->target->settings );
		}
	}

	return cmds;
}
Beispiel #7
0
static void
make1list_batched(
        MD5SUM *md5forcmd,
        LIST**plt,
        LIST**pls,
        TARGETS *targets,
        TARGETS *sources,
        int     flags )
{
    /* walk sources and targets simultaneously */
    for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) )
    {
	TARGET *t = targets->target;
	TARGET *s = sources!=NULL ? sources->target : NULL;

	if ( t->flags & T_FLAG_USEFILECACHE )
	{
	    LIST *filecache;
	    pushsettings( t->settings );
	    filecache = var_get( "FILECACHE" );
	    if ( filecache ) {
		LIST *l;
		char *ptr;
		strcpy( filecache_buffer, "FILECACHE." );
		strcat( filecache_buffer, filecache->string );
		ptr = filecache_buffer + strlen( filecache_buffer );
		strcat( ptr, ".USE" );
		l = var_get( filecache_buffer );
		if ( l  &&  atoi( l->string ) != 0) {
		    t->filecache_use = 1;
		}
		strcat( ptr, ".GENERATE" );
		l = var_get( filecache_buffer );
		if ( l  &&  atoi( l->string ) != 0) {
		    t->filecache_generate = 1;
		}
	    }
	    popsettings( t->settings );
	}

	/* Sources to 'actions existing' are never in the dependency */
	/* graph (if they were, they'd get built and 'existing' would */
	/* be superfluous, so throttle warning message about independent */
	/* targets. */

	if( t->binding == T_BIND_UNBOUND )
	    make1bind( t, 0 );
	if( s!=NULL) {
	    if ( s->binding == T_BIND_UNBOUND )
		make1bind( s, !( flags & RULE_EXISTING ) );
	    if ( s->binding == T_BIND_UNBOUND )
		printf("Warning using unbound source %s for batched action.\n", s->name);
	}


	if( ( flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS )
	    continue;

	if( t->fate < T_FATE_BUILD )
	    continue;

	/* if this target could be cacheable */
	if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) {
	    /* find its final md5sum */
	    MD5_CTX context;
	    MD5SUM buildsumorg;
	    memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum));
	    MD5Init( &context );

	    /* add the path of the file to the sum - it is significant because one command can create more than one file */
	    MD5Update( &context, t->name, strlen( t->name ) );
	    MD5Final( t->buildmd5sum, &context );
	    if (DEBUG_MD5HASH) {
		printf( "Cacheable: %s buildmd5: %s org: %s\n",
		    t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) );
	    }
	}

	/* if this target could be cacheable */
	if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) {
	    const char *cachedname;
	    time_t cachedtime;

	    /* if using cache is allowed */
	    if (t->filecache_use) {
		/* if the target is available in the cache */
		cachedname = filecache_getfilename(t, t->buildmd5sum, "");
		if (cachedname!=NULL) {
		    if ( file_time( cachedname, &cachedtime ) == 0 ) {
			/* try to get it from the cache */
			if (copyfile(t->boundname, cachedname, NULL)) {
			    printf( "Using cached %s\n", t->boundname );
			    continue;
			} else {
			    printf( "Cannot retrieve %s from cache (will build normally)\n", t->boundname );
			}
		    } else {
			if( DEBUG_MD5HASH) {
			    printf( "Cannot find %s in cache as %s\n", t->boundname, cachedname );
			}
		    }
		}
	    }
	}

	/* Build new lists */

	*plt = list_new( *plt, t->boundname, 1 );
	if (s!=NULL) {
	    *pls = list_new( *pls, s->boundname, 1 );
	}
    }

    if (sources!=NULL) {
	printf("warning: more sources than targets in a batched action!\n");
    }
}
Beispiel #8
0
void filecache_update(TARGET *t, MD5SUM buildmd5sum)
{
	MD5SUM blobmd5sum;
	int haveblobmd5sum = 0;
	const char *cachedname;
	const char *blobname;
	int cacheerror;

	if (!t->filecache_generate)
		return;

	/* If the buildmd5sum is empty, then the file doesn't exist. */
	cacheerror = ismd5empty(buildmd5sum);
	if (cacheerror)
		return;

	haveblobmd5sum = 0;
	cachedname = filecache_getfilename(t, buildmd5sum, NULL);
	if (!cachedname)
		return;

	/* Search for the appropriate .link file that matches the target. */
	haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum);

	/* If we weren't able to determine the target md5sum, do it now. */
	if (!haveblobmd5sum)
	{
		getcachedmd5sum( t, 1 );
		memcpy(blobmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE);
		if (ismd5empty(t->contentchecksum->contentmd5sum))
			return;
	}

	{
		/* Is the blob already there? */
		time_t blobtime;
		blobname = filecache_getfilename(t, blobmd5sum, ".blob");
		if (file_time(blobname, &blobtime) == -1)
		{
			time_t blobpartialtime;
			const char *blobpartialname;

			if(DEBUG_MD5HASH)
				printf("Caching %s as %s\n", t->name, cachedname);
			else
				printf("Caching %s\n", t->name);

			/* Write the new .blob to the cache. */
			blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial");
			if (file_time(blobpartialname, &blobpartialtime) == -1)
			{
				if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0  ||
					rename(blobpartialname, blobname) != 0)
				{
					printf("** Unable to write %s to cache.\n", t->name);
					filecache_disable(t);
					return;
				}
			}
		}
	}

	/* Write the new .link file to the cache. */
	{
		FILE *file;
		BUFFER linknamebuff;
		buffer_init(&linknamebuff);
		buffer_addstring(&linknamebuff, cachedname, strlen(cachedname));
		buffer_addchar(&linknamebuff, '-');
		buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32);
		buffer_addstring(&linknamebuff, ".link", 5);
		buffer_addchar(&linknamebuff, 0);

		file_mkdir(buffer_ptr(&linknamebuff));
		file = fopen(buffer_ptr(&linknamebuff), "wb");
		if (file)
		{
			write_md5sum(file, blobmd5sum);
			write_string(file, t->name);
			fclose(file);
		}

		buffer_free(&linknamebuff);
	}
}