diff mbox series

[RFC/PoC] scripts: {package-}metadata: use 'SUBMENU' as subcategory path

Message ID 20240229101958.76011-1-pepe2k@gmail.com
State RFC
Delegated to: Piotr Dymacz
Headers show
Series [RFC/PoC] scripts: {package-}metadata: use 'SUBMENU' as subcategory path | expand

Commit Message

Piotr Dymacz Feb. 29, 2024, 10:19 a.m. UTC
Motivation for this change is to allow for a more nested menu structure
when manually configuring build system with 'make {menu,n,x}config'.

The current solution provides only 2 levels of nesting (without using
external/custom config/Config.in):
  - top level menu/category (Makefile variable 'CATEGORY')
  - 2nd level sub menu/category (Makefile variable 'SUBMENU')

To allow placing packages in a more nested menu structure, the 'SUBMENU'
variable is treated as a menu path with '\' character as separator*.

Defining 'SUBMENU' as 'Foo\Bar\Qux' for package 'Bob' and 'Foo\Bar' for
package 'Ben' with this change would create menu structure as follows:

  top level menu 'CATEGORY'  --->
  ..menu 'Foo'  --->
  ....menu 'Bar'  --->
  ......menu 'Qux'  --->
  ........[] package 'Bob'
  ......[] package 'Ben'

Currently existing menus and packages sorting methods were preserved
(menu first, packages below, alphabetical order) and the only difference
applies to the usage of 'SUBMENUDEP' Makefile variable which will affect
only last path element (the one package is placed under).

* The backslash instead of a more natural slash '/' was selected due to
  the fact that some of already existing core and community packages use
  slash in 'SUBMENU' variables. As this is more a RFC/PoC, final change
  might use different character or approach for defining menu path.

Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
---
 scripts/metadata.pm         |  6 ++-
 scripts/package-metadata.pl | 96 ++++++++++++++++++++++++-------------
 2 files changed, 68 insertions(+), 34 deletions(-)
diff mbox series

Patch

diff --git a/scripts/metadata.pm b/scripts/metadata.pm
index ecfe42c0bc..21e1a4b250 100644
--- a/scripts/metadata.pm
+++ b/scripts/metadata.pm
@@ -283,7 +283,11 @@  sub parse_package_metadata($) {
 			defined $category{$1}{$src->{name}} or $category{$1}{$src->{name}} = [];
 			push @{$category{$1}{$src->{name}}}, $pkg;
 		};
-		/^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t ");
+		/^Description: \s*(.*)\s*$/ and do {
+			my $tabs = 2;
+			$pkg->{submenu} and $tabs += scalar(split(/\\/, $pkg->{submenu}));
+			$pkg->{description} = ("\t" x $tabs)." $1\n".get_multiline(*FILE, ("\t" x $tabs)." ");
+		};
 		/^Type: \s*(.+)\s*$/ and do {
 			$pkg->{type} = [ split /\s+/, $1 ];
 			undef $pkg->{tristate};
diff --git a/scripts/package-metadata.pl b/scripts/package-metadata.pl
index 9e0e6dd9e5..fa6b007f38 100755
--- a/scripts/package-metadata.pl
+++ b/scripts/package-metadata.pl
@@ -143,6 +143,7 @@  sub package_depends($$) {
 }
 
 sub mconf_depends {
+	my $tabs = shift;
 	my $pkgname = shift;
 	my $depends = shift;
 	my $only_dep = shift;
@@ -233,24 +234,25 @@  sub mconf_depends {
 	}
 
 	foreach my $tdep (@t_depends) {
-		mconf_depends($pkgname, $tdep->[0], 1, $dep, $seen, $tdep->[1]);
+		mconf_depends($tabs, $pkgname, $tdep->[0], 1, $dep, $seen, $tdep->[1]);
 	}
 
 	foreach my $depend (sort keys %$dep) {
 		my $m = $dep->{$depend};
-		$res .= "\t\t$m $depend\n";
+		$res .= ("\t" x $tabs)."$m $depend\n";
 	}
 	return $res;
 }
 
 sub mconf_conflicts {
+	my $tabs = shift;
 	my $pkgname = shift;
 	my $depends = shift;
 	my $res = "";
 
 	foreach my $depend (@$depends) {
 		next unless $package{$depend};
-		$res .= "\t\tdepends on m || (PACKAGE_$depend != y)\n";
+		$res .= ("\t" x $tabs)."depends on m || (PACKAGE_$depend != y)\n";
 	}
 	return $res;
 }
@@ -265,34 +267,69 @@  sub print_package_config_category($) {
 	print "menu \"$cat\"\n\n";
 	my %spkg = %{$category{$cat}};
 
+	$menus{$cat} = {};
+
 	foreach my $spkg (sort {uc($a) cmp uc($b)} keys %spkg) {
 		foreach my $pkg (@{$spkg{$spkg}}) {
 			next if $pkg->{buildonly};
-			my $menu = $pkg->{submenu};
-			if ($menu) {
-				$menu_dep{$menu} or $menu_dep{$menu} = $pkg->{submenudep};
+			my $menu = $menus{$cat};
+			if ($pkg->{submenu}) {
+				my @submenus = split(/\\/, $pkg->{submenu});
+				foreach (@submenus) {
+					next unless length($_);
+					if (!$menu->{$_}) {
+						$menu->{$_} = {};
+					}
+
+					$menu = $menu->{$_};
+
+					if ($_ eq $submenus[-1]) {
+						$pkg->{submenudep} and $menu->{'_deps'} = $pkg->{submenudep};
+						push(@{$menu->{'_pkgs'}}, $pkg);
+					}
+				}
 			} else {
-				$menu = 'undef';
+				push(@{$menu->{'_pkgs'}}, $pkg);
 			}
-			$menus{$menu} or $menus{$menu} = [];
-			push @{$menus{$menu}}, $pkg;
 		}
 	}
+
+	print_package_config_subcategory($menus{$cat}, 0);
+	print "endmenu\n\n";
+
+	undef $category{$cat};
+}
+
+sub print_package_config_subcategory($$) {
+	my $subcategory = shift;
+	my $tabs = shift;
+
 	my @menus = sort {
-		($a eq 'undef' ?  1 : 0) or
-		($b eq 'undef' ? -1 : 0) or
+		($a eq '_pkgs' ?  1 : 0) or
+		($b eq '_pkgs' ? -1 : 0) or
 		($a cmp $b)
-	} keys %menus;
+	} keys %{$subcategory};
+
+	$tabs++;
+	foreach (@menus) {
+		next if $_ eq '_deps';
+
+		if ($_ ne '_pkgs') {
+			$subcategory->{$_}->{'_deps'} and print "\t" x $tabs, "if $subcategory->{$_}->{'_deps'}\n";
+			print "\t" x $tabs, "menu \"$_\"\n\n";
+			print_package_config_subcategory($subcategory->{$_}, $tabs);
+			print "\t" x $tabs, "endmenu\n";
+			$subcategory->{$_}->{'_deps'} and print "\t" x $tabs, "endif\n";
+			print "\n";
+
+			next;
+		}
 
-	foreach my $menu (@menus) {
 		my @pkgs = sort {
 			package_depends($a, $b) or
 			($a->{name} cmp $b->{name})
-		} @{$menus{$menu}};
-		if ($menu ne 'undef') {
-			$menu_dep{$menu} and print "if $menu_dep{$menu}\n";
-			print "menu \"$menu\"\n";
-		}
+		} @{$subcategory->{$_}};
+
 		foreach my $pkg (@pkgs) {
 			next if $pkg->{src}{ignore};
 			my $title = $pkg->{name};
@@ -301,12 +338,12 @@  sub print_package_config_category($) {
 				$title .= ("." x $c). " ". $pkg->{title};
 			}
 			$title = "\"$title\"";
-			print "\t";
+			print "\t" x $tabs;
 			$pkg->{menu} and print "menu";
 			print "config PACKAGE_".$pkg->{name}."\n";
 			$pkg->{hidden} and $title = "";
-			print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
-			print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
+			print "\t" x ($tabs + 1), ($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
+			print "\t" x ($tabs + 1), "default y if DEFAULT_".$pkg->{name}."\n";
 			unless ($pkg->{hidden}) {
 				my @def = ("ALL");
 				if (!exists($pkg->{repository})) {
@@ -319,26 +356,19 @@  sub print_package_config_category($) {
 			}
 			if ($pkg->{default}) {
 				foreach my $default (split /\s*,\s*/, $pkg->{default}) {
-					print "\t\tdefault $default\n";
+					print "\t" x ($tabs + 1), "default $default\n";
 				}
 			}
-			print mconf_depends($pkg->{name}, $pkg->{depends}, 0);
-			print mconf_depends($pkg->{name}, $pkg->{mdepends}, 0);
-			print mconf_conflicts($pkg->{name}, $pkg->{conflicts});
-			print "\t\thelp\n";
+			print mconf_depends($tabs + 1, $pkg->{name}, $pkg->{depends}, 0);
+			print mconf_depends($tabs + 1, $pkg->{name}, $pkg->{mdepends}, 0);
+			print mconf_conflicts($tabs + 1, $pkg->{name}, $pkg->{conflicts});
+			print "\t" x ($tabs + 1), "help\n";
 			print $pkg->{description};
 			print "\n";
 
 			$pkg->{config} and print $pkg->{config}."\n";
 		}
-		if ($menu ne 'undef') {
-			print "endmenu\n";
-			$menu_dep{$menu} and print "endif\n";
-		}
 	}
-	print "endmenu\n\n";
-
-	undef $category{$cat};
 }
 
 sub print_package_overrides() {