From 9ec54b012c7e2e7d19c19a6155bb5da242b180b1 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Sun, 24 Feb 2013 17:56:44 +0100 Subject: [PATCH 01/35] SQL (sqlite) DB schema --- doc/schema.sql | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 doc/schema.sql diff --git a/doc/schema.sql b/doc/schema.sql new file mode 100644 index 0000000..d69e9fe --- /dev/null +++ b/doc/schema.sql @@ -0,0 +1,24 @@ +BEGIN TRANSACTION; +CREATE TABLE source_files ( + id INTEGER PRIMARY KEY, + filename TEXT UNIQUE COLLATE NOT NULL, + size INTEGER NOT NULL, + hash TEXT, + last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')) + last_seen INTEGER NOT NULL DEFAULT (strftime('%s','now')) +); +CREATE TABLE destinations ( + id INTEGER PRIMARY KEY, + path TEXT UNIQUE COLLATE NOT NULL +); +CREATE TABLE destination_files ( + id INTEGER PRIMARY KEY, + filename TEXT UNIQUE COLLATE NOT NULL, + last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), + to_delete NOT NULL DEFAULT 0, + update_needed NOT NULL DEFAULT 1, + FOREIGN KEY(source_file) REFERENCES source_files(id), + FOREIGN KEY(destination) REFERENCES destinations(id) +); + +COMMIT; From 29ce0c7b9791f67b290e61ab0816e23fa98c3ad6 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Sun, 24 Feb 2013 17:57:05 +0100 Subject: [PATCH 02/35] example config file --- doc/example.cfg | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 doc/example.cfg diff --git a/doc/example.cfg b/doc/example.cfg new file mode 100644 index 0000000..1982010 --- /dev/null +++ b/doc/example.cfg @@ -0,0 +1,36 @@ +[general] +max-load 6 +load-interval 30 +temporary-directory $HOME/.atom/tmp +debug 0 + +[source] +path /var/lib/mpd/music +id3charset iso-8859-15 +# you should not skip application/octet-stream, they could be somthing similar +# to "Audio file with ID3 version 2.4.0, unsynchronized frames" +skip_mime-type text/* +skip_mime-type image/* + +[Ogg] +path /mnt/Musique-OggQ2 +format vorbis +quality 1 +channels 2 +frequency 44100 + +[MP3] +path /mnt/Musique-mp3.test +format mp3 +bitrate 96 +# rename file, path unchanged +rename %{track}--%{artist}-%{title} +# change the whole filepath +#rename %{genre}/%{albumartist}/%{year}-%{album}/%{track}--%{artist}-%{title} + +[asterisk] +path /mnt/Musique-asterisk +format vorbis +channels 1 +frequency 8000 + From 380c9ac3afbf10d13e1fe9d28a26101ffbd8bba8 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Sun, 24 Feb 2013 18:25:25 +0100 Subject: [PATCH 03/35] add DB path in config --- doc/example.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/example.cfg b/doc/example.cfg index 1982010..853194b 100644 --- a/doc/example.cfg +++ b/doc/example.cfg @@ -2,6 +2,7 @@ max-load 6 load-interval 30 temporary-directory $HOME/.atom/tmp +database $HOME/.atom/atom.db debug 0 [source] From 2911ee43d480230c0b3a7ba94f68147bc3c41a1c Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Sun, 24 Feb 2013 21:50:15 +0100 Subject: [PATCH 04/35] mime-type exceptions per destination --- doc/example.cfg | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/example.cfg b/doc/example.cfg index 853194b..8d5bece 100644 --- a/doc/example.cfg +++ b/doc/example.cfg @@ -10,8 +10,6 @@ path /var/lib/mpd/music id3charset iso-8859-15 # you should not skip application/octet-stream, they could be somthing similar # to "Audio file with ID3 version 2.4.0, unsynchronized frames" -skip_mime-type text/* -skip_mime-type image/* [Ogg] path /mnt/Musique-OggQ2 @@ -19,6 +17,8 @@ format vorbis quality 1 channels 2 frequency 44100 +copy_mime-type image/* +copy_mime-type text/* [MP3] path /mnt/Musique-mp3.test @@ -28,10 +28,14 @@ bitrate 96 rename %{track}--%{artist}-%{title} # change the whole filepath #rename %{genre}/%{albumartist}/%{year}-%{album}/%{track}--%{artist}-%{title} +skip_mime-type image/* +skip_mime-type text/* [asterisk] path /mnt/Musique-asterisk format vorbis channels 1 frequency 8000 +skip_mime-type image/* +skip_mime-type text/* From c2be5814fac252841b8ee005ac17f2bf5806e1d0 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Sun, 24 Feb 2013 21:54:25 +0100 Subject: [PATCH 05/35] parse & dump config (features exposed there may or may not be implemented) --- atom | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 1 deletion(-) mode change 100644 => 100755 atom diff --git a/atom b/atom old mode 100644 new mode 100755 index c84441f..554bb2f --- a/atom +++ b/atom @@ -1,7 +1,196 @@ #!/bin/bash +## Define exit codes +# General config errors [10-19] +ELOAD=10 +EINTERVAL=11 +# Source cofig errors [20-29] +# Destination config errors [30-49] +EFORMAT=30 +ECHANNEL=31 +EFMTINVPARM=49 + +# config structures +declare -A \ + destinationchannels \ + destinationcopymime \ + destinationformat \ + destinationfrequency \ + destinationpath \ + destinationquality \ + destinationrename \ + destinationrenamepath \ + destinationskipmime \ +|| { + echo "Check your Bash version. You need >= 4.0" >&2 + exit $EBASHVERS +} + #parse arguments #parse config +getConfigGeneral() { + case $key in + 'max-load') + expr='^[0-9]*$' + if [[ $value =~ $expr ]] + then + maxload="$value" + else + echo "Invalid max-load value: $value" >&2 + exit $ELOAD + fi + unset expr + ;; + 'load-interval') + expr='^[0-9]*$' + if [[ $value =~ $expr ]] + then + loadinterval="$value" + else + echo "Invalid load-interval value: $value" >&2 + exit $EINTERVAL + fi + unset expr + ;; + 'temporary-directory') + tempdir="$value" + ;; + debug) + #unimplemented + ;; + esac +} + +getConfigSource() { + case "$key" in + 'path') + sourcepath="$value" + ;; + 'id3charset') + sourceid3charset="$value" + ;; + esac +} + +getConfigDestination() { + case "$key" in + 'path') + destinationpath["$destination"]="$value" + ;; + 'format') + case "$value" in + 'mp3') + destinationformat["$destination"]=mp3 + ;; + 'vorbis') + destinationformat["$destination"]=vorbis + ;; + *) + echo "Unsupported destination format: $value" >2& + exit $EFORMAT + ;; + esac + ;; + 'quality') + expr='^[0-9]*$' + if ! [[ $value =~ $expr ]] + then + echo "Invalid quality value: $value" >&2 + exit $EQUALITY + fi + unset expr + case "${destinationformat["$destination"]}" in + 'vorbis') + destinationquality["$destination"]="$value" + ;; + *) + echo "$Invalid parameter \"$key\" for format \"${destinationformat["$destination"]}\"" >&2 + exit $EFMTINVPARM + ;; + esac + ;; + 'bitrate') + expr='^[0-9]*$' + if ! [[ $value =~ $expr ]] + then + echo "Invalid bitrate value: $value" >&2 + exit $EQUALITY + fi + unset expr + case "${destinationformat["$destination"]}" in + 'mp3') + destinationquality["$destination"]="$value" + ;; + *) + echo "$Invalid parameter \"$key\" for format \"${destinationformat["$destination"]}\"" >&2 + exit $EFMTINVPARM + ;; + esac + ;; + 'channels') + expr='^[0-9]*$' + if ! [[ $value =~ $expr ]] + then + echo "Invalid channel count: $value" >&2 + exit $ECHANNEL + fi + unset expr + destinationchannels["$destination"]=$value + ;; + 'frequency') + expr='^[0-9]*$' + if ! [[ $value =~ $expr ]] + then + echo "Invalid frequency value: $value" >&2 + exit $ECHANNEL + fi + unset expr + destinationfrequency["$destination"]=$value + ;; + 'rename') + case "$value" in + */*) + destinationrenamepath["$destination"]="${value%/*}" + ;; + esac + destinationrename["$destination"]="${value##*/}" + ;; + 'skip_mime-type') + destinationskipmime[$destination]="${destinationskipmime[$destination]:+${destinationskipmime[$destination]}|}$value" + ;; + 'copy_mime-type') + destinationcopymime[$destination]="${destinationcopymime[$destination]:+${destinationcopymime[$destination]}|}$value" + ;; + esac +} +getConfig() { + while read key value + do + case $key in + '#'*) + #comment + ;; + '') + #empty line + ;; + '[general]') + context=General + ;; + '[source]') + context=Source + ;; + \[*\]) + context=Destination + destination="${key#[}" + destination="${destination%]}" + ;; + *) + getConfig$context + ;; + esac + done < ~/.atom/atom.cfg +} + #check sanity getFiles() { @@ -89,5 +278,33 @@ transcodeLauncher() { } #UI +getConfig +{ +cat < Date: Mon, 25 Feb 2013 11:53:26 +0100 Subject: [PATCH 06/35] fix schema --- {doc => share}/schema.sql | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) rename {doc => share}/schema.sql (57%) diff --git a/doc/schema.sql b/share/schema.sql similarity index 57% rename from doc/schema.sql rename to share/schema.sql index d69e9fe..c644b44 100644 --- a/doc/schema.sql +++ b/share/schema.sql @@ -1,24 +1,26 @@ BEGIN TRANSACTION; CREATE TABLE source_files ( id INTEGER PRIMARY KEY, - filename TEXT UNIQUE COLLATE NOT NULL, + filename TEXT UNIQUE NOT NULL, size INTEGER NOT NULL, hash TEXT, - last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')) + last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), last_seen INTEGER NOT NULL DEFAULT (strftime('%s','now')) ); CREATE TABLE destinations ( id INTEGER PRIMARY KEY, - path TEXT UNIQUE COLLATE NOT NULL + path TEXT UNIQUE NOT NULL ); CREATE TABLE destination_files ( id INTEGER PRIMARY KEY, - filename TEXT UNIQUE COLLATE NOT NULL, + filename TEXT UNIQUE NOT NULL, last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), to_delete NOT NULL DEFAULT 0, update_needed NOT NULL DEFAULT 1, - FOREIGN KEY(source_file) REFERENCES source_files(id), - FOREIGN KEY(destination) REFERENCES destinations(id) + source_file_id INTEGER, + destination_id INTEGER, + FOREIGN KEY (source_file_id) REFERENCES source_files(id), + FOREIGN KEY (destination_id) REFERENCES destinations(id) ); COMMIT; From 3d9786cc6c55bcbb3f7d9087b9b253ba6ed9b141 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 12:53:58 +0100 Subject: [PATCH 07/35] example config: improve readability, make paths sed'able --- doc/example.cfg | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/example.cfg b/doc/example.cfg index 8d5bece..3e9f5f3 100644 --- a/doc/example.cfg +++ b/doc/example.cfg @@ -1,15 +1,13 @@ [general] max-load 6 load-interval 30 -temporary-directory $HOME/.atom/tmp -database $HOME/.atom/atom.db +temporary-directory %HOME%/.atom/tmp +database %HOME%/.atom/atom.db debug 0 [source] path /var/lib/mpd/music id3charset iso-8859-15 -# you should not skip application/octet-stream, they could be somthing similar -# to "Audio file with ID3 version 2.4.0, unsynchronized frames" [Ogg] path /mnt/Musique-OggQ2 @@ -17,6 +15,9 @@ format vorbis quality 1 channels 2 frequency 44100 + +# you should not skip or copy application/octet-stream, they could be something +# similar to "Audio file with ID3 version 2.4.0, unsynchronized frames" copy_mime-type image/* copy_mime-type text/* @@ -24,6 +25,7 @@ copy_mime-type text/* path /mnt/Musique-mp3.test format mp3 bitrate 96 + # rename file, path unchanged rename %{track}--%{artist}-%{title} # change the whole filepath From 62b3b2ff297ede7a810741bdd648c9139b2a6eb9 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 13:03:58 +0100 Subject: [PATCH 08/35] create user configuration file, entice user to change it --- atom | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/atom b/atom index 554bb2f..b1aa548 100755 --- a/atom +++ b/atom @@ -4,6 +4,7 @@ # General config errors [10-19] ELOAD=10 EINTERVAL=11 +ENOCFG=19 # Source cofig errors [20-29] # Destination config errors [30-49] EFORMAT=30 @@ -26,6 +27,9 @@ declare -A \ exit $EBASHVERS } +DOCDIR=./doc +exampleconf=$DOCDIR/example.cfg + #parse arguments #parse config getConfigGeneral() { @@ -278,6 +282,23 @@ transcodeLauncher() { } #UI + +if [ ! -f ~/.atom/atom.cfg ] +then + if [ ! -d ~/.atom ] + then + mkdir -p ~/.atom + fi + sed "s/%HOME%/$HOME/" "$exampleconf" ~/.atom/atom.cfg + cat >&2 <<-EOCfgNotice + No configuration file found! + An example file has been created as ~/.atom/atom.cfg. + You should change it to your likings using you favorite editor. + + Bailing out. + EOCfgNotice + exit $ENOCFG +fi getConfig { cat < Date: Mon, 25 Feb 2013 13:11:07 +0100 Subject: [PATCH 09/35] create, open and close database --- atom | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/atom b/atom index b1aa548..a122d94 100755 --- a/atom +++ b/atom @@ -28,7 +28,9 @@ declare -A \ } DOCDIR=./doc +SHAREDIR=./share exampleconf=$DOCDIR/example.cfg +schema=$SHAREDIR/schema.sql #parse arguments #parse config @@ -59,6 +61,9 @@ getConfigGeneral() { 'temporary-directory') tempdir="$value" ;; + 'database') + database="$value" + ;; debug) #unimplemented ;; @@ -197,6 +202,33 @@ getConfig() { #check sanity +openDatabase() { + if [ ! -d "$tempdir" ] + then + mkdir -p "$tempdir" + fi + mkfifo "$tempdir"/sqlite.{in,out} + if [ ! -f "$database" ] + then + if [ ! -d "${database%/*}" ] + then + mkdir -p "${database%/*}" + fi + sqlite3 "$database" < $schema + fi + sqlite3 -line "$database" \ + < "$tempdir/sqlite.in" \ + > "$tempdir/sqlite.out" & + exec 3> "$tempdir"/sqlite.in + exec 4< "$tempdir"/sqlite.out +} + +closeDatabase() { + exec 3>&- + exec 4<&- + rm "$tempdir"/sqlite.{in,out} +} + getFiles() { : } @@ -328,4 +360,8 @@ echo "|Copied mime-type|${destinationcopymime[$destination]//\|/ done }|column -t -s'|' -n +openDatabase + +closeDatabase + # vim:set ts=8 sw=8: From d285884090142d11ea21e8139b991c79d19a091c Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 15:51:34 +0100 Subject: [PATCH 10/35] basic SQL functions --- atom | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/atom b/atom index a122d94..1de77d0 100755 --- a/atom +++ b/atom @@ -229,6 +229,190 @@ closeDatabase() { rm "$tempdir"/sqlite.{in,out} } +Select() { +#Select table [col1 [col2 [..]]] < WHERE_key WHERE_value +# [WHERE_key WHERE_value +# […]] + local \ + table="$1" \ + col \ + columns \ + results \ + where_statement + shift + for col + do + (( ${#columns} )) && columns+=',' + columns+="$col" + done + while read key value + do + (( ${#where_statement} )) && where_statement+=( "AND" ) + if [[ $value == NULL ]] + then + where_statement+=( "$key is NULL" ) + else + where_statement+=( "$key='$value'" ) + fi + done + echo "SELECT IFNULL(" \ + "(SELECT $columns FROM $table" \ + "WHERE ${where_statement[@]})" \ + ",'SQL::Select:not found'" \ + ");" >&3 + read -u 4 results + if ! [[ $results == "SQL::Select:not found" ]] + then + echo "$results" + else + return 1 + fi +} +Insert() { +#Insert table [no_id] < key value +# [key value +# […]] + local \ + table="$1" \ + no_id="${2:-0}" \ + insert_keys \ + insert_values \ + results + while read key value + do + (( ${#insert_keys} )) && insert_keys+="," + insert_keys+='`'"$key"'`' + (( ${#insert_values} )) && insert_values+="," + if [[ $value == NULL ]] + then + insert_values+="NULL" + else + insert_values+='"'"${value//\"/\\\"}"'"' + fi + done + echo "INSERT INTO $table" \ + "( $insert_keys )" \ + "VALUES" \ + "( $insert_values );" >&3 + (( no_id )) || { + echo 'SELECT LAST_INSERT_ID();' >&3 + read -u 4 results + echo "$results" + } +} +Update(){ +#Update table set_key set_value [set_key set_value […]] < where_key where_value +# [where_key where_value +# […]] + local \ + table="$1" \ + key \ + argument \ + value \ + set_statement \ + where_keys \ + where_values \ + what \ + where_statement \ + results + shift + what=key + for argument + do + case $what in + key) + set_statement="${set_statement:+${set_statement+,}}\`$argument\`" + what=value + ;; + value) + set_statement="${set_statement}='$argument'" + what=key + ;; + esac + done + while read key value + do + (( ${#where_statement} )) && where_statement+=( "AND" ) + if [[ $value == NULL ]] + then + where_statement+=( "$key is NULL" ) + else + where_statement+=( "$key='$value'" ) + fi + done + echo "UPDATE '$table' SET" \ + "$set_statement" \ + "WHERE" \ + "${where_statement[@]}" \ + ";" >&3 +} +InsertOrUpdate() { +#InsertOrUpdate table set_key set_value [set_key set_value […]] < where_key where_value +# [where_key where_value +# […]] + local \ + table="$1" \ + argument \ + key \ + keys \ + set_keys \ + set_values \ + value \ + values \ + what \ + results + shift + what=key + for argument + do + case $what in + key) + set_keys+=( "$argument" ) + what=value + ;; + value) + set_values+=( "$argument" ) + what=key + ;; + esac + done + while read key value + do + keys+=( "$key" ) + values+=( "$value" ) + done + if results=$( + Select "$table" id < <( + for key in ${!keys[@]} + do + echo "${keys[$key]}" "${values[$key]}" + done + ) + ) + then + Update "$table" "$@" < <( + for key in ${!keys[@]} + do + echo "${keys[$key]}" "${values[$key]}" + done + ) + else + results=$( + Insert "$table" < <( + for key in ${!set_keys[@]} + do + echo "${set_keys[$key]}" "${set_values[$key]}" + done + for key in ${!keys[@]} + do + echo "${keys[$key]}" "${values[$key]}" + done + ) + ) + fi + echo "$results" +} + getFiles() { : } From 66f816c5d4c8ee5b61b42dd199309495681bd252 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 16:25:40 +0100 Subject: [PATCH 11/35] beginner error... --- atom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom b/atom index 1de77d0..8132a5e 100755 --- a/atom +++ b/atom @@ -505,7 +505,7 @@ then then mkdir -p ~/.atom fi - sed "s/%HOME%/$HOME/" "$exampleconf" ~/.atom/atom.cfg + sed "s:%HOME%:$HOME:" "$exampleconf" > ~/.atom/atom.cfg cat >&2 <<-EOCfgNotice No configuration file found! An example file has been created as ~/.atom/atom.cfg. From 2dbe51bd29b1a10685b2bd95e4b6a00eaf377032 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 17:07:53 +0100 Subject: [PATCH 12/35] sqlite is not mysql --- atom | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atom b/atom index 8132a5e..8e70de2 100755 --- a/atom +++ b/atom @@ -261,6 +261,7 @@ Select() { ",'SQL::Select:not found'" \ ");" >&3 read -u 4 results + results="${results# = }" if ! [[ $results == "SQL::Select:not found" ]] then echo "$results" @@ -295,8 +296,9 @@ Insert() { "VALUES" \ "( $insert_values );" >&3 (( no_id )) || { - echo 'SELECT LAST_INSERT_ID();' >&3 + echo 'SELECT LAST_INSERT_ROWID();' >&3 read -u 4 results + results="${results# = }" echo "$results" } } @@ -410,6 +412,7 @@ InsertOrUpdate() { ) ) fi + results="${results# = }" echo "$results" } From 1c253abfc02c34e16aedc3b75e7cf5b30c96537f Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 17:13:14 +0100 Subject: [PATCH 13/35] fix SET statement in Update() --- atom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom b/atom index 8e70de2..63d19b2 100755 --- a/atom +++ b/atom @@ -323,7 +323,7 @@ Update(){ do case $what in key) - set_statement="${set_statement:+${set_statement+,}}\`$argument\`" + set_statement="${set_statement:+${set_statement},}\`$argument\`" what=value ;; value) From 51dea2ea17b5504b880eddd5ff1c28f30f7a66cd Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 17:18:29 +0100 Subject: [PATCH 14/35] sqlite is not mysql part 2: fix parameter expansion --- atom | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom b/atom index 63d19b2..d962645 100755 --- a/atom +++ b/atom @@ -261,7 +261,7 @@ Select() { ",'SQL::Select:not found'" \ ");" >&3 read -u 4 results - results="${results# = }" + results="${results#* = }" if ! [[ $results == "SQL::Select:not found" ]] then echo "$results" @@ -298,7 +298,7 @@ Insert() { (( no_id )) || { echo 'SELECT LAST_INSERT_ROWID();' >&3 read -u 4 results - results="${results# = }" + results="${results#* = }" echo "$results" } } @@ -412,7 +412,7 @@ InsertOrUpdate() { ) ) fi - results="${results# = }" + results="${results#* = }" echo "$results" } From e1d592a964119909f9f857f5650944272d1e7dac Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 17:29:57 +0100 Subject: [PATCH 15/35] safer variable handling --- atom | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom b/atom index d962645..fad28d1 100755 --- a/atom +++ b/atom @@ -252,7 +252,7 @@ Select() { then where_statement+=( "$key is NULL" ) else - where_statement+=( "$key='$value'" ) + where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) fi done echo "SELECT IFNULL(" \ @@ -327,7 +327,7 @@ Update(){ what=value ;; value) - set_statement="${set_statement}='$argument'" + set_statement="${set_statement}="'"'"${value//\"/\\\"}"'"' what=key ;; esac @@ -339,7 +339,7 @@ Update(){ then where_statement+=( "$key is NULL" ) else - where_statement+=( "$key='$value'" ) + where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) fi done echo "UPDATE '$table' SET" \ From 00635b3ce9954e4bf37f6d744983668eff0ea767 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Mon, 25 Feb 2013 17:33:36 +0100 Subject: [PATCH 16/35] populate source_files table --- atom | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/atom b/atom index fad28d1..55ff687 100755 --- a/atom +++ b/atom @@ -417,7 +417,22 @@ InsertOrUpdate() { } getFiles() { - : + scantime=$(date +%s) + while read time size filename + do + sourcefileid=$( + InsertOrUpdate source_files \ + last_change ${time%.*} \ + size $size \ + last_seen $scantime \ + <<-EOWhere + filename $filename + EOWhere + ) + echo $sourcefileid "$filename" + done < <( + find "$sourcepath" -type f -printf "%T@ %s %P\n" + ) } getType() { @@ -549,6 +564,8 @@ done openDatabase +getFiles + closeDatabase # vim:set ts=8 sw=8: From f50fcdb8f0f96218e53787678a8ba69e6a8c5352 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 02:11:40 +0100 Subject: [PATCH 17/35] use a transaction for getFiles --- atom | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atom b/atom index 55ff687..a370c32 100755 --- a/atom +++ b/atom @@ -418,6 +418,8 @@ InsertOrUpdate() { getFiles() { scantime=$(date +%s) + # We probably have thousands of files, don't waste time on disk writes + echo 'BEGIN TRANSACTION;' >&3 while read time size filename do sourcefileid=$( @@ -429,10 +431,11 @@ getFiles() { filename $filename EOWhere ) - echo $sourcefileid "$filename" + echo -ne '\r'$sourcefileid done < <( find "$sourcepath" -type f -printf "%T@ %s %P\n" ) + echo 'COMMIT;' >&3 } getType() { From a6f4b94099c53f0911d4cb0d365342c256f51551 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 02:12:20 +0100 Subject: [PATCH 18/35] add index o source_file.filename --- share/schema.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/share/schema.sql b/share/schema.sql index c644b44..78ff9e2 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -23,4 +23,6 @@ CREATE TABLE destination_files ( FOREIGN KEY (destination_id) REFERENCES destinations(id) ); +CREATE INDEX sourcefiles_by_name ON source_files (filename,id); + COMMIT; From c6e84b1056568ec16f8d7efe3b7f9faff5f738ef Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 02:54:43 +0100 Subject: [PATCH 19/35] InsertOrUpdate SQL function --- atom | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/atom b/atom index a370c32..58475b5 100755 --- a/atom +++ b/atom @@ -348,6 +348,48 @@ Update(){ "${where_statement[@]}" \ ";" >&3 } +InsertIfUnset() { +#InsertIfUnset table [no_id] < key value \n key value + local \ + table="$1" \ + no_id="${2:-0}" \ + column \ + key \ + keys \ + results \ + value \ + values + while read key value + do + keys+=( "$key" ) + values+=( "$value" ) + done + if (( no_id )) + then + column="${keys[0]}" + else + column='id' + fi + if ! results=$( + Select "$table" "$column" < <( + for key in ${!keys[@]} + do + echo "${keys[$key]}" "${values[$key]}" + done + ) + ) + then + results=$( + Insert "$table" < <( + for key in ${!keys[@]} + do + echo "${keys[$key]}" "${values[$key]}" + done + ) + ) + fi + echo "$results" +} InsertOrUpdate() { #InsertOrUpdate table set_key set_value [set_key set_value […]] < where_key where_value # [where_key where_value From efe661615cf434112fe930f933c06194cdb0d566 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 02:55:19 +0100 Subject: [PATCH 20/35] populate destinations table --- atom | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/atom b/atom index 58475b5..01a8069 100755 --- a/atom +++ b/atom @@ -17,6 +17,7 @@ declare -A \ destinationcopymime \ destinationformat \ destinationfrequency \ + destinationid \ destinationpath \ destinationquality \ destinationrename \ @@ -458,6 +459,23 @@ InsertOrUpdate() { echo "$results" } +createDestinations() { + for destination in ${!destinationpath[@]} + do + if ! [ -d "${destinationpath["$destination"]}" ] + then + if ! mkdir -p "${destinationpath["$destination"]}" + then + echo "$destination: Could not create ${destinationpath["$destination"]}!" + exit $EINVDEST + fi + fi + destinationid["$destination"]=$( + InsertIfUnset destinations <<<"name $destination" + ) + done +} + getFiles() { scantime=$(date +%s) # We probably have thousands of files, don't waste time on disk writes @@ -609,6 +627,8 @@ done openDatabase +createDestinations + getFiles closeDatabase From 6d45a634b7e340fd638339e4dc58bedf29f6c760 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 11:18:06 +0100 Subject: [PATCH 21/35] Update(): used wrong variables --- atom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom b/atom index 01a8069..4358cb8 100755 --- a/atom +++ b/atom @@ -328,7 +328,7 @@ Update(){ what=value ;; value) - set_statement="${set_statement}="'"'"${value//\"/\\\"}"'"' + set_statement="${set_statement}="'"'"${argument//\"/\\\"}"'"' what=key ;; esac From 611d4ad1af772523387fa4ecbff3b8e857cfc575 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 11:20:37 +0100 Subject: [PATCH 22/35] change column name, remove useless columns --- share/schema.sql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/share/schema.sql b/share/schema.sql index 78ff9e2..0cf08fc 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -9,14 +9,12 @@ CREATE TABLE source_files ( ); CREATE TABLE destinations ( id INTEGER PRIMARY KEY, - path TEXT UNIQUE NOT NULL + name TEXT UNIQUE NOT NULL ); CREATE TABLE destination_files ( id INTEGER PRIMARY KEY, filename TEXT UNIQUE NOT NULL, last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), - to_delete NOT NULL DEFAULT 0, - update_needed NOT NULL DEFAULT 1, source_file_id INTEGER, destination_id INTEGER, FOREIGN KEY (source_file_id) REFERENCES source_files(id), From b1e35f038a1048f1e25d9e1dc121b36b3e7de8f3 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 11:21:47 +0100 Subject: [PATCH 23/35] remove (potentially) harmful constraints on destination_files.filename --- share/schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/schema.sql b/share/schema.sql index 0cf08fc..5b854ca 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE destinations ( ); CREATE TABLE destination_files ( id INTEGER PRIMARY KEY, - filename TEXT UNIQUE NOT NULL, + filename TEXT, last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), source_file_id INTEGER, destination_id INTEGER, From 0ce73ac805efedf9bf586c843402399e1e683f65 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 11:22:53 +0100 Subject: [PATCH 24/35] add triggers on source_files insert/delete --- share/schema.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/share/schema.sql b/share/schema.sql index 5b854ca..89ca5bf 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -23,4 +23,16 @@ CREATE TABLE destination_files ( CREATE INDEX sourcefiles_by_name ON source_files (filename,id); +CREATE TRIGGER create_destinations AFTER INSERT ON source_files +BEGIN + INSERT INTO destination_files (source_file_id,destination_id) + SELECT source_files.id,destinations.id FROM source_files + INNER JOIN destinations + WHERE source_files.id=new.id; +END; +CREATE TRIGGER delete_destinations_files AFTER DELETE ON source_files +BEGIN + UPDATE destination_files SET source_file_id=NULL WHERE source_file_id=old.id; +END; + COMMIT; From 48716f325104385c28c6a7d8383f137b5d2f4447 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 11:43:21 +0100 Subject: [PATCH 25/35] Delete() function --- atom | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/atom b/atom index 4358cb8..d0fc6fe 100755 --- a/atom +++ b/atom @@ -458,6 +458,28 @@ InsertOrUpdate() { results="${results#* = }" echo "$results" } +Delete() { +#Delete table < where_key where_value +# [where_key where_value +# […]] + local \ + table="$1" \ + key \ + value \ + where_statement \ + results + while read key value + do + (( ${#where_statement} )) && where_statement+=( "AND" ) + if [[ $value == NULL ]] + then + where_statement+=( "$key is NULL" ) + else + where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) + fi + done + echo "DELETE from $table WHERE ${where_statement[@]};" >&3 +} createDestinations() { for destination in ${!destinationpath[@]} @@ -496,6 +518,7 @@ getFiles() { find "$sourcepath" -type f -printf "%T@ %s %P\n" ) echo 'COMMIT;' >&3 + echo } getType() { From 38d248af427ccdf74d7c46f2ff832db0dfa46594 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 12:12:05 +0100 Subject: [PATCH 26/35] Flexible WHERE clauses --- atom | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/atom b/atom index d0fc6fe..2465ac4 100755 --- a/atom +++ b/atom @@ -231,13 +231,14 @@ closeDatabase() { } Select() { -#Select table [col1 [col2 [..]]] < WHERE_key WHERE_value -# [WHERE_key WHERE_value +#Select table [col1 [col2 [..]]] < WHERE_key WHERE_operator WHERE_value +# [WHERE_key WHERE_operator WHERE_value # […]] local \ table="$1" \ col \ columns \ + operator \ results \ where_statement shift @@ -246,15 +247,10 @@ Select() { (( ${#columns} )) && columns+=',' columns+="$col" done - while read key value + while read key operator value do (( ${#where_statement} )) && where_statement+=( "AND" ) - if [[ $value == NULL ]] - then - where_statement+=( "$key is NULL" ) - else - where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) - fi + where_statement+=( "$key $operator "'"'"${value//\"/\\\"}"'"' ) done echo "SELECT IFNULL(" \ "(SELECT $columns FROM $table" \ @@ -262,7 +258,6 @@ Select() { ",'SQL::Select:not found'" \ ");" >&3 read -u 4 results - results="${results#* = }" if ! [[ $results == "SQL::Select:not found" ]] then echo "$results" @@ -299,18 +294,18 @@ Insert() { (( no_id )) || { echo 'SELECT LAST_INSERT_ROWID();' >&3 read -u 4 results - results="${results#* = }" echo "$results" } } Update(){ -#Update table set_key set_value [set_key set_value […]] < where_key where_value -# [where_key where_value +#Update table set_key set_value [set_key set_value […]] < where_key where_operator where_value +# [where_key where_operator where_value # […]] local \ table="$1" \ key \ argument \ + operator \ value \ set_statement \ where_keys \ @@ -333,14 +328,14 @@ Update(){ ;; esac done - while read key value + while read key operator value do (( ${#where_statement} )) && where_statement+=( "AND" ) if [[ $value == NULL ]] then where_statement+=( "$key is NULL" ) else - where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) + where_statement+=( "$key $operator "'"'"${value//\"/\\\"}"'"' ) fi done echo "UPDATE '$table' SET" \ @@ -375,7 +370,7 @@ InsertIfUnset() { Select "$table" "$column" < <( for key in ${!keys[@]} do - echo "${keys[$key]}" "${values[$key]}" + echo "${keys[$key]}" = "${values[$key]}" done ) ) @@ -430,7 +425,7 @@ InsertOrUpdate() { Select "$table" id < <( for key in ${!keys[@]} do - echo "${keys[$key]}" "${values[$key]}" + echo "${keys[$key]}" = "${values[$key]}" done ) ) @@ -438,7 +433,7 @@ InsertOrUpdate() { Update "$table" "$@" < <( for key in ${!keys[@]} do - echo "${keys[$key]}" "${values[$key]}" + echo "${keys[$key]}" = "${values[$key]}" done ) else @@ -455,27 +450,27 @@ InsertOrUpdate() { ) ) fi - results="${results#* = }" echo "$results" } Delete() { -#Delete table < where_key where_value -# [where_key where_value +#Delete table < where_key where_operator where_value +# [where_key where_operator where_value # […]] local \ table="$1" \ key \ + operator \ value \ where_statement \ results - while read key value + while read key operator value do (( ${#where_statement} )) && where_statement+=( "AND" ) if [[ $value == NULL ]] then where_statement+=( "$key is NULL" ) else - where_statement+=( "$key="'"'"${value//\"/\\\"}"'"' ) + where_statement+=( "$key $operator "'"'"${value//\"/\\\"}"'"' ) fi done echo "DELETE from $table WHERE ${where_statement[@]};" >&3 From baf60e027dbf42d022e5f2f84cf83bad776c07b5 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 12:12:43 +0100 Subject: [PATCH 27/35] don't use sqlite's line output --- atom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom b/atom index 2465ac4..75e113e 100755 --- a/atom +++ b/atom @@ -217,7 +217,7 @@ openDatabase() { fi sqlite3 "$database" < $schema fi - sqlite3 -line "$database" \ + sqlite3 "$database" \ < "$tempdir/sqlite.in" \ > "$tempdir/sqlite.out" & exec 3> "$tempdir"/sqlite.in From 41ddbc934f638a5fd2d0cc6c4a1f4368aa5d8154 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 12:23:47 +0100 Subject: [PATCH 28/35] scan for obsolete files --- atom | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/atom b/atom index 75e113e..5f78de1 100755 --- a/atom +++ b/atom @@ -516,6 +516,12 @@ getFiles() { echo } +removeObsoleteFiles() { + Delete source_files <<-EOWhere + last_seen < $scantime + EOWhere +} + getType() { : } @@ -649,6 +655,8 @@ createDestinations getFiles +removeObsoleteFiles + closeDatabase # vim:set ts=8 sw=8: From e6a4db4762a9b5a09f75a6a21016d25d82e5bf38 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 13:31:08 +0100 Subject: [PATCH 29/35] destination_files.last_chage: change DEFAULT --- share/schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/schema.sql b/share/schema.sql index 89ca5bf..be2888e 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -14,7 +14,7 @@ CREATE TABLE destinations ( CREATE TABLE destination_files ( id INTEGER PRIMARY KEY, filename TEXT, - last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), + last_change INTEGER NOT NULL DEFAULT 0, source_file_id INTEGER, destination_id INTEGER, FOREIGN KEY (source_file_id) REFERENCES source_files(id), From 377e3f4eed26ce886b4658ec3c5291782bbcebb7 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 13:34:06 +0100 Subject: [PATCH 30/35] create constants readonly --- atom | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/atom b/atom index 5f78de1..fe164f2 100755 --- a/atom +++ b/atom @@ -28,10 +28,13 @@ declare -A \ exit $EBASHVERS } -DOCDIR=./doc -SHAREDIR=./share -exampleconf=$DOCDIR/example.cfg -schema=$SHAREDIR/schema.sql +declare -r \ + DOCDIR=./doc \ + SHAREDIR=./share \ + exampleconf=$DOCDIR/example.cfg \ + schema=$SHAREDIR/schema.sql \ + \ + oldIFS="$IFS" #parse arguments #parse config From 632a65dbcb04671eaa58f48777dc80c6cde0647b Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 13:53:31 +0100 Subject: [PATCH 31/35] add mime_types table --- share/schema.sql | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/share/schema.sql b/share/schema.sql index be2888e..791d02f 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -4,8 +4,10 @@ CREATE TABLE source_files ( filename TEXT UNIQUE NOT NULL, size INTEGER NOT NULL, hash TEXT, + mime_type INTEGER, last_change INTEGER NOT NULL DEFAULT (strftime('%s','now')), - last_seen INTEGER NOT NULL DEFAULT (strftime('%s','now')) + last_seen INTEGER NOT NULL DEFAULT (strftime('%s','now')), + FOREIGN KEY (mime_type) REFERENCES mime_types(id) ); CREATE TABLE destinations ( id INTEGER PRIMARY KEY, @@ -20,6 +22,12 @@ CREATE TABLE destination_files ( FOREIGN KEY (source_file_id) REFERENCES source_files(id), FOREIGN KEY (destination_id) REFERENCES destinations(id) ); +CREATE TABLE mime_types ( + id INTEGER PRIMARY KEY, + destination_id INTEGER, + mime_text TEXT UNIQUE NOT NULL, + action INTEGER DEFAULT 1 +); CREATE INDEX sourcefiles_by_name ON source_files (filename,id); From 506bf59a24b2d87bf02f96fb7693723944aec3a4 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 14:26:44 +0100 Subject: [PATCH 32/35] split constant declarations --- atom | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom b/atom index fe164f2..e1d0e9b 100755 --- a/atom +++ b/atom @@ -30,7 +30,8 @@ declare -A \ declare -r \ DOCDIR=./doc \ - SHAREDIR=./share \ + SHAREDIR=./share +declare -r \ exampleconf=$DOCDIR/example.cfg \ schema=$SHAREDIR/schema.sql \ \ From f7a6fba366426b5130c357fc5ced3cceccac4946 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Tue, 26 Feb 2013 14:52:12 +0100 Subject: [PATCH 33/35] update mime_types --- atom | 34 ++++++++++++++++++++++++++++++++++ share/schema.sql | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/atom b/atom index e1d0e9b..a863d88 100755 --- a/atom +++ b/atom @@ -520,6 +520,38 @@ getFiles() { echo } +updateMimes() { + Update mime_types action 1 <<<"action != 1" + for destination in ${!destinationskipmime[@]} + do + IFS='|' + for mime_type in ${destinationskipmime["$destination"]} + do + IFS="$oldIFS" + Update mime_types action 0 >/dev/null < <( + cat <<-EOWhere + destination_id ${destinationid["$destination"]} + mime_text LIKE ${mime_type//*/%} + EOWhere + ) + done + done + for destination in ${!destinationcopymime[@]} + do + IFS='|' + for mime_type in ${destinationcopymime["$destination"]} + do + IFS="$oldIFS" + Update mime_types action 2 >/dev/null < <( + cat <<-EOWhere + destination_id ${destinationid["$destination"]} + mime_text LIKE ${mime_type//*/%} + EOWhere + ) + done + done +} + removeObsoleteFiles() { Delete source_files <<-EOWhere last_seen < $scantime @@ -659,6 +691,8 @@ createDestinations getFiles +updateMimes + removeObsoleteFiles closeDatabase diff --git a/share/schema.sql b/share/schema.sql index 791d02f..6121b78 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -26,7 +26,8 @@ CREATE TABLE mime_types ( id INTEGER PRIMARY KEY, destination_id INTEGER, mime_text TEXT UNIQUE NOT NULL, - action INTEGER DEFAULT 1 + action INTEGER DEFAULT 1, + FOREIGN KEY (destination_id) REFERENCES destinations(id) ); CREATE INDEX sourcefiles_by_name ON source_files (filename,id); From d9e7a87a0123d82786eb8d6a74c9082672c104d5 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Wed, 27 Feb 2013 00:32:26 +0100 Subject: [PATCH 34/35] change mime_types schema --- atom | 10 +++++----- share/schema.sql | 26 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/atom b/atom index a863d88..b592d30 100755 --- a/atom +++ b/atom @@ -521,16 +521,16 @@ getFiles() { } updateMimes() { - Update mime_types action 1 <<<"action != 1" + Update mime_actions action 1 <<<"action != 1" for destination in ${!destinationskipmime[@]} do IFS='|' for mime_type in ${destinationskipmime["$destination"]} do IFS="$oldIFS" - Update mime_types action 0 >/dev/null < <( + Update mime_type_actions action 0 >/dev/null < <( cat <<-EOWhere - destination_id ${destinationid["$destination"]} + destination_id = ${destinationid["$destination"]} mime_text LIKE ${mime_type//*/%} EOWhere ) @@ -542,9 +542,9 @@ updateMimes() { for mime_type in ${destinationcopymime["$destination"]} do IFS="$oldIFS" - Update mime_types action 2 >/dev/null < <( + Update mime_type_actions action 2 >/dev/null < <( cat <<-EOWhere - destination_id ${destinationid["$destination"]} + destination_id = ${destinationid["$destination"]} mime_text LIKE ${mime_type//*/%} EOWhere ) diff --git a/share/schema.sql b/share/schema.sql index 6121b78..3562f1e 100644 --- a/share/schema.sql +++ b/share/schema.sql @@ -24,12 +24,36 @@ CREATE TABLE destination_files ( ); CREATE TABLE mime_types ( id INTEGER PRIMARY KEY, + mime_text TEXT UNIQUE NOT NULL +); +CREATE TABLE mime_actions ( + id INTEGER PRIMARY KEY, + mime_type INTEGER, destination_id INTEGER, - mime_text TEXT UNIQUE NOT NULL, action INTEGER DEFAULT 1, + FOREIGN KEY (mime_type) REFERENCES mime_types(id) FOREIGN KEY (destination_id) REFERENCES destinations(id) ); +CREATE VIEW mime_type_actions AS + SELECT + mime_types.id,mime_types.mime_text, + mime_actions.destination_id,mime_actions.action + FROM mime_types INNER JOIN mime_actions + ON mime_actions.mime_type = mime_types.id; +CREATE TRIGGER update_mime_actions INSTEAD OF UPDATE OF action ON mime_type_actions +BEGIN + UPDATE mime_actions SET action=new.action WHERE mime_type=old.id; +END; + +CREATE TRIGGER create_mime_actions AFTER INSERT ON mime_types +BEGIN + INSERT INTO mime_actions (mime_type,destination_id) + SELECT mime_types.id,destinations.id + FROM mime_types INNER JOIN destinations + WHERE mime_types.id=new.id; +END; + CREATE INDEX sourcefiles_by_name ON source_files (filename,id); CREATE TRIGGER create_destinations AFTER INSERT ON source_files From 45e61ee8a68fe557882fd7dce31fd1cf41e7c808 Mon Sep 17 00:00:00 2001 From: Vincent Riquer Date: Wed, 27 Feb 2013 13:14:42 +0100 Subject: [PATCH 35/35] nice progress --- atom | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/atom b/atom index b592d30..c52042d 100755 --- a/atom +++ b/atom @@ -512,12 +512,17 @@ getFiles() { filename $filename EOWhere ) - echo -ne '\r'$sourcefileid + case $(( ++count % 4 )) in + 0) echo -ne '\r|' ;; + 1) echo -ne '\r/' ;; + 2) echo -en '\r-' ;; + 3) echo -ne '\r\\' ;; + esac done < <( find "$sourcepath" -type f -printf "%T@ %s %P\n" ) echo 'COMMIT;' >&3 - echo + echo -e "\r$count files found." } updateMimes() {