#!/usr/bin/perl

# Invoke as:
#
#  ./gen-grub-cfg KEY1 VAL1 KEY2 VAL2 ... -- COMMAND LINE
#
# Keys are:
#    KERNEL             Normal kernel to use (required)
#    INITRD             Normal initrd to use (required)
#    INITRD_GTK         Graphical installer initrd (optional)
#
#    KERNEL64           Alternative kernel for optional 64-bit entries
#    INITRD64           Alternative initrd for optional 64-bit entries
#    INITRD64_GTK       Alternative graphical initrd for optional 64-bit entries
#
#    THEME_PATH         Path (in boot env) where themes are kept
#    HEADER             Local path to file cat include as a header
#
# At least KERNEL and INITRD must be given.
#
# Unsupported:
#    DEBIAN_VERSION
#    BUILD_DATE
#
# TODO: Theme generation from template
#
# When invoked as:
#
#  ./gen-grub-cfg \
#    KERNEL "/%install%/vmlinuz" \
#    KERNEL64 "/%install-amd%/vmlinuz" \
#    INITRD "/%install%/initrd.gz" \
#    INITRD64 "/%install-amd%/initrd.gz" \
#    INITRD_GTK "/%install%/gtk/initrd.gz" \
#    INITRD64_GTK "/%install-amd%/gtk/initrd.gz" \
#    THEME_PATH "/boot/grub/theme/" \
#    HEADER "build/boot/x86/grub/grub-efi.cfg" \
#    -- vga=788
#
# Will reproduce something similar to
# debian-testing-amd64-netinst.iso::/boot/grub/grub.cfg weekly build
# circa 2014-09-27.

use warnings;
use strict;

my %VARS;

while (@ARGV) {
    my $key=shift;
    last if $key eq "--";

    my $value=shift;
    $VARS{$key}=$value;
}

my @OPTS = @ARGV;

die "No kernel?" unless $VARS{KERNEL};
die "No initrd?" unless $VARS{INITRD};

my $graphical = defined $VARS{INITRD_GTK};
my $sixtyfour = defined $VARS{KERNEL64} && defined $VARS{INITRD64}
    && (!$graphical || defined $VARS{INITRD64_GTK});
my $themed = defined $VARS{THEME_PATH};

my @menu_number = (1);

sub print_indented ($)
{
    my ($text) = @_;
    foreach ( split "\n", $text ) {
        my $i = 1;
        print "    " while ( $i++ < $#menu_number );
        print "$_";
        print "\n";
    }
}

sub menu_theme ()
{
    my $name = join "-", @menu_number;
}
sub print_set_theme ($)
{
    my ($theme) = @_;
    return unless $themed;

    print_indented("set theme=$VARS{THEME_PATH}$theme\n");
}

sub start_submenu ($)
{
    my ($title) = @_;

    print_indented("submenu '$title' {\n");

    my $theme = menu_theme();
    push @menu_number, 1;

    print_indented("set menu_color_normal=white/black\n");
    print_indented("set menu_color_highlight=black/light-gray\n");
    print_indented("if background_color 44,0,30,0; then\n");
    print_indented("    clear\n");
    print_indented("fi\n");

    print_set_theme($theme);
}
sub end_submenu ()
{
    pop @menu_number;
    $menu_number[$#menu_number]++;
    print_indented("}\n");
}

sub menuentry ($;%)
{
    my ($title,%xattr) = @_;

    $xattr{SixtyFour} ||= 0;
    $xattr{Graphical} ||= 0;

    $xattr{Expert} ||= 0;
    $xattr{Auto} ||= 0;
    $xattr{Rescue} ||= 0;
    $xattr{Speach} ||= 0;

    $xattr{Quiet} = !$xattr{Expert} unless defined $xattr{Quiet};

    return if $xattr{Graphical} && !$graphical;
    return if $xattr{SixtyFour} && !$sixtyfour;

    die "automated expert?" if $xattr{Expert} && $xattr{Auto};

    my $kernel = $xattr{SixtyFour} ? $VARS{KERNEL64} : $VARS{KERNEL};
    my $initrd = $xattr{Graphical} ? $VARS{INITRD_GTK} : $VARS{INITRD};
    $initrd = $xattr{Graphical} ? $VARS{INITRD64_GTK} : $VARS{INITRD64}
        if $xattr{SixtyFour};

    die "no kernel" unless $kernel;
    die "no initrd" unless $initrd;

    my @cmdline;
    # Ordering here is to allow diffing against previous versions of this file.
    push @cmdline, "desktop=$xattr{Desktop}" if $xattr{Desktop};
    push @cmdline, "priority=low" if $xattr{Expert};
    push @cmdline, ("auto=true", "priority=critical") if $xattr{Auto};
    push @cmdline, @OPTS;
    push @cmdline, "rescue/enable=true" if $xattr{Rescue};
    push @cmdline, "speakup.synth=soft" if $xattr{Speach};
    push @cmdline, "---";
    push @cmdline, "quiet" if $xattr{Quiet};

    my $cmdline = join(" ", @cmdline);

    print_indented (<<EOE);
menuentry '$title' {
    set background_color=black
    linux    $kernel $cmdline
    initrd   $initrd
}
EOE
}

if ( defined $VARS{HEADER} )
{
    open(HEADER, "<$VARS{HEADER}") or die "open header: $!";
    print <HEADER> or die "write header: $!";
    close(HEADER) or die "close header: $!";
}

print_set_theme(menu_theme());
push @menu_number, 1;

menuentry("Install");
menuentry("Graphical install", Graphical => 1);

start_submenu("Advanced options ..."); {
    menuentry("... Expert install", Expert => 1);
    menuentry("... Rescue mode", Rescue => 1);
    menuentry("... Automated install", Auto => 1);
    menuentry("... Graphical expert install", Graphical => 1, Expert => 1);
    menuentry("... Graphical rescue mode", Graphical => 1, Rescue => 1);
    menuentry("... Graphical automated install", Graphical => 1, Auto => 1);

    start_submenu("... Desktop environment menu ..."); {

        foreach ( ["GNOME", "gnome"], ["KDE", "kde"], ["LXDE", "lxde"] ) {
            my ($desktop,$opt) = @{$_};

            my $one = sub { my ($title, %xargs) = @_;
                            $xargs{Desktop} = $opt;
                            menuentry($title, %xargs);
            };
            start_submenu("... $desktop desktop boot menu ..."); {
                $one->("... Install");
                $one->("... Graphical install", Graphical => 1);

                start_submenu("... $desktop advanced options ..."); {
                    $one->("... Expert install", Expert => 1);
                    $one->("... Automated install", Auto => 1);
                    $one->("... Graphical expert install", Graphical => 1, Expert => 1);
                    $one->("... Graphical automated install", Graphical => 1, Auto => 1);
                } end_submenu(); # $desktop advanced

                $one->("... Install with speech synthesis", Speach => 1);
                $one->("... Install with speech synthesis", Graphical => 1, Speach => 1);
                $one->("... 64 bit speech install", SixtyFour => 1, Graphical => 1, Speach => 1)
                    if $sixtyfour;
            } end_submenu(); # $desktop submenu
        } # Desktop loop
    } end_submenu(); # Desktop submenu
} end_submenu(); # Advanced
menuentry('Install with speech synthesis', Graphical => $graphical, Speach => 1);
