sweeper 2.0.0 + add and/or, tooltips, moveset

This commit is contained in:
hummypkg 2014-06-12 17:45:11 +00:00
parent 270701873d
commit d5319e6f0d
12 changed files with 494 additions and 224 deletions

View File

@ -1 +0,0 @@
etc/sweeper.conf

View File

@ -1,9 +1,9 @@
Package: sweeper
Priority: optional
Section: misc
Version: 1.0.19
Version: 2.0.0
Architecture: mipsel
Maintainer: af123@hummypkg.org.uk
Depends: webif(>=1.0.14-8)
Description: Sweeper is a package for managing recordings in a variety of ways using custom rules [Add delete action. Some online help.]
Depends: webif(>=1.0.14-10)
Description: Sweeper is a package for managing recordings in a variety of ways using custom rules [Add and/or clauses. See forum.]
Tags: http://hummy.tv/forum/threads/5138/

View File

@ -69,67 +69,135 @@ proc ::sweeper::strcontains {ref val} {
>= 0]
}
######################################################################
# Rule criteria
proc ::sweeper::moveset {ts dst {op rename}} {
set file [$ts get file]
log "${op}set($file) -> $dst" 0
proc ::sweeper::flag {ts flag} {
# Handle alias for rename
if {$op eq "move"} { set op "rename" }
# Determine whether this is a cross-filesystem move.
file stat [$ts get file] sts
file stat $dst std
set xfs 0
if {$sts(dev) ne $std(dev)} {
log " Cross-filesystem - will copy then delete." 0
set xfs 1
}
set fset [lsort [$ts fileset]]
if {$xfs && $op eq "rename"} {
# For cross-filesystem moves, copy the whole file set
# and then delete the originals if all the copies were
# successful.
foreach f $fset {
set tail [file tail $f]
if {[catch {file copy $f "$dst/$tail"} msg]} {
log " ....... $f: XFS copy failed, $msg." 0
file delete -force "$dst/$tail"
log " .... Leaving originals intact." 0
return
}
log " ....... $f: OK" 0
}
log " Now deleting original files." 0
foreach f $fset {
set tail [file tail $f]
if {[file exists "$dst/$tail"] &&
[file size "$dst/$tail"] ==
[file size $f]} {
file tdelete $f
log " ....... $f: OK" 0
} else {
log " ....... $f: ERROR, sizes differ." 0
return
}
}
return
}
# Otherwise - copy or local FS move.
foreach f $fset {
set tail [file tail $f]
if {$op eq "copy" && [file exists "$dst/$tail"]} {
if {[file size "$dst/$tail"] == [file size $f]} {
log " ....... $f: Already copied." 2
continue
}
log "Deleting truncated copy $dst/$tail" 0
file tdelete "$dst/$tail"
}
log " ....... $f"
if {[catch {file $op $f "$dst/[file tail $f]"} msg]} {
log "$op failed, $msg.", 0
return
}
}
}
######################################################################
# Rule conditions
proc ::sweeper::flag {ts flag folder} {
return [$ts flag $flag]
}
proc ::sweeper::lcn {ts num} {
proc ::sweeper::lcn {ts num folder} {
return [::sweeper::intcomp [$ts get channel_num] $num]
}
proc ::sweeper::duration {ts dur} {
proc ::sweeper::duration {ts dur folder} {
return [::sweeper::intcomp [$ts duration] $dur]
}
proc ::sweeper::hour {ts str} {
proc ::sweeper::hour {ts str folder} {
set hour [clock format [$ts get start] -format "%H"]
return [::sweeper::intcomp $hour $str]
}
proc ::sweeper::schedduration {ts dur} {
proc ::sweeper::schedduration {ts dur folder} {
return [::sweeper::intcomp [$ts get scheddur] $dur]
}
proc ::sweeper::size {ts size} {
proc ::sweeper::size {ts size folder} {
return [::sweeper::intcomp [$ts size] $size]
}
proc ::sweeper::age {ts age} {
proc ::sweeper::age {ts age folder} {
set recage $(([clock seconds] - [$ts get end]) / 3600)
log " ... Recording age: $recage" 2
return [::sweeper::intcomp $recage $age]
}
proc ::sweeper::wage {ts age} {
proc ::sweeper::wage {ts age folder} {
set recage $(([clock seconds] - [$ts lastmod]) / 3600)
log " ... Watched age: $recage" 2
return [::sweeper::intcomp $recage $age]
}
proc ::sweeper::definition {ts def} {
proc ::sweeper::definition {ts def folder} {
return [::sweeper::strcontains [$ts get definition] $def]
}
proc ::sweeper::filename {ts str} {
proc ::sweeper::filename {ts str folder} {
return [::sweeper::strcontains [$ts bfile] $str]
}
proc ::sweeper::title {ts str} {
proc ::sweeper::title {ts str folder} {
return [::sweeper::strcontains [$ts get title] $str]
}
proc ::sweeper::synopsis {ts str} {
proc ::sweeper::synopsis {ts str folder} {
return [::sweeper::strcontains [$ts get synopsis] $str]
}
proc ::sweeper::guidance {ts str} {
proc ::sweeper::guidance {ts str folder} {
return [::sweeper::strcontains [$ts get guidance] $str]
}
proc ::sweeper::genre {ts genre} {
proc ::sweeper::genre {ts genre folder} {
set glist [ts genrelist]
set tsg [$ts get genre]
@ -139,7 +207,7 @@ proc ::sweeper::genre {ts genre} {
return 0
}
proc ::sweeper::lock {ts g} {
proc ::sweeper::lock {ts g folder} {
if {$g} {
if {![$ts flag Locked]} {
log "Locked recording." 0
@ -154,13 +222,13 @@ proc ::sweeper::lock {ts g} {
return 1
}
proc ::sweeper::folder_fflag {ts flag} {
proc ::sweeper::folder_fflag {ts flag folder} {
return [file exists "[file dirname [$ts get file]]/.$flag"]
}
######################################################################
proc ::sweeper::action {ts cmds} {
proc ::sweeper::action {ts cmds folder} {
global root
lassign $cmds cmd rest
@ -171,12 +239,19 @@ proc ::sweeper::action {ts cmds} {
continue { return 0 }
stop { return 1 }
preserve { return 1 }
copy -
copycreate -
move -
movecreate {
set rest [::sweeper::expand $ts $rest]
set dir [::sweeper::resolvedir $rest]
set create 0
if {[string range $cmd end-5 end] eq "create"} {
set create 1
set cmd [string range $cmd 0 end-6]
}
if {![file isdirectory $dir]} {
if {$cmd eq "move"} {
if {!$create} {
log " ... No such directory $dir" 2
return 1
}
@ -190,14 +265,11 @@ proc ::sweeper::action {ts cmds} {
}
}
}
log "Moving [$ts get file] to $rest" 0
foreach f [$ts fileset] {
log " ....... $f"
if {!$::sweeper::dryrun} {
file rename $f "$dir/[file tail $f]"
if {"$dir" ni $::sweeper::recalc} {
lappend ::sweeper::recalc $dir
}
log "$cmd [$ts get file] to $rest" 0
if {!$::sweeper::dryrun} {
::sweeper::moveset $ts $dir $cmd
if {"$dir" ni $::sweeper::recalc} {
lappend ::sweeper::recalc $dir
}
}
return 1
@ -291,7 +363,8 @@ proc ::sweeper::folder_apply {dir callback} {
proc ::sweeper:folder_merge {src dst {op rename}} {
if {$src eq $dst} return
log "Moving recordings from $src to $dst" 0
if {$op eq "move"} { set op "rename" }
log "$op recordings from $src to $dst" 0
foreach e [readdir -nocomplain $src] {
if {![string match {*.ts} $e]} continue
set entry "$src/$e"
@ -313,12 +386,7 @@ proc ::sweeper:folder_merge {src dst {op rename}} {
continue
}
foreach f [$ts fileset] {
if {$op eq "copy" \
&& [file exists "$dst/[file tail $f]"]} continue
log " ....... $f"
file $op $f "$dst/[file tail $f]"
}
::sweeper::moveset $ts $dst $op
}
if {$op eq "rename" && ![system rmdir_if_empty $src]} {
log "Failed to remove directory" 0
@ -331,7 +399,7 @@ proc ::sweeper:folder_merge {src dst {op rename}} {
}
}
proc ::sweeper::folder_action {ts cmds} {
proc ::sweeper::folder_action {ts cmds folder} {
global root
lassign $cmds cmd rest
@ -345,12 +413,19 @@ proc ::sweeper::folder_action {ts cmds} {
continue { return 0 }
stop { return 1 }
preserve { return 1 }
copycreate -
copy -
movecreate -
move {
set rest [::sweeper::expand $ts $rest]
set dir [::sweeper::resolvedir $rest]
set create 0
if {[string range $cmd end-5 end] eq "create"} {
set create 1
set cmd [string range $cmd 0 end-6]
}
if {![file isdirectory $dir]} {
if {$cmd eq "move"} {
if {!$create} {
log " ... No such directory $dir" 2
return 1
}
@ -365,7 +440,7 @@ proc ::sweeper::folder_action {ts cmds} {
}
}
if {!$::sweeper::dryrun} {
::sweeper:folder_merge $folder $dir
::sweeper:folder_merge $folder $dir $cmd
}
return 1
}
@ -450,6 +525,64 @@ proc ::sweeper::folder_action {ts cmds} {
return 0
}
proc ::sweeper::or {ts clause folder} {
log " --> OR:" 2
set ret 0
while {[llength $clause] > 1} {
set clause [lassign $clause cmd arg]
set ret [::sweeper::clause $folder $cmd $arg $ts]
if {$ret} {
log " <-- OR true." 2
break
}
}
if {!$ret} {
log " <-- OR false." 2
}
return $ret
}
proc ::sweeper::and {ts clause folder} {
log " --> AND:" 2
set ret 0
while {[llength $clause] > 1} {
set clause [lassign $clause cmd arg]
set ret [::sweeper::clause $folder $cmd $arg $ts]
if {!$ret} {
log " <-- AND false." 2
break
}
}
if {$ret} {
log " <-- AND true." 2
}
return $ret
}
proc ::sweeper::clause {folder cmd arg ts} {
log " $cmd\($arg)" 2
if {[string index $cmd 0] eq "!"} {
set negate 1
set cmd [string range $cmd 1 end]
} else {
set negate 0
}
if {$folder && [exists -proc ::sweeper::folder_$cmd]} {
set ret [::sweeper::folder_$cmd $ts $arg $folder]
} else {
set ret [::sweeper::$cmd $ts $arg $folder]
}
if {$cmd eq "action"} { return $ret }
if {$negate} { set ret $(!$ret) }
if {!$ret} {
log " Nomatch" 2
} else {
log " MATCH" 2
}
return $ret
}
proc ::sweeper::runrule {ts rule} {
log "Processing \[$rule]" 2
@ -462,25 +595,9 @@ proc ::sweeper::runrule {ts rule} {
}
while {[llength $rule] > 1} {
set rule [lassign $rule cmd arg]
log " $cmd\($arg)" 2
if {[string index $cmd 0] eq "!"} {
set negate 1
set cmd [string range $cmd 1 end]
} else {
set negate 0
}
if {$folder && [exists -proc ::sweeper::folder_$cmd]} {
set ret [::sweeper::folder_$cmd $ts $arg]
} else {
set ret [::sweeper::$cmd $ts $arg]
}
set ret [::sweeper::clause $folder $cmd $arg $ts]
if {$cmd eq "action"} { return $ret }
if {$negate} { set ret $(!$ret) }
if {!$ret} {
log " Nomatch" 2
break
}
log " MATCH" 2
if {!$ret} break
}
return 0
@ -498,12 +615,18 @@ proc ::sweeper::apply {dir cf} {
$fp close
set runfolder 0
set nrules 0
foreach rule $rules {
if {[lindex $rule 0] eq "folder"} { incr runfolder }
if {[string index $rule 0] ne "#" && [llength $rule] > 1} {
incr nrules
}
}
if {!$nrules} return
log "" 2
log "--- SWEEP SCAN STARTING FOR $dir ---" 2
log "--- SWEEP SCAN STARTING FOR $dir ($nrules) ---" 2
log "" 2
foreach e [readdir -nocomplain $dir] {
@ -530,7 +653,7 @@ proc ::sweeper::apply {dir cf} {
foreach rule $rules {
if {[lindex $rule 0] eq "folder"} continue
if {[string index $rule 0] eq "#" || \
if {[string index $rule 0] eq "#" ||
[llength $rule] < 2} continue
if {[::sweeper::runrule $ts $rule]} break
}
@ -608,7 +731,7 @@ proc ::sweeper::apply {dir cf} {
}
foreach rule $rules {
if {[string index $rule 0] eq "#" || \
if {[string index $rule 0] eq "#" ||
[llength $rule] < 2} continue
if {[lindex $rule 0] ne "folder"} continue
if {[::sweeper::runrule $ts $rule]} break

View File

@ -74,30 +74,29 @@ Add pre-defined ruleset:
</span>
<a class=enadisrule href=#>
<img src=img/disable.png
alt="Enable/Disable Rule"
title="Enable/Disable Rule">
</a>
<a class=delrule href=#>
<img src=/img/context/delete.png
alt="Delete Rule" title="Delete Rule">
title="Delete Rule">
</a>
<a class=cprule href=#>
<img src=/img/context/page_white_copy.png
alt="Duplicate Rule" title="Duplicate Rule">
title="Duplicate Rule">
</a>
<a class=uprule href=#>
<img src=/img/nav/up.png
alt="Move Rule Up" title="Move Rule Up">
title="Move Rule Up">
</a>
<a class=downrule href=#>
<img src=/img/nav/down.png
alt="Move Rule Down" title="Move Rule Down">
title="Move Rule Down">
</a>
</span>
</legend>
<a href=# class=addcriterion>
<img src=/img/context/plus.png
alt="Add condition" title="Add condition">
<img src=img/plus.png
title="Add condition">
</a>
<div class=criteria>
<table class="criteria"><tbody></tbody></table>
@ -153,7 +152,7 @@ Add pre-defined ruleset:
<select id=newcondition_cmd name=newcondition_cmd></select>
</td></tr><tr><th>Negate?</th><td>
<input id=newcondition_negate name=newcondition_negate type=checkbox
value='1' />
value='1' title="Invert the sense of the condition."/>
</td></tr>
</table>
</div>

View File

@ -0,0 +1,45 @@
source /mod/webif/lib/setup
require lock system.class ts.class pretty_size browse.class \
safe_delete settings.class plugin
proc log {msg {level 1}} {
puts "[\
clock format [clock seconds] -format "%d/%m/%Y %H:%M"\
] - $msg"
}
proc elapsed {start} {
return $(([clock milliseconds] - $start) / 1000.0)
}
proc startclock {} {
set ::startclock_s [clock milliseconds]
}
proc endclock {size} {
set el [elapsed $::startclock_s]
set rate $($size / $el)
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
}
proc register {args} {}
proc scan_run {dir flag callback} {
global dustbin
if {[string match {\[*} [file tail $dir]]} return
if {[file exists "$dir/.$flag"]} { $callback $dir }
foreach entry [readdir -nocomplain $dir] {
if {[file isdirectory "$dir/$entry"]} {
scan_run "$dir/$entry" $flag $callback
}
}
}
set root [system mediaroot]
source auto.hook

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -6,6 +6,10 @@ require system.class
set dir [cgi_get dir ""]
if {$dir eq "" && [llength $argv]} {
set dir [lindex $argv 0]
}
set root [system mediaroot]
if {$dir eq "" || $dir eq $root} {
@ -45,8 +49,43 @@ proc quot {str} {
return [cgi_quote_html $str]
}
set composite {and or}
proc clause {cmd arg {indent 6}} {
global lockfound composite
set istr [string repeat " " $indent]
if {[string index $cmd 0] eq "!"} {
set negate 1
set cmd [string range $cmd 1 end]
} else {
set negate 0
}
if {$cmd eq "lock"} { set lockfound $arg }
add_json "$istr{\n"
add_json "$istr \"negate\": $negate,\n"
add_json "$istr \"cmd\": \"[quot $cmd]\",\n"
add_json "$istr \"arg\": \"[quot $arg]\""
if {$cmd in $composite} {
add_json ",\n"
add_json "$istr \"criteria\": \[\n"
set c 0
while {[llength $arg] > 1} {
set arg [lassign $arg subcmd subarg]
if {$c} { add_json ",\n" }
incr c
clause $subcmd $subarg $($indent + 6)
}
add_json "\n$istr ]"
}
add_json "\n"
add_json "$istr}"
}
proc rule {id rule} {
global clausedescr lcomment
global lcomment lockfound
set enabled 1
if {[lindex $rule 0] eq "##"} {
@ -76,22 +115,11 @@ proc rule {id rule} {
set lockfound -1
while {[llength $rule] > 1} {
set rule [lassign $rule cmd arg]
if {[string index $cmd 0] eq "!"} {
set negate 1
set cmd [string range $cmd 1 end]
} else {
set negate 0
}
if {$cmd eq "action"} break
if {$cmd eq "lock"} { set lockfound $arg }
if {$c} { add_json ",\n" }
incr c
add_json " {\n"
add_json " \"negate\": $negate,\n"
add_json " \"cmd\": \"[quot $cmd]\",\n"
add_json " \"arg\": \"[quot $arg]\"\n"
add_json " }"
clause $cmd $arg
}
add_json "\n"
if {$cmd ne "action"} {

View File

@ -4,42 +4,49 @@ var schema = {
'class': 'all',
type: 'int',
desc: 'Logical Channel Number',
negate: true,
def: "0"
},
duration: {
'class': 'all',
type: 'int',
desc: 'Recording duration (in minutes)',
negate: true,
def: "0"
},
schedduration: {
'class': 'all',
type: 'int',
desc: 'Scheduled duration (in minutes)',
negate: true,
def: "0"
},
size: {
'class': 'all',
type: 'int',
desc: 'Recording size (in bytes)',
negate: true,
def: "0"
},
hour: {
'class': 'all',
type: 'int',
desc: 'Hour in which the recording started',
negate: true,
def: "0"
},
age: {
'class': 'all',
type: 'int',
desc: 'Age (in hours)',
negate: true,
def: "0"
},
wage: {
'class': 'all',
type: 'int',
desc: 'Time since last watched, or recorded (in hours)',
negate: true,
def: "0"
},
title: {
@ -47,6 +54,7 @@ var schema = {
type: 'substr',
desc: 'Recording Title contains',
idesc: 'Recording Title does not contain',
negate: true,
def: 'Enter text here...'
},
synopsis: {
@ -54,6 +62,7 @@ var schema = {
type: 'substr',
desc: 'Synopsis contains',
idesc: 'Synopsis does not contain',
negate: true,
def: 'Enter text here...'
},
guidance: {
@ -61,12 +70,14 @@ var schema = {
type: 'substr',
desc: 'Guidance Text contains',
idesc: 'Guidance Text does not contain',
negate: true,
def: 'Enter text here...'
},
genre: {
'class': 'all',
type: 'select',
desc: 'Recording Genre',
negate: true,
select: {
Unclassified: 'Unclassified',
Film: 'Film',
@ -84,6 +95,7 @@ var schema = {
'class': 'all',
type: 'select',
desc: 'Recording Definition',
negate: true,
select: {
SD: 'Standard Definition',
HD: 'High Definition'
@ -95,6 +107,7 @@ var schema = {
type: 'select',
desc: 'Recording Flagged as',
idesc: 'Recording not Flagged as',
negate: true,
select: {
Locked: 'Locked',
New: 'New',
@ -110,6 +123,7 @@ var schema = {
'class': 'all',
type: 'select',
desc: 'Change Recording Lock',
negate: true,
select: {
1: 'Lock Recording',
0: 'Unlock Recording'
@ -121,6 +135,8 @@ var schema = {
'class': 'all',
type: 'substr',
desc: 'Filename contains',
idesc: 'Filename does not contain',
negate: true,
def: 'Enter text here...'
},
fflag: {
@ -128,7 +144,24 @@ var schema = {
type: 'string',
desc: 'Folder flagged as',
idesc: 'Folder not flagged as',
negate: true,
def: 'nosweep'
},
'or': {
'class': 'all',
type: 'composite',
label: 'Or',
desc: 'If any of...',
negate: false,
def: ''
},
'and': {
'class': 'all',
type: 'composite',
label: 'And',
desc: 'If all of...',
negate: false,
def: ''
}
},
action: {
@ -150,24 +183,24 @@ var schema = {
desc: 'Move recording to folder...',
continues: false
},
lock: {
'class': 'all',
argtype: 'none',
desc: 'Lock recordings',
continues: true
},
unlock: {
'class': 'all',
argtype: 'none',
desc: 'Unlock recordings',
continues: true
},
movecreate: {
'class': 'all',
argtype: 'folder',
desc: 'Move recording to folder (creating if necessary)',
continues: false
},
copy: {
'class': 'all',
argtype: 'folder',
desc: 'Copy recording to folder...',
continues: false
},
copycreate: {
'class': 'all',
argtype: 'folder',
desc: 'Copy recording to folder (creating if necessary)',
continues: false
},
fileunder: {
'class': 'folder',
argtype: 'folder',
@ -187,6 +220,18 @@ var schema = {
desc: 'Rename recording files to...',
continues: true
},
lock: {
'class': 'all',
argtype: 'none',
desc: 'Lock recordings',
continues: true
},
unlock: {
'class': 'all',
argtype: 'none',
desc: 'Unlock recordings',
continues: true
},
delete: {
'class': 'all',
argtype: 'none',
@ -216,47 +261,38 @@ var macros = {
example: {
desc: 'Example rules',
rules: [
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} duration {&gt;= 90} action {move Children/Films}",
"name": "Move any Children's films (by length)",
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} or {duration {&gt;= 90} genre Film } action {move Children/Films}",
"name": "Move any Children's films",
"type": "file",
"enabled": "0",
"criteria": [
{
"negate": 0,
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"negate": 0,
"cmd": "lcn",
"arg": "&lt;= 79"
},
{
"cmd": "duration",
"arg": "&gt;= 90"
}
],
"action": {
"cmd": "move",
"arg": "Children/Films"
}
},
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} genre Film action {move Children/Films}",
"name": "Move any Children's films (by genre)",
"type": "file",
"enabled": "0",
"criteria": [
{
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"cmd": "lcn",
"arg": "&lt;= 79"
},
{
"cmd": "genre",
"arg": "Film"
"negate": 0,
"cmd": "or",
"arg": "duration {&gt;= 90} genre Film ",
"criteria": [
{
"negate": 0,
"cmd": "duration",
"arg": "&gt;= 90"
},
{
"negate": 0,
"cmd": "genre",
"arg": "Film"
}
]
}
],
"action": {

View File

@ -90,16 +90,20 @@ var getters = {
}
};
function ruleconf(rule)
function clauseconf(clause)
{
var s = '';
if (rule.hasClass('ruledisabled'))
s += '## ';
if (rule.attr('type') == 'folder')
s += 'folder ';
rule.find('tr.clause').each(function(i) {
clause.find('tbody:first > tr.clause,tbody:first > tr.compositeclause')
.each(function() {
if ($(this).hasClass('compositeclause'))
{
cc = clauseconf($(this).find('table:first'));
cmd = $(this).attr('cmd');
if (cc && cc.length)
s += cmd + ' {' + cc + '} ';
return;
}
cmd = $(this).find('th.cmd').attr('cmd');
negate = $(this).find('th.cmd').attr('negate');
c = schema.criterion[cmd];
@ -111,6 +115,19 @@ function ruleconf(rule)
s += '!';
s += cmd + ' ' + quot(val) + ' ';
});
return s;
}
function ruleconf(rule)
{
var s = '';
if (rule.hasClass('ruledisabled'))
s += '## ';
if (rule.attr('type') == 'folder')
s += 'folder ';
s += clauseconf(rule);
act = rule.find('tr.action th.cmd').attr('cmd');
arg = $.trim(rule.find('tr.action td.val').text());
@ -144,18 +161,23 @@ function rulerefresh(rule)
if (!showraw)
rule.find('.raw').hide();
rule.find('.raw').html(ruleconf(rule));
rule.find('tr.clause th.title').text('And:').first().text('If:');
if (rule.find('tr.clause').length < 1)
rule.find('tr.clause th.title,tr.compositeclause th.title')
.text('And:').first().text('If:');
rule.find('tr.compositeclause').each(function(e) {
cmd = $(this).attr('cmd');
label = schema.criterion[cmd].label;
$(this).find('table th.title').text(label + ':')
.first().text('If:');
});
if (rule.find('tr.clause,tr.compositeclause').length < 1)
{
rule.find('tr.action th.title').text('Always:');
rule.find('tr.otherwise').hide();
rule.find('div.criteria,div.arrow').hide();
rule.find('tr.otherwise,div.criteria,div.arrow').hide();
}
else
{
rule.find('tr.action th.title').text('Then:');
rule.find('tr.otherwise').show();
rule.find('div.criteria,div.arrow').show();
rule.find('tr.otherwise,div.criteria,div.arrow').show();
}
}
@ -172,7 +194,34 @@ function critdesc(cmd, negate)
return c.desc;
}
function criterion(data)
function composite_criterion(c, data)
{
s = '<tr class="compositeclause" cmd=' + data.cmd + '>' +
'<th class=title>And:</th>' +
'<td colspan=3>' +
'<table class=compositeclause>' +
'<tr><td colspan=4>' +
'<a href=# class=addsubcriterion>' +
'<img src=img/plus.png height=15 ' +
'title="Add condition to sub-clause"></a>' +
'&nbsp;' +
'<a class=delsubclause href=# ' +
'title="Delete sub-clause and the conditions within it">' +
'<img src=/img/context/delete.png></a>' +
'&nbsp;' +
c.desc +
'</td></tr>';
$.each(data.criteria, function(key, val) {
s += criterion(val, 'comp');
});
s += '</table></td></tr>';
return s;
}
function criterion(data, classes)
{
var c = schema.criterion[data.cmd];
var s;
@ -182,7 +231,12 @@ function criterion(data)
alert('Unknown Criterion (' + data.cmd + ')');
return;
}
s = '<tr class=clause><th class=title>And:</th>' +
if (c.type == 'composite')
return composite_criterion(c, data);
s = '<tr class="clause';
if (classes) s += ' ' + classes;
s += '"><th class=title>And:</th>' +
'<th class=cmd negate=' + data.negate + ' cmd=' + data.cmd + '>' +
critdesc(data.cmd, data.negate) + '</th><td class=val>';
@ -192,10 +246,10 @@ function criterion(data)
s += 'UNKNOWN (' + data.arg + ')';
s += '</td><td>' +
'<a class=editclause href=#>' +
'<a class=editclause href=# title="Edit condition">' +
'<img src=/img/context/edit.png></a>' +
'&nbsp;' +
'<a class=delclause href=#>' +
'<a class=delclause href=# title="Delete condition">' +
'<img src=/img/context/delete.png></a>' +
'</td></tr>';
return s;
@ -264,8 +318,12 @@ function addrule(id, data)
$.each(data.criteria, function(key, val) {
if (val.cmd == 'lock' && (
data.action.cmd == 'lock' || data.action.cmd == 'unlock'))
{
alert('Removed legacy lock/unlock - ' +
'check rules before saving.');
return;
$c.find('tbody').append(criterion(val));
}
$c.find('tbody:first').append(criterion(val));
});
$c.find('th.title:first').text('If:');
@ -599,7 +657,7 @@ $('#macros').on('click', '#b_macro', function(e) {
changed(0);
function addcriterion(rule)
function addcriterion(rule, target)
{
var type = rule.attr('type');
@ -616,6 +674,7 @@ function addcriterion(rule)
);
});
$('#newcondition_negate').prop('checked', false);
$('#newcondition_cmd').trigger('change');
$('#newcondition').dialog({
height: 'auto', width: 'auto',
@ -624,21 +683,22 @@ function addcriterion(rule)
position: {
my: 'bottom left',
at: 'top right',
of: rule
of: target
},
buttons: {
"Add Condition": function() {
$(this).dialog('close');
var id = rule.attr('id');
var val = $('#newcondition_cmd').val();
var negate = $('#newcondition_negate')
.prop('checked') ? '1' : '0';
rule.find('table.criteria tbody')
.append(criterion({
var obj = {
cmd: val,
negate: negate,
arg: schema.criterion[val].def
}));
arg: schema.criterion[val].def,
criteria: []
};
target.find('tbody:first')
.append(criterion(obj));
changed(1);
rulerefresh(rule);
},
@ -656,7 +716,8 @@ $('#ruleset')
})
.on('click', 'a.addcriterion', function(e) {
e.preventDefault();
addcriterion($(this).closest('div.rule'));
var rule = $(this).closest('div.rule');
addcriterion(rule, rule.find('table.criteria'));
})
.on('click', 'a.editcomment', function(e) {
e.preventDefault();
@ -827,6 +888,32 @@ $('#ruleset')
.html($('#empty_rulebase').html());
});
});
})
.on('click', 'a.delsubclause', function(e) {
e.preventDefault();
$(this).dojConfirmAction({
question: 'Delete sub-condition?',
yesAnswer: 'Yes',
cancelAnswer: 'No'
}, function(el) {
var rule = $(el).closest('div.rule');
$(el).closest('tr.compositeclause')
.fadeOut('slow', function() {
$(this).remove();
rulerefresh(rule);
changed(1);
});
});
})
.on('click', 'a.addsubcriterion', function(e) {
e.preventDefault();
var rule = $(this).closest('div.rule');
var clause = $(this).closest('table.compositeclause');
addcriterion(rule, clause);
})
.on('dblclick', 'div.raw', function(e) {
e.preventDefault();
$(this).toggleClass("rawvis");
});
$('#edit_action_act').on('change', function(e) {
@ -837,7 +924,17 @@ $('#ruleset')
$('#edit_action_arg').enable();
$('.edit_action_help').hide();
$('#edit_action_help_' + schema.action[cmd].argtype).show();
})
});
$('#newcondition_cmd').on('change', function(e) {
var cmd = $(this).val();
if (schema.criterion[cmd].negate)
$('#newcondition_negate').enable();
else
$('#newcondition_negate')
.prop('checked', false)
.disable();
});
// Set up macros
$.each(macros, function(key, val) {
@ -854,5 +951,7 @@ $('#ruleset')
});
loadrules($('span.dir').text());
$(document).tooltip();
});

View File

@ -62,6 +62,11 @@ div.raw
right: 12px;
}
div.rawvis
{
background: #ccc;
}
div#buttons
{
padding-top: 1em;
@ -107,6 +112,7 @@ span.legendright
table
{
border: 0;
line-height: 1em;
}
table th

View File

@ -1,50 +1,12 @@
#!/mod/bin/jimsh
source /mod/webif/lib/setup
require lock system.class ts.class tdelete pretty_size browse.class \
safe_delete settings.class plugin
source /mod/webif/plugin/sweeper/harness.jim
proc log {msg {level 1}} {
puts "[\
clock format [clock seconds] -format "%d/%m/%Y %H:%M"\
] - $msg"
if {![llength $argv]} {
::sweeper::scan 0
} else {
scan_run [lindex $argv 0] sweeper ::sweeper::sweep
}
proc elapsed {start} {
return $(([clock milliseconds] - $start) / 1000.0)
}
proc startclock {} {
set ::startclock_s [clock milliseconds]
}
proc endclock {size} {
set el [elapsed $::startclock_s]
set rate $($size / $el)
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
}
proc register {args} {}
proc scan_run {dir flag callback} {
global dustbin
if {[string match {\[*} [file tail $dir]]} return
if {[file exists "$dir/.$flag"]} { $callback $dir }
foreach entry [readdir -nocomplain $dir] {
if {[file isdirectory "$dir/$entry"]} {
scan_run "$dir/$entry" $flag $callback
}
}
}
set root [system mediaroot]
source auto.hook
::sweeper::scan 0
#::sweeper::apply $::root $::sweeper::cf

View File

@ -1,14 +1,11 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require lock system.class ts.class tdelete pretty_size browse.class \
safe_delete settings.class plugin
source /mod/webif/plugin/sweeper/harness.jim
httpheader
set dir [cgi_get dir ""]
set root [system mediaroot]
set cf "/tmp/sweepertest.cf"
@ -31,30 +28,6 @@ if {[catch {set fp [open $cf w]} msg]} {
$fp puts -nonewline $data
close $fp
proc log {msg {level 1}} {
puts $msg
}
proc elapsed {start} {
return $(([clock milliseconds] - $start) / 1000.0)
}
proc startclock {} {
set ::startclock_s [clock milliseconds]
}
proc endclock {size} {
set el [elapsed $::startclock_s]
set rate $($size / $el)
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
}
proc register {args} {}
set root [system mediaroot]
source auto.hook
set ::sweeper::dryrun 1
::sweeper::apply $dir $cf