ADUC_Result workflow_create_from_inline_step()

in src/utils/workflow_utils/src/workflow_utils.c [2661:2810]


ADUC_Result workflow_create_from_inline_step(ADUC_WorkflowHandle base, size_t stepIndex, ADUC_WorkflowHandle* handle)
{
    ADUC_Result result = { ADUC_GeneralResult_Failure };
    JSON_Status jsonStatus = JSONFailure;
    JSON_Value* updateActionValue = NULL;
    JSON_Value* updateManifestValue = NULL;
    ADUC_Workflow* wf = NULL;
    JSON_Array* steps = workflow_get_instructions_steps_array(base);
    JSON_Value* stepValue = json_array_get_value(steps, stepIndex);

    if (stepValue == NULL)
    {
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_STEP_INDEX;
        goto done;
    }

    *handle = NULL;

    ADUC_Workflow* wfBase = workflow_from_handle(base);

    wf = malloc(sizeof(*wf));
    if (wf == NULL)
    {
        result.ExtendedResultCode = ADUC_ERC_NOMEM;
        goto done;
    }

    memset(wf, 0, sizeof(*wf));

    updateActionValue = json_value_deep_copy(json_object_get_wrapping_value(wfBase->UpdateActionObject));
    if (updateActionValue == NULL)
    {
        Log_Error("Cannot copy Update Action json from base");
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_FROM_BASE_FAILURE;
        goto done;
    }

    JSON_Object* updateActionObject = json_object(updateActionValue);

    updateManifestValue = json_value_deep_copy(json_object_get_wrapping_value(wfBase->UpdateManifestObject));
    if (updateManifestValue == NULL)
    {
        Log_Error("Cannot copy Update Manifest json from base");
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_FROM_BASE_FAILURE;
        goto done;
    }

    JSON_Object* updateManifestObject = json_object(updateManifestValue);
    JSON_Object* stepObject = json_object(stepValue);

    char* currentStepData = json_serialize_to_string_pretty(stepValue);
    Log_Debug("Processing current step:\n%s", currentStepData);
    json_free_serialized_string(currentStepData);

    // Replace 'updateType' with step's handler type.
    const char* updateType = json_object_get_string(stepObject, STEP_PROPERTY_FIELD_HANDLER);
    if (updateType == NULL || *updateType == 0)
    {
        Log_Error("Invalid step entry.");
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_STEP_ENTRY_NO_HANDLER_TYPE;
        goto done;
    }
    jsonStatus = json_object_set_string(updateManifestObject, ADUCITF_FIELDNAME_UPDATETYPE, updateType);
    if (jsonStatus == JSONFailure)
    {
        Log_Error("Cannot update step entry updateType.");
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_SET_UPDATE_TYPE_FAILURE;
        goto done;
    }

    // Copy 'handlerProperties'.
    JSON_Value* handlerProperties =
        json_value_deep_copy(json_object_get_value(stepObject, STEP_PROPERTY_FIELD_HANDLER_PROPERTIES));
    jsonStatus =
        json_object_set_value(updateManifestObject, STEP_PROPERTY_FIELD_HANDLER_PROPERTIES, handlerProperties);
    if (jsonStatus == JSONFailure)
    {
        json_value_free(handlerProperties);
        handlerProperties = NULL;
        Log_Error("Cannot copy 'handlerProperties'.");
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_COPY_HANDLER_PROPERTIES_FAILED;
        goto done;
    }

    // Keep only file needed by this step entry. Remove the rest.
    JSON_Array* stepFiles = json_object_get_array(stepObject, ADUCITF_FIELDNAME_FILES);
    JSON_Object* baseFiles = json_object_get_object(updateManifestObject, ADUCITF_FIELDNAME_FILES);

    size_t fileCount = json_object_get_count(baseFiles);
    while (fileCount > 0)
    {
        fileCount--;

        const char* baseFileId = json_object_get_name(baseFiles, fileCount);

        // If file is in the instruction, merge their properties.
        bool fileRequired = false;

        size_t stepFilesCount = json_array_get_count(stepFiles);
        while (stepFilesCount > 0)
        {
            stepFilesCount--;

            // Note: step's files is an array of file ids.
            const char* stepFileId = json_array_get_string(stepFiles, stepFilesCount);

            if (baseFileId != NULL && stepFileId != NULL && strcmp(baseFileId, stepFileId) == 0)
            {
                // Found.
                fileRequired = true;

                // Done with this file, remove it (and free).
                json_array_remove(stepFiles, stepFilesCount);
                break;
            }
        }

        // Remove file from base files list, if no longer needed.
        if (!fileRequired)
        {
            json_object_remove(baseFiles, json_object_get_name(baseFiles, fileCount));
        }
    }

    // Remove 'instructions' list...
    json_object_set_null(updateManifestObject, "instructions");

    wf->UpdateActionObject = updateActionObject;
    wf->UpdateManifestObject = updateManifestObject;

    {
        char* baseWorkfolder = workflow_get_workfolder(base);
        workflow_set_workfolder(wf, baseWorkfolder);
        workflow_free_string(baseWorkfolder);
    }

    *handle = wf;
    result.ResultCode = ADUC_GeneralResult_Success;
    result.ExtendedResultCode = 0;

done:
    if (IsAducResultCodeFailure(result.ResultCode))
    {
        json_value_free(updateActionValue);
        json_value_free(updateManifestValue);
        workflow_free(wf);
    }

    return result;
}