#!/usr/bin/perl
# import files to subversion one by one and adjust commit date to file's mtime
# this method is rather slow!
# directory timestamps are set to the mtime of the oldest file

# 2005-07-15 Oliver Betz
# 2007-03-27 A. L. Taurog   www.aryehleib.com

# Aryeh Leib Taurog provides this modified script AS IS with no warranty as
# to its usability or fitness for any purpose.  Aryeh Leib disclaim all
# responsibility for any damage whatsoever resulting from the download or
# use of this software.

# instructions:
# create an empty repository, make sure to have a "pre-revprop-change" hook
# check out a working copy from the empty repository
# copy the whole tree of files to the working copy
# run this script from the WC root

# caution:
# - stat() fails on filenames with foreign characters.
# maybe conflicting translations from svn and perl?
# - (stat())->mtime reports wrong data using ActivePerl with NTFS. Cygwin works.

use strict;

use File::stat; # by-name access to mtime
use File::Find;

my $rev; # revision of committed file
my $svnstat; # response of "svn stat"
my %files;
my $filename; # path to current file
my $fileset;  # list of files in current set
my $mtime;    # mtime of current file set 
              # special format of svn time: 2005-07-11T09:17:35.000000Z

$ENV{Lang}="C"; # else we might get localized responses

find({wanted => \&getfile, no_chdir => 1}, '.'); # all files and directories in the tree

$mtime = svntime((sort(values(%files)))[0]), "\n"; # oldest file
print "svn propset svn:date $mtime --revprop -r HEAD\n";
print `svn propset svn:date $mtime --revprop -r HEAD\n`;

# first add all directories, they receive the time of the oldest file
foreach $filename (sort keys(%files)){
  next unless (-d $filename);
  print "svn add -N \"$filename\"\n";
  print `svn add -N "$filename"`; # put the file under svn control, print response
}

undef $mtime;

foreach $filename (sort { $files{$a} <=> $files{$b} } keys(%files)) {
  next if (-d $filename); # directories have already been added
  $svnstat = `svn stat "$filename"`;
  next unless $svnstat =~ m/^\?.....\s+(\S.*)$/;
  # skip if ignored or already under version control

  my $ftime = svntime($files{$filename});

  if (defined $mtime and $mtime ne $ftime)
  {
    $rev=`svn ci -m "mtime-keeping add of files:$fileset"`; # commit last set of files
    print "$rev"; # show complete response (several lines)
    die "wrong response $rev" unless $rev =~ /Committed revision (\d+)\./;
    # this is rather restrictive - 'next' might be a good alternative
    # (with appropriate warning)

    $rev = $1; # numerical value -> $rev

    print `svn propset svn:date $mtime --revprop -r $rev`;
    $fileset = "";
  }

  $mtime = $ftime;
  $fileset .= " $filename\n";
  print `svn add -N "$filename"`; # put the file under svn control
}
print "ready\n";

# add file dates and file/dir types to hash
sub getfile {
  return if $File::Find::name eq "."; # don't add "."
  return if $File::Find::name =~ m{/.svn}; # don't add svn directories
  $files{$File::Find::name} = (stat($File::Find::name))->mtime; # add file to hash
}

sub svntime {
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(@_[0]);
  return sprintf "%4d-%02d-%02dT%02d:%02d:%02d.000000Z",1900+$year,$mon+1,$mday,$hour,$min,$sec;
}
__END__ 
