[REBOL] File synchronization
From: g::santilli::tiscalinet::it at: 28-Nov-2002 23:25
[This is a resend... dunno why the first time it didn't arrive. If
it did to you, please accept my apologies for the duplicate.]
Hello all,
I just "finished" (meaning that now it is almost usable :-) a
script to sync two dirs (I use it to sync the REBOL dir between my
desktop PC and my laptop). The GUI is probably awful (and
beta-depended, sorry Carl :-( ), but it is a start.
What it does: it asks you the two dirs you want to sync. It then
scans them to find all the differences. (This process can take
time, and there is no progress bar, so be patient please --- or
add a progress bar to it. :-)
It then displays a list to let you decide the action to take on
files that are missing or that have been modified (only the
modification date is checked). The default is to copy any modified
file over the old one and add any new file to where it is missing;
so if you leave the list alone and just click on "Do it!" it will
just do that.
But you can also click on the list items to toggle the action.
Basically for each item you can select between the default "copy"
action, the "leave it alone" action (i.e. do nothing on that
file), and the "delete" or "restore" action (depending on the
file). If the file is missing on one of the two directories, you
can this way delete it from where it is present; if the file is
modified but you want to restore the old version, you can by
selecting the "restore" option. (I think it is easier to try it
out than to explain it.)
This can be useful to backup your data files to another drive or
so; you can easily keep the backup up to date by synching it every
day or so.
I hope it can be useful. Also, I hope someone with more free time
than me can make a better GUI for it. :-)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
REBOL [
Title: "File synchronization"
File: %file-sync.r
Author: "Gabriele Santilli"
]
sync-dirs: func [
"Create list of operations needed to synchronize two directories"
a [file!] "First dir"
b [file!] "Second dir"
/local u result
] [
u: union read a read b
result: make block! 256
foreach file u [
switch to-bits exists? a/:file exists? b/:file [
1 [miss-file result a b file]
2 [miss-file result b a file]
3 [check-file result a b file]
]
]
result
]
to-bits: func [a b] [a: to-integer a b: to-integer b a * 2 + b]
miss-file: func [result dest src file] [
either dir? src/:file [
insert/only tail result compose/deep [
(reform ["Copy directory" file "to" dest]) [
either error? try [make-dir (dest/:file)] [
print ["Cannot create" (file) "on" (dest)]
] [
use [result] [
result: make block! 256
modified-file result (dest) (src) (file)
do-it result
]
]
]
(reform ["Leave directory" file "on" src]) [ ]
(reform ["Delete directory" file "from" src]) [
if error? try [delete-r (src/:file)] [
print ["Cannot delete" (file) "from" (src)]
]
]
]
;print ["Directory" file "does not exist in" dest]
] [
insert/only tail result compose/deep [
(reform ["Copy new file" file "to" dest]) [
if error? try [clone-file (dest) (src) (file)] [
print ["Cannot clone" (file) "on" (dest)]
]
]
(reform ["Leave file" file "on" src]) [ ]
(reform ["Delete file" file "from" src]) [
if error? try [delete (src/:file)] [
print ["Cannot delete" (file) "from" (src)]
]
]
]
;print ["File" file "does not exist in" dest]
]
]
delete-r: func [dir [file!]] [
if dir? dir [
foreach file read dir [
delete-r dir/:file
]
]
delete dir
]
check-file: func [result a b file /local ma mb] [
ma: modified? a/:file
mb: modified? b/:file
any [
if ma = mb [
;print ["File" file "seems synched"]
true
]
if ma > mb [
modified-file result b a file
true
]
do [
modified-file result a b file
]
]
]
modified-file: func [result dest src file] [
either dir? src/:file [
;print ["Synching" dest/:file "and" src/:file]
insert tail result sync-dirs dest/:file src/:file
;if error? try [
; set-modes dest/:file get-modes src/:file get-modes src/:file 'file-modes
;] [
; ;print "Cannot clone directory attributes."
;]
] [
insert/only tail result compose/deep [
(reform ["Clone modified file" file "to" dest]) [
if error? try [clone-file (dest) (src) (file)] [
print ["Cannot clone" (file) "to" (dest)]
]
]
(reform ["Leave modified file" file "on" src]) [ ]
(reform ["Restore old file" file "from" dest]) [
if error? try [clone-file (src) (dest) (file)] [
print ["Cannot restore" (file) "to" (src)]
]
]
]
;print ["File" file "has been modified on" src]
]
]
clone-file: func [dest src file /local data] [
dest: open/binary/direct/write dest/:file
src: open/binary/direct/read src/:file
clear dest
while [data: copy/part src 1048576] [
insert dest data
]
close dest
close src
set-modes dest get-modes src get-modes src 'file-modes
]
do-it: func [
"Do the list of operations returned by sync-dirs"
operations [block!]
] [
foreach operation operations [
; print operation/1
do operation/2
]
]
view layout [
Banner "Sync dirs"
Across
f1: Field 300 Btn "Browse..." [
if f1/text: request-file [f1/text: mold first split-path first f1/text]
show f1
]
Return
f2: Field 300 Btn "Browse..." [
if f2/text: request-file [f2/text: mold first split-path first f2/text]
show f2
]
Return
Btn-Enter "Sync" [unview] Btn-Cancel "Quit" [quit]
]
f1: attempt [load f1/text]
f2: attempt [load f2/text]
if all [file? f1 file? f2] [
operations: sync-dirs f1 f2
list: make block! length? operations
i: 1
foreach operation operations [
insert tail list join i [") " operation/1]
i: i + 1
]
view layout [
text-list data (list) 700x500 [
i: index? pos: find face/data face/picked
operation: next next pick operations i
if tail? operation [operation: head operation]
poke operations i operation
pos/1: join i [") " operation/1]
face/picked/1: pos/1
show face
]
Across Btn-Enter "Do it!" [do-it operations quit] Btn-Cancel "Quit" [quit]
]
]