#!/usr/bin/perl -w
# $Id: svn_set_ignore 985 2018-01-03 08:59:40Z mueller $
#
# Copyright 2007-2017 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
#
# This program is free software; you may redistribute and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3, 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 complete details.
#
#  Revision History:
# Date         Rev  Vers    Comment
# 2017-05-27   899   1.2.1  check svn:ignore existance before reading it
# 2016-12-17   821   1.2    use .gitignore rather .cvsignore
# 2014-11-04   601   1.1    use 'svn info' rather /.svn check for svn >= 1.7
# 2010-04-26   284   1.0.1  add error check for GetOptions
# 2007-06-16    56   1.0    Initial version
#

use 5.14.0;                                 # require Perl 5.14 or higher
use strict;                                 # require strict checking

use Getopt::Long;

sub do_dir;

my @dirlist;
my %ignores;

my %opts = ();

GetOptions(\%opts, "trace", "dry-run")
  or die "bad options";

if (@ARGV) {
  push @dirlist, @ARGV;
} else {
  @dirlist = `find -type d | sort`;
  die "bad find|grep" if $?;
  chomp @dirlist;
  # drop some directories at this level
  @dirlist = grep {! /\/(\.svn|\.Xil)/} @dirlist;
}

foreach (@dirlist) { do_dir($_); }

#-------------------------------------------------------------------------------

sub do_dir {
  my ($dirname) = @_;
  my @cur_ipat;
  my @new_ipat;
  my %ipat;

  # skip ise directories (they have sometimes strange chars in dir names
  return if $dirname =~ m|/ise/|;
  # check for svn working directory
  my $svn_info = `svn info $dirname 2>&1`;
  return if $?;

  print "$dirname\n";

  my @dpelist = split '/', $dirname;
  my @dpecurr = ();
  foreach my $e (@dpelist) {
    push @dpecurr, $e;
    my $d = join '/',@dpecurr;
    if (not exists $ignores{$d}) {
      $ignores{$d} = ();
      if (-r "$d/.gitignore") {
        print "read $d/.gitignore\n" if exists $opts{trace};
        open (CVSIG, "$d/.gitignore")
          or die "failed to read $d/.gitignore";
        while (<CVSIG>) {
          chomp;
          next if /^\s*$/;                  # ignore empty or space only lines
          next if /^#/;                     # ignore comments
          push @{$ignores{$d}}, $_;
          print "   $_\n" if exists $opts{trace};
        }
        close (CVSIG);
      }
    }
    foreach my $i (@{$ignores{$d}}) {
      next if exists $ipat{$i};
      $ipat{$i} = 1;
      push @new_ipat, $i;
    }
  }

  # check whether svn:ignore already defined
  my $has_ignore = 0;
  open (SVN, "svn pl $dirname|")
    or die "failed to open svn pl pipe for '$dirname'";
  while (<SVN>) {
    chomp;
    if (m/^\s*svn:ignore\s*$/) {
      $has_ignore = 1;
      last;
    }
  }
  close (SVN);

  # read svn:ignore, if it exists
  if ($has_ignore) {
    open (SVN, "svn pg svn:ignore $dirname|")
      or die "failed to open svn pg pipe for '$dirname'";
    while (<SVN>) {
      chomp;
      next if /^\s*$/;                        # ignore empty or space only lines
      push @cur_ipat, $_;
    }
    close (SVN);
  }

  if (join("\n",@cur_ipat) ne join("\n",@new_ipat)) {
    if ($has_ignore) {
      print "update svn:ignore for $dirname\n";
      print "old svn:ignore:\n";
      print "   ", join("\n   ",@cur_ipat),"\n";
    } else {
      print "setup svn:ignore for $dirname\n";
    }
    print "new svn:ignore:\n";
    print "   ", join("\n   ",@new_ipat),"\n";

    if (not exists $opts{"dry-run"}) {
      open (TMP, ">/tmp/svn_set_ignore_$$") or die "failed to open tmp file";
      print TMP join("\n",@new_ipat),"\n";
      close (TMP);
      print `svn ps svn:ignore -F /tmp/svn_set_ignore_$$ $dirname`;
      die "bad svn ps" if $?;
      unlink "/tmp/svn_set_ignore_$$" or die "failed to delete tmp file";
    }

  }

}
