#!/usr/bin/perl
use strict;
# Laittaa harjoitustyön svn:ään
# Käyttöohje ks. kohdasta help()
#
#  Idea:  1) jos hakemistossa on jo svn käytössä, niin tehdään update ja commit
#         2) jos ei ole ja se on tyhjä, tehdään checkout
#         3) jos hakemistossa on files.txt
#              - luodaan user/trunk ja user/tags
#              - chekcoutataan tuo tyhjä tähän
#              - sitten commit files.txt:n mukaan
#         4) muuten valitetaan epätyhjästä hakemistosta
#
# Vesa Lappalainen 12.1.2014
#
# Vaihda seuraavaan svn:si sijainti.  Myös pelkkä svn kelpaa
# jos se löytyy polusta. Jos asetetaan .bat, niin pitää
# laittaa svn.bat
# $svn = "svn.cmd";
my $svn = "svn";
# $svn="\"C:\\Program Files\\TortoiseSVN\\bin\\svn.exe\"";

# Vaihda seuraavaan oletuseditorisi
my $default_editor = "notepad.exe";

#Vaihda tarvittaessa seuraaviin kurssin tietoja
my $default_repo = "trunk";
my $default_kurssi = "ohj2";
my $default_kausi = "k2014";

my $kayttaja = $ENV{LOGNAME} || $ENV{USER} || $ENV{USERNAME} || getpwuid($<);

print "Kayttaja $kayttaja \n";

my $a1 = $ARGV[0]; # pyydetäänkö apua?
for ( ("?","-?","/?","h","-h","/h","help","-help","/help","a","-a","/a","apua","-apua","/apua" ) ) {
  if ( $a1 eq $_  ) { help();  exit(); }
}


# muutParametrit
# Asetataan ensin parametrit ja oletusarvot:
my $projdir=$ARGV[0]; if ( $projdir eq "" ) { $projdir=$kayttaja; }
my $kurssi=$ARGV[1];
my $kausi=$default_kausi; if ( $kurssi eq "" ) { $kurssi=$default_kurssi; $kausi=$default_kausi; }
my $repo=$ARGV[2]; if ( $repo eq "" ) { $repo=$default_repo; }
my $svnuser=$ARGV[3]; if ( $svnuser == "" ) { $svnuser=" --username $kayttaja"; }

if ( $projdir  eq "PROJNAME" ) { KirjoitaKunnonProjnimi(); exit(); }

my $SVN_EDITOR = $ENV{SVN_EDITOR};
if  ( $SVN_EDITOR eq "" ) {
  $SVN_EDITOR=$default_editor;
  $ENV{SVN_EDITOR} = $SVN_EDITOR;
}

my $svntarget="https://svn.cc.jyu.fi/srv/svn/$kurssi"."ht/$kausi/$projdir";

print "$projdir $kurssi $kausi $repo $svnuser $SVN_EDITOR $svntarget\n";

# Onko jo svn hakemisto olemassa?
if (-e '.svn' ) { svnready(); exit(); }

if ( isDirEmpty() ) { doCheckout(); exit(); } # ei .svn:ää eikä mitään muutakaan joten tehdään checkout

# Mutta uutta ei edes yritetä luoda jollei ole files.txt:tä
if ( ! -e "files.txt" ) { helpOnlyEmptyFile(); exit(); }
createNewRepo();
svnready();
exit();

###############################################################################
sub createNewRepo() {
  print "Luodaan uusi $repo\n";
  print "Luodaan oma varasto: svn mkdir -m \"Luonti\" $svntarget \n";
  system("$svn mkdir -m \"Luonti\" $svntarget $svnuser");
  system("$svn mkdir -m \"Luonti\" $svntarget/$repo $svnuser");
  system("$svn mkdir -m \"Luonti\" $svntarget/tags $svnuser");
  doCheckout();
}

###############################################################################
sub doCheckout() {
  print "svn checkout --force -r HEAD $svntarget/$repo . \n";
  system("$svn checkout --force -r HEAD $svntarget/$repo .");
  luoIgnore();
}

###############################################################################
sub luoIgnore() {
  # luodaan tarvittaessa .svnignore -tiedosto
  if ( ! -e ".svnignore" ) {
    open(OUT, ">.svnignore") || die "Ei voi avata .svnignore \n";
    print OUT "*\n";
	close OUT;
    print "Lisataan .svnignore:  $svn add .svnignore \n";
    system("$svn add .svnignore");
  }
}


###############################################################################
sub svnready() {
  print "Varasto $svntarget/$repo olemassa\n";
  print "Luetaan files.txt ja lisataan siina luetellut tiedostot versionhallintaan\n";
  # system("perl -S lue.pl SVN files.txt");
  addSvn("files.txt");
  luoIgnore();
  system("$svn propset -R svn:ignore -F .svnignore .");
  print("Paivitetaan varastosta: svn update\n");
  system("$svn update");
  if ( ! -e "files.txt" ) { mustHaveFilesTxt(); }
  print "Viedaan omat muutokset varastoon: svn commit\n";
  system("$svn commit $svnuser");
}


###############################################################################
sub isDirEmpty() {
  opendir(DIR,'.') or die "$!";
  readdir DIR; # reads .
  readdir DIR; # reads ..
  my $result = 1;
  if (readdir DIR) { #now there should be a file or folder
    $result = 0;
  }
  close DIR;
  return $result;
}


###############################################################################
sub helpOnlyEmptyFile() {
print <<STOP;

 Hakemisto ei ole tyhja!!!

 Komennon saa antaa vain
   1) taysin tyhjassa hakemistossa jotta hakee olemassa olevan projektin
   2) hakemistossa jossa on jo valmiina versionhallinnasta haettu versio
   3) epatyhjassa hakemistossa joka on tarkoitus 1. kerran vieda
      versionhallintaan hakemistossa on talloin oltava files.txt
      jossa on lueteltu siirrettavat tiedostot
STOP
}


###############################################################################
sub help() {
print <<STOP;
 Luo SVN-repositoryn jos sita ei ole.
 Laittaa files.txt-tiedostossa olevat tiedostot
 sinne. Committaa muutokset ja tekee javadoc yms. jutut

 Kutsu: svnht [kayttajahak] [kurssi] [repository] [kayttaja]
  esim: svnht villev ohj2 trunk villev
  esim: svnht villev
  esim: svnht             Tehdaan kaikilla oletuksilla

 Oletukset:
  kayttajahak: $kayttaja
  kurssi:      ohj2  
  repository:  trunk
  kayttaja:    $kayttaja
STOP
}


###############################################################################
sub KirjoitaKunnonProjnimi() {
print <<STOP;

  ensimmainen parametri pitaa olla projektin nimi eika PROJNAME
  esim. oma kayttajatunnuksesi $kayttaja on ihan hyva nimi
STOP
}

###############################################################################
sub addSvn($) {
# Lisätään svn:ään files.txt:ssä luetellut tiedostot
	my ($filename) = @_;

	my @tiedostot  = ();
	my @alkuosat   = ();
	my @lahdepolut = ();
	my @lahteet    = ();
	my %hakemistot = ();  # Käytetään vain hashin avainosaa :-)
	my $sourcepath = "";
	my $destination = "";
    my $subpath = "";

	open(TIEDOSTOT,$filename) or die("File not found: $filename!\n");


	while (my $rivi=<TIEDOSTOT>) {
	  $rivi = trim($rivi);
	  my ($alkuosa, $kommentti) = split(/\B= *|=\B */,$rivi,2);
	  $alkuosa = trim($alkuosa);
	  if ( $alkuosa eq '=' ) {
		$alkuosa = "";
	  }
	  if ( $alkuosa eq '' ) { next; }
	  if ( $alkuosa =~ /overview-tree.html/ ) { next; }
	  if ( $alkuosa eq '$SOURCEPATH' )  { next; }
	  if ( $alkuosa eq '$DESTINATION' ) { next; }

	  if ( $alkuosa =~ m/^[\!@].*/ ) { # alkaa ! tai @, eli linkki
		next;
	  }

	  push @alkuosat, ($alkuosa);

	  if ( $alkuosa ge "           " ) {
		push @lahdepolut,($sourcepath);
		push @tiedostot, ($alkuosa);
		hakemisto_lista("$destination$alkuosa",\%hakemistot);
	  }
	}
	close(TIEDOSTOT);

  my @lajiteltu = sort(keys(%hakemistot));
  my %polun_palat = ();  # Käytetään vain hashin avainosaa :-)
  hakemisto_lista("$subpath/.",\%polun_palat);
  my @spolun_palat = sort(keys(%polun_palat));

#  print %polun_palat; print "\n";
#  print @spolun_palat; print "\n";

  foreach my $hak (@spolun_palat) {
    print `svn add -N $hak 2>nul`;
  }
  print `svn add -N .svnignore 2>nul`;
  print `svn add -N files.txt 2>nul`;
  print `svn add -N .classpath 2>nul`;
  print `svn add -N .project 2>nul`;

  foreach my $hak (@lajiteltu) {
    print `svn add -N $hak 2>nul`;
  }


  for (my $i=0; $i < @tiedostot; $i++ ) {
    my $tied = trim($tiedostot[$i]);
    if ( $lahdepolut[$i] gt "        " ) { next; }

#    print "svn add -N $tied 2>nul\n";
    print `svn add -N $tied 2>nul`;
#    print `svn add -N $tied `;
  }
}

sub hakemisto_lista($$) { # $hakemisto,\%hakemistot
#------------------------------------------------------------------------------
# Lisää %hakemistot-listaan kaikki hakemiston alihakemistot joita ei vielä ole
# listassa.
# Esim: $hakemisto = "oma1/oma2"  => lisätään ("oma1","oma1/oma2")
###############################################################################
  my ($hakemisto,$hakemistot) = @_;
  my $loput = $hakemisto;
  my $alku = "";
  my $hak;
  while ( 1 ) {
    ($hak,$loput) = split("[/\\x5c]",$loput,2);
#    print "$hak $loput \n";
    if ( not $loput ) { last; }
    if ( not $hak ) { next; }
    $alku .= $hak;
    $$hakemistot{($alku)} = "";
#    $$hakemistot{lc($alku)} = "";
    $alku .= "/";
  }
}

###############################################################################
sub trim($) { # merkkijono => merkkijono
  my($s) = @_;
# Poistetaan merkkijonosta alkutyhjat, lopputyhjat ja rivinvaihdot (lopusta)
# Esim. "   kissa istuu\n   "  => "kissa istuu"
  $s =~ s/^\s*//;      # alkutyhjat
  $s =~ s/\s*$//;      # lopputyhjat (myös rivinvaihdot)
# s/^\s*(.*?)\s*$/\1/;
  return $s;
}


