int filecache_retrieve(TARGET *t, MD5SUM buildmd5sum) { MD5SUM blobmd5sum; MD5SUM copymd5sum; time_t time; /* if the target is available in the cache */ const char *cachedname = filecache_getfilename(t, buildmd5sum, 0); if (!cachedname) return 0; if (!filecache_findlink(cachedname, blobmd5sum)) { if( DEBUG_MD5HASH) { printf("Cannot find %s in cache as %s\n", t->name, cachedname); filecache_disable(t); } return 0; } getcachedmd5sum( t, 1 ); if ( file_time( t->boundname, &time ) == 0 ) { if (memcmp(blobmd5sum, t->contentmd5sum, sizeof(MD5SUM)) == 0) { if (!(t->flags & T_FLAG_NOCARE)) #ifdef _MSC_VER _utime(t->boundname, NULL); #else utime(t->boundname, NULL); #endif printf("%s is already the proper cached target.\n", t->name); return 1; } } cachedname = filecache_getfilename(t, blobmd5sum, ".blob"); /* try to get it from the cache */ if (copyfile(t->boundname, cachedname, ©md5sum) && memcmp(copymd5sum, blobmd5sum, sizeof(MD5SUM)) == 0) { printf( "Using cached %s\n", t->name ); return 1; } else if (!(t->flags & T_FLAG_OPTIONALFILECACHE)) { printf( "Cannot retrieve %s from cache (will build normally)\n", t->name ); return 0; } if( DEBUG_MD5HASH) { printf( "Cannot find %s in cache as %s\n", t->name, cachedname ); } return 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; }
static void make1b( TARGET *t ) { TARGETS *c; const char *failed; #ifdef OPT_MULTIPASS_EXT int missing; #endif #ifdef OPT_BUILTIN_NEEDS_EXT int childmightnotupdate; int childscancontents; int childupdated; #endif #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1b\t--\t%s (asynccnt %d)\n" , t->name, t->asynccnt); } #endif /* If any dependents are still outstanding, wait until they */ /* call make1b() to signal their completion. */ if( --t->asynccnt ) return; #ifdef OPT_INTERRUPT_FIX if( intr ) return; #endif failed = "dependents"; #ifdef OPT_MULTIPASS_EXT missing = 0; #endif #ifdef OPT_BUILTIN_NEEDS_EXT childmightnotupdate = 0; childscancontents = 0; childupdated = 0; #endif #ifdef OPT_SEMAPHORE if( t->semaphore && t->semaphore->asynccnt ) { /* We can't launch yet. Try again when the semaphore is free */ #ifdef OPT_BUILTIN_NEEDS_EXT t->semaphore->parents = targetentry( t->semaphore->parents, t, 0 ); #else t->semaphore->parents = targetentry( t->semaphore->parents, t ); #endif t->asynccnt++; if( DEBUG_EXECCMD ) printf( "SEM: %s is busy, delaying launch of %s\n", t->semaphore->name, t->name); return; } #endif /* Now ready to build target 't'... if dependents built ok. */ /* Collect status from dependents */ for( c = t->depends; c; c = c->next ) { if ( !(t->flags & T_FLAG_INTERNAL) && c->target->asynccnt ) { // printf("warning: Trying to build '%s' before dependent '%s' is done!\n", t->name, c->target->name); } #ifdef OPT_BUILTIN_NEEDS_EXT /* Only test a target's MightNotUpdate flag if the target's build was successful. */ if( c->target->status == EXEC_CMD_OK ) { if ( c->target->flags & T_FLAG_MIGHTNOTUPDATE ) { time_t timestamp; /* Mark that we've seen a MightNotUpdate flag in this set of children. */ childmightnotupdate = 1; /* Grab the generated target's timestamp. */ if ( file_time( c->target->boundname, ×tamp ) == 0 ) { /* If the child's timestamp is greater that the target's timestamp, then it updated. */ if ( timestamp > t->time ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { childscancontents = 1; if ( getcachedmd5sum( c->target, 1 ) ) childupdated = 1; } else childupdated = 1; } else { childscancontents = 1; } } } /* If it didn't have the MightNotUpdate flag but did update, mark it. */ else if ( c->target->fate > T_FATE_STABLE && !c->needs ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { childscancontents = 1; if ( getcachedmd5sum( c->target, 1 ) ) childupdated = 1; } else childupdated = 1; } } #endif if( c->target->status > t->status ) { failed = c->target->name; t->status = c->target->status; #ifdef OPT_MULTIPASS_EXT if ( ( c->target->fate == T_FATE_MISSING && ! ( c->target->flags & T_FLAG_NOCARE ) && !c->target->actions ) || t->status == EXEC_CMD_NEXTPASS ) { missing = 1; if ( queuedjamfiles ) { ACTIONS *actions; t->status = EXEC_CMD_NEXTPASS; for( actions = t->actions; actions; actions = actions->next ) { actions->action->pass++; } } } #endif } #ifdef OPT_NOCARE_NODES_EXT /* CWM */ /* If actions on deps have failed, but if this is a 'nocare' target */ /* then continue anyway. */ if( ( t->flags & T_FLAG_NOCARE ) && t->status == EXEC_CMD_FAIL ) { printf( "...dependency on %s failed, but don't care...\n", t->name ); t->status = EXEC_CMD_OK; } #endif } #ifdef OPT_BUILTIN_NEEDS_EXT /* If we found a MightNotUpdate flag and there was an update, mark the fate as updated. */ if ( childmightnotupdate && childupdated && t->fate == T_FATE_STABLE ) t->fate = T_FATE_UPDATE; if ( childscancontents ) { if ( !childupdated ) { if ( t->includes ) { for( c = t->includes->depends; c; c = c->next ) { if ( c->target->fate > T_FATE_STABLE && !c->needs ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { if ( getcachedmd5sum( c->target, 1 ) || !md5matchescommandline( c->target ) ) { childupdated = 1; break; } } else { childupdated = 1; break; } } } } if ( !childupdated ) t->fate = T_FATE_STABLE; } else if ( t->fate == T_FATE_STABLE ) t->fate = T_FATE_UPDATE; } if ( t->fate == T_FATE_UPDATE && !childupdated && t->status != EXEC_CMD_NEXTPASS ) if ( md5matchescommandline( t ) ) t->fate = T_FATE_STABLE; if ( t->flags & ( T_FLAG_MIGHTNOTUPDATE | T_FLAG_SCANCONTENTS ) && t->actions ) { #ifdef OPT_ACTIONS_WAIT_FIX /* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */ /* Determine if an action is already running on behalf of another target, and if so, */ /* bail out of make1b() prior to calling make1cmds() by adding more parents to the */ /* in-progress target and incrementing the asynccnt of the new target. */ make1wait( t ); if ( t->asynccnt != 0 ) return; #endif } #endif /* If actions on deps have failed, bail. */ /* Otherwise, execute all actions to make target */ #ifdef OPT_MULTIPASS_EXT if( t->status == EXEC_CMD_FAIL && t->actions && !missing ) #else if( t->status == EXEC_CMD_FAIL && t->actions ) #endif { ++counts->skipped; printf( "*** skipped %s for lack of %s...\n", t->name, failed ); } if( t->status == EXEC_CMD_OK ) switch( t->fate ) { case T_FATE_INIT: case T_FATE_MAKING: /* shouldn't happen */ case T_FATE_STABLE: case T_FATE_NEWER: break; case T_FATE_CANTFIND: case T_FATE_CANTMAKE: t->status = EXEC_CMD_FAIL; break; case T_FATE_ISTMP: if( DEBUG_MAKEQ ) printf( "*** using %s...\n", t->name ); break; case T_FATE_TOUCHED: case T_FATE_MISSING: case T_FATE_NEEDTMP: case T_FATE_OUTDATED: case T_FATE_UPDATE: /* Set "on target" vars, build actions, unset vars */ /* Set "progress" so that make1c() counts this target among */ /* the successes/failures. */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1b\t--\t%s (has actions)\n" , t->name ); } #endif if( t->actions ) { #ifdef OPT_ACTIONS_WAIT_FIX /* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */ /* Determine if an action is already running on behalf of another target, and if so, */ /* bail out of make1b() prior to calling make1cmds() by adding more parents to the */ /* in-progress target and incrementing the asynccnt of the new target. */ make1wait( t ); if ( t->asynccnt != 0 ) return; #endif ++counts->total; #ifndef OPT_IMPROVED_PROGRESS_EXT if( DEBUG_MAKE && !( counts->total % 100 ) ) printf( "*** on %dth target...\n", counts->total ); #else { double est_remaining; est_remaining = progress_update(globs.progress, counts->total); if (est_remaining > 0) { int minutes = (int)est_remaining / 60; int seconds = (int)est_remaining % 60; if (minutes > 0 || seconds > 0) { printf("*** completed %.0f%% (", ((double)counts->total * 100 / globs.updating)); if (minutes > 0) printf("%d min ", minutes); if (seconds >= 0) printf("%d sec ", seconds); printf("remaining)...\n"); } } } #endif #ifdef OPT_BUILTIN_MD5CACHE_EXT pushsettings( t->settings ); filecache_fillvalues( t ); popsettings( t->settings ); t->cmds = (char *)make1cmds( t, t->actions ); #else pushsettings( t->settings ); t->cmds = (char *)make1cmds( t->actions ); popsettings( t->settings ); #endif t->progress = T_MAKE_RUNNING; } break; } #ifdef OPT_SEMAPHORE /* If there is a semaphore, indicate that its in use */ if( t->semaphore ) { ++(t->semaphore->asynccnt); if( DEBUG_EXECCMD ) printf( "SEM: %s now used by %s\n", t->semaphore->name, t->name ); } #endif /* Call make1c() to begin the execution of the chain of commands */ /* needed to build target. If we're not going to build target */ /* (because of dependency failures or because no commands need to */ /* be run) the chain will be empty and make1c() will directly */ /* signal the completion of target. */ make1c( t ); }
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); } }