#!/usr/bin/perl
#
# $Id$
#
# PBA builder 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;

require "/usr/lib/pba/pba-functions.pl";
require "/usr/lib/pba/build-functions.pl";
require "/usr/lib/pba/rpmbuild-functions.pl";

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

prepareGetopts();

initPBAFunctions();

initBuildFunctions();

initRpmBuildFunctions();

parseConfig();

checkBuildConfig();

checkRpmBuildConfig();


if ($main::buildOperation =~ /^(enter|login)-pbabuilder$/) {

  ($main::verbosity > 0) && print "PBA-rpmbuilder running in ".$main::buildOperation." mode.\n";
  dieIfNotRoot();

  my $rpmBuilderLog = $main::logDir."/login-pbabuilder_".$main::targetDistribution."-".$main::targetArchitecture."-pba-base.log";
  if ($main::buildOperation =~ /^enter-pbabuilder$/) {
    $rpmBuilderLog = $main::logDir."/enter-pbabuilder_".$main::targetDistribution."-".$main::targetArchitecture."-pba-base.log";
  }

  extractRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);

  my $chrootDir = $main::cacheDir."/".$$."/".$main::targetDistribution;
  executeOrDie("/bin/cp -av /etc/resolv.conf ".$chrootDir."/etc/");

  executeInRpmBuilder( "-", $main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture );
  my $tarball = $main::libDir."/".$main::targetDistribution.".tar.gz";
  ($main::verbosity > 0) && print "PBA-rpmbuilder has exited from ".$tarball."\n";

  if ($main::buildOperation =~ /^enter-pbabuilder$/) {
    retarRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);
  }

  cleanup();
  exit 0;
}


if ($main::buildOperation eq "create-pbabuilder") {
  ($main::verbosity > 0) && print "PBA-rpmbuilder running in create-pbabuilder mode.\n";

  # evtl. check /etc/pki/rpm-gpg
  # but centos-release-*.rpm below contains them anyway

  my $targetDir = $main::cacheDir."/".$main::targetDistribution;
 
  if ( -d $targetDir ) {
    cleanupAndDie("Target directory already exists: ".$targetDir);
  }
  my $tarball = $main::libDir."/".$main::targetDistribution.".tar.gz";
  if ( -f $tarball ) {
    cleanupAndDie("Tarball already exists: ".$tarball);
  }

  my $release = $main::distributionBootstrapHints{$main::targetDistribution};
  if ( length($release) == 0 ) {
    cleanupAndDie("\$release empty, please specifiy CentOS/RHEL release as BootstrapHint in /etc/distributions.d/".$main::targetDistribution);
  }
  my $basearch="x86_64";

  my $rpmBuilderLog = $main::logDir."/create-pbabuilder_".$main::targetDistribution."-".$main::targetArchitecture."-pba-base.log";

  executeOrDie("/bin/mkdir -pv ".$targetDir."/etc/yum.repos.d");
  my $tempRepoFile = $targetDir."/etc/yum.repos.d/".$main::targetDistribution."-bootstrap.repo";

  my $tempRepoText = "";
  $tempRepoText .= "[base]\n";
  $tempRepoText .= "name=CentOS-".$release." - Base\n";
  if ( $release le 7 ) {
    #$tempRepoText .= "mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=os\n";
    $tempRepoText .= "baseurl=".$main::distributionMirrors{$main::targetDistribution}."/".$release."/os/".$basearch."/\n";
  } else {
    $tempRepoText .= "baseurl=".$main::distributionMirrors{$main::targetDistribution}."/".$release."/BaseOS/".$basearch."/os/\n";
  }
  $tempRepoText .= "\n";
  if ( $release le 7 ) {
    $tempRepoText .= "[updates]\n";
    $tempRepoText .= "name=CentOS-$release - Updates\n";
    #$tempRepoText .= "mirrorlist=http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=updates\n";
    $tempRepoText .= "baseurl=".$main::distributionMirrors{$main::targetDistribution}."/".$release."/updates/".$basearch."/\n";
    $tempRepoText .= "\n";
  }
  printToFile($tempRepoFile, $tempRepoText);

  my $initialPackages = "yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils net-tools yum-utils rpm-build tar deltarpm epel-release";
  if ( $release ge 8 ) {
    # no deltarpm, add hostname
    $initialPackages = "yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils net-tools yum-utils rpm-build tar epel-release hostname";
  }

  executeOrDie("mkdir -p ".$targetDir."/dev");
  executeOrDie("mknod -m 666 ".$targetDir."/dev/null c 1 3");
  executeOrDie("mknod -m 666 ".$targetDir."/dev/urandom c 1 9");

  my $yumCommand = "yum --installroot=".$targetDir;
  if ($main::configParams{"HttpProxy"} ne "") {
    $yumCommand .= " --setopt=proxy=".$main::configParams{"HttpProxy"};
  }
  $yumCommand .= " install -y --nogpgcheck ".$initialPackages;
  ($main::verbosity > 0) && print "Executing this yum command:\n".$yumCommand."\n";
  executeOrDie($yumCommand);

  #if (length($main::proxy) > 0) {
  #  printToFile( $targetDir."/etc/yum.conf", "proxy=".$main::proxy);
  #}

  # will be overwritten by actually overwritten in case of actual build actions anyway
  executeOrDie("/bin/cp -av /etc/resolv.conf ".$targetDir."/etc/");

  if ( -f $targetDir."/root/.rpmdb/Name" ) {
    ($main::verbosity > 0) && print "Detected ".$targetDir."/root/.rpmdb/Name, repairing this.\n";
    executeOrDie("/bin/rm -v ".$targetDir."/root/.rpmdb/Name");
    executeOrDie("/bin/mv -v ".$targetDir."/root/.rpmdb/[A-Z]* ".$targetDir."/var/lib/rpm/");
    executeOrDie("/bin/rm -rfv ".$targetDir."/root/.rpmdb");

    my $chrootCommand = "/usr/sbin/chroot ".$targetDir." rpm --rebuilddb";
    ($main::verbosity > 0) && print "Executing this chroot command:\n".$chrootCommand."\n";
    executeOrDie($chrootCommand);
  }

  my $chrootCommand = "/usr/sbin/chroot ".$targetDir." rpm -q yum";
  ($main::verbosity > 0) && print "Executing this chroot command:\n".$chrootCommand."\n";
  executeOrDie($chrootCommand);

  my $timezone = readCompleteFile("/etc/timezone");
  if (length($timezone) > 0) {
    if ( -f $targetDir."/etc/localtime" ) {
      unlink $targetDir."/etc/localtime" || cleanupAndDie("FATAL: Cannot /bin/rm ".$targetDir."/etc/localtime\n");
    }
    if ( -d $targetDir."/usr/share/zoneinfo/".$timezone ) {
      executeOrDie("/bin/ln -sfv /usr/share/zoneinfo/".$timezone." ".$targetDir."/etc/localtime");
    }
  }
 
  executeOrDie("/bin/rm -rf ".$targetDir."/var/cache/yum/*");
  executeOrDie("/bin/rm -v ".$tempRepoFile);
  my $mirror = $main::distributionMirrors{$main::targetDistribution};
  $mirror =~ s/\//\\\//g;
  my $sedCommand = "/bin/sed -i -e 's/^mirrorlist/#mirrorlist/g' -e '".'s/^#baseurl=http:\/\/[a-z\.]\+\/centos\//baseurl='.$mirror."/g' ".$targetDir."/etc/yum.repos.d/CentOS-Base.repo";
  if ( $release ge 8 ) {
    $sedCommand =  "/bin/sed -i -e 's/^mirrorlist/#mirrorlist/g' -e '".'s/^#baseurl=http:\/\/[a-z\.]\+\/\$contentdir\//baseurl='.$mirror."/g' ".$targetDir."/etc/yum.repos.d/CentOS-*Base*.repo";
  }
  ($main::verbosity > 0) && print "Executing this sed command:\n".$sedCommand."\n";
  executeOrDie($sedCommand);

  # import /etc/pki/rpm-gpg/RPM-GPG-KEY-*
  chdir $targetDir."/etc/pki/rpm-gpg" || cleanupAndDie("Cannot chdir to ".$targetDir."/etc/pki/rpm-gpg");
  $chrootCommand = "/usr/sbin/chroot ".$targetDir." rpm --import";
  my @keyFiles = glob("RPM-*");
  foreach my $keyFile (@keyFiles) {
    $chrootCommand .= " /etc/pki/rpm-gpg/".$keyFile;
  }
  ($main::verbosity > 0) && print "Executing this chroot command:\n".$chrootCommand."\n";
  executeOrDie($chrootCommand);
 
  chdir $main::cacheDir || cleanupAndDie("Cannot chdir to ".$main::cacheDir);

  #$tarball = $main::libDir."/".$main::targetDistribution.".tar.gz";
  my $tarCommand = "tar -czSf ".$tarball." ".$main::targetDistribution;
  ($main::verbosity > 0) && print "Executing this tar command while in ".$main::cacheDir.":\n".$tarCommand."\n";
  executeOrDie($tarCommand);

  my $rmCommand = "rm -rf ".$main::targetDistribution;
  ($main::verbosity > 0) && print "Executing this rm command while in ".$main::cacheDir.":\n".$rmCommand."\n";
  executeOrDie($rmCommand);

  ($main::verbosity > 0) && print "PBA-RPMBuilder has successfully created ".$main::libDir."/".$tarball."\nSee ".$rpmBuilderLog."\n";

  cleanup();
  exit 0;
}


if ($main::buildOperation eq "update-pbabuilder") {

  ($main::verbosity > 0) && print "PBA-rpmbuilder running in update-pbabuilder mode.\n";
  dieIfNotRoot();

  my $script = "#!/bin/sh\n";
  $script .= "yum ";
  if ($main::configParams{"HttpProxy"} ne "") {
    $script .= " --setopt=proxy=".$main::configParams{"HttpProxy"};
  }
  $script .= " update -y || exit 1\n";
  $script .= "exit 0\n";

  my $rpmBuilderLog = $main::logDir."/update-pbabuilder_".$main::targetDistribution."-".$main::targetArchitecture."-pba-base.log";

  chdir $main::cacheDir || cleanupAndDie("Cannot chdir to ".$main::cacheDir);

  extractRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);

  my $chrootDir = $main::cacheDir."/".$$."/".$main::targetDistribution;
  executeOrDie("/bin/cp -av /etc/resolv.conf ".$chrootDir."/etc/");

  executeInRpmBuilder( $script, $main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture );

  retarRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);

  my $tarball = $main::libDir."/".$main::targetDistribution.".tar.gz";
  print "PBA-RPMBuilder has successfully updated ".$tarball."\nSee ".$rpmBuilderLog."\n";
  
  cleanup();
  exit 0;
}


if ($main::buildOperation eq "execute-in-pbabuilder") {

  ($main::verbosity > 0) && print "PBA-rpmbuilder running in execute-in-pbabuilder mode.\n";
  dieIfNotRoot();

  my $rpmBuilderLog = "/var/log/pba-builder/execute-in-pbabuilder_".$main::targetDistribution."-".$main::targetArchitecture."-pba-base.log";

  extractRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);

  executeInBuilder( $main::scriptToExecute, $main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture );

  retarRpmBuilder($main::targetDistribution, $rpmBuilderLog, $main::targetArchitecture);

  my $tarball = $main::libDir."/".$main::targetDistribution.".tar.gz";
  print "PBA-rpmbuilder has successfully executed ".$main::scriptToExecute."\nin ".$tarball."\nSee ".$rpmBuilderLog."\n";
  
  cleanup();
  exit 0;
}


if ($main::buildOperation eq "auto-build-directory") {
  ($main::verbosity > 0) && print "PBA-rpmbuilder running in auto-build-directory mode, delegating to auto-build from ".$main::incomingDirs."\n";
  $main::buildOperation = "auto-build";
}

if ($main::buildOperation eq "auto-build") {

  ($main::verbosity > 0) && print "PBA-rpmbuilder running in auto-build mode.\n";
  dieIfNotRoot();


  # check running builds || exit

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

  my @brotherPIDFiles = glob("*.pid");
  if (scalar(@brotherPIDFiles) >= $main::maxParallelBuilds) {
    if ($main::ignoreMaxParallelBuilds > 0) {
      ($main::verbosity > 0) && print "PBA-rpmbuilder will disturb (slow down) its ".scalar(@brotherPIDFiles)." already running brothers.\n";
    } else {
      ($main::verbosity > 0) && print "PBA-rpmbuilder 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";
    }
    if ($main::ignoreMaxParallelBuilds == 0) {
      cleanup();
      exit 0;
    }
  }
  
  my $pidFile = "/var/run/pba-builder/".$$.".pid";
  printToFile( $pidFile, $$ );
  push @main::filesToCleanup, $pidFile;

  # search new source package || exit

  scanForIncomingSrpmFiles();
  my $filesWorked = 0;

  while ($main::srpmFileToBuild ne "") {

    ($main::verbosity > 1) && print "Selected a source package to build: ".$main::srpmFileToBuild."\n";

    buildSrpmFile($main::srpmFileToBuild);

    $filesWorked += 1;
    if ($filesWorked >= 8) {
      ($main::verbosity > 0) && print "Going to winter sleep after ".$filesWorked." finishing source packages files.\n";
      $main::srpmFileToBuild = "";
    } else {
      scanForIncomingSrpmFiles();
    }
  }

  ($main::verbosity > 0) && print "PBA-rpmbuilder OK: No new source package to build.\n";
  if  (-f $pidFile) { unlink $pidFile || cleanupAndDie("FATAL: Cannot /bin/rm ".$pidFile."\n"); }
  cleanup();
  exit 0;
}


if ($main::buildOperation eq "test") {
  #cleanupAndDie("pba-rpmbuilder $main::buildOperation NYI");
  #exit 1;
  signRpm("test.rpm");
  exit 0;
}


print "PBA-rpmbuilder called without a valid command\n";
exit 1;

