#!/bin/sh
#
# Copyright 2006-2009 by Purdue Research Foundation, West Lafayette, IN 47906.
# All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#
#------------------------------------------------------------------------
# UTILITY: addrepo
#
# Creates a trac project and corresponding svn repository for any
# tool development project on a HUBzero site.
#------------------------------------------------------------------------
# Michael McLennan (mmclennan@purdue.edu)
# Copyright (c) 2007  Purdue Research Foundation
#------------------------------------------------------------------------
#\
exec tclsh "$0" "$@"

set usage "
USAGE: addrepo <project> ?-option value -option value...?

  options:  -title ......... full name of the project
            -description ... 1-line description of the project
            -password ...... password needed to bind to LDAP

  examples:
    addrepo rappture -title \"Rappture Toolkit\" \\
      -description \"Toolkit for building graphical interfaces\" \\
      -password fy1k4zz \\
      -hubdir /www/myhub
"

###################### parse command line arguments ######################

if {$argc < 1} {
    puts stderr $usage
    exit 1
}

array set params [list \
    -project [lindex $argv 0] \
    -title "???" \
    -description "???" \
    -password "???" \
    -hubdir "???" \
]

for {set i 1} {$i < [llength $argv]} {incr i} {
    set token [lindex $argv $i]
    if {![info exists params($token)]} {
        puts stderr "bad option \"$token\""
        puts stderr $usage
        exit 1
    }
    if {$i+1 >= [llength $argv]} {
        puts stderr "missing value for $token"
        exit 1
    }
    set str [lindex $argv [incr i]]
    #
    # BE CAREFUL:  The way arguments are quoted, some strings have
    #   stuff like "hello \' world", where the \ is embedded as
    #   part of the string.  Change all \' to plain ' marks.
    #
    regsub -all {\\\'} $str ' str
    set params($token) $str
}

###################### configuration scan (poor hack) ######################

if {![file exists $params(-hubdir)]} {
        puts stderr "ERROR: specified base directory does not exist"
        puts stderr " at $params(-hubdir)"
        exit 5
}

if { ![ catch { set fid [open [file join $params(-hubdir) "hubconfiguration.php"] r] } ] } {
while { [gets $fid line] >= 0 } { if { [regexp {^\s*class\s+HubConfig\s+\{\s*$} $line] } { break } }
while { [gets $fid line] >= 0 } {
        if { [regexp {^\s*\}\s*$} $line] } { break }
        set key ""
        set value ""
        regexp {^\s*var\s*\$(\w+)\s*=\s*"([^"\\]*(\\.[^"\\]*)*)"} $line -> key value
        if { [string compare $key {}] == 0 } { regexp {^\s*var\s*\$(\w+)\s*=\s*'([^'\\]*(\\.[^'\\]*)*)'} $line -> key value }
        if { [string compare $key {}] == 0 } { regexp {^\s*var\s*\$(\w+)\s*\=\s*(\w+)\s*\;\s*$} $line -> key value }
        set cfg($key) $value
}
close $fid
}

if { ![ catch { set fid [open [file join $params(-hubdir) "hubconfiguration-local.php"] r] } ] } {
while { [gets $fid line] >= 0 } { if { [regexp {^\s*class\s+HubConfigOverride\s+\{\s*$} $line] } { break } }
while { [gets $fid line] >= 0 } {
        if { [regexp {^\s*\}\s*$} $line] } { break }
        set key ""
        set value ""
        regexp {^\s*var\s*\$(\w+)\s*=\s*"([^"\\]*(\\.[^"\\]*)*)"} $line -> key value
        if { [string compare $key {}] == 0 } { regexp {^\s*var\s*\$(\w+)\s*=\s*'([^'\\]*(\\.[^'\\]*)*)'} $line -> key value }
        if { [string compare $key {}] == 0 } { regexp {^\s*var\s*\$(\w+)\s*\=\s*(\w+)\s*\;\s*$} $line -> key value }
        set cfg($key) $value
}
close $fid
}

###################### site parameterization ######################

proc getcfg key {
        global cfg
        if {[info exists cfg($key)]} { return $cfg($key); }
}

set dirs(svn)           /opt/svn/tools
set dirs(trac)          /opt/trac/tools
set installdir [file dirname [info script]]
if {$installdir == "."} { set installdir [pwd] }
set hubLDAPBaseDN       [getcfg hubLDAPBaseDN]
set hubLDAPSearchUserDN [getcfg hubLDAPSearchUserDN]
set hubLDAPSearchUserPW [getcfg hubLDAPSearchUserPW]
set hubShortName        [getcfg hubShortName]
set hubLongURL          [getcfg hubLongURL]
set hubSupportEmail     [getcfg hubSupportEmail]
set forgeRepoURL        [getcfg forgeRepoURL]
set forgeName           [getcfg forgeName]
set projectURL          [getcfg forgeURL]/tools/$params(-project);
set svndir [file join $dirs(svn) $params(-project)]
set tracdir [file join $dirs(trac) $params(-project)]

set hubLDAPPort [expr ([regexp {\s*ldaps://\s*} [getcfg hubLDAPMasterHost]]) ? 636 : 389]

regsub {\s*ldap[s]{0,1}://} [getcfg hubLDAPMasterHost] {} hubLDAPMasterHost
regsub {\s*(yes|1|true)\s*} [getcfg hubLDAPNegotiateTLS] {true} hubLDAPNegotiateTLS
regsub {\s*(no|0|false)\s*} $hubLDAPNegotiateTLS {false} hubLDAPNegotiateTLS

###################### end site parameterization ######################

proc attempt {args} {
    flush stdout;
    if {[catch "exec $args" result] != 0} {
        puts stderr "FAILED: $args"
        puts stderr $result
        exit 1
    }
}

###############################################################################
# SVN setup
###############################################################################
if {![file exists $svndir]} {
    cd $dirs(svn)
    attempt svnadmin create --fs-type fsfs $params(-project)
    set svnfiles [glob $params(-project) $params(-project)/* $params(-project)/*/* $params(-project)/*/*/*]
    foreach {f} $svnfiles {
        file attributes $f -group www-data -permissions g+w
        if { [file isdirectory $f] } {
            file attributes $f -permissions g+s
        }
    }
    #
    # Import the initial source tree 
    # [do before trac as trac 0.10.x didn't like empty subversion trees --njk]
    #
    # attempt svn import [file join $installdir svn] file://$svndir -m "initial directory structure"

    set tmpdir [file join / tmp addrepotmp[pid]]
    file copy [file join $installdir svn] $tmpdir
    file attributes [file join $tmpdir trunk src] -permissions go-rx
    set invokescript [file join $tmpdir trunk middleware invoke]
    if {[catch {
                set fid [open $invokescript w]
                puts $fid "#!/bin/sh\n"
                puts $fid "/apps/rappture/invoke_app \"$@\" -t $params(-project)"
                close $fid
                file attributes $invokescript -permissions ugo+rx
               } result] == 0} {
        puts "            Created default middleware/invoke script."
    } else {
        puts stderr "== ERROR: Attempt to create invoke script failed."
        puts stderr $result
    }
    attempt svn import $tmpdir file://$svndir -m "initial directory structure"
    file delete -force $tmpdir
} else {
    puts "Subversion repository already exists at $svndir... skipping svn creation."
}

###############################################################################
# TRAC setup
###############################################################################

proc wikifile {fname title} {
    global installdir params hubShortName forgeRepoURL

    set tmpfile /tmp/addrepo[pid].txt
    file delete -force $tmpfile 

    substfile [list \
      @PROJECT@ $params(-project) \
      @TITLE@ $params(-title) \
      @DESCRIPTION@ $params(-description) \
      @HUBSHORTNAME@ $hubShortName \
      @REPOURL@ $forgeRepoURL \
    ] [file join $installdir $fname] $tmpfile

    attempt trac-admin $params(-project) wiki import $title $tmpfile
    file delete -force $tmpfile 
}

proc substfile {substlist ifname ofname} {
    set fid [open $ifname r]
    set info [read $fid]
    close $fid

    foreach {pattern value} $substlist {
        if {[string index $pattern 0] == "@"} {
            set info [string map [list $pattern $value] $info]
        } else {
            regsub -all & $value {\\\&} value
            regsub -all {\\[0-9]} $value {\\&} value
            regsub $pattern $info $value info
        }
    }

    set fid [open $ofname w]
    puts -nonewline $fid $info
    close $fid
}

if {![file exists $tracdir]} {
cd $dirs(trac)
#attempt trac-admin [file join $dirs(trac) $params(-project)] initenv $params(-project) sqlite:db/trac.db svn $svndir /usr/share/trac/templates
attempt trac-admin [file join $dirs(trac) $params(-project)] initenv app:$params(-project) sqlite:db/trac.db svn $svndir
set tracfiles [glob $params(-project) $params(-project)/* $params(-project)/*/* ]
foreach {f} $tracfiles {
    file attributes $f -group www-data -permissions g+w
    if { [file isdirectory $f] } {
        file attributes $f -permissions g+s
    }
}

#
# Copy the site.html file that adds the customized CSS
#
file copy -force [file join $installdir templates site.html] \
    [file join $tracdir templates]

#
# Tweak the page look.
#
file copy \
    [file join $tracdir conf trac.ini] \
    [file join $tracdir conf trac.ini.bak]

if {[string match {^group-} $params(-project)] == 1} {
   set fid [open [file join $installdir ldapconfGroup.in] r]
} else {
   set fid [open [file join $installdir ldapconf.in] r]
}
set ldapinfo [read $fid]
close $fid

set pbasename $params(-project)
regsub {^app-} $pbasename "" pbasename  ;# cut off leading app- stuff
regsub {^group-} $pbasename "" pbasename  ;# cut off leading group- stuff

set ldapinfo [string map [list \
    @PROJECT@ $pbasename \
    @PASSWORD@ $params(-password) \
    @LDAP_HOST@ $hubLDAPMasterHost \
    @LDAP_BASEDN@ $hubLDAPBaseDN \
    @LDAP_PORT@ $hubLDAPPort \
    @LDAP_SEARCH_USER@ $hubLDAPSearchUserDN \
    @LDAP_USETLS@ $hubLDAPNegotiateTLS \
] $ldapinfo]

substfile [list \
  {\nsrc +=[^\n]+logo.png} "\nsrc = /tools/images/forge.png" \
  {\nalt +=[^\n]+} "\nalt = $forgeName" \
  {\nlink +=[^\n]+} "\nlink = $hubLongURL" \
  {\nheight +=[^\n]+} "\nheight = 75" \
  {\nwidth +=[^\n]+} "\nwidth = 275" \
  {\nlog_level +=[^\n]+} "\nlog_level = ERROR" \
  {\nlog_type +=[^\n]+} "\nlog_type = syslog" \
  {\nmax_size +=[^\n]+} "\nmax_size = 10000000" \
  {\nmax_preview_size +=[^\n]+} "\nmax_preview_size = 3000000" \
  {\nsmtp_enabled +=[^\n]+} "\nsmtp_enabled = true" \
  {\nsmtp_replyto +=[^\n]+} "\nsmtp_replyto = $hubSupportEmail" \
  {\nsmtp_server +=[^\n]+} "\nsmtp_server = localhost" \
  {\nsmtp_from +=[^\n]+} "\nsmtp_from = \[$hubShortName\] notifier" \
  {\npermission_store +=[^\n]+} "\npermission_store = HubzeroPermissionStore" \
  {\nurl +=[^\n]+} "\nurl = $projectURL" \
  {\nfooter +=[^\n]+} "\nfooter = Visit our companion site at<br /><a href=\"$hubLongURL/\">$hubLongURL</a>" \
  {\ndescr +=[^\n]+} "\ndescr = $params(-description)" \
  {\nicon +=[^\n]+} "\nicon = ncnicon.ico" \
  {\nmax_daysback +=[^\n]+} "\nmax_daysback = -1" \
  {$} $ldapinfo \
] [file join $tracdir conf trac.ini.bak] [file join $tracdir conf trac.ini]

#
# Copy wiki macros
#
substfile [list \
  @PROJECT@ $params(-project) \
  @TITLE@ $params(-title) \
  @DESCRIPTION@ $params(-description) \
] [file join $installdir image.py.in] [file join $tracdir plugins image.py]

substfile [list \
  @PROJECT@ $params(-project) \
  @TITLE@ $params(-title) \
  @DESCRIPTION@ $params(-description) \
] [file join $installdir link.py.in] [file join $tracdir plugins link.py]

wikifile images.txt.in Images
wikifile getstart.txt.in GettingStarted
wikifile cover.txt.in WikiStart
} else {
    puts "Trac project already exists at $tracdir... skipping trac project creation."
}

#
# Update permissions for Apache svn access
#
if {![file exists /etc/apache2/svn.conf]} {
    set fid [open "/etc/apache2/svn.conf" a+]
    close $fid
    file attributes /etc/apache2/svn.conf -group www-data -permissions 0664
}
#if {![file exists /etc/apache2/svn-repo.conf]} {
#    set fid [open "/etc/apache2/svn-repo.conf" a+]
#    close $fid
#    file attributes /etc/apache2/svn-repo.conf -group www-data -permissions 0664
#}

attempt cat /etc/apache2/svn.conf > /etc/apache2/svn.bak
#attempt cat /etc/apache2/svn-repo.conf > /etc/apache2/svn-repo.bak
attempt [file join $installdir gensvnapache.py] /opt/svn/tools /tools/@PROJECT@/svn $params(-hubdir) tool > /etc/apache2/svn.conf
#attempt [file join $installdir gensvnapache.py] /opt/svn/infrastructure /infrastructure/@PROJECT@/svn $params(-hubdir) infrastructure >> /etc/apache2/svn.conf
#attempt [file join $installdir gensvnapache.py] /opt/svn/groups /groups/@PROJECT@/svn $params(-hubdir) group >> /etc/apache2/svn.conf
#attempt [file join $installdir gensvnapache.py] /opt/svn/infrastructure /svn/@PROJECT@ $params(-hubdir) infrastructure > /etc/apache2/svn-repo.conf
#attempt [file join $installdir gensvnapache.py] /opt/svn/groups /svn/group-@PROJECT@ $params(-hubdir) group >> /etc/apache2/svn-repo.conf
#attempt [file join $installdir gensvnapache.py] /opt/svn/tools /svn/app-@PROJECT@ $params(-hubdir) tool >> /etc/apache2/svn-repo.conf
attempt sudo /etc/init.d/apache2 reload
exit 0
