#!/usr/bin/env perl
# maybe refresh Emacs builds for Windows
## Copyright 2022 Corwin Brust <corwin@bru.st>

## This file is not part of GNU Emacs.
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.

## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## You should have received a copy of the GNU General Public License
## along with This program.  If not, see <https://www.gnu.org/licenses/>.

# script to build a release

use strict;
use warnings;

use Carp;


# Branch name to snapshot indicator. snapshot builds have different
# semantics, such as indcluding the build date when naming files.
my %branches = qw[emacs-28 no master yes];

# we invoke a shell script to build using ENV vars to control it
my $env_cmd = q(/usr/bin/env);
my $rel_script = q(/d/projects/emacs-build/new-hotness/build-release.sh);
# this approach really wants a package. worth?
# my %bldenv = ( EMACS_SNAPSHOT => sub {$branches{$_[0]} || '' eq 'yes' ? 1 : ''},
#                EMACS_FULL_AOT => sub {($_[1]||0) == 1 ? 1 : ''});

my $branch_path = q(/c/Users/corwi/emacs-build/git/);
my $git_check = q([ $(git rev-parse HEAD) == $(git rev-parse master@{upstream}) ]);
my $git_pull = q(git pull);
#my $git_check = q(git diff --quiet --ignore-submodules HEAD 2>/dev/null);

my $target_dir = q(/c/Users/corwi/emacs-upload);
my $rsync_cmd = q(rsync -vvte "ssh -i ${HOME}.ssh/ed.crv" )
              . q(${HOME}/emacs-upload/* )
              . q(dh_aw28jd@corwin.bru.st:~/corwin-emacs/emacs-28)
              ;

local $| = 1; # write agressively to STDOUT

sub build_release($;$$) {
  my ($log, $branch, $aot) = @_;
  $log or confess(q[No logfile in call to build_release]);
  my $snap_env = ($branches{$branch}||'') eq 'yes' ? 1 : '';
  my $aot_env = $aot  == 1 ? 1 : '';
  my $command= join ' ',( $env_cmd,
			  qq(EMACS_SNAPSHOT=$snap_env),
			  qq(EMACS_FULL_AOT=$aot_env),
			  $rel_script
			);
  # my $command= join ' ',($env_cmd, #q(%s  EMACS_SNAPSHOT=%s EMACS_FULL_AOT=%s %s)
  # 			 (map { $bldenv{$_}->($branch, $aot) } reverse sort keys %bldenv),
  # 			 $rel_script);
  open my $JOB, '-|', $command or confess qq(Failed to start $command => $!);
  open my $LOG, '>', $log or confess(qq[Failed to open $log => $!]);
  $LOG->autoflush(1);
  print $LOG $command, "\n";
  print $command, "\n";

  while(my $line = <$JOB>) {
    print $LOG $line;
    print $line;
  }
  my $exit_val = $? >> 8;

  #https://docstore.mik.ua/orelly/perl/prog/ch06_02.htm#PERL2-CH-6-SECT-2.1
  # esp see cautions at the close of section "6.2.2.1 Anonymous pipes"
  close $JOB or # failure closing pipeline probably means command failure
    return Carp::longmess(q[failed in pipeline command $command]);
  #whereas issues closing the log are unlikely and probably won't stop us
  close $LOG or Carp::cluck(qq[error closing $log (\$!$!, \$?$?)]);

  return $exit_val == 0;
}

sub run_in_dir($$) {
  my ($dir, $one_line_script) = @_;
  my $cmd = sprintf q[(cd %s; %s)], $dir, $one_line_script;
  my $cdepth = 3;
  my @c; @c = caller($cdepth) until not $cdepth-- or $c[3];
  print localtime(time) . q( BATCH: starting command for )
                        . (join ' ', @c[1..3])
			. qq[ (info)\n#]
			,
	$cmd, "\n";
  system($cmd);
  return $? >> 8;
}

sub branch_needs_pull($) {
  my $dir = $branch_path . shift || confess q(branch name is required);
  return 1 == run_in_dir($dir, $git_check);
}

my $build_count = 0;

for my $branch(sort {$b cmp $a} keys %branches) {
  my $force = scalar( grep /\Q$branch\E/i, @ARGV);
  my $need_pull_rv;
  unless ($force or $need_pull_rv = branch_needs_pull($branch)) {
    print localtime(time)." Nothing to do for $branch\n";
  } else {
    my $rv;
    run_in_dir(qq($branch_path$branch), $git_pull) if $need_pull_rv;
    for my$aot(reverse 0..1) { #make with then without aot
      printf localtime(time) . " Starting%s release of %s with%s ahead of time native elisp compilation.\n"
	                     , ($force ? q(forced ) : '')
                             , $branch
			     , $aot ? 1 : 'no, please';

      my $logfile = sprintf(q[%s%s.log],
			    $branch,
			    $_ ? '-aot' : '');
      ++$build_count if build_release($logfile, $branch, $aot);
    } #end for $aot
    warn "build_release rv: $rv";
  } #end else
} #end for $branch

if($build_count) {
  my $rv;
  unless(my $rv = run_in_dir($target_dir, $rsync_cmd)) {
    print localtime(time).qq( BATCH: rsync may have failed. (warning)\n);
    #exit($rv) if $rv;
  }
}
print "Build emacs $build_count times.";
#exit;

#(for exp in '(/usr/bin/env EMACS_FULL_AOT= EMACS_SNAPSHOT= /d/projects/emacs-build/new-hotness/build-release.sh)' ; do echo $exp ; /bin/bash -c "$exp" ; done )| tee ~/emacs-upload/emacs-28.log ; (for exp in '(/usr/bin/env EMACS_FULL_AOT=1 EMACS_SNAPSHOT= /d/projects/emacs-build/new-hotness/build-release.sh)' ; do echo $exp ; /bin/bash -c "$exp" ; done )| tee ~/emacs-upload/emacs-28-aot.log ; (for exp in '(/usr/bin/env EMACS_FULL_AOT= EMACS_SNAPSHOT=1 /d/projects/emacs-build/new-hotness/build-release.sh)' ; do echo $exp ; /bin/bash -c "$exp" ; done )| tee ~/emacs-upload/emacs-29.log ; (for exp in '(/usr/bin/env EMACS_FULL_AOT=1 EMACS_SNAPSHOT=1 /d/projects/emacs-build/new-hotness/build-release.sh)' ; do echo $exp ; /bin/bash -c "$exp" ; done )| tee ~/emacs-upload/emacs-29-aot.log

#  echo "$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/\1$( git diff --quiet --ignore-submodules HEAD 2>/dev/null; [ $? -eq 1 ] && echo "*")/")@$(git rev-parse --short HEAD 2> /dev/nul)"
