Patch title: Release 87 bulk changes
Abstract:
File: /pliant/appli/forum/patch.pli
Key:
    Removed line
    Added line
module "/pliant/language/unsafe.pli"
module "/pliant/language/stream.pli"
module "/pliant/admin/file.pli"
module "difference.pli"
module "/pliant/protocol/http/server.pli"
module "/pliant/protocol/http/style/default.style"
module "/pliant/util/remote/client.pli"
module "/pliant/admin/execute.pli"


method page study_live_changes reference_path live_path patch_path
  arg_rw HtmlPage page ; arg Str reference_path live_path patch_path
  implicit page
    var Array:FileInfo live := file_list live_path standard+recursive+relative
    table columns 2
      cell header [File] ; cell header [Status]
      for (var Int i) 0 live:size-1
        if live:i:extension<>".dump"
          var FileInfo f := file_query reference_path+live:i:name standard
          if f:datetime<>live:i:datetime
            cell
              fixed (text live:i:name)
            cell
              if (file_query patch_path+live:i:name standard)=defined
                var Str patch2 := file_temporary
                file_difference reference_path+live:i:name live_path+live:i:name patch2
                var Str file2 := file_temporary ; file_extract_new patch_path+live:i:name file2
                if (file_patch_apply patch2 "" file2 "" "")=success
                  [some more changes]
                else
                  [conflicting changes]
                file_delete patch2
                file_delete file2
              else
                [changed]

function catch_live_changes reference_path live_path filter patch_path rejected_path
  arg Str reference_path live_path filter patch_path rejected_path
  var Array:FileInfo live := file_list live_path standard+recursive+relative
  for (var Int i) 0 live:size-1
    if live:i:extension<>".dump"
      var FileInfo f := file_query reference_path+live:i:name standard
      if f:datetime<>live:i:datetime and (live:i:name 0 filter:len)=filter
        if (file_query patch_path+live:i:name standard)=defined
          var Str patch2 := file_temporary
          file_difference reference_path+live:i:name live_path+live:i:name patch2
          var Str file1 := file_temporary ; file_extract patch_path+live:i:name false "" file1 (var (Index Int Str) sections)
          var Str file2 := file_temporary ; file_extract patch_path+live:i:name true "" file2
          var Str final := file_temporary
          file_patch_apply patch2 "" file2 final rejected_path+live:i:name
          file_difference file1 final patch_path+live:i:name false sections
          file_copy live_path+live:i:name reference_path+live:i:name
          file_delete patch2
          file_delete file1 ; file_delete file2
          file_delete final
        else
          file_difference reference_path+live:i:name live_path+live:i:name patch_path+live:i:name false (null map (Index Int Str))
          file_copy live_path+live:i:name reference_path+live:i:name


method page study_patch reference_path patch_path section
  arg_rw HtmlPage page ; arg Str reference_path patch_path section
  implicit page
    var Array:FileInfo patch := file_list patch_path standard+recursive+relative
    table columns 2
      cell header [File] ; cell header [Status]
      for (var Int i) 0 patch:size-1
        if (file_extract patch_path+patch:i:name true section "")
          cell
            fixed (text patch:i:name)
          cell
            var Status status := file_patch_apply patch_path+patch:i:name section reference_path+patch:i:name "" ""
            text (shunt status=success "ok" "conflicting")

function apply_patch reference_path live_path patch_path section rejected_path
  arg Str reference_path live_path patch_path section rejected_path
  var Array:FileInfo patch := file_list patch_path standard+recursive+relative
  for (var Int i) 0 patch:size-1
    if (file_extract patch_path+patch:i:name true section "")
      file_patch_apply patch_path+patch:i:name section reference_path+patch:i:name reference_path+patch:i:name rejected_path+patch:i:name
      if live_path<>""
        file_copy reference_path+patch:i:name live_path+patch:i:name
 

method page study_reverse reference_path patch_path section
  arg_rw HtmlPage page ; arg Str reference_path patch_path section
  implicit page
    var Array:FileInfo patch := file_list patch_path standard+recursive+relative
    table columns 2
      cell header [File] ; cell header [Status]
      for (var Int i) 0 patch:size-1
        if (file_extract patch_path+patch:i:name true section "")
          cell
            fixed (text patch:i:name)
          cell
            var Str file1 := file_temporary ; file_extract patch_path+patch:i:name false section file1
            var Str file2 := file_temporary ; file_extract patch_path+patch:i:name true section file2
            var Str reverse := file_temporary ; file_difference file2 file1 reverse
            file_delete file1 ; file_delete file2
            var Status status := file_patch_apply reverse "" reference_path+patch:i:name "" ""
            text (shunt status=success "ok" "conflicting")
            file_delete reverse

function reverse_patch reference_path live_path patch_path section rejected_path
  arg Str reference_path live_path patch_path section rejected_path
  var Array:FileInfo patch := file_list patch_path standard+recursive+relative
  for (var Int i) 0 patch:size-1
    if (file_extract patch_path+patch:i:name true section "")
      var Str file1 := file_temporary ; file_extract patch_path+patch:i:name false section file1
      var Str file2 := file_temporary ; file_extract patch_path+patch:i:name true section file2
      var Str reverse := file_temporary ; file_difference file2 file1 reverse
      file_delete file1 ; file_delete file2
      file_patch_apply reverse "" reference_path+patch:i:name reference_path+patch:i:name rejected_path+patch:i:name
      file_delete reverse
      if live_path<>""
        file_copy reference_path+patch:i:name live_path+patch:i:name
 

method page study_upgrade reference_path patch_path
  arg_rw HtmlPage page ; arg Str reference_path patch_path

function upgrade_patch reference_path live_path patch_path rejected_path
  arg Str reference_path live_path patch_path rejected_path
 
  
function patch_pack path file -> status
  arg Str path file ; arg Status status
  (var Stream patch) open file out+safe
  patch writeline "Pliant patch"
  patch writeline ""
  status := patch file_tree_send path

function patch_unpack file path -> status
  arg Str file path ; arg ExtendedStatus status
  (var Stream patch) open file in+safe
  if patch:readline<>"Pliant patch"
    return failure:"This is not a Pliant patch file"
  while patch:readline<>""
    void
  file_tree_delete path
  status := patch file_tree_receive path
  

method page patch_tgz_download path official
  arg_rw HtmlPage page ; arg Str path official
  var Str dir := file_temporary+"/"
  var Str sub := official
  if sub<>"" and sub:0="/"
    sub := sub 1 sub:len
  if sub<>"" and (sub sub:len-1)<>"/"
    sub += "/"
  file_tree_create dir+sub
  var Array:FileInfo all := file_list path standard+recursive+relative
  for (var Int i) 0 all:size-1
    file_tree_create dir+sub+all:i:name
    file_extract_new path+all:i:name dir+sub+all:i:name
  var Str temp := file_temporary
  if (execute "tar -zc -f "+file_os_name:temp+" "+(shunt sub<>"" sub ".") path dir)=0
    page reset_http_answer
    page:http_request send_static_file temp "filter_binary"
    page:http_request send_static_file temp "mime [dq]binary/*[dq]"
  else
    page text "Failed to build the tarball !"
  file_tree_delete dir
  file_delete temp



export '. study_live_changes' catch_live_changes
export '. study_patch' apply_patch
export '. study_reverse' reverse_patch
export '. study_upgrade' upgrade_patch
export patch_pack patch_unpack
export '. patch_tgz_download'