#! /bin/tclsh
#
# This file collects all files in its home directory and all directories below
# it, excludes a selected few (see Exclude list below) and packages them in
# a tar.gz archive.

# For the version, we find the AC_INIT macro in configure.in which must be
# in our home directory..  This also sets the package name.
#
# The file list is composed either by:
# 1) asking the subversion control system which files are under control
#    subversion files are not included (1 is default)
# 2) same as 1, but include subversion control files
# 3) reading a pattern list from the file 'excludelist'
# 4) a fixed pattern list hard coded below
#
# By default, the first successful option is used. 
# If you want to bypass one or more of these methods, code the start as:
#
# buildrelease 2       (or 3 to just use the fixed)
#
# Additional patterns can
# be added to by putting them in the command line i.e.:

# buildrelese -*.svn* +newfile

# will exclude all svn files and include newfile
# List of files not to include... derive from the file 'excludelist'
#
# Here is the canned exclude list

set ExcludeList [list Makefile \
		     *~\
		     config.* \
		     pkgIndex.tcl \
		     *.cache/* \
		     ".#*" \
		     "#*" \
		     *.gz \
		     *.o \
		     *.so \
		     *.orig]

# process any arguments...
set includelist {}
set excludelist {}
set skipto 1

foreach ent $argv {
  switch -glob $ent {
    +* {lappend includelist [string range $ent 1 end]}
    -* {lappend excludelist [string range $ent 1 end]}
    2  {lappend includelist "*.svn*"}
    1  -
    3  -
    4 {set skipto $ent}
    default {
      puts "Unrecognize option $ent."
      puts "Use '2' to include subversion control files."
      puts "Use '3' to skip subversion look up to find files."
      puts "Use '4' to skip 'excludelist' look up of files."
      puts "Use '+name' to include files that match pattern 'name' in the list."
      puts "Use '-name' to exclude files that match pattern 'name' in the list."
    }
  }
}
set r [catch "exec svn info {*}[glob ./*] >/dev/null" out]
if {[string match "*couldn't execute *: no such file or directory*" $out] || \
	[string match "* not a working copy *" $out] || \
	[string match "* is too old *" $out] } {
  puts "Subversion look up failed with:\n $out"
  puts "Fix this or try another method."
  exit 1
}

if {$skipto == 3} {
  if {![file readable "excludelist"] || \
	  [catch {open "excludelist" r} fid] != 0 || \
	  [catch {read -nonewline $fid} content] != 0} {
    puts "Could not find a readable 'excludelist' file in [pwd]"
    puts "Continuing with an approximation..."
    lappend excludelist {*}$ExcludeList

  } else {
    foreach line [split $content "\n"] {
      switch -glob $line {
	{}   -
	"#*" {continue}
	default {lappend excludelist $line}
      }
    }
  }
}
if {$skipto == 4} {
  lappend excludelist {*}$ExcludeList
}
  
#puts "$excludeList"
#
if {![file readable "configure.in"] || \
	[catch {open "configure.in" r} fid] != 0 || \
	[catch {read -nonewline $fid} content] != 0} {
  puts "Could not find a readable 'configure.in' file in [pwd]"
  exit 1
}

foreach line [split $content "\n"] {
  if {[regexp {AC_INIT.\[(.*)\].*,.*\[(.*)\]} $line match name rev]} {
    puts "$name $rev"
  }
}

# We don't require a ChangeLog, but if there is one it better talk about
# this rev...
if {[file readable "ChangeLog"] &&
    [catch {open "ChangeLog" r} fid] == 0 &&
    [catch {read -nonewline $fid} content] == 0} {
  if {! [string match "$rev *" $content] } {
    puts "The 'ChangeLog' does not start with rev '$rev '. Fix this."
    exit 1
  }
}
proc excludeThis { this } {
  foreach pat $::excludelist {
    if {[string match $pat $this]} {
      #puts "$this matched $pat"
      return -code continue
    }
  }
}

proc getFilesFrom { dir } {
  set filelist {}
  set dirlist {}

  if {$::skipto == 1} {
    # There is a svn 'ls' command, but it is really really slow 
    # (I think it is going to the repository for more info than we need) and 
    # harder to process as it does not produce the path name leaving that
    # to us.  This works and is rather fast...
    set r [catch "exec svn info {*}[glob -nocomplain $dir*] |& grep ^Path" path]
    #puts ">$path<"
    foreach ent [split $path "\n"] {
      lassign $ent pa fl er
      #puts "$ent<$fl "
      if {$er != {} } {break}
      if {[file isdirectory $fl]} {
	lappend dirlist $fl
      } else {
	lappend filelist $fl
      }
    }
    if {$::includelist != {}} {
      set thisfile [glob -nocomplain -type {f} $dir* $dir.*]
      set thisdir [glob -nocomplain -type d $dir* $dir.*]
      foreach pat $::includelist {
	foreach fldr {file dir} {
	  foreach fl [set this$fldr] {
	    if {[string match $pat $fl]} {
	      lappend ${fldr}list $fl
	    }
	  }
	}
      }
      set filelist [lsort -unique $filelist]
      set dirlist [lsort -unique $dirlist]
    }
  } else {
    set filelist [lsort [glob -nocomplain -type {f} $dir* $dir.*]]
    set dirlist [lsort [glob -nocomplain -type d $dir* $dir.*]]
  }
  foreach type {file dir} {
    set fil${type}list {}
    set fil${type}list {}
    foreach file [set ${type}list] {
      excludeThis $file
      lappend fil${type}list $file
    }
  }
  return [list [lsort $filelist] [lsort $dirlist]]
}

proc recurFileSearch { dir } {
  lassign [getFilesFrom $dir] flist inodelist
#  lappend filelist {*}[lsort [glob -nocomplain -type {f} $dir* $dir.*]]
  lappend filelist {*}$flist
  foreach inode $inodelist {
#    puts "$inode"
    switch -glob $inode {
      */.  -
      */.. -
      .    -
      ..   {continue}
      default {lappend filelist {*}[recurFileSearch $inode/]}
    }
  }
  return $filelist
}

set files [recurFileSearch {}]
# make the pay load... 
#puts "$files"
set x [exec tar -czf tcl-$name-$rev.tar.gz --numeric-owner\
	   --transform=s%^%tcl-$name-$rev/% {*}$files]
#puts "finish: $x"
