build-repository.tcl

Does not contain a contract.

Location:
/packages/acs-tcl/lib/build-repository.tcl

Related Files

[ hide source ] | [ make this the default ]

File Contents

if {![exists_and_not_null debug_p]} {
    set debug_p 0
}
if {![exists_and_not_null head_channel]} {
    set head_channel 5-9
}

#    Rebuild the repository on the local machine.  Only useful for the openacs.org site.   Adapted from Lars' build-repository.tcl page.
#    @param debug_p Set to 1 to test with only a small subset of packages instead of the whole cvs tree.
#    @param head_channel The artificial branch label to apply to HEAD.  Should be one minor version past the current release.
#    @author Lars Pind (lars@collaboraid.biz)
#    @return 0 for success.   Also outputs debug strings to log.


#----------------------------------------------------------------------
# Configuration Settings
#----------------------------------------------------------------------

ns_log Notice "============== JA DEBUG: Rebuild Repository checkpoint 1"
set cvs_command "cvs"
set cd_helper "cd-helper"
set cvs_root ":pserver:anonymous@cvs.openacs.org:/cvsroot"

set work_dir "[acs_root_dir]/repository-builder/"

set repository_dir "[acs_root_dir]/www/repository/"
set repository_url "http://openacs.org/repository/"

set channel_index_template "/packages/acs-admin/www/apm/repository-channel-index"
set index_template "/packages/acs-admin/www/apm/repository-index"

ns_log notice "JA DEBUG: Rebuild Repository checkpoint 2"

set exclude_package_list {}

#----------------------------------------------------------------------
# Prepare output
#----------------------------------------------------------------------

ns_log notice [ad_header "Building repository"]
ns_log notice "Repository: Building Package Repository"

#----------------------------------------------------------------------
# Find available channels
#----------------------------------------------------------------------


# Prepare work dir
file mkdir $work_dir
ns_log notice "JA work_dir=$work_dir"

cd $work_dir
catch { exec $cd_helper $work_dir cvs -d $cvs_root -z3 co openacs-4/readme.txt } msg
catch { exec $cd_helper $work_dir cvs -d $cvs_root -z3 log -h openacs-4/readme.txt } output

set lines [split $output \n]
for { set i 0 } { $i < [llength $lines] } { incr i } {
    if { [string equal [string trim [lindex $lines $i]] "symbolic names:"] } {
    incr i
    break
    }
}

array set channel_tag [list]
array set channel_bugfix_version [list]

for { } { $i < [llength $lines] } { incr i } {
    # Tag lines have the form   tag: cvs-version
    #     openacs-5-0-0-final: 1.25.2.5

    if { ![regexp {^\s+([^:]+):\s+([0-9.]+)} [lindex $lines $i] match tag_name version_name] } {
    break
    }
    
    # Look for tags named 'openacs-x-y-compat'
    if { [regexp {^openacs-([1-9][0-9]*-[0-9]+)-compat$} $tag_name match oacs_version] } {
    
    set major_version [lindex [split $oacs_version "-"] 0]
    set minor_version [lindex [split $oacs_version "-"] 1]

    if { $major_version >= 5 && $minor_version > 3} {
        set channel "${major_version}-${minor_version}"
        
        ns_log notice "Repository: Found channel $channel using tag $tag_name"

        set channel_tag($channel$tag_name
    }
    }
}

set channel_tag($head_channel) HEAD

ns_log notice "Repository: Channels are: [array get channel_tag]</ul>"
ns_log notice "JA DEBUG: Rebuild Repository checkpoint 4 workdir=${work_dir}"

#----------------------------------------------------------------------
# Read all package .info files, building manifest file
#----------------------------------------------------------------------

# Wipe and re-create the working directory
file delete -force $work_dir
file mkdir ${work_dir}
ns_log notice "change to $work_dir"
set update_pretty_date [lc_time_fmt [clock format [clock seconds] -format "%Y-%m-%d %T"] %c]
foreach channel [lsort -decreasing [array names channel_tag]] {
    ns_log notice "Repository: <h2>Channel $channel using tag $channel_tag($channel)</h2><ul>"
    
    # Wipe and re-create the checkout directory
    file delete -force "${work_dir}openacs-4"
    file delete -force "${work_dir}dotlrn"
    file mkdir "${work_dir}dotlrn/packages"
    
    # Prepare channel directory
    set channel_dir "${work_dir}repository/${channel}/"
    file mkdir $channel_dir
    ns_log notice "JA created channel_dir $channel_dir"

    # Store the list of packages we've seen for this channel, so we don't include the same package twice
    # Seems odd, but we have to do this given the forked packages sitting in /contrib
    set packages [list]
    
    # Checkout from the tag given by channel_tag($channel)
    if { $debug_p } {
    # Smaller list for debugging purposes
    set checkout_list [list \
                   $work_dir $cvs_root openacs-4/packages/acs-core-docs
              ]
    } else {
    # Full list for real use
    set checkout_list [list \
                   $work_dir $cvs_root openacs-4/packages \
                   $work_dir $cvs_root openacs-4/contrib/packages]
    }
    
    foreach { cur_work_dir cur_cvs_root cur_module } $checkout_list {
    cd $cur_work_dir
    if { ![string equal $channel_tag($channel) HEAD] } {
        ns_log notice "Repository: Checking out $cur_module from CVS (-r $channel_tag($channel)):"
        catch { exec $cd_helper $cur_work_dir cvs -d $cur_cvs_root -z3 co -r $channel_tag($channel) $cur_module } output
        ns_log notice "$output"
        ns_log notice "Repository: $cur_module [llength $output] files ($channel_tag($channel))"
    } else {
        ns_log notice "Repository: Checking out $cur_module from CVS (-r $channel_tag($channel)):"
        catch { exec $cd_helper $cur_work_dir cvs -d $cur_cvs_root -z3 co $cur_module } output
        ns_log notice "$output"
        ns_log notice "Repository: $cur_module [llength $output] files ($channel_tag($channel))"
    }
    }
    cd $work_dir

    ns_log notice "JA DEBUG: Rebuild Repository checkpoint 5"
    set manifest {<manifest>}
    append manifest \n

    template::multirow create packages \
    package_path package_key version pretty_name \
    package_type summary description \
    release_date vendor_url vendor \
        maturity maturity_text
   
    foreach packages_dir \
    [list "${work_dir}openacs-4/packages" \
         "${work_dir}openacs-4/contrib/packages" ] {
         
         foreach spec_file [lsort [apm_scan_packages $packages_dir]] {
             
             set package_path [eval file join [lrange [file split $spec_file] 0 end-1]]
             set package_key [lindex [file split $spec_file] end-1]
             
             if { [lsearch -exact $exclude_package_list $package_key] != -1 } {
             ns_log notice "Repository: Package $package_key is on list of packages to exclude - skipping"
             continue
             }

             if { [array exists version] } {
             array unset version
             }
             if { [info exists version] } {
             unset version
             }

             with_catch errmsg {
             array set version [apm_read_package_info_file $spec_file]
             
             if { [lsearch -exact $packages $version(package.key)] != -1 } {
                 ns_log notice "Repository: Skipping package $package_key, because we already have another version of it"
             } else {
                 lappend packages $version(package.key)
                 
                 append manifest {  } {<package>} \n
                 
                 append manifest {    } {<package-key>} [ns_quotehtml $version(package.key)] {</package-key>} \n
                 append manifest {    } {<version>} [ns_quotehtml $version(name)] {</version>} \n
                 append manifest {    } {<pretty-name>} [ns_quotehtml $version(package-name)] {</pretty-name>} \n
                 append manifest {    } {<package-type>} [ns_quotehtml $version(package.type)] {</package-type>} \n
                 append manifest {    } {<summary>} [ns_quotehtml $version(summary)] {</summary>} \n
                 append manifest {    } {<description format="} [ns_quotehtml $version(description.format)] {">} 
                 append manifest [ns_quotehtml $version(description)] {</description>} \n
                 append manifest {    } {<release-date>} [ns_quotehtml $version(release-date)] {</release-date>} \n
                 append manifest {    } {<vendor url="} [ns_quotehtml $version(vendor.url)] {">} 
                 append manifest [ns_quotehtml $version(vendor)] {</vendor>} \n
                 append manifest {    } {<license url="} [ns_quotehtml $version(license_url)] {">} 
                 append manifest [ns_quotehtml $version(license)] {</license>} \n
                 append manifest {    } {<maturity>} $version(maturity) {</maturity>} \n
                 if {![info exists version(maturity_text)]} {
                 set version(maturity_text) ""
                 }
                 template::multirow append packages \
                 $package_path $package_key $version(name) $version(package-name) \
                 $version(package.type) $version(summary) $version(description) \
                 $version(release-date) $version(vendor.url) $version(vendor) \
                                 $version(maturity) $version(maturity_text)

                 set apm_file "${channel_dir}${version(package.key)}-${version(name)}.apm"

                 ns_log notice "Repository: Building package $package_key for channel $channel"
                 
                 set files [apm_get_package_files \
                                            -all \
                        -include_data_model_files \
                        -all_db_types \
                        -package_key $version(package.key) \
                        -package_path $package_path]
                 
                 if { [llength $files] == 0 } {
                 ns_log notice "Repository: No files in package $version(package.key) ($channel)"
                 } else {
                 ns_log notice "Repository: [llength $files] files in package $version(package.key) ($channel)"
                 set cmd [list [apm_tar_cmd] cf -  2>/dev/null]

                 # The path to the 'packages' directory in the checkout
                 set packages_root_path [eval file join [lrange [file split $spec_file] 0 end-2]]
                 set tmp_filename [ns_mktemp "apm_build__XXXXXX"]
                 lappend cmd  --files-from $tmp_filename -C $packages_root_path

                 set fp [open $tmp_filename w]
                 foreach file $files {
                   puts $fp $package_key/$file
                   #puts $fp $packages_root_path/$package_key/$file
                 }
                 close $fp

                                 file mkdir $channel_dir
                 lappend cmd "|" [apm_gzip_cmd] -c ">" $apm_file
                 ns_log notice "ja channel_dir $channel_dir"
                 ns_log notice "Executing: $cmd"
                 cd $packages_root_path            ;# no idea, why this became necessary
                 if {[catch "exec $cd_helper $packages_root_path $cmd" msg]} {
                                    ns_log notice "Error during tar in repository creation for file ${channel_dir}${version(package.key)}-${version(name)}.apm: \n$msg\n$::errorCode,$::errorInfo"
                                 }
                 }

                 set apm_url "${repository_url}${channel}/${version(package.key)}-${version(name)}.apm"

                 append manifest {    } {<download-url>} $apm_url {</download-url>} \n
                 foreach elm $version(provides) {
                 append manifest {    } "<provides url=\"[ns_quotehtml [lindex $elm 0]]\" version=\"[ns_quotehtml [lindex $elm 1]]\" />" \n
                 }
                 
                 foreach elm $version(requires) {
                 append manifest {    } "<requires url=\"[ns_quotehtml [lindex $elm 0]]\" version=\"[ns_quotehtml [lindex $elm 1]]\" />" \n
                 }
                 
                 append manifest {  } {</package>} \n
             } 
             } {
             global errorInfo
             ns_log notice "Repository:  Error on spec_file $spec_file: [ns_quotehtml $errmsg]<br>[ns_quotehtml $errorInfo]\n"
             }
         }
         }
    append manifest {</manifest>} \n
    cd $work_dir
    
    ns_log notice "Repository: Writing $channel manifest to ${channel_dir}manifest.xml"
    set fw [open "${channel_dir}manifest.xml" w]
    puts $fw $manifest
    close $fw

    ns_log notice "Repository: Writing $channel index page to ${channel_dir}index.html"
    set fw [open "${channel_dir}index.html" w]
    
    # sort by package name
    set packages [lsort $packages]
    puts $fw [template::adp_include $channel_index_template [list channel $channel &packages packages update_pretty_date $update_pretty_date]]
    close $fw

    ns_log notice "Repository:  Channel $channel complete."
    
}

ns_log notice "Repository: Finishing Repository"

# Write the index page
ns_log notice "Repository: Writing repository index page to ${work_dir}repository/index.html"
set update_pretty_date [lc_time_fmt [clock format [clock seconds] -format "%Y-%m-%d %T"] %c]
template::multirow create channels name
foreach channel [lsort -decreasing [array names channel_tag]] {
    template::multirow append channels $channel
}
set fw [open "${work_dir}repository/index.html" w]
puts $fw [template::adp_include -- $index_template [list &channels channels update_pretty_date $update_pretty_date]]
close $fw


# Without the trailing slash
set work_repository_dirname "${work_dir}repository"
set repository_dirname [string range $repository_dir 0 end-1]
set repository_bak "[string range $repository_dir 0 end-1]_bak"

ns_log notice "Repository: Moving work repository $work_repository_dirname to live repository dir at <a href=\"/repository\/>$repository_dir</a>\n"

if { [file exists $repository_bak] } {
    file delete -force $repository_bak
}
if { [file exists $repository_dirname] } {
    file rename $repository_dirname $repository_bak
}
file rename $work_repository_dirname  $repository_dirname

ns_log notice "Repository: DONE"