Skip to content

Commit 2665aeb

Browse files
committed
kconfig: add optional selective yaml output support
kconfig is used outside of Linux, and one of uses of Kconfig is to also allow kconfig to be used for automation on kdevops by leveraging a smaller subset of variables for yaml run time for ansible runs. There is no need to clutter a full yaml file with every single config we have as we do in the kernel, and so this lets users decide if they want all or just a few select key symbols as part of the yaml output. What this will do is save us the pain of doing the selective transformation we currently do. You can test with: export KCONFIG_YAMLCFG=".yaml" export KCONFIG_YAMLCFG_ALL="y" rm -f .config .yaml make defconfig head -10 .yaml
1 parent 90bdd1b commit 2665aeb

File tree

4 files changed

+163
-3
lines changed

4 files changed

+163
-3
lines changed

confdata.c

Lines changed: 149 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,20 @@ static const char *conf_get_rustccfg_name(void)
234234
return name ? name : "include/generated/rustc_cfg";
235235
}
236236

237+
static bool conf_yaml_enable_all(void)
238+
{
239+
char *name = getenv("KCONFIG_YAMLCFG_ALL");
240+
241+
return name ? true: false;
242+
}
243+
244+
static const char *conf_get_yaml_config_name(void)
245+
{
246+
char *name = getenv("KCONFIG_YAMLCFG");
247+
248+
return name ? name : NULL;
249+
}
250+
237251
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
238252
{
239253
char *p2;
@@ -624,9 +638,103 @@ static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
624638
free(escaped);
625639
}
626640

627-
static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
641+
static char *conf_name_to_yaml(struct symbol *sym)
642+
{
643+
const char *name = sym->name;
644+
size_t len = strlen(name);
645+
size_t i, j = 0;
646+
char *yaml_name = (char *) malloc(len + 1);
647+
648+
if (!yaml_name)
649+
return NULL;
650+
651+
for (i = 0; i < len; i++) {
652+
if (name[i] == '_')
653+
yaml_name[j++] = '_';
654+
else
655+
yaml_name[j++] = tolower(name[i]);
656+
}
657+
658+
yaml_name[j] = '\0';
659+
660+
return yaml_name;
661+
}
662+
663+
static char *conf_value_to_yaml(struct symbol *sym, const char *val)
664+
{
665+
char *yaml_value = NULL;
666+
667+
switch (sym->type) {
668+
case S_INT:
669+
yaml_value = strdup(val);
670+
break;
671+
case S_HEX:
672+
asprintf(&yaml_value, "0x%s", val);
673+
break;
674+
case S_STRING:
675+
/* Wrap strings in quotes */
676+
asprintf(&yaml_value, "\"%s\"", val);
677+
break;
678+
case S_BOOLEAN:
679+
case S_TRISTATE:
680+
if (strcmp(val, "y") == 0)
681+
yaml_value = strdup("True");
682+
else if (strcmp(val, "n") == 0)
683+
yaml_value = strdup("False");
684+
else
685+
yaml_value = strdup(val); /* m in tristate */
686+
break;
687+
default:
688+
/* In case type is unknown */
689+
yaml_value = strdup(val);
690+
break;
691+
}
692+
693+
return yaml_value;
694+
}
695+
696+
static void __print_yaml_symbol(FILE *fp, struct symbol *sym,
697+
enum output_n output_n,
698+
bool escape_string)
699+
{
700+
const char *val;
701+
char *yaml_config = NULL;
702+
char *yaml_config_value = NULL;
703+
704+
if (!fp || sym->type == S_UNKNOWN)
705+
return;
706+
if (!conf_yaml_enable_all() && !(sym->flags & SYMBOL_YAML))
707+
return;
708+
709+
val = sym_get_string_value(sym);
710+
711+
yaml_config = conf_name_to_yaml(sym);
712+
if (!yaml_config)
713+
return;
714+
715+
yaml_config_value = conf_value_to_yaml(sym, val);
716+
if (!yaml_config_value) {
717+
free(yaml_config);
718+
return;
719+
}
720+
721+
if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
722+
output_n != OUTPUT_N && *val == 'n') {
723+
if (output_n == OUTPUT_N_AS_UNSET && conf_yaml_enable_all())
724+
fprintf(fp, "# %s: False\n", yaml_config);
725+
return;
726+
}
727+
728+
fprintf(fp, "%s: %s\n", yaml_config, yaml_config_value);
729+
730+
free(yaml_config);
731+
free(yaml_config_value);
732+
}
733+
734+
static void print_symbol_for_dotconfig(FILE *fp, FILE *yaml, struct symbol *sym)
628735
{
629736
__print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
737+
__print_yaml_symbol(yaml, sym, OUTPUT_N_AS_UNSET, true);
630738
}
631739

632740
static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
@@ -749,11 +857,24 @@ int conf_write_defconfig(const char *filename)
749857
struct symbol *sym;
750858
struct menu *menu;
751859
FILE *out;
860+
FILE *yaml_out = NULL;
861+
const char *yaml_config = NULL;
862+
863+
yaml_config = conf_get_yaml_config_name();
752864

753865
out = fopen(filename, "w");
754866
if (!out)
755867
return 1;
756868

869+
if (yaml_config) {
870+
yaml_out = fopen(yaml_config, "w");
871+
if (!yaml_out) {
872+
fclose(out);
873+
return 1;
874+
}
875+
fprintf(yaml_out, "---\n");
876+
}
877+
757878
sym_clear_all_valid();
758879

759880
menu_for_each_entry(menu) {
@@ -784,21 +905,25 @@ int conf_write_defconfig(const char *filename)
784905
if (sym == ds && sym_get_tristate_value(sym) == yes)
785906
continue;
786907
}
787-
print_symbol_for_dotconfig(out, sym);
908+
print_symbol_for_dotconfig(out, yaml_out, sym);
788909
}
789910
fclose(out);
911+
if (yaml_out)
912+
fclose(yaml_out);
790913
return 0;
791914
}
792915

793916
int conf_write(const char *name)
794917
{
795918
FILE *out;
919+
FILE *yaml_out = NULL;
796920
struct symbol *sym;
797921
struct menu *menu;
798922
const char *str;
799923
char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
800924
char *env;
801925
bool need_newline = false;
926+
const char *yaml_config;
802927

803928
if (!name)
804929
name = conf_get_configname();
@@ -816,18 +941,33 @@ int conf_write(const char *name)
816941
if (make_parent_dir(name))
817942
return -1;
818943

944+
yaml_config = conf_get_yaml_config_name();
945+
819946
env = getenv("KCONFIG_OVERWRITECONFIG");
820947
if (env && *env) {
821948
*tmpname = 0;
822949
out = fopen(name, "w");
950+
if (yaml_config)
951+
yaml_out = fopen(yaml_config, "w");
823952
} else {
824953
snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
825954
name, (int)getpid());
826955
out = fopen(tmpname, "w");
956+
if (yaml_config)
957+
yaml_out = fopen(yaml_config, "w");
827958
}
828959
if (!out)
829960
return 1;
830961

962+
if (yaml_config) {
963+
if (!yaml_out) {
964+
fclose(out);
965+
return 1;
966+
}
967+
fprintf(yaml_out, "---\n");
968+
}
969+
970+
831971
conf_write_heading(out, &comment_style_pound);
832972

833973
if (!conf_get_changed())
@@ -853,9 +993,11 @@ int conf_write(const char *name)
853993
if (need_newline) {
854994
fprintf(out, "\n");
855995
need_newline = false;
996+
if (yaml_config)
997+
fprintf(yaml_out, "\n");
856998
}
857999
sym->flags |= SYMBOL_WRITTEN;
858-
print_symbol_for_dotconfig(out, sym);
1000+
print_symbol_for_dotconfig(out, yaml_out, sym);
8591001
}
8601002

8611003
next:
@@ -880,6 +1022,8 @@ int conf_write(const char *name)
8801022
}
8811023
}
8821024
fclose(out);
1025+
if (yaml_out)
1026+
fclose(yaml_out);
8831027

8841028
for_all_symbols(sym)
8851029
sym->flags &= ~SYMBOL_WRITTEN;
@@ -899,6 +1043,8 @@ int conf_write(const char *name)
8991043
}
9001044

9011045
conf_message("configuration written to %s", name);
1046+
if (yaml_config)
1047+
conf_message("yaml configuration written to %s", yaml_config);
9021048

9031049
conf_set_changed(false);
9041050

expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ struct symbol {
132132
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
133133
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
134134
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
135+
#define SYMBOL_YAML 0x0400 /* write symbol to file (KCONFIG_YAMLCFG) */
135136
#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
136137
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
137138
#define SYMBOL_WARNED 0x8000 /* warning has been issued */

lexer.l

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,15 @@ n [A-Za-z0-9_-]
121121
"menuconfig" return T_MENUCONFIG;
122122
"modules" return T_MODULES;
123123
"on" return T_ON;
124+
"output" return T_OUTPUT;
124125
"prompt" return T_PROMPT;
125126
"range" return T_RANGE;
126127
"select" return T_SELECT;
127128
"source" return T_SOURCE;
128129
"string" return T_STRING;
129130
"tristate" return T_TRISTATE;
130131
"visible" return T_VISIBLE;
132+
"yaml" return T_YAML;
131133
"||" return T_OR;
132134
"&&" return T_AND;
133135
"=" return T_EQUAL;

parser.y

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct menu *current_menu, *current_entry, *current_choice;
7070
%token T_MODULES
7171
%token T_ON
7272
%token T_OPEN_PAREN
73+
%token T_OUTPUT
7374
%token T_PLUS_EQUAL
7475
%token T_PROMPT
7576
%token T_RANGE
@@ -78,6 +79,7 @@ struct menu *current_menu, *current_entry, *current_choice;
7879
%token T_STRING
7980
%token T_TRISTATE
8081
%token T_VISIBLE
82+
%token T_YAML
8183
%token T_EOL
8284
%token <string> T_ASSIGN_VAL
8385

@@ -235,6 +237,15 @@ config_option: T_MODULES T_EOL
235237
modules_sym = current_entry->sym;
236238
};
237239

240+
/* When we want to output symbols as part of an additional output formats */
241+
242+
config_option: T_OUTPUT T_YAML T_EOL
243+
{
244+
printd(DEBUG_PARSE, "%s will be part of the yaml output file %s:%d:\n",
245+
current_entry->sym->name, cur_filename, cur_lineno);
246+
current_entry->sym->flags |= SYMBOL_YAML;
247+
};
248+
238249
/* choice entry */
239250

240251
choice: T_CHOICE T_EOL

0 commit comments

Comments
 (0)