Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/flb_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ const char *flb_env_get(struct flb_env *env, const char *key)
/*
* Given a 'value', lookup for variables, if found, return a new composed
* sds string.
*
* Supports bash-style default substitution inside ${...}:
* ${name:-word} — if unset or empty, expand word; do not assign.
*/
flb_sds_t flb_env_var_translate(struct flb_env *env, const char *value)
{
Expand All @@ -321,6 +324,9 @@ flb_sds_t flb_env_var_translate(struct flb_env *env, const char *value)
int pre_var;
int have_var = FLB_FALSE;
const char *env_var = NULL;
char *v_sep;
const char *def_val;
int def_len;
char *v_start = NULL;
char *v_end = NULL;
char tmp[4096];
Expand Down Expand Up @@ -358,6 +364,18 @@ flb_sds_t flb_env_var_translate(struct flb_env *env, const char *value)
strncpy(tmp, v_start, v_len);
tmp[v_len] = '\0';
have_var = FLB_TRUE;

/* Bash-style default value expansion :- */
v_sep = strstr(tmp, ":");
def_val = NULL;
def_len = 0;

if (v_sep && (v_sep[1] == '-')) {
def_val = v_sep + 2;
def_len = strlen(def_val);
*v_sep = '\0';
}


/* Append pre-variable content */
pre_var = (v_start - 2) - (value + i);
Expand All @@ -374,7 +392,8 @@ flb_sds_t flb_env_var_translate(struct flb_env *env, const char *value)

/* Lookup the variable in our env-hash */
env_var = flb_env_get(env, tmp);
if (env_var) {
/* Skip env if it's empty and have a fallback defined */
if (env_var && !(def_val && strlen(env_var) == 0)) {
e_len = strlen(env_var);
s = buf_append(buf, env_var, e_len);
if (!s) {
Expand All @@ -385,6 +404,16 @@ flb_sds_t flb_env_var_translate(struct flb_env *env, const char *value)
buf = s;
}
}
else if (def_val) {
if (def_len > 0) {
s = buf_append(buf, def_val, def_len);
if (!s) {
flb_sds_destroy(buf);
return NULL;
}
buf = s;
}
}
Comment on lines +407 to +416
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a nitpick comment but bash shell also supports nested style of expanding variable like:
result=${A:-${B:-default}}.

Do we need to plan for this style of nested variable for default variable?
Just leaving as-is is also better to keep simplicity of implementation.

else if (env->warn_unused == FLB_TRUE) {
flb_warn("[env] variable ${%s} is used but not set", tmp);
}
Expand Down
155 changes: 155 additions & 0 deletions tests/internal/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,158 @@ void test_file_env_var_missing()
flb_env_destroy(env);
}

/* ${name:-word} when unset or empty */
void test_expand_default_hyphen()
{
struct flb_env *env;
flb_sds_t buf = NULL;
const char *v;
int ret;

env = flb_env_create();
if (!TEST_CHECK(env != NULL)) {
TEST_MSG("flb_env_create failed");
return;
}

buf = flb_env_var_translate(env, "${FLB_IT_DEFHYPH_Z:-fallback}");
if (!TEST_CHECK(buf != NULL)) {
TEST_MSG("translate failed");
flb_env_destroy(env);
return;
}
if (!TEST_CHECK(strcmp(buf, "fallback") == 0)) {
TEST_MSG("expected fallback, got=%s", buf);
}
flb_sds_destroy(buf);

v = flb_env_get(env, "FLB_IT_DEFHYPH_Z");
if (!TEST_CHECK(v == NULL)) {
TEST_MSG(":- must not assign locally");
}

ret = flb_env_set(env, "FLB_IT_DEFHYPH_Z", "");
if (!TEST_CHECK(ret >= 0)) {
TEST_MSG("flb_env_set empty failed");
flb_env_destroy(env);
return;
}
buf = flb_env_var_translate(env, "${FLB_IT_DEFHYPH_Z:-empty_fallback}");
if (!TEST_CHECK(buf != NULL)) {
TEST_MSG("translate empty failed");
flb_env_destroy(env);
return;
}
if (!TEST_CHECK(strcmp(buf, "empty_fallback") == 0)) {
TEST_MSG("empty local should use default, got=%s", buf);
}
flb_sds_destroy(buf);
flb_env_destroy(env);
}


/* ${name:-} should return an empty string if name is unset or empty */
void test_expand_empty_default()
{
struct flb_env *env;
flb_sds_t buf = NULL;
int ret;

env = flb_env_create();
if (!TEST_CHECK(env != NULL)) {
TEST_MSG("flb_env_create failed");
return;
}

/* Case 1: Variable is unset */
buf = flb_env_var_translate(env, "val=${VAR_NOT_SET:-}");
if (!TEST_CHECK(buf != NULL)) {
TEST_MSG("translate failed");
flb_env_destroy(env);
return;
}
if (!TEST_CHECK(strcmp(buf, "val=") == 0)) {
TEST_MSG("expected 'val=', got='%s'", buf);
}
flb_sds_destroy(buf);

/* Case 2: Variable is explicitly set to empty string */
ret = flb_env_set(env, "VAR_EMPTY", "");
if (!TEST_CHECK(ret >= 0)) {
TEST_MSG("flb_env_set failed");
flb_env_destroy(env);
return;
}

buf = flb_env_var_translate(env, "${VAR_EMPTY:-}");
if (!TEST_CHECK(buf != NULL)) {
TEST_MSG("translate failed");
flb_env_destroy(env);
return;
}

/* Result should be length 0 */
if (!TEST_CHECK(strlen(buf) == 0)) {
TEST_MSG("expected empty string, got='%s'", buf);
}

flb_sds_destroy(buf);
flb_env_destroy(env);
}


void test_expand_default_hyphen_from_os()
{
struct flb_env *env;
flb_sds_t buf = NULL;
char *var_name = "FLB_IT_DEFHYPH_OS";
char *var_val = "from_process";
int ret;

/* Set OS environment inline */
#ifdef FLB_SYSTEM_WINDOWS
ret = _putenv_s(var_name, var_val);
#else
ret = setenv(var_name, var_val, 1);
#endif

if (!TEST_CHECK(ret == 0)) {
TEST_MSG("putenv failed");
return;
}

env = flb_env_create();
if (!TEST_CHECK(env != NULL)) {
TEST_MSG("flb_env_create failed");
#ifdef FLB_SYSTEM_WINDOWS
_putenv_s(var_name, "");
#else
unsetenv(var_name);
#endif
return;
}

buf = flb_env_var_translate(env, "${FLB_IT_DEFHYPH_OS:-fallback}");
if (!TEST_CHECK(buf != NULL)) {
TEST_MSG("translate failed");
}
else {
if (!TEST_CHECK(strcmp(buf, var_val) == 0)) {
TEST_MSG("expected from_process, got=%s", buf);
}
flb_sds_destroy(buf);
}

flb_env_destroy(env);

/* Unset OS environment inline */
#ifdef FLB_SYSTEM_WINDOWS
_putenv_s(var_name, "");
#else
unsetenv(var_name);
#endif
}


TEST_LIST = {
{ "translate_long_env" , test_translate_long_env},
Expand All @@ -421,5 +573,8 @@ TEST_LIST = {
{ "file_env_var_uri" , test_file_env_var_uri},
{ "mixed_env_vars" , test_mixed_env_vars},
{ "file_env_var_missing" , test_file_env_var_missing},
{ "expand_default_hyphen" , test_expand_default_hyphen},
{ "expand_empty_default", test_expand_empty_default},
{ "expand_default_hyphen_from_os", test_expand_default_hyphen_from_os},
{ NULL, NULL }
};
Loading