#
# Copyright (c) 2011-2014, 2017-2018, 2026 LAAS/CNRS
# All rights reserved.
#
# Permission to use, copy, modify, and distribute this software for any purpose
# with or without   fee is hereby granted, provided   that the above  copyright
# notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS  SOFTWARE INCLUDING ALL  IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR  BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR  ANY DAMAGES WHATSOEVER RESULTING  FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION,   ARISING OUT OF OR IN    CONNECTION WITH THE USE   OR
# PERFORMANCE OF THIS SOFTWARE.
#
#                                            Anthony Mallet on Sun Jul 24 2011
#


# --- log2db ---------------------------------------------------------------
#
proc log2db { dir db path } {
  infox "Collecting session logs in $dir"

  set count 0
  set dir [file normalize $dir]
  set entries [glob -no -dir $dir -types d *]

  set db [opendb $db]

  # iterate over log dirs
  foreach ent $entries {
    incr count [dir2db $ent $db $path]
  }
  infox "processed $count packages"
  if {[llength $entries] > $count} {
    warnx "ignored [expr {[llength $entries] - $count}] packages"
  }

  # delete old db entries
  foreach ent $entries {
    purgedb $ent $db $path
    file delete -force $ent
  }

  # log session, delete (old?) session tags with no pkg
  foreach log [glob -no -dir $dir -types f *.log] {
    set f [open $log]; set data [read $f]; close $f
    set tag [file rootname [file tail $log]]
    set date [file mtime $log]
    $db eval {
      insert into session (tag, log, date, updates, running)
      values ($tag, $data, $date, $count, 0)
    }
    file delete $log
  }
  $db eval { delete from session where tag not in (select tag from pkg) }

  # analyze/vacuum
  closedb $db on
  return
}


# --- dir2db ---------------------------------------------------------------
#
proc dir2db { dir db path } {
  cd $dir
  if {![file exists meta.txt]} {
    warnx "skipping non-bulk log directory \"[file tail $dir]\""
    return 0
  }

  # read meta data
  set f [open meta.txt]
  while {[gets $f v] >= 0} {
    lappend meta([lindex $v 0]) {*}[lrange $v 1 end]
  }
  close $f
  if {![info exists meta(PKGPATH)] ||
      ![info exists meta(PKGBASE)] ||
      ![info exists meta(PKGNAME)] ||
      ![info exists meta(DATE_START)] ||
      ![info exists meta(DATE_STOP)] ||
      ![info exists meta(BULK_TAG)]} {
    warnx "skipping broken log directory \"[file tail $dir]\""
    return 0
  }
  if {[file exists cbbh.log]} { set meta(na) $meta(DATE_START) }
  if {[file exists sysdep.log]} { set meta(sysdep) $meta(DATE_START) }
  if {[file exists broken.log]} { set meta(broken) $meta(DATE_START) }
  if {[file exists pkg.log] || [file exists plist.log] ||
      [file exists mirror.log]} {
    set meta(warning) $meta(DATE_START)
  }
  if {[info exists meta(sysdep)] ||
      [info exists meta(broken)] ||
      [info exists meta(warning)] ||
      [info exists meta(na)]} {
    set meta(fixed) 1
  }

  # skip unwanted paths
  if {![string match ${path}* $meta(PKGPATH)]} {
    infox "skipped $meta(PKGNAME)"
    return 0
  }

  # get old meta
  $db eval {
    select pkgname, sysdep,broken,warning,na from meta natural join pkg
    where pkgbase = $meta(PKGBASE) and tag = $meta(BULK_TAG)
  } {
    # check same options
    if {[regsub {^[^~]*} $pkgname {}] ne [regsub {^[^~]*} $meta(PKGNAME) {}]} {
      continue
    }

    catch { unset meta(fixed) }

    if {(($sysdep ne "") ^ [info exists meta(sysdep)]) ||
        (($broken ne "") ^ [info exists meta(broken)]) ||
        (($warning ne "") ^ [info exists meta(warning)]) ||
        (($na ne "") ^ [info exists meta(na)])} {
      binary scan [expr {($sysdep ne "") ? "s" :
                         ($broken ne "") ? "b" :
                         ($warning ne "") ? "w" :
                         ($na ne "") ? "n" :
                         "\0"}] c code
      set meta(fixed) $code
    }
  }

  # record pkg
  $db eval {
    insert into pkg
    (tag, pkgname) values ($meta(BULK_TAG), $meta(PKGNAME))
  }
  set meta(id) [$db eval {
    select id from pkg where
    tag is $meta(BULK_TAG) and pkgname is $meta(PKGNAME)
  }]

  # record brokenby
  $db eval { delete from breaks where breaks is $meta(id) }
  if {[file exists brokenby.log]} {
    set f [open brokenby.log]
    while {[gets $f v] >= 0} {
      $db eval {
        select id from pkg where
        tag is $meta(BULK_TAG) and pkgname is $v
      } {
        $db eval {
          insert into breaks (id, breaks) values ($id, $meta(id))
        }
      }
    }
    close $f
  }

  # record meta
  $db eval {
    insert into meta
    (id, path, pkgbase, na, date_start, date_stop, warning, broken, sysdep,
     fixed)
    values ($meta(id), $meta(PKGPATH), $meta(PKGBASE), $meta(na),
            $meta(DATE_START), $meta(DATE_STOP), $meta(warning),
            $meta(broken), $meta(sysdep), $meta(fixed))
  }
  $db eval { delete from category where id is $meta(id) }
  foreach c $meta(CATEGORIES) {
    $db eval {
      insert into category (id, category) values ($meta(id), $c)
    }
  }

  # record logs
  $db eval {delete from log where id is $meta(id)}
  if {[info exists meta(na)] ||
      [info exists meta(sysdep)] ||
      [info exists meta(broken)] ||
      [info exists meta(warning)]} {
    foreach log [glob -no -types f *.log] {
      set f [open $log]; set data [read $f]; close $f
      $db eval {insert into log
        (id, file, data) values ($meta(id), $log, $data)
      }
    }
  }

  infox "updated $meta(PKGNAME)"
  return 1
}


# --- purgedb --------------------------------------------------------------
#
proc purgedb { dir db path } {
  cd $dir
  if {![file exists meta.txt]} { return 0 }

  # read meta data
  set f [open meta.txt]
  while {[gets $f v] >= 0} {
    lappend meta([lindex $v 0]) {*}[lrange $v 1 end]
  }
  close $f
  if {![info exists meta(PKGPATH)] ||
      ![info exists meta(AVAIL)] ||
      ![info exists meta(BULK_TAG)]} {
    return 0
  }

  # skip unwanted paths
  if {![string match ${path}* $meta(PKGPATH)]} { return 0 }

  # delete obsolete records
  $db eval [subst {
    select id from pkg natural join meta where
    tag = '$meta(BULK_TAG)' and path = '$meta(PKGPATH)'
    and pkgname not in ('[join $meta(AVAIL) {','}]')
  }] {
    $db eval { delete from pkg where id is $id }
    $db eval { delete from meta where id is $id }
    $db eval { delete from breaks where id is $id or breaks is $id}
    $db eval { delete from category where id is $id}
    $db eval { delete from log where id is $id }
  }

  return 1
}
package provide rbulk-report 20260610
