Monday, November 08, 2010 at 12:02 AM.
system.verbs.builtins.file.reconcileFolder
on reconcileFolder (sourcefolder, destfolder, adrCopyFilter=nil, adrErrorTable=nil) {
<<Changes
<<5/22/10; 7:36:27 PM by DW
<<If the destfolder doesn't exist, create it.
<<5/15/10; 9:17:53 AM by DW
<<Added optional errortable parameter. If it's not nil, errors don't stop the reconciler, they're just added to table and the process continues.
<<Added error-checking. If adrCopyFilter is nil, we provide one. Error messages are now sentences. Don't roll the beachball (this might be running in a background thread or on a server, waste of cycles, distraction).
<<http://frontiernews.org/2010/05/15/file-reconcilefolder-rewrite/
<<3.0.2: validate input parameters as folders. also fixed path calcuation
<<when the case of original or clone differed from that used in the file system
on defaultFilter (f) { //we use this filter if one isn't specified, 5/15/10 by DW
return (true)};
if adrCopyFilter == nil {
adrCopyFilter = @defaultFilter};
bundle { //make sure the destfolder exists, 5/22/10 by DW
file.surefilepath (destfolder + "xxx")};
bundle { //make sure both folders are folders
on checkIsFolder (folder) {
if not file.isFolder (folder) {
scriptError ("Can't reconcile the folder because \"" + file.fileFromPath (folder) + "\" is not a folder.")};
folder = filespec (folder);
return (folder)};
sourcefolder = checkIsFolder (sourcefolder);
destfolder = checkIsFolder (destfolder)};
bundle { //set up the error table, 5/15/10 by DW
if adrErrorTable != nil {
new (tabletype, adrErrorTable)}};
on pushErrorTable (errorstring, fsource, fdest) {
local (adrsub = @adrErrorTable^.[string.padwithzeros (sizeof (adrErrorTable^), 5)]);
new (tabletype, adrsub);
adrsub^.errorstring = errorstring;
adrsub^.fsource = fsource;
adrsub^.fdest = fdest};
local (extraname = "Extra Files" + file.getPathChar ());
on checkForMissingFiles (path) {
local (fsource, fdest);
fileloop (fsource in path) { //loop over files in the original folder
try {
if file.isFolder (fsource) { //skip any folder named Extra Files
if file.fileFromPath (fsource) == extraname {
continue}};
fdest = destfolder + (fsource - sourcefolder);
if not file.exists (fdest) { //file or folder is missing
file.filteredCopy (fsource, fdest, adrCopyFilter)}
else {
if file.isFolder (fsource) {
checkForMissingFiles (fsource)}
else {
if file.modified (fsource) > file.modified (fdest) { //the user changed the file
file.filteredCopy (fsource, fdest, adrCopyFilter)}}}}
else {
if adrErrorTable == nil { //re-throw the error
scripterror (tryerror)};
pushErrorTable (tryerror, fsource, fdest)}}};
checkForMissingFiles (sourcefolder);
local (userfolder = destfolder + extraname);
on checkForExtraFiles (path) {
local (fdest, fsource);
fileloop (fdest in path) {
try {
<<rollBeachBall ()
if fdest != userfolder { //don't look at or inside of the user's personal folder
fsource = sourcefolder + (fdest - destfolder);
if not file.exists (fsource) { //new file created by user, move it to personal folder
if file.exists (userfolder) {
if not file.isFolder (userfolder) { //we're really paranoid
file.delete (userfolder);
file.newFolder (userfolder)}}
else {
msg (userfolder);
file.newFolder (userfolder)};
file.move (fdest, userfolder)}
else { //the file is a copy from the original folder
if file.isFolder (fdest) {
checkForExtraFiles (fdest)}}}}
else {
if adrErrorTable == nil { //re-throw the error
scripterror (tryerror)};
pushErrorTable (tryerror, fsource, fdest)}}};
checkForExtraFiles (destfolder)} //make sure there aren't any extra files or folders in the clone
<<bundle //test code
<<local (sourcefolder = "Albert:Stuff from Leon:")
<<local (destfolder = "Ohio2:Leon:Contents of his hard disk:")
<<on filter (f) //we use this filter if one isn't specified, 5/15/10 by DW
<<scratchpad.f = f
<<return (true)
<<reconcileFolder (sourcefolder, destfolder, @filter, adrerrortable:@scratchpad.reconcileErrors)
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.