#!/usr/bin/perl -w
# this turns a spec template file into a real spec file. it uses a bunch
# of environment variables to handle the various parts used by CCE.
#

# build templates for each section
sub xlate_line
{
    my ($line, $tag, $tag2) = @_;
    my $arch = $ENV{BUILDARCH} ? "BuildArchitectures: $ENV{BUILDARCH}" : '';
    my $provides = $ENV{PROVIDES} ? "Provides: $ENV{PROVIDES}" : '';
    my $license = $ENV{LICENSE} ? $ENV{LICENSE} : 'Sun modified BSD';

    my(@Time) = localtime(time);
    $Time[5] += 1900;
    $Time[4]++;

    $line =~ s/\[VENDOR\]/$ENV{VENDOR}/go;
    $line =~ s/\[VENDORNAME\]/$ENV{VENDORNAME}/go;
    $line =~ s/\[SERVICE\]/$ENV{SERVICE}/go;
    $line =~ s/\[VERSION\]/$ENV{VERSION}/go;
    $line =~ s/\[RELEASE\]/$ENV{RELEASE}/go;
    $line =~ s/\[ROOTDIR\]/$ENV{CCEBASE}/go;
    $line =~ s/\[CCEWEB\]/$ENV{CCEWEB}/go; 
    $line =~ s/\[DEFLOCALE\]/$ENV{DEFLOCALE}/go; 
    $line =~ s/\[LABEL\]/$tag/g;
    $line =~ s/\[AUTOFILL\]/$tag2/g;
    $line =~ s/\[BUILDARCH\]/$arch/go;
    $line =~ s/\[PROVIDES\]/$provides/go; 
    $line =~ s/\[LICENSE\]/$license/go;
    return $line;
}
        
sub print_type
{
    my ($fh, $section, $type, $tag1, $tag2, %hash) = @_;

    print $fh xlate_line($hash{$section}{HEADER}, $tag1) 
    if $hash{$section}{HEADER};
        
    if ($hash{$section}{$type}) {
    print $fh xlate_line($hash{$section}{$type}, $tag1, $tag2);
    } elsif (ref(\$hash{$section}) eq 'SCALAR') {
    print $fh xlate_line($hash{$section}, $tag1, $tag2);
    }
    
}

# get the file path for RPM spec file %file section
# param: dirDepth: the depth of the file/directory relative to Sausalito root
# param: files: an array of all the full file names relative to the Sausalito
#     root
sub get_file_path
{
    my ($dirDepth, @files) = @_;

    my @fullPaths = ();
    my $file;
    foreach $file (@files) {
    $file =~ /^(([^\/]+\/){$dirDepth})(.*)$/;
    push @fullPaths, '%{RootDir}/' . $1 . '%{Vendor}/%{Service}/' . $3 . "\n";
    }

    return @fullPaths;
}

sub print_section 
{
    my ($fh, $section, %hash) = @_;
    my $requires = 'Requires: ' . $ENV{REQUIRES};
    my $provides = 'Provides: ' . $ENV{PROVIDES};
    my $requires_glue;
    if ($ENV{REQUIRES_GLUE} ne '') {
        $requires_glue = 'Requires: ' . $ENV{REQUIRES_GLUE};
    }
    my $requires_ui;
    if ($ENV{REQUIRES_UI} ne '') {
        $requires_ui = 'Requires: ' . $ENV{REQUIRES_UI};
    }
    
    # capstone comes last
    my @types = ('GLUE', 'UI', 'LOCALE', 'CAPSTONE'); 
    my $type;

    # locales
    my @locales = split ' ', $ENV{LOCALES};
    my $locale;

    # ui stuff
    my @uibits = ();
    # be backward compatible
    if ($ENV{UIDIRS})
    {    
        @uibits = split ' ', $ENV{UIDIRS};
    }
    else # handle old style
    {
        push @uibits, split(' ', $ENV{UIMENUS});
        push @uibits, split(' ', $ENV{UISERVICES});
    }

    # capstone bits
    my @capbits = ('constructor', 'destructor');

    # glue bits
    my @gluebits = ('conf', 'schemas', 'handlers', 'am', 'rules');

    foreach $type (@types) 
    {
       	next if ($type eq 'CAPSTONE' and $ENV{NOCAPSTONES});

        if (($type eq 'CAPSTONE') or (($ENV{"BUILD$type"} eq 'yes') or ($ENV{"BUILDUI"} eq 'old') or ($ENV{"BUILDUI"} eq 'new')))
        {
            $type = lc $type;

            if ($section eq 'DESCRIPTION') 
            {

                my $seen_locale = "0";

                # special-case locale 
                if ($type eq 'locale') 
                {

                    foreach $locale (@locales) 
                    {

			if ($seen_locale eq "0") {
			    $provides = 'Provides: ' . $ENV{PROVIDES};
	        	    $provides .= "[VENDOR]-[SERVICE]-locale-$locale ";
	        	    $seen_locale++;
	        	}
	        	else {
	        	    $provides = "";
	        	}

                        print_type($fh, $section, $type, "$type-$locale", xlate_line($provides), %hash);

                        $requires .= "[VENDOR]-[SERVICE]-locale-$locale ";

                    }

                } 
                elsif ($type eq 'glue' && $requires_glue ne '')
                {
                    print_type($fh, $section, $type, $type, xlate_line($requires_glue) , %hash);
                    $requires .= "[VENDOR]-[SERVICE]-$type ";
                }
                elsif ($type eq 'ui' && $requires_ui ne '')
                {
                    print_type($fh, $section, $type, $type, xlate_line($requires_ui) , %hash);
                    $requires .= "[VENDOR]-[SERVICE]-$type ";
                }
                else 
                {
                    print_type($fh, $section, $type, $type, ($type eq 'capstone') ? xlate_line($requires) : '', %hash);
                    $requires .= "[VENDOR]-[SERVICE]-$type ";
                }

            } 
            elsif ($section eq 'CHANGELOG')
            {
                if ($type eq 'capstone')
                {
                    print_type($fh, $section, $type, $type, $line, %hash);
                }
            }
            elsif ($section eq 'TRIGGERIN')
            {
                if ($type eq 'capstone')
                {
                    print_type($fh, $section, $type, $type, $line, %hash);
                }
            }
            elsif ($section eq 'TRIGGERUN')
            {
                if ($type eq 'capstone')
                {
                    print_type($fh, $section, $type, $type, $line, %hash);
                }
            }
            elsif (($section eq 'FILES') and not ($type eq 'locale')) 
            {
                my $line;
                if ($type eq 'ui') 
                {
                    foreach my $uibit (@uibits) 
        		    {

                        print "PROCESSING UIBIT: $uibit \n";

                        my $uidir = "ui/$ENV{VENDORNAME}/$uibit";
                        my $uidirSegments = 3;
                        if (! -d $uidir) 
                        {
                            $uidir = "ui/$uibit";
                            $uidirSegments = 2;
                            # see if the sub directory is there at all
                            if (! -d $uidir) { next; }
                        }

                        # find all locale-sensitive files to exclude
                        my $exclude = '';
                        my $locale;
                        foreach $locale (@locales) 
                        {
                            $exclude .= " -and -not -path \"*\\.$locale\"";
                        }

                        my @files = ();

                        # FIXME: as with many things in this file there are 
                        # special cases.  The way things are setup needs to
                        # be rethought, so we can avoid the need for special
                        # cases all over the place.
                        if ($uibit eq 'lcd')
                        {
                            # special case 1
                            #call recursive subroutine to get all the files
                            if (($ENV{"BUILDUI"} eq 'old') || ($ENV{"BUILDUI"} eq 'yes')) {
                                $line .= join("\n", &generate_full_paths($uidir, $ENV{LCDDIR}, '.\/CVS\/*|.\/\.'));
                            }
                        }
                        elsif ($uibit eq 'extensions') # special case 2
                        {
                            if (($ENV{"BUILDUI"} eq 'old') || ($ENV{"BUILDUI"} eq 'yes')) {
                                opendir(EXTS, $uidir) 
                                or die { "Can't open $uidir: $!\n" };
                                while (my $file = readdir(EXTS))
                                {
                                    if (! -f "$uidir/$file") { next; }
                                    $file =~ /^([^\.]+\.[^\.]+)\.([^\.]+\.[^\.]+)$/;
                                    my ($install_file, $domain) = ($1, $2);
                                    if ($install_file && $domain)
                                    {
                                        $line .= '%{RootDir}' . "/ui/$uibit/$domain/$install_file\n";
                                    }
                                }
                                closedir(EXTS);
                            }
                        }

                        #
                        ## Start: Handle Chorizo UI (menu)
                        #
                        elsif ($uibit eq 'chorizo/menu') {

                            if (($ENV{"BUILDUI"} eq 'new') || ($ENV{"BUILDUI"} eq 'yes')) {
                                opendir(CHO, $uidir) or die { "CHORIZO menu: Can't open $uidir: $!\n" };
                                while (my $file = readdir(CHO)) {
                                    if (! -f "$uidir/$file") {
                                        print "CHORIZO menu: $uidir/$file is not a file! \n";
                                        next; 
                                    }
                                    print "CHORIZO menu: Processing uidir/file: $uidir / $file \n";
                                    $line .= '%{RootDir}' . "/ui/chorizo/menu/%{Vendor}/%{Service}/$file\n";
                                }
                                closedir(CHO);
                            }
                        }
                        #
                        ## End: Handle Chorizo UI (menu)
                        #

                        #
                        ## Start: Handle Chorizo UI (web)
                        #
                        elsif ($uibit eq 'chorizo/web') {
                            if (($ENV{"BUILDUI"} eq 'new') || ($ENV{"BUILDUI"} eq 'yes')) {
                                opendir(CHO, $uidir) or die { "CHORIZO web: Can't open $uidir: $!\n" };
                                while (my $file = readdir(CHO)) {
                                    if ($file eq '.') { next; }
                                    if ($file eq '..') { next; }
                                    if ($file eq '.svn') { next; }
                                    if (! -d "$uidir/$file") {
                                        print "CHORIZO web: $uidir/$file is not a directory! \n";
                                        next; 
                                    }
                                    print "CHORIZO web: Processing uidir/file: $uidir / $file \n";
                                    my $chosub = "$uidir/$file";
                                    opendir(CHOSUB, $chosub) or die { "CHORIZO web: Can't open $chosub: $!\n" };
                                    while (my $subfile = readdir(CHOSUB)) {
                                        if (! -f "$uidir/$file/$subfile") {
                                            print "CHORIZO menu: $uidir/$file/$subfile is not a file! \n";
                                            next; 
                                        }
                                        print "CHORIZO web: Processing subfile $subfile \n";
                                        $line .= '%{RootDir}' . '/ui/chorizo/ci4/Modules/' . ucfirst($ENV{VENDOR}) . '/' . ucfirst($ENV{SERVICE}) . "/$file/$subfile\n";
                                        print "CHORIZO web file-line: " . '%{RootDir}' . '/ui/chorizo/ci4/Modules/' . ucfirst($ENV{VENDOR}) . '/' . ucfirst($ENV{SERVICE}) . "/$file/$subfile\n";
                                    }
                                    closedir(CHOSUB);
                                }
                                closedir(CHO);
                            }
                        }

                        #
                        ## End: Handle Chorizo UI (web)
                        #

                        #
                        ## Start: Handle Chorizo UI (extensions)
                        #
                        elsif ($uibit eq 'chorizo/extensions') {

                            if (($ENV{"BUILDUI"} eq 'new') || ($ENV{"BUILDUI"} eq 'yes')) {
                                opendir(CHO, $uidir) or die { "CHORIZO extensions: Can't open $uidir: $!\n" };
                                while (my $file = readdir(CHO)) {
                                    if (! -f "$uidir/$file") { next; }
                                    $file =~ /^([^\.]+\.[^\.]+)\.([^\.]+\.[^\.]+)$/;
                                    my ($install_file, $domain) = ($1, $2);
                                    if ($install_file && $domain)
                                    {
                                        print "CHORIZO extensions: Processing uidir/file: $uidir / $file to destination: /ui/chorizo/ci4/extensions/$domain/$install_file \n";
                                        $line .= '%{RootDir}' . "/ui/chorizo/ci4/extensions/$domain/$install_file\n";
                                    }
                                }
                                closedir(CHO);
                            }
                        }

                        #
                        ## End: Handle Chorizo UI (extensions)
                        #

                        else # the default behaviour
                        {
                            if (($ENV{"BUILDUI"} eq 'old') || ($ENV{"BUILDUI"} eq 'yes')) {
                                # find all files to include
                                # exclude all hidden files (.whatever) since nfs 
                                # and cvs seem to like to drop these
                                @files = `find $uidir -type f -and -not -path "*/\\.*" $exclude | grep -v CVS`;

                                # RPM needs full path
                                $line .= join '', 
                                get_file_path($uidirSegments, @files);
                            }
                        } # end if $uibit eq 'something'
                    }
                } 
                elsif ($type eq 'capstone') 
                {
                    # we also special-case capstones
                    my $name;
                    foreach $name (@capbits) 
                    {
                        my $capdir = "$name/$ENV{VENDORNAME}";
                        $capdir = "$name" unless -d $capdir;
                        if (opendir(CAPDIR, $capdir)) 
                        {
                            while ($_ = readdir(CAPDIR)) 
                            {
                                next if /^\.{1,2}/;
                                next unless -f "${capdir}/$_";
                                $line .= '%{RootDir}/' . $name. 
                                    '/%{Vendor}/%{Service}' . "\n";
                                last;
                            }
                            close(CAPDIR);
                        }
                    }

                } 
                elsif ($type eq 'glue') 
                {
                    my $name;
                    foreach $name (@gluebits) 
                    {
                        my $gluedir = "glue/$ENV{VENDORNAME}/$name";
                        if (! -d $gluedir) 
                        {
                            $gluedir = "glue/$name";
                        }
            
                        if (opendir(GDIR, $gluedir))
                        {
                            my $flag = 0;
                            my $tgtname = $name;
                            if ($name eq "am") 
                            {
                                $tgtname = "swatch/conf";
                            }
                            while ($_ = readdir(GDIR)) 
                            {
                                next if /^\.{1,2}/;
                                next unless -f "${gluedir}/$_";
                                $line .= '%{RootDir}/' . $tgtname. '/%{Vendor}/%{Service}' . "\n";
                                $flag = 1;
                                print STDERR "$name:\n";
                                last;
                            }
                            $flag || print STDERR "WARNING: $gluedir was empty.\n";
                            close(GDIR);
                        } 
                        else 
                        {
                            print STDERR "Couldn't open glue/$name\n";
                        } 
                    }

                    # handle perl directory here too, hardcoded fix later
                    # if desirable
                    my $perldir = 'perl';
                    if (-d $perldir)
                    {
                        $line .= '%{RootDir}' . "/$perldir/" 
                            . ucfirst($ENV{VENDOR}) . "/*\n";
                    }

        		    # Another hard-coded section.  Handle the ccewrap xml 
        		    # files
        		    my $ccewrapdir = 'ccewrap';
        		    if (-d "glue/$ccewrapdir") 
        		    {
        		        $line .= '/etc/ccewrap.d/%{Vendor}/%{Service}' . "\n";
        		    }
                }

        		# now print out what we have
                print STDERR "$section $type =\n$line\n\n";
                print_type($fh, $section, $type, $type, $line, %hash);

            }
            elsif ($type eq 'locale') 
            {
	        # we always deal with locales differently 
                # figure out where locales are kept
                my $localedir = 'locale';
    
                if (-d 'locale/$ENV{VENDOR}') 
                {
                    $localedir = 'locale/$ENV{VENDOR}';
                }

                foreach $locale (@locales) 
                {
                    next if ($ENV{XLOCALEPAT} =~ /"$locale"/);
		    
                    my $line = "";

                    # add all .mo files in locale directory
                    opendir LOCALE, "$localedir/$locale/" 
                        or die "Can't open $localedir/$locale/: $!\n";
                    while (my $entry = readdir(LOCALE)) 
                    {
                        if ($entry =~ /^(.*)\.po$/) 
                        {
                            $line .= "/usr/share/locale/$locale/LC_MESSAGES/";
                            $line .= ($ENV{LOCALE_NO_VENDOR}) ? "${1}.mo\n" : "%{Vendor}-${1}.mo\n";
                        }
                        # this is to handle style XML files in gallery
                        elsif ($entry =~ /^(.*)\.xml$/i) 
                        {
                            $line .= "$ENV{CCEBASE}/ui/style/$1.xml.$locale\n";
                        }
                    }

                    close LOCALE;

                    # add .prop file if exist
                    if(-f "$localedir/$locale/$ENV{SERVICE}.prop") 
                    {
                        $line .= "/usr/share/locale/$locale/%{Vendor}-%{Service}.prop\n";
                    }

                    my $uidir = "ui/$ENV{VENDORNAME}/web";
                    my $uidirSegments = 3;
                    if (! -d $uidir) 
                    {
                        $uidir = "ui/web";
                        $uidirSegments = 2;
                    }

                    # find all locale-sensitive UI files to include
                    my @files = `find $uidir -type f -and -not -path "*/\\.*" -and -path "*\\.$locale" | grep -v CVS`;

                    # RPM needs full path
                    $line .= join '', get_file_path($uidirSegments, @files);

                    print_type($fh, $section, $type, "$type-$locale", $line, %hash);
                }
            } 
            else 
            {
                print_type($fh, $section, $type, $type, '', %hash);
            }
        }
    }
}



die "$0 <defines> <template> <spec file>\n" if $#ARGV lt 2;
my $defines = $ARGV[0];
my $template = $ARGV[1];
my $spec = $ARGV[2];

# check for important environment variables
die "you need to pass in the following environment variables:
  CCEBASE, VENDOR, VENDORNAME, SERVICE, VERSION, RELEASE,
  BUILDUI, UIDIRS, BUILDGLUE, LOCALES, and BUILDLOCALE\n" 
    unless ($ENV{CCEBASE} and $ENV{VENDOR} and 
        $ENV{SERVICE} and $ENV{VERSION} and 
        $ENV{RELEASE} and $ENV{BUILDUI} and 
        $ENV{BUILDGLUE} and $ENV{BUILDLOCALE}
        and ($ENV{UIDIRS} or $ENV{UIMENUS} or $ENV{UISERVICES}) and $ENV{VENDORNAME}
        and defined($ENV{LOCALES}));

open(DEFINES, $defines) or die "Can't open $defines!\n";
open(TMPL, $template) or die "Can't open $template!\n";
open(SPEC, ">$spec") or die "Can't open $spec for writing!\n";

my %hash;
my $tmp;
while (<DEFINES>) 
{
    if (/<begin \$(\S+)>/) 
    {
        $tmp = $1;
        while (<DEFINES>) 
        {
            last if $_ =~ /<end \$$tmp>/;
            $hash{$tmp} .= $_;
        }
    } 
    elsif (/<begin \%(\S+)>/) 
    {
        my $hashname; 
        $tmp = $1;
        while (<DEFINES>) 
        {
            if (/<end \%$tmp>/) 
            {
                last;
            } 
            elsif (/<begin (\S+)>/) 
            {
                $hashname = $1;        
            } 
            elsif (/<end $hashname>/) 
            {
                $hashname = undef;
            } 
            elsif ($hashname) 
            {
                $hash{$tmp}{$hashname} .= $_;
            }
        }
    }
}
close(DEFINES);

while (<TMPL>) 
{
    if (/^\[(\S+)_SECTION\]/) 
    {
        print_section(\*SPEC, $1, %hash);
    } 
    else 
    {
        $_ = xlate_line($_);
        print SPEC;
    }
}

# recursive subroutine that generates a file list to add to a spec file
# arguments:
#       directory name - the directory the complete structure is under
#       install prefix - the directory prefix to prepend to files found
#       ignore regex - patterns that when found should be ignored as a string
#                      (ie 'CVS|.\/\.') to exclude CVS and dot files
#
# returns:
#       if directories or files are found returns the list as an array
#       with the install prefix prepended or the empty array.  

sub generate_full_paths
{
    my ($search_dir, $prefix, $regex) = @_;

    my @files = ();
    my @dirs = ();

    if (opendir(SEARCH, $search_dir))
    {
        my $error = 0;
        while (my $file = readdir(SEARCH))
        {
	  # skip stuff that should be skipped
            next if ("$search_dir/$file" =~ /$regex/);
           
            # avoid infinite recursion by skipping . and .. entries
            next if ($file =~ /^\.{1,2}$/);

            if (-f "$search_dir/$file")
            { # found a regular file, add it to the list
                push @files, "$prefix/$file";
	      }
            elsif (-d "$search_dir/$file")
            { #found a directory, push into @dirs so we can recurse later
	      push @dirs, $file;
	    } 
        }
	close(SEARCH);
    }
    else
    {
        warn("opendir failed: $!");
    }
    
    # recurse into each subdirectory.
    foreach my $dir (@dirs) {
      push @files, &generate_full_paths("$search_dir/$dir",
					"$prefix/$dir", $regex);
    }

    return @files;
}

# 
# Copyright (c) 2014-2022 Michael Stauber, SOLARSPEED.NET
# Copyright (c) 2014-2022 Team BlueOnyx, BLUEONYX.IT
# Copyright (c) 2003 Sun Microsystems, Inc. 
# All Rights Reserved.
# 
# 1. Redistributions of source code must retain the above copyright 
#     notice, this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright 
#     notice, this list of conditions and the following disclaimer in 
#     the documentation and/or other materials provided with the 
#     distribution.
# 
# 3. Neither the name of the copyright holder nor the names of its 
#     contributors may be used to endorse or promote products derived 
#     from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
# 
# You acknowledge that this software is not designed or intended for 
# use in the design, construction, operation or maintenance of any 
# nuclear facility.
# 