#!/usr/bin/perl
#
# $Id$
#
# PBA rpm archiver main program
#
# (C) ITEG IT-Engineers GmbH 2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

use strict;

#use Date::Format;

require "/usr/lib/pba/archive-functions.pl";
require "/usr/lib/pba/rpmarchive-functions.pl";
require "/usr/lib/pba/pba-functions.pl";

$main::scriptName = "pba-archiver";

prepareGetopts();

initPBAFunctions();

initRPMArchiveFunctions();

parseConfig();

checkRPMArchiverConfig();


if ($main::targetArchitecture eq "amd64") {
  $main::targetArchitecture = "x86_64";
}
if ($main::targetArchitecture eq "") {
  $main::targetArchitecture = "x86_64";
}


# start working

# search new binary package || exit 

if ($main::archiveOperation eq "list-archives") {
  # list archives
  ($main::verbosity > 0) && print "PBA-rpmarchiver running in list mode.\n";

  my $repositoryRoot = $main::repositoryRoots{$main::targetRpmRepository};
  my %foundArchives = ();
  my %archiveWarnings = ();
  my %foundOthers = ();
  chdir $repositoryRoot || cleanupAndDie("FATAL: Cannot chdir to ".$repositoryRoot."\n");
  my $findCmd = "find . -mindepth 3 -maxdepth 3 -type d -name ".$main::targetArchitecture;
  #if ($main::verbosity > 2) { print "In ".pwd().", find . -mindepth 3 -maxdepth 3 -type d -name x86_64\n"; }
  open (FINDOUTPUT, $findCmd."|") || cleanupAndDie("FATAL: Cannot search. Find command was:\n".$findCmd."\npwd was: ".pwd()."\n");
  while ( my $distsDir = <FINDOUTPUT> ) {
    chomp $distsDir;
    #if ($main::verbosity > 2) { print "Investigating ".$distsDir."\n"; }
    chdir $repositoryRoot."/".$distsDir || cleanupAndDie("FATAL: Cannot chdir to ".$distsDir."\n");
    my ($dot, $dcgCategoryGeneration, $dcgDistribution, $rest) = split /\//, $distsDir;
    if ($dcgCategoryGeneration =~ /[a-z0-9_]+-[a-z0-9_]/) {
      my ($dcgCategory, $dcgGeneration) = split /-/, $dcgCategoryGeneration, 2;
      $foundArchives{$dcgDistribution."-".$dcgCategory."-".$dcgGeneration} = $dcgDistribution."-".$dcgCategory."-".$dcgGeneration;
      my $warnings = "";
      if (not(defined $main::distributionLongNames{$dcgDistribution})) {
        $warnings .= "Distribution unknown: '".$dcgDistribution."'. ";
      }
      $archiveWarnings{$dcgDistribution."-".$dcgCategory."-".$dcgGeneration} = $warnings;
    } else {
      $foundOthers{$dcgDistribution."-".$dcgCategoryGeneration} = $dcgDistribution."-".$dcgCategoryGeneration;
    }
  }
  close FINDOUTPUT;

  ($main::verbosity > 0) && print "Found these distribution-category-generation archives:\n";
  foreach my $dcg (sort(keys(%foundArchives))) {
    if ( ($archiveWarnings{$dcg} eq "") or ($main::verbosity < 1) ) {
      print $dcg."\n";
    } else {
      print $dcg."\tWARNINGS: ".$archiveWarnings{$dcg}."\n";
    }
  }
  if ( ($main::verbosity > 0) and (scalar(keys(%foundOthers)) > 0) ) {
    print "Found these other possible distributions:\n";
    foreach my $otherSubdir (sort(keys(%foundOthers))) {
      print "'".$otherSubdir."'\n";
    }
  }

  exit 0;
}


if ($main::archiveOperation eq "refresh-archive") {
  # only rerelease single archive
  ($main::verbosity > 0) && print "PBA-rpmarchiver running in forced refresh mode.\n";
  refreshRPMArchive($main::targetDCGArchive);

  ($main::verbosity > 0) && print "PBA-rpmarchiver successfully refreshed archive ".$main::targetDCGArchive."\n";
  exit 0;
}


if ($main::archiveOperation eq "auto-import") {

  # check running builds || exit

  if (! -d "/var/run/pba-archiver") {
    ($main::verbosity > 0) && print "Auto-creating /var/run/pba-archiver\n";
    mkdir "/var/run/pba-archiver" || cleanupAndDie("FATAL: Cannot auto-create /var/run/pba-archiver\n");
  }
  chdir "/var/run/pba-archiver" || cleanupAndDie("FATAL: Cannot chdir to /var/run/pba-archiver\n");

  my @brotherPIDFiles = glob("*.pid");
  if (scalar(@brotherPIDFiles) > 0) {
    ($main::verbosity > 0) && print "PBA-rpmarchiver refuses to disturb its ".scalar(@brotherPIDFiles)." already running brothers.\n";
    if ($main::verbosity > 1) {
      print "Those brothers have these PIDs:";
      foreach my $brotherPIDFile (@brotherPIDFiles) {
        my ($brotherPID, $ext) = split /\./, $brotherPIDFile, 2;
        print " ".$brotherPID;
      }
      print "\n";
    }
    exit 0;
  }
  
  my $pidFile = "/var/run/pba-archiver/".$$.".pid";
  printToFile( $pidFile, $$ );
  push @main::filesToCleanup, $pidFile;

  # begin normal scan-import-refresh run
  ($main::verbosity > 0) && print "PBA-rpmarchiver running in auto-import (and refresh) mode.\n";

  scanForIncomingTargzFiles();

  if (scalar(@main::packageFilesToImport) == 0) {
    ($main::verbosity > 0) && print "PBA-rpmarchiver OK: No new package files to import.\n";
    if  (-f $pidFile) { unlink $pidFile || cleanupAndDie("FATAL: Cannot /bin/rm ".$pidFile."\n"); }
    exit 0;
  }

  ($main::verbosity > 1) && print "Found ".scalar(@main::packageFilesToImport)." new package file(s) to import.\n";

  # loop targz files
  my $workDir = "/var/spool/pba-archiver/work/".$$;
  push @main::dirsToCleanup, $workDir;
  mkdir $workDir || cleanupAndDie("FATAL: Cannot mkdir ".$workDir."\n");
  chdir $workDir || cleanupAndDie("FATAL: Cannot chdir ".$workDir."\n");
  my %touchedDCGArchivesByDCG = ();

  # future: parse repodata.conf for repository list

  for my $packageFile (@main::packageFilesToImport) {
    # untar
    if ($main::verbosity > 2) { print "Un-taring ".$packageFile." in ".pwd()."\n"; }
    my $untarCmd = "tar -xzf ".$packageFile;
    executeOrDie($untarCmd);
    #if ($main::verbosity > 2) { print "Done un-taring ".$packageFile." in ".pwd()."\n"; }

    # read repodata.conf, check repository list
    if (!open (REPODATA, "<repodata.conf")) {
      print "WARNING: Skipping ".$packageFile." because it does not contain a repodata.conf file\n";
      next;
    }
    my $packageAllowsRepository = 0;
    while ( my $curLine = <REPODATA> ) {
      chomp $curLine;
      next if ($curLine eq "");
      next if ($curLine =~ m/^\s*[#;]/);
      my ( $pn, $pv ) = split / *= */, $curLine, 2;
      if ($pn eq "repositories") { 
        foreach my $packageRepository (split /,? +/, $pv) {
          #if ($main::verbosity > 2) { print "package repository: ".$packageRepository."\n"; }
          if ($main::targetRpmRepository eq $packageRepository) 
          { $packageAllowsRepository += 1; }
        }
      }
    }
    close REPODATA;
    if ($packageAllowsRepository == 0) {
      print "WARNING: Skipping ".$packageFile." because it does allow my target repository ".$main::targetRpmRepository."\n";
      next;
    }
 
    # find rpm files 
    my @rpmFilesToImport = ();
    my $findCmd = "find ".$workDir." -mindepth 4 -maxdepth 4 -type f -name '*.rpm'";
    #if ($main::verbosity > 2) { print $findCmd."\n"; }
    open (FINDOUTPUT, $findCmd."|") || cleanupAndDie("FATAL: Cannot search. Find command was:\n".$findCmd."\npwd was: ".pwd()."\n");
    while ( my $rpmFile = <FINDOUTPUT> ) {
      chomp $rpmFile;
      push @rpmFilesToImport, $rpmFile; 
    } 

    # work rpm files
    foreach my $rpmFile (@rpmFilesToImport) {
      #($main::verbosity > 2) && print "Working rpm file ".$rpmFile."\n";

      # check srpm signature
      if (checkRpmSignature($rpmFile)) {
        ($main::verbosity > 2) && print "GOOD: Signature checked OK: ".$rpmFile."\n";
      } else {
        #($main::verbosity > 2) && print "SKIPPING ".$rpmFile." because signature check failed\n";
        #next;
        ($main::verbosity > 1) && print "WARNING: Signature check failed on ".$rpmFile."\n";
      }

      my $rpmDCG = importRpmFile($rpmFile);
      $touchedDCGArchivesByDCG{$rpmDCG} = $rpmDCG;
    }

    chdir "/var/run/pba-archiver/" || cleanupAndDie("FATAL: Cannot chdir /var/run/pba-archiver/\n");
    system "/bin/rm -rf ".$workDir;
    mkdir $workDir || cleanupAndDie("FATAL: Cannot re-mkdir ".$workDir."\n");
    chdir $workDir || cleanupAndDie("FATAL: Cannot chdir ".$workDir."\n");

    execute("/bin/rm -fv ".$packageFile);  
  } 

  foreach my $touchedDCGArchive (sort(keys(%touchedDCGArchivesByDCG))) {
    #print "Beta: Not calling refreshRPMArchive(".$touchedDCGArchive.")\n";
    refreshRPMArchive( $touchedDCGArchive );
  }

  ($main::verbosity > 0) && print "PBA-rpmarchiver successfully imported ".scalar(@main::packageFilesToImport)." new packages.\n";
  if  (-f $pidFile) { unlink $pidFile || cleanupAndDie("FATAL: Cannot /bin/rm ".$pidFile."\n"); }

  cleanup();
  exit 0;
}

cleanupAndDie("ERROR: pba-rpmarchiver called without a valid command\n");
exit 1;


