I went looking a year or so ago for a means to synch folders on my home Mac and my Laptop, mainly motivated due to some disk problems caused by MS products on the laptop… I wanted to synchronize like-named folders.
I somehow found a script in French (Synchro Folders) , I believe it is from Thomas Robisson (http://tcfj.pagesperso-orange.fr/site/), that seemed to do the trick in a nice fashion. I had to use Google Translate to at least understand what the concepts were in the script, and the comments.
Over time I have modified it, added the progress bar, and generally tweaked it to get the results I want. My next effort is to learn rsync in my spare time and see if that gives me better performance over the network while skipping folders that have not changed since last synch. Of course, I could add skip folders to this script, but then rsync seems a better next step. Let’s see.
So, for simple synchronization of folders, and some entertainment via progress bar (from Spork), here is the script.
NOTE: Through the use of “ignoring application responses” the script is able to ‘parallel process’ file/folder copying.
property pLogEventsOn : true -- generate a log file
property pUseGrowl : true -- Use Growl notifications (under construction)
property pGrowlRunning : false -- assumes Growl is not running...
property pBaseFolder : "" --the desktop, or where the log file should be
property pSyncFileResultsFolder : "Folder Sync Log Messages"
property pLogFolder : "" -- filled in at run time with the desktop folder path
property pLogFileName : "Folder Sync.txt" --version 4.0 changed from log to txt file type
property pLineEndingMac : ASCII number return -- carriage return (13)
property pLineEndingUnix : ASCII character 10 -- line feed character
property pLinefeed : pLineEndingUnix -- use this line feed character in logs
property PSkipFolderFlag : false -- this determines if specific sub-folders should be skipped or checked, if true then they are skipped
-- note that this only checks going from A to B so far
property pSkipFolder1 : "DS2" -- the first folder to skip name
property pSkipFolder2 : "Graphics" -- the second folder skip name
property Mod_Date_Diff_Secs : 30
-- It adds a margin because there are a few seconds difference in the modification date when you copy elements between 2 networked Macs.
property Copy_Timeout_Value : 400 -- seconds or almost 7 minutes timeout to allow time if remote gets bogged down over the network
property fldr_A_Cnt : 0 -- this is the count of folders checked on the A side
property fldr_B_Cnt : 0 -- This is the folder count on the B side beyond those matching A
property fldr_A_File_Cnt : 0 -- the number of files done directly (note that some files are not counted as they are part of complete folder copying)
property fldr_B_File_Cnt : 0 -- the number of files done directly (note that some files are not counted as they are part of complete folder copying)
property Files_Deleted_Cnt : 0 -- the number of files deleted directly
property fldr_A_File_Copied : 0 -- the number of files copied directly to B (note that some files are done as part of complete folder copying)
property fldr_B_File_Copied : 0 -- the number of files copied directly to A (note that some files are done as part of complete folder copying)
property fldr_A_fldr_Copied : 0 -- the number of folders copied directly to B (note that some folders are done as part of complete folder copying, as they are nested)
property fldr_B_fldr_Copied : 0 -- the number of folders copied directly to A (note that some files are done as part of complete folder copying, as they are nested)
--Added as v4.0 to track progress bar progress
property fldr_A_Top_Ttl_Cnt : 0 -- this is the count of all types in the A side folder top level
property fldr_A_Current_Ttl_Cnt : 0 -- this is the count of all types in the A side folder current level
property fldr_B_Top_Ttl_Cnt : 0 -- this is the count of all types in the B side folder top level
property fldr_B_Current_Ttl_Cnt : 0 -- this is the count of all types in the B side folder current level
property fldr_A_Top_Done_Cnt : 0 -- this is the count of all types in the A side folder top level done so far
property fldr_A_Current_Done_Cnt : 0 -- this is the count of all types in the A side folder top level done so far
property fldr_B_Top_Done_Cnt : 0 -- this is the count of all types in the B side folder current level done so far
property fldr_B_Current_Done_Cnt : 0 -- this is the count of all types in the B side folder current level done so far
set fldr_A_Lvl to 0 -- this is the level we are at on the A side (0 is top level then increases from there as we go into levels)
set fldr_B_Lvl to 0 -- This is the level we are at on the B side (0 is top level then increases from there as we go into levels)
property PBexists : false -- Added this to make sure the ProgBar is present or not presumes the PB is not present...
global sync -- sync is detected in the proceedings (otherwise sync would be considered a new variable in the procedure)
global Stop_Handler
global ptimeStart
set ptimeStart to current date
global The_Selection_List
set The_First_Choice to "1. A<=>B Reciprocal - A to B, if B newer, then B to A; unique files/folders copied both ways"
set The_Second_Choice to "2. A=>Bn - A updates B, newer on B goes to A, unique to A copied, unique to B left alone"
set The_Third_Choice to "3. A>>B - Overwrite B except newer on B then copied to A, delete unique on B"
set The_Fourth_Choice to "4. A=>Ba - A replaces B. All and Any of A copied, unique to B deleted, newer in B overwritten with warning"
set The_Fifth_Choice to "5. Report of A versus B" --(under construction)
set The_Selection_List to {The_First_Choice, The_Second_Choice, The_Third_Choice, The_Fourth_Choice, The_Fifth_Choice}
-- V4.0 changes
set fldr_A_Lvl to 0
set fldr_B_Lvl to 0
set fldr_A_Top_Ttl_Cnt to 0
set fldr_A_Current_Ttl_Cnt to 0
set fldr_B_Top_Ttl_Cnt to 0
set fldr_B_Current_Ttl_Cnt to 0
set fldr_A_Top_Done_Cnt to 0
set fldr_A_Current_Done_Cnt to 0
set fldr_B_Top_Done_Cnt to 0
set fldr_B_Current_Done_Cnt to 0
--------------------------------------------------------
(*
The synchro options are:
1. Reciprocal - where all files and folders are harmonized and older ones replaced with newer ones. Is a 2-way process
A<=>B Reciprocal
2. Folder A (first selected) is copied over to folder B, unless Folder B has newer files, then these are copied to A. Files unique to folder A are copied to B but files unique to B are not copied to A.
A=>Bn newer copied either way, unique to A copied, unique to B left alone
3. Files on folder A copied to B, any files unique on B are deleted. Newer files on B are copied to A
A>>>B Overwrite B except newer on B copied to A, delete unique to B
4. Folder A copied to B regardless. All of B's contents are removed and A contents put in their place. (there is a warning if a B file is newer)
A=>Ba All and Any of A copied, unique to B deleted, newer in B overwritten but with warning
5. Folder A evaluated versus B and a report generated. No other actions done.
*)
-------------------------------------------------------
-- set up log file on desktop
set pBaseFolder to (the path to the desktop) as text
set pLogFolder to pBaseFolder & pSyncFileResultsFolder & ":"
if pUseGrowl is true then
tell application "System Events" to set pGrowlRunning to exists application process "GrowlHelperApp"
-- if GrowlRunning is true then Growl can be sent notifications
--set MyName to name of me--this was supposed to get the script's name
end if
if pLogEventsOn is true then
-- create the Log folder on disk if not created before
if not my FileExists(pLogFolder) then
tell application "Finder"
make new folder at (pBaseFolder as alias) with properties {name:pSyncFileResultsFolder}
end tell
my LogEntry("Created folder: " & pLogFolder, 0)
end if
set ptimeStart to current date
my LogEntry("................... Starting up...", 1)
my LogEntry("................... Running automated folder sync between machines", 0)
end if
---==============================================
(*
For me, this program synchronizes folders between the laptop & the desktop, or between two drives, or on the same drive, if the folders are named differently
NEED TO FIND OUT SECONDARY DRIVE VS NETWORK DRIVE DIFFERENCES, could use local volume to determine if a network drive Y/N, then use startup true or false to know if it is main drive
*)
--================= Select the sync steps here =======================
tell application "Finder"
activate
set Stop_Handler to false
try -- V4.1 stuff added to improve performance, avoid errors, and add some sizzle to bars
ignoring application responses
open application file id "com.spork.progbar"
end ignoring
set PBexists to true -- means the program exists and has started up, else will skip all PB related instructions
on error m number n
my LogEntry("................... the Progress Bar app (ProgBar) was not found. Error # " & m, 0)
end try
set sync to choose from list The_Selection_List with prompt "Select an option" with title "Select a synchro action" default items The_First_Choice without multiple selections allowed
if sync is equal to false then return -- The script stops if cancel selected
set TheChoice to item 1 of sync --variable used here and confirmation dialog
my LogEntry("Selected: " & TheChoice, 0)
repeat with i from 1 to length of The_Selection_List
if item i of The_Selection_List is equal to item 1 of sync then
set sync to i
exit repeat
end if
end repeat
--===================== Select the specific Folders to sync ================
set Folder_A_selected to choose folder with prompt "Select the first (A) folder :"
if Folder_A_selected = false then return -- The script stops because you clicked Cancel, no folder chosen
set Folder_B_selected to choose folder with prompt "Select the second (B) folder :"
if Folder_B_selected = false then return -- The script stops because you clicked Cancel, no folder chosen
set Folder_A to item Folder_A_selected -- Folder_A is an alias
set Folder_B to item Folder_B_selected -- Folder_B is an alias
set Disk_A to disk of Folder_A
--find out if this is start up, attahced disk, or a network disk? I don't know if there is a difference between attached and network, needs rresearch
--if local volume is true than the disk is on the main computer and so can trash the files...
set fldr_A_Cnt to 1 --this is the first folder checked (top level, level 0), so increment the count by 1
set fldr_A_File_Cnt to 0 --no files checked as yet, so reset to zero
set Disk_B to disk of Folder_B --ditto
set fldr_B_Cnt to 0 --set to 0 as of V4.0 as was giving erroneous result of 1 B folder checked when none were
set fldr_B_File_Cnt to 0 --ditto
--resulting statistics on processes, tracking registers, so to speak
set Files_Deleted_Cnt to 0
set fldr_A_File_Copied to 0
set fldr_B_File_Copied to 0
set fldr_A_fldr_Copied to 0
set fldr_B_fldr_Copied to 0
if Disk_A = Disk_B then -- if on the same disk, then the same alias, are the same folder so end after a dialog
if Folder_A = Folder_B then
beep
display dialog "You have selected the same folder." with icon 0 buttons {"Stop"} default button 1
return -- The script stops
end if
if ((Folder_A as text) is in (Folder_B as text)) or ((Folder_B as text) is in (Folder_A as text)) then --if on same disk, and one folder is in the other, then end
beep
display dialog "You've selected 1 folder inside the other..." with icon 0 buttons {"Stop"} default button 1
return -- The script stops
end if
end if
--confirmation dialog
set BtnChoice to display dialog "You have chosen option: " & return & TheChoice & return & return & "Folder A: " & Folder_A & return & return & "Folder B: " & Folder_B with icon 1 buttons {"OK", "Cancel"} default button 1 -- in V4.0 added & return to spaces between text and A and A and B
if BtnChoice = "Cancel" then return
--========================== Establsih trash folders based on disk of folder A or B ===========
if sync is not equal to 5 then
set trash_A to Create_Trash_Folder(Folder_A, "A") of me -- create a trash forlder for A
if trash_A is false then return -- We stop the script because there was a problem, the alert was given in the previous subroutine
set trash_B to Create_Trash_Folder(Folder_B, "B") of me -- create a trash folder for B
if trash_B is false then return -- We stop the script because there was a problem, the alert was given in the previous subroutine
end if
--=========================== Synchronize the folders according to the selected actions ==========
SyncFolders(Folder_A, Folder_B, trash_A, trash_B, fldr_A_Lvl, fldr_B_Lvl) of me
my LogEntry("................... Run completed", 2)
if PBexists is true then my QuitBar() -- modified with V4.1 to include the if statement
end tell
--======================== Move, replicate, and/or delete ===========================
-- Copy files in FolderA in FolderB if they are not already If the file exists, it will not replicate unless it is newer
on SyncFolders(folderA, folderB, trashA, trashB, fldr_A_Lvl, fldr_B_Lvl)
my LogEntry(".............................. Folder A being checked: " & name of folderA & " (" & fldr_A_Lvl & ")", 0) -- & tab & "Folder B : " & name of folderB
tell application "Finder"
set the FolderAContents to {} & name of items in folderA as list
-- Set to list FolderAContents for FolderA -- Provides all the elements of FolderA, including hidden files (. DS_Store, icon, ...)
-- Must be '{} &' because if there are no files, FolderAContents will not be an array
if PBexists is true then -- V4.1 changes here, although bulk was 4.0
set BarberPoleOn to false
set Cnt_Items_Fldr_A to count of items in folderA -- As of V4.0 this cuts time down processing a little
if fldr_A_Lvl = 0 then -- this added as of V4.0
if fldr_A_Top_Ttl_Cnt = 0 then
set fldr_A_Top_Ttl_Cnt to Cnt_Items_Fldr_A -- if top level get folder A items count
set windowName to "alum_prog_window2"
set Wndw_title to name of folderA
my prepProgress(fldr_A_Top_Ttl_Cnt, windowName, Wndw_title)
set BarberPoleOn to true
my barberPole(windowName)
my ShowProgBar(windowName)
end if
else
if fldr_A_Current_Ttl_Cnt ≠Cnt_Items_Fldr_A then
set fldr_A_Current_Ttl_Cnt to Cnt_Items_Fldr_A -- if a lower level in A get item count this level
set windowName to "mini_prog_window"
set Wndw_title to name of folderA
my prepProgress(fldr_A_Current_Ttl_Cnt, windowName, Wndw_title)
my ShowProgBar(windowName)
end if
end if
end if
set the FolderBContents to {} & name of items in folderB as list -- same as for folder A
set AppleScript's text item delimiters to tab -- tab stop
set the FolderAContents to FolderAContents as text
set the FolderAContents to every text item of the FolderAContents as list
set the FolderBContents to FolderBContents as text
set the FolderBContents to every text item of the FolderBContents as list
set AppleScript's text item delimiters to ""
if FolderAContents = {""} then set FolderAContents to {}
if FolderBContents = {""} then set FolderBContents to {}
set TempFolderContents to FolderAContents
repeat with x in FolderAContents
set IndexQuery to index of item x of folderA -- this added as of V4.0, this line reduces IAC script calls
set Class_Item_X to class of item x of folderA -- This converts a lookup to a variable
if fldr_A_Lvl ≠0 then -- If this is not the top level then chk if total items in bar is same as total items in A
if fldr_A_Current_Ttl_Cnt ≠(Cnt_Items_Fldr_A) then -- If not the same then prep the bar for this
set fldr_A_Current_Ttl_Cnt to Cnt_Items_Fldr_A -- if a lower level in A get item count this level
set windowName to "mini_prog_window"
set Wndw_title to name of folderA
my prepProgress(fldr_A_Current_Ttl_Cnt, windowName, Wndw_title)
end if
end if
if Class_Item_X is folder then -- from V4.0 classify if it is a folder or file being checked, then increment the appropriate counter
set fldr_A_Lvl to fldr_A_Lvl + 1 -- added V4.0
set x_Folder_Value to true -- some value to track if this is a folder versus a file
set fldr_A_Cnt to fldr_A_Cnt + 1
else
set fldr_A_File_Cnt to fldr_A_File_Cnt + 1
set x_Folder_Value to false
if fldr_A_Lvl ≠0 then -- this added as of V4.0
set windowName to "mini_prog_window" -- added V4.0
set fldr_A_Current_Done_Cnt to IndexQuery -- if a lower level in A increase items done
set PassInfo to "Completed: " & IndexQuery & " out of " & Cnt_Items_Fldr_A
my incrementProgBar(fldr_A_Current_Done_Cnt, windowName, "Level deep: " & fldr_A_Lvl, PassInfo)
end if
end if
set x1 to x as text
set Class_Item_X1 to (class of item x1 of folderA) -- V4.0 This converts a lookup to a variable
set skip_this_folder to false -- this whole thing is to see if we can skip folders
if x_Folder_Value is true then
if PSkipFolderFlag is true then
if x1 = pSkipFolder1 or x1 = pSkipFolder2 then
set skip_this_folder to true
my LogEntry("...... there was a folder skipped", 0)
end if
end if
end if
if skip_this_folder is false then
if x1 is not in FolderBContents then -- Means this is either a file or a folder and does not show up in folder B
with timeout of Copy_Timeout_Value seconds
try
ignoring application responses
duplicate (item x1 of folderA) to folderB -- Do not bother with replacing to since there is no identical item in folderB
end ignoring
if Class_Item_X1 is folder then
set fldr_A_fldr_Copied to fldr_A_fldr_Copied + 1
else
set fldr_A_File_Copied to fldr_A_File_Copied + 1
end if
if pLogEventsOn is true then my LogEntry(">>>>>>>>>> Copied " & x1 & " of folder A to " & folderB, 0)
on error
beep (2)
display dialog "Cannot copy the file..." & (folderA as text) & x1 & " The disk appears full." with icon 0 buttons {"Stop"} default button 1
set Stop_Handler to true
return -- It quits the handler
end try
end timeout
else -- Means that this is matched name for name in Folder B, so must do a compare and then react
if Class_Item_X1 is folder and class of (item x1 of folderB) is folder then
SyncFolders((item x1 of folderA), (item x1 of folderB), trashA, trashB, fldr_A_Lvl, fldr_B_Lvl) of me
-- item must be or we will not record the proceedings but a text string
if Stop_Handler then return -- It quits the handler
else
set error_cnt to 0
set Sheet_error to true
-- On networked computers (remote), sometimes the Finder does not read the modification date of the file
repeat until Sheet_error is false
try
set date1 to (modification date of (item x1 of folderA)) + 0 -- Triggers an error if the modification date is not a number
set date2 to (modification date of (item x1 of folderB)) + 0
set Sheet_error to false -- This line is not executed if an error above
on error
set Sheet_error to true -- useless because it was not made false, the error is generated before
set error_cnt to error_cnt + 1
if error_cnt > 2 then -- does not try 2 times???
beep (3)
display dialog "Impossible to read the modification date of file " & x1 with icon 0 buttons {"Stop"} default button 1
set Stop_Handler to true
return -- It quits the handler
end if
end try
end repeat
set Copy_Sheet to false
if date2 > (date1 + Mod_Date_Diff_Secs) then -- It adds the margin of time
--- SYNC
if sync = 1 or sync = 2 or sync = 3 then -- Reciprocal fashion, therefore we copy from folderB to FolderA
set RemovedDuplicates to Delete_File(folderA, x1, trashA) of me -- You move the element in folderA -> Trash-before
if RemovedDuplicates > 30 then -- We stop the script because there was a problem, the alert was given in the proceedings
set Stop_Handler to true
return -- It quits the handler
end if
with timeout of Copy_Timeout_Value seconds
try
ignoring application responses
duplicate (item x1 of folderB) to folderA
end ignoring
if class of item x1 of folderB is folder then
set fldr_B_fldr_Copied to fldr_B_fldr_Copied + 1
else
set fldr_B_File_Copied to fldr_B_File_Copied + 1
end if
if pLogEventsOn is true then my LogEntry(">>>>>>>>>> Copied " & x1 & " of folder B to " & folderA, 0)
-- Try update item X1 in folderA --
on error
beep (2)
display dialog "Cannot copy the file..." & (folderB as text) & x1 & " The disk appears full" with icon 0 buttons {"Stop"} default button 1
set Stop_Handler to true
return -- It quits the handler
end try
end timeout
else -- Not Reciprocal mode, so we request to replace the newer file not the oldest
beep
set demav to display dialog "The item " & x1 & (", is older in folder 1 than in folder 2." & return & "Do you wish to copy it anyway?") with icon 2 buttons {"Stop", "Yes", "No"} default button 3 giving up after 25 -- seconds
if button returned of demav = "Stop" then
set Stop_Handler to true
return -- It quits the handler
else if button returned of demav = "Yes" then
set Copy_Sheet to true
end if
end if
end if -- date2 > date1
if (date1 > (date2 + Mod_Date_Diff_Secs)) or (Copy_Sheet = true) then
set RemovedDuplicates to Delete_File(folderB, x1, trashB) of me -- You move the element in folderB -> Trash-before
if RemovedDuplicates > 30 then -- We stop the script because there was a problem, the alert was given in the preceeding
set Stop_Handler to true
return -- It quits the handler
end if
with timeout of Copy_Timeout_Value seconds
try
ignoring application responses
duplicate (item x1 of folderA) to folderB
end ignoring
--to copy because if you tried with replacing folderB item, it will be deleted and can not be retrieved from the trash
if Class_Item_X1 is folder then
set fldr_A_fldr_Copied to fldr_A_fldr_Copied + 1
else
set fldr_A_File_Copied to fldr_A_File_Copied + 1
end if
if pLogEventsOn is true then my LogEntry(">>>>>>>>>> Copied " & x1 & " of folder A to " & folderB, 0)
-- Furthermore, if the disc is in another Mac (via network), replacing instruction does not work
--because you can not erase files from another Mac without a dialog, unless coming in as admin and dialogs turned off
on error
beep (2)
display dialog "Cannot copy the file..." & (folderA as text) & x1 & " The disk appears full." with icon 0 buttons {"Stop"} default button 1
set Stop_Handler to true
return -- It quits the handler
end try
end timeout
end if -- date1 > date2
end if -- item X1 of folderA and item X1 of folderB is a folder
end if -- X1 is not in FolderBContents
end if -- this is the skip_folder is false end
-- ***
if PBexists then
if fldr_A_Lvl > 0 then -- V4.0 stuff
if Class_Item_X1 is folder then
set fldr_A_Lvl to fldr_A_Lvl - 1 -- done with a level, jump back one
end if
end if
if fldr_A_Lvl = 0 then -- this added as of V4.0, must be after decrement as the sub-folder would not be tracked properly at level 0
if BarberPoleOn is true then
my killBarberPole(windowName)
set BarberPoleOn to false
end if
if fldr_A_Top_Done_Cnt ≠IndexQuery then
set windowName to "alum_prog_window2"
set fldr_A_Top_Done_Cnt to IndexQuery -- if top level increase folder A items done
set PassInfo to "Completed: " & IndexQuery & " out of " & fldr_A_Top_Ttl_Cnt
my incrementProgBar(fldr_A_Top_Done_Cnt, windowName, "Top Level...", PassInfo)
end if
end if
end if
end repeat
-- It handles files of folderB not previously evaluated
repeat with x2 in FolderBContents
set x2 to x2 as text -- Always the problem of filenames with accented characters as text unmanaged
if x2 is not in TempFolderContents then
-- It matches none of the elements of TempFolderContents because they have been dealt with (either copied or deleted)
-- x2 is not necessarily in Folder A Contents since it is not in TempFolderContents
if class of item x2 of folderB is folder then
set fldr_B_Cnt to fldr_B_Cnt + 1
else
set fldr_B_File_Cnt to fldr_B_File_Cnt + 1
end if
set drap_x_eff to false
if number of characters of x2 > 4 then
if (characters 1 thru 4 of x2 as text) is "->t-" then
set drap_x_eff to true
set RemovedDuplicates to Delete_File(folderB, x2, trashB) of me -- It moves the file that starts with "-> t-" of folderB to trash storage folder
if RemovedDuplicates > 30 then -- We stop the script because there was a problem, the alert was given in the proceedings
set Stop_Handler to true
return -- It quits the handler
end if
end if
end if
if drap_x_eff is false then
-- SYNC
if sync = 1 then -- Reciprocal fashion, therefore we copy folderB to folderA
with timeout of Copy_Timeout_Value seconds
try
ignoring application responses
duplicate (item x2 of folderB) to folderA -- Do not bother with replacing to since there are no items in this FolderA
end ignoring
if class of item x2 of folderB is folder then
set fldr_B_fldr_Copied to fldr_B_fldr_Copied + 1
else
set fldr_B_File_Copied to fldr_B_File_Copied + 1
end if
if pLogEventsOn is true then my LogEntry(">>>>>>>>>> Copied " & x2 & " of folder B to " & folderA, 0)
on error
beep (2)
display dialog "Cannot copy the file..." & (folderB as text) & x2 & " The disk appears full." with icon 0 buttons {"Stop"} default button 1
set Stop_Handler to true
return -- It quits the handler
end try
end timeout
-- The 2 files are now identical, we copied a file from folderA to folderB
-- SYNC
else if sync = 3 or sync = 4 then -- Sync choices 3, 4 trigger this
set RemovedDuplicates to Delete_File(folderB, x2, trashB) of me -- You move the element in folderB ->-Trash
if RemovedDuplicates > 30 then -- We stop the script because there was a problem, the alert was given in the proceedings
set Stop_Handler to true
return -- It quits the handler
end if
end if
end if
end if -- x2 is not in TempFolderContents
end repeat
end tell
if fldr_A_Lvl > 0 then
set fldr_A_Lvl to fldr_A_Lvl - 1 -- done with a level, jump back one
end if
end SyncFolders
--======================== Delete files (move to temp trash folders) ==============
-- You move File2Delete of Original_Folder to the folder Trash_Folder, first check to see if there is already a file of the same name in the trash, if yes, add a digit (up to the # 20) to the end of the file name
on Delete_File(Original_Folder, File2Delete, trash_Folder)
set RemovedDuplicates to 1
tell application "Finder"
set Temp_File_Check to trash_Folder & File2Delete
if my FileExists(Temp_File_Check) then
-- if the file to be moved to the 'trash' is named same as a file already in the 'trash,' then append a digit (1-20) to end of file name but first remove the 'dot . and file extension to get rid of confusion
set item_file2delete to item File2Delete of Original_Folder
set File2DeleteName to File2Delete
set find_the_dot to (offset of "." in File2DeleteName)
set File2DeleteName to characters 1 thru (find_the_dot - 1) of File2DeleteName
set match_exists to true
repeat until match_exists = false
try
set Temp_File_Record to trash_Folder & File2DeleteName & "-" & RemovedDuplicates
if pLogEventsOn is true then my LogEntry(".......... checked: " & File2DeleteName & "-" & RemovedDuplicates & tab & "The Temp_File_Record: " & Temp_File_Record, 0)
if my FileExists(Temp_File_Record) then
set RemovedDuplicates to RemovedDuplicates + 1
if RemovedDuplicates > 30 then set match_exists to false
else
set match_exists to false
end if
on error errStr number errorNumber
if pLogEventsOn is true then my LogEntry(".......... " & File2DeleteName & " has trouble from " & Original_Folder, 0)
if pLogEventsOn is true then my LogEntry(".......... Error " & errStr & tab & number & tab & errorNumber, 0)
end try
end repeat
if RemovedDuplicates > 30 then
beep
display dialog "Too many items with the same name have been moved for deletion." with icon 0 buttons {"Stop"} default button 1
else
set name of item File2Delete of Original_Folder to (File2DeleteName & "-" & RemovedDuplicates) as text
set File2Delete to (File2DeleteName & "-" & RemovedDuplicates) as text
move item File2Delete of Original_Folder to trash_Folder
set Files_Deleted_Cnt to Files_Deleted_Cnt + 1
if pLogEventsOn is true then my LogEntry("......Deleted: " & File2Delete & " moved to " & trash_Folder & " from " & Original_Folder, 0)
end if
else
move item File2Delete of Original_Folder to trash_Folder
set Files_Deleted_Cnt to Files_Deleted_Cnt + 1
if pLogEventsOn is true then my LogEntry("......Deleted: " & File2Delete & " moved to " & trash_Folder & " from " & Original_Folder, 0)
end if
return RemovedDuplicates -- To determine whether there was a problem or not
end tell
end Delete_File
---================= Log File Entry =============================
on LogEntry(someText, timingAct)
if pLogEventsOn is false then return
--create text entry to log file, append to end of file to maintain long record
set logFile to (pLogFolder as text) & pLogFileName
set logRef to 0
try
set logRef to open for access file logFile with write permission
end try
if logRef ≠0 then
if timingAct is 1 then
set ptimeStart to current date
write return & pLinefeed & pLinefeed starting at eof to logRef
write FormatDateTime(current date) & ": " & someText & pLinefeed starting at eof to logRef
else
write FormatDateTime(current date) & ": " & someText & pLinefeed starting at eof to logRef
end if
if timingAct is 2 then
set TotalSeconds to (current date) - ptimeStart
set ElapsedMinutes to (((TotalSeconds - (TotalSeconds mod 60)) / 60) as integer)
set ElapsedSeconds to (TotalSeconds mod 60)
if ElapsedSeconds < 10 then set ElapsedSeconds to "0" & ElapsedSeconds
write pLinefeed & "Time to complete (minutes & seconds): " & ElapsedMinutes & ":" & ElapsedSeconds & pLinefeed starting at eof to logRef
write "Files and Folders checked: " & return & pLinefeed starting at eof to logRef
write "................ A folders:" & fldr_A_Cnt & return & pLinefeed starting at eof to logRef
write "................ A files:" & fldr_A_File_Cnt & return & pLinefeed starting at eof to logRef
write "................ B folders:" & fldr_B_Cnt & return & pLinefeed starting at eof to logRef
write "................ B files:" & fldr_B_File_Cnt & return & pLinefeed starting at eof to logRef
write "Total files moved (delete after verification): " & Files_Deleted_Cnt & return & pLinefeed starting at eof to logRef
write "Files and Folders copied: " & return & pLinefeed starting at eof to logRef
write "................ A folders to B:" & fldr_A_fldr_Copied & return & pLinefeed starting at eof to logRef
write "................ A files to B:" & fldr_A_File_Copied & return & pLinefeed starting at eof to logRef
write "................ B folders to A:" & fldr_B_fldr_Copied & return & pLinefeed starting at eof to logRef
write "................ B files to A:" & fldr_B_File_Copied & return & pLinefeed starting at eof to logRef
end if
close access logRef
end if
end LogEntry
---================= Date infor for date stamp in Log file =============================
on FormatDateTime(theDate)
set theDate to theDate as date
set dd to text -2 thru -1 of ("0" & theDate's day)
copy theDate to tempDate
set the month of tempDate to January
set mm to text -2 thru -1 of ("0" & 1 + (theDate - tempDate + 1314864) div 2629728)
set yy to text -1 thru -4 of ((year of theDate) as text)
set hh to time string of theDate
return (yy & "/" & mm & "/" & dd & " " & hh as text)
end FormatDateTime
---=================== Check to see if a file or folder exists ===========================
on FileExists(someFile)
try
set anAlias to (someFile as alias)
return true
on error
return false
end try
end FileExists
---================== Progress Bars Added Below in v4.0 ============================
-- ============================= Start a bar ==========
on startProgBar()
tell application "ProgBar"
launch
end tell
end startProgBar
-- Prepare progress bar subroutine.
on prepProgress(someMaxCount, windowName, Wndw_title)
tell application "ProgBar"
if windowName = "mini_prog_window" then
tell text field "field_one" of window windowName to set contents to "Initializing..."
tell text field "field_one" of window windowName to set contents to "Initializing..."
end if
tell progress indicator "prog_one" of window windowName
set content to 0
set uses threaded animation to true
start
set minimum value to 1
set maximum value to someMaxCount
end tell
set title of window windowName to Wndw_title
end tell
end prepProgress
--Show Progress Bar with no fanfare
on ShowProgBar(windowName)
tell application "ProgBar"
show window windowName
end tell
end ShowProgBar
-- Increment progress bar subroutine.
on incrementProgBar(itemNumber, windowName, Level_Name, Current_Job)
tell application "ProgBar"
tell text field "field_one" of window windowName to set contents to Level_Name
tell progress indicator "prog_one" of window windowName to set content to itemNumber
tell text field "field_two" of window windowName to set contents to Current_Job
end tell
end incrementProgBar
-- End progress bar subroutine.
on endProgress(windowName)
tell application "ProgBar"
tell progress indicator "prog_one" of window windowName to stop
tell progress indicator "prog_one" of window windowName to set content to 0
tell text field "field_two" of window windowName to set contents to ""
end tell
end endProgress
--===================================== Fade In/Out Window ======================================
-- Fade in a progress bar window.
on fadeIn(windowName)
tell application "ProgBar"
set alpha value of window windowName to 0
show window windowName
repeat with i from 1 to 9
set alpha value of window windowName to (("0." & i) as real)
end repeat
set alpha value of window windowName to 1.0
set opaque of window windowName to true
end tell
end fadeIn
-- Fade out a progress bar window.
on fadeOut(windowName)
tell application "ProgBar"
set fadeValue to (1 as real)
repeat with i from 1 to 9
set alpha value of window windowName to fadeValue
set fadeValue to fadeValue - 0.1
end repeat
set alpha value of window windowName to 0.1
set opaque of window windowName to false
hide window windowName
end tell
end fadeOut
--============================== Barber Pole behavior on/off =============================
-- Give a progress bar the 'barber pole' behavior.
on barberPole(windowName)
tell application "ProgBar"
set indeterminate of progress indicator "prog_one" of window windowName to true
end tell
end barberPole
-- Disable the 'barber pole' behavior of a progress bar.
on killBarberPole(windowName)
tell application "ProgBar"
set indeterminate of progress indicator "prog_one" of window windowName to false
end tell
end killBarberPole
--======================= Quit ProgBar ========================
on QuitBar()
try
tell application "ProgBar"
quit
end tell
end try
end QuitBar
--======================== Create Trash folders for each of the synced folders inside a common folder ==================
(*
the script creates a folder for trashed files on each drive at the level of A or B selection, with files/folders marked for deletion for that drive placed into these temp trash folders, for later clean up or recovery
Moved down here as of V4.0
*)
-- creates at the desktop of the start up disk a folder named '=>Removed Files:' or a "Synchro Removed Files" folder on a remote disk
on Create_Trash_Folder(Working_Folder, Selected_directory) -- Working_Folder is Folder A or Folder B passed to handler
tell application "Finder"
set disk_parent to the disk of Working_Folder -- Get the disk containing Working_Folder
if startup of disk_parent is true then --local volume for a second volume does not work here
if class of Working_Folder is folder then
set Common_trash_Folder to pLogFolder & "=>Removed Files:"
if not my FileExists(Common_trash_Folder) then --If the overall trash folder does not exist, create it
tell application "Finder"
make new folder at (pLogFolder as alias) with properties {name:"=>Removed Files"}
end tell
my LogEntry("Created folder: " & Common_trash_Folder, 0)
end if
set date_String to current date
set date_String to short date string of date_String as text
set Working_Folder_Result to name of Working_Folder & "_" & date_String as text
set trash_Folder to Common_trash_Folder & name of Working_Folder & "_" & date_String & ":"
if not my FileExists(trash_Folder) then -- If the specific trash folder for the folder to be synced does not exist for this date, create it
tell application "Finder"
make new folder at (Common_trash_Folder as alias) with properties {name:Working_Folder_Result}
end tell
end if
else
set trash_Folder to false
beep
if pLogEventsOn is true then my LogEntry("Not a Folder: " & Working_Folder, 0)
display dialog "Synchronization needs 2 folders. Please select 2 folders." with icon 0 buttons {"Stop"} default button 1
end if
else
if item "Synchro Removed Items" of disk_parent exists then
if class of item "Synchro Removed Items" of disk_parent is folder then
set trash_Folder to name of folder "Synchro Removed Items" of disk_parent
set trash_Folder to name of disk_parent & ":" & trash_Folder & ":" as text
else
set trash_Folder to true
beep
display dialog "The folder '=>Removed Items' was created on " & disk_parent & ". This acts as a temporary deposit for older files to be deleted" with icon 0 buttons "Stop" default button 1
end if
else
set trash_Folder to make new folder at disk_parent with properties {name:"Synchro Removed Items"}
set trash_Folder to name of disk_parent & ":" & "Synchro Removed Items:" as text
display dialog "A folder 'Synchro Removed Items' was created on " & disk_parent & ". All items to be deleted from the far drive will be moved here (old items replaced by more recent ones)" with icon 1 buttons {"OK"} default button 1 giving up after 25 -- seconds
end if
end if
my LogEntry("Directory " & Selected_directory & ":" & return & Working_Folder & return & "Trash Folder: " & return & trash_Folder as text, 0)
return trash_Folder
end tell
end Create_Trash_Folder
Model: MacBook (early 2009)
Browser: Safari 533.16
Operating System: Mac OS X (10.6)