static PromiseResult ExpandPromiseAndDo(EvalContext *ctx, PromiseIterator *iterctx, PromiseActuator *act_on_promise, void *param) { PromiseResult result = PROMISE_RESULT_SKIPPED; /* TODO this loop could be completely skipped for for non vars/classes if * act_on_promise is CommonEvalPromise(). */ while (PromiseIteratorNext(iterctx, ctx)) { /* * ACTUAL WORK PART 1: Get a (another) copy of the promise. * * Basically this evaluates all constraints. As a result it evaluates * all functions, even if they are not to be used immediately (for * example promises that the actuator skips because of ifvarclass). */ const Promise *pexp = /* expanded promise */ EvalContextStackPushPromiseIterationFrame(ctx, iterctx); if (pexp == NULL) /* is the promise excluded? */ { result = PromiseResultUpdate(result, PROMISE_RESULT_SKIPPED); continue; } /* ACTUAL WORK PART 2: run the actuator */ PromiseResult iteration_result = act_on_promise(ctx, pexp, param); /* iteration_result is always NOOP for PRE-EVAL. */ result = PromiseResultUpdate(result, iteration_result); /* Redmine#6484: Do not store promise handles during PRE-EVAL, to * avoid package promise always running. */ if (act_on_promise != &CommonEvalPromise) { NotifyDependantPromises(ctx, pexp, iteration_result); } /* EVALUATE VARS PROMISES again, allowing redefinition of * variables. The theory behind this is that the "sampling rate" of * vars promise needs to be double than the rest. */ if (strcmp(pexp->parent_promise_type->name, "vars") == 0 || strcmp(pexp->parent_promise_type->name, "meta") == 0) { if (act_on_promise != &VerifyVarPromise) { VerifyVarPromise(ctx, pexp, NULL); } } /* Why do we push/pop an iteration frame, if all iterated variables * are Put() on the previous scope? */ EvalContextStackPopFrame(ctx); } return result; }
static PromiseResult ExpandPromiseAndDo(EvalContext *ctx, const Promise *pp, Rlist *lists, Rlist *containers, PromiseActuator *ActOnPromise, void *param) { const char *handle = PromiseGetHandle(pp); EvalContextStackPushPromiseFrame(ctx, pp, true); PromiseIterator *iter_ctx = NULL; size_t i = 0; PromiseResult result = PROMISE_RESULT_NOOP; Buffer *expbuf = BufferNew(); for (iter_ctx = PromiseIteratorNew(ctx, pp, lists, containers); PromiseIteratorHasMore(iter_ctx); i++, PromiseIteratorNext(iter_ctx)) { if (handle) { // This ordering is necessary to get automated canonification BufferClear(expbuf); ExpandScalar(ctx, NULL, "this", handle, expbuf); CanonifyNameInPlace(BufferGet(expbuf)); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", BufferData(expbuf), CF_DATA_TYPE_STRING, "source=promise"); } else { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", PromiseID(pp), CF_DATA_TYPE_STRING, "source=promise"); } const Promise *pexp = EvalContextStackPushPromiseIterationFrame(ctx, i, iter_ctx); if (!pexp) { // excluded result = PromiseResultUpdate(result, PROMISE_RESULT_SKIPPED); continue; } PromiseResult iteration_result = ActOnPromise(ctx, pexp, param); NotifyDependantPromises(ctx, pexp, iteration_result); result = PromiseResultUpdate(result, iteration_result); if (strcmp(pp->parent_promise_type->name, "vars") == 0 || strcmp(pp->parent_promise_type->name, "meta") == 0) { VerifyVarPromise(ctx, pexp, true); } EvalContextStackPopFrame(ctx); } BufferDestroy(expbuf); PromiseIteratorDestroy(iter_ctx); EvalContextStackPopFrame(ctx); return result; }
static void ResolveVariablesPromises(EvalContext *ctx, PromiseType *pt) { assert(strcmp("vars", pt->name) == 0); for (size_t i = 0; i < SeqLength(pt->promises); i++) { Promise *pp = SeqAt(pt->promises, i); EvalContextStackPushPromiseFrame(ctx, pp, false); EvalContextStackPushPromiseIterationFrame(ctx, 0, NULL); VerifyVarPromise(ctx, pp, false); EvalContextStackPopFrame(ctx); EvalContextStackPopFrame(ctx); } }
static void ExpandPromiseAndDo(EvalContext *ctx, const Promise *pp, Rlist *lists, Rlist *containers, PromiseActuator *ActOnPromise, void *param) { const char *handle = PromiseGetHandle(pp); char v[CF_MAXVARSIZE]; EvalContextStackPushPromiseFrame(ctx, pp, true); PromiseIterator *iter_ctx = NULL; for (iter_ctx = PromiseIteratorNew(ctx, pp, lists, containers); PromiseIteratorHasMore(iter_ctx); PromiseIteratorNext(iter_ctx)) { EvalContextStackPushPromiseIterationFrame(ctx, iter_ctx); char number[CF_SMALLBUF]; /* Allow $(this.handle) etc variables */ if (PromiseGetBundle(pp)->source_path) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promise_filename",PromiseGetBundle(pp)->source_path, DATA_TYPE_STRING); snprintf(number, CF_SMALLBUF, "%zu", pp->offset.line); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promise_linenumber", number, DATA_TYPE_STRING); } snprintf(v, CF_MAXVARSIZE, "%d", (int) getuid()); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser_uid", v, DATA_TYPE_INT); snprintf(v, CF_MAXVARSIZE, "%d", (int) getgid()); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser_gid", v, DATA_TYPE_INT); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "bundle", PromiseGetBundle(pp)->name, DATA_TYPE_STRING); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "namespace", PromiseGetNamespace(pp), DATA_TYPE_STRING); /* Must expand $(this.promiser) here for arg dereferencing in things like edit_line and methods, but we might have to adjust again later if the value changes -- need to qualify this so we don't expand too early for some other promsies */ if (pp->has_subbundles) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, DATA_TYPE_STRING); } if (handle) { char tmp[CF_EXPANDSIZE]; // This ordering is necessary to get automated canonification ExpandScalar(ctx, NULL, "this", handle, tmp); CanonifyNameInPlace(tmp); Log(LOG_LEVEL_DEBUG, "Expanded handle to '%s'", tmp); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", tmp, DATA_TYPE_STRING); } else { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", PromiseID(pp), DATA_TYPE_STRING); } Promise *pexp = ExpandDeRefPromise(ctx, pp); assert(ActOnPromise); ActOnPromise(ctx, pexp, param); if (strcmp(pp->parent_promise_type->name, "vars") == 0 || strcmp(pp->parent_promise_type->name, "meta") == 0) { VerifyVarPromise(ctx, pexp, true); } PromiseDestroy(pexp); EvalContextStackPopFrame(ctx); } PromiseIteratorDestroy(iter_ctx); EvalContextStackPopFrame(ctx); }