#!/usr/bin/env perl
# $Id: check-wrapper-consistency 34220 2014-05-22 23:52:46Z karl $
# Public domain.  Originally written 2008.
# 
# Check that the same set of files are wrappers on w32 and symlinks on
# all others.

BEGIN {
  $^W = 1;
  ($mydir = $0) =~ s,/[^/]*$,,;
  unshift (@INC, "$mydir/..");
  chomp ($Master = `cd $mydir/../.. && pwd`);
}

use Getopt::Long;
use Pod::Usage;

our ($mydir, $Master);

my $help = 0;
GetOptions("help|?"       => \$help) or pod2usage(1);
pod2usage(-exitstatus => 0, -verbose => 2) if $help;

exit (&main ());


sub main {
  my $err = 0;
  
  my $bindir = "$Master/bin";
  chdir ($bindir) || die "chdir($bindir) failed: $!";
  
  my %w = &unx_wrapper_entries ("i386-linux");

  # add some additional wrappers which are not found 
  # automatically since they are not .. symlinks on Unix.
  $w{'updmap'} = 1;
  $w{'updmap-sys'} = 1;

  chomp (my $srcdir = `cd $Master/../Build/source/texk/texlive && pwd`);
  $cww = "$srcdir/w32_wrapper/runscript.exe";
  $err += &check_w32 ("win32", $cww, %w);

  return $err;
}



# return all symlinks starting with ".." in DIR as a hash, with symlink
# targets as the values.  Check that targets are executable.
# 
sub unx_wrapper_entries {
  my ($DIR) = @_;
  my %ret;
  
  chomp (my $olddir = `pwd`);
  chdir ($DIR) || die "chdir($DIR) failed: $!";

  local *DIR;
  opendir (DIR, ".") || die "opendir($DIR) failed: $!";
  while (my $ent = readdir (DIR)) {
    next unless -l $ent;  # skip all but symlinks
    next if -d $ent;      # and skip directories (i.e., man/)

    my $target = readlink ($ent);
    die "readlink($ent) failed: $!" if !defined ($target);
    next unless $target =~ /^\.\./;  # skip all but .. symlinks
    
    # the target of the symlink should be executable.
    warn "$ent: target $target not executable\n" if ! -x $target;

    $ret{$ent} = $target;  # remember name and link target
  }
  closedir (DIR) || warn "closedir($DIR) failed: $!";
  chdir ($olddir) || die "chdir($olddir) failed: $!";

  return %ret;
}



# Windows is painfully special, as usual.  Given the list of wrappers in
# UW, check that each of those entries (excluding shell scripts) exists
# in W32DIR as a .exe, and furthermore is a copy of the canonical w32
# wrapper exe specified in W32CANONICAL.
# 
sub check_w32 {
  my ($w32dir, $w32canonical, %uw) = @_;
  my $diff = 0;
  
  my %is_shell_script = &list_shell_scripts ();
  for my $k (sort keys %uw) {
    next if $is_shell_script{$k};    # skip shell scripts
    #
    # also skip these special cases:
    next if $k =~ /^(texdoctk|tlmgr|xasy)$/;
    #
    # else do the diff with the canonical wrapper:
    $diff += system ("cmp $w32dir/$k.exe $w32canonical");
  }

  opendir (DIR, $w32dir) || die "opendir($DIR) failed: $!";
  my @binfiles = readdir (DIR);
  closedir (DIR) || warn "closedir($DIR) failed: $!";

  foreach my $f (@binfiles) {
    next unless ($f =~ s/\.(bat|cmd)$//); # only batch files
    next if $uw{$f};                      # already checked
    $diff += system ("cmp $w32dir/$f.exe $w32canonical");
  }

  # extra check for fmtutil-sys.exe, since fmtutil is an executable.
  $diff += system ("cmp $w32dir/fmtutil-sys.exe $w32canonical");
  
  return $diff;
}

# As it happens, we already distinguish sh scripts from others in the
# build process, for basically the same reason.  So return the list
# maintained there by using a target defined in linked_scripts/Makefie
# for us.
# 
sub list_shell_scripts {
  my %sh;
  
  # has to be the Work/ directory to get the Makefile, not Makefile.{in,am}.
  my $Work = "$Master/../Build/source/Work";
  my $Work_linked_scripts = "$Work/texk/texlive/linked_scripts";
  my $Work_tl_scripts = "$Work/texk/texlive/tl_scripts";
  
  # use make; ensure we get only the last line, although that should be
  # all there is.
  my $lst = `make -s -C $Work_linked_scripts echo-shell-scripts | tail -1`;
    $lst .= `make -s -C $Work_tl_scripts     echo-shell-scripts | tail -1`;
  
  for my $script (split (" ", $lst)) {
    $script =~ s,^.*/,,;
    $sh{$script} = 1;  # save with extension (for listings-ext.sh)
    #
    $script =~ s,\.[^.]*$,,;
    $sh{$script} = 1;  # save without extension (everything else)
  }

  # more shell scripts, that are not part of linked_scripts.
  $sh{"chkweb"} = 1;
  
  return %sh;
}
