Once again, we'll start out with the actual file, then
notes. The code is
getting quite large. But we'll still keep it all on one journal.
Synchronize Folder Kevin C. Wong -- 20011026 -- v 1.0b4 Synchronize destination folder to match source folder.
Issues May not copy Application frameworks that don't end with ".app".
20011026 1.0b4 -- Use "list folder" instead of "get items of folder alias". Then use file specifications instead of actual files, use "info for " to get most if item info we need. These changes work with applications and invisible items, which didn't work with "get items of folder alias". Lots of little changes to support the new mechanism.
20011025 1.0b3 -- Bug: No date by comparison if m_copy_newer_files_only is false -- Fix: Delete or move non-folder file before we create folder to replace it. -- Fix: Close m_log_file when done. -- Fix: Close m_log_file before opening it again in case it's already open. -- Fix: Test for log write should be "class of m_log_file is file specification". -- Fix: Start writing to log file at the end of the file, not the beginning. -- Fix: Added line endings to log output. -- Workaround: Skip Application files.
----------------------------------------------------------------------------
set m_source_folder to "" set m_destination_folder to "" set m_deleted_folder to true set m_copy_newer_files_only to false set m_create_index2_files to false -- !!! EXTRA !!! set m_log_file to false
set m_quit to false
tell application "Finder" -- Get source and destination folders if (m_source_folder = "") then try set m_source_folder to choose folder with prompt "Items will be copied FROM this folder (Cancel to quit):" on error l_error set m_quit to true end try end if if (m_quit is false) then if (m_destination_folder = "") then try set m_destination_folder to choose folder with prompt "Items will be copied TO this folder (Cancel to quit):" on error l_error set m_quit to true end try end if end if if (m_quit is false) then if (m_deleted_folder is true) then try set m_deleted_folder to choose folder with prompt "Deleted items will be moved to this folder (Cancel to delete items instead):" on error l_error set m_deleted_folder to false end try end if if (m_log_file is false) then try set m_log_file to  choose file name with prompt  "Write synchronize log to this file (Cancel for no logging):" default name "Synchronize Folder Log File" on error l_error end try end if -- Should we only copy newer files? set l_record to display dialog "Copy only if source file is newer?" buttons {"yes", "no"} if (button returned of l_record is "yes") then set m_copy_newer_files_only to true end if -- !!! EXTRA !!! -- Should we create index2.html files? set l_record to display dialog "Copy index.html to index2.html?" buttons {"yes", "no"} if (button returned of l_record is "yes") then set m_create_index2_files to true end if -- Log start time set l_start_time to current date log "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" log "Backup source: " & m_source_folder as string log "Backup destination: " & m_destination_folder as string log "Deleted folder: " & m_deleted_folder as string log "Copy only if source is newer: " & m_copy_newer_files_only log "Copy index.html to index2.html: " & m_create_index2_files log "Backup start time: " & l_start_time as string log "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" if (class of m_log_file is file specification) then try close access m_log_file on error l_error end try try open for access m_log_file with write permission on error l_error log l_error as string log "Disabling log file..." set m_log_file to false end try write "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ " starting at (get eof m_log_file) + 1 to m_log_file write "Backup source: " & m_source_folder & " " to m_log_file write "Backup destination: " & m_destination_folder & " " to m_log_file write "Deleted folder: " & m_deleted_folder & " " to m_log_file write "Copy only if source is newer: " & m_copy_newer_files_only & " " to m_log_file write "Copy index.html to index2.html: " & m_create_index2_files & " " to m_log_file write "Backup start time: " & l_start_time & " " to m_log_file write "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ " to m_log_file end if -- Get source folder length so that we can strip it out of each source folder's path set l_source_length to (length of (m_source_folder as string)) + 1 -- Convert folder class to string (":...") set l_destination_folder_string to m_destination_folder as string -- Set queue items and start main repeat loop. set l_pending_folders to {m_source_folder} -- While items remain in queue, process each one repeat while ((length of l_pending_folders) > 0) -- Remove the first item from l_pending_folders set l_current_folder to first item of l_pending_folders if (length of l_pending_folders = 1) then set l_pending_folders to {} else set l_pending_folders to rest of l_pending_folders end if -- Log current folder log "Checking folder " & l_current_folder as string if (class of m_log_file is file specification) then write "Checking folder " & l_current_folder & " " to m_log_file end if -- Determine destination folder string set l_string to l_current_folder as string try set l_string to (text l_source_length through (length of l_string) of l_string) on error l_error -- error if this is the source folder base string set l_string to "" end try set l_string to l_destination_folder_string & l_string -- Determine destination folder. -- Note that destination folder must exist. set l_dest_folder to alias l_string -- Cycle through items in the current folder and process each item set l_items to list folder of l_current_folder repeat with l_source_item_name in l_items set l_source_invalid to false try set l_source_item to (item (l_source_item_name as string) of l_current_folder) as file specification set l_source_info to my addIsFolderAttribute(info for l_source_item) set l_copy_item to false set l_dest_item to "" set l_dest_info to "" set l_source_app to false on error l_error set l_source_invalid to true log "*****Error processing source item " & l_current_folder & l_source_item_name log "*****" & l_error if (class of m_log_file is file specification) then write "*****Error processing source item " & l_current_folder & l_source_item_name & " " to m_log_file write "*****" & l_error & " " to m_log_file end if end try if (l_source_invalid is false) then -- See if the item exists at the destination try set l_dest_item to (item (name of l_source_info) of l_dest_folder) as file specification set l_dest_info to my addIsFolderAttribute(info for l_dest_item) on error l_error set l_copy_item to true end try -- Check to see if source and destination differ. if (l_copy_item is false) then if (file type of l_source_info is not equal to file type of l_dest_info) then -- First check class of items set l_copy_item to true else if (m_copy_newer_files_only is true and  isFolder of l_source_info is false and  modification date of l_source_info is after modification date of l_dest_info) then -- Second, check source item is newer than destination. Only for non-folders set l_copy_item to true else if (m_copy_newer_files_only is false and  isFolder of l_source_info is false and  modification date of l_source_info is not equal to modification date of l_dest_info) then -- Or, check date of source item is different than destination. Only for non-folders set l_copy_item to true end if end if -- If we need to copy the item... if (l_copy_item is true) then -- Log event log "----Copying item " & l_source_item as string if (class of m_log_file is file specification) then write "----Copying item " & l_source_item & " " to m_log_file end if -- Copy source to destination if (isFolder of l_source_info is false) then -- If source is not a folder then copy it to destination with timeout of 86400 seconds -- 1 day timeout try duplicate l_source_item to l_dest_folder with replacing on error l_error log "****" & l_error if (class of m_log_file is file specification) then write "****" & l_error & " " to m_log_file end if end try end timeout else try -- move or delete non-folder item if (class of l_dest_item is not string and isFolder of l_dest_info is false) then if (class of m_deleted_folder is alias) then move l_dest_item to m_deleted_folder with replacing else delete l_dest_item end if end if -- If source is a folder then create destination folder set l_folder to make new folder at l_dest_folder set name of l_folder to (name of l_source_info) on error l_error log "****" & l_error if (class of m_log_file is file specification) then write "****" & l_error & " " to m_log_file end if end try end if -- !!! EXTRA !!! -- If this item is index.html, duplicate it to index2.html and copy it over. -- We only need to create index2.html if we're copying over index.html. -- Extra copy covers case when index2.html did not initially exist. if (m_create_index2_files is true and name of l_source_info is "index.html") then try delete file "index2.html" of l_current_folder on error l_error end try set l_dup to (duplicate l_source_item) set name of l_dup to "index2.html" log "----Copying item index2.html" if (class of m_log_file is file specification) then write "----Copying item index2.html " to m_log_file end if with timeout of 86400 seconds -- 1 day timeout try duplicate file "index2.html" of l_current_folder to l_dest_folder with replacing on error l_error log "****" & l_error if (class of m_log_file is file specification) then write "****" & l_error & " " to m_log_file end if end try end timeout end if end if -- If source item is a folder, add it to pending folders list if (isFolder of l_source_info is true) then -- We know l_source_item is a folder, not an application -- But it is a file specification, we need queue the actual item set l_pending_folders to l_pending_folders & {get folder l_source_item as alias} end if end if end repeat end repeat -- Log delete start time set l_delete_time to current date log "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" log "Starting delete sync at " & l_delete_time as string log "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" if (class of m_log_file is file specification) then write "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ " to m_log_file write "Starting delete sync at " & l_delete_time & " " to m_log_file write "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ " to m_log_file end if -- Get destination folder length so that we can strip it out of each destination folder's path set l_destination_length to (length of (m_destination_folder as string)) + 1 -- Convert folder class to string (":...") set l_source_folder_string to m_source_folder as string -- Set queue items and start main repeat loop. set l_pending_folders to {m_destination_folder} -- While items remain in queue, process each one repeat while ((length of l_pending_folders) > 0) -- Remove the first item from l_pending_folders set l_current_folder to first item of l_pending_folders if (length of l_pending_folders = 1) then set l_pending_folders to {} else set l_pending_folders to rest of l_pending_folders end if -- Log current folder log "Checking folder " & l_current_folder as string if (class of m_log_file is file specification) then write "Checking folder " & l_current_folder & " " to m_log_file end if -- Determine source folder string set l_string to l_current_folder as string try set l_string to (text l_destination_length through (length of l_string) of l_string) on error l_error -- error if this is the destination folder base string set l_string to "" end try set l_string to l_source_folder_string & l_string -- Determine source folder. -- Note that source folder must exist. set l_source_folder to alias l_string -- Cycle through items in the current folder and process each item set l_items to list folder of l_current_folder repeat with l_destination_item_name in l_items set l_dest_invalid to false try set l_destination_item to (item (l_destination_item_name as string) of l_current_folder) as file specification set l_destination_info to my addIsFolderAttribute(info for l_destination_item) set l_delete_item to false set l_source_item to "" set l_dest_app to false on error l_error set l_dest_invalid to true log "*****Error processing destination item " & l_current_folder & l_destination_item_name log "*****" & l_error if (class of m_log_file is file specification) then write "*****Error processing destination item " & l_current_folder & l_destination_item_name & " " to m_log_file write "*****" & l_error & " " to m_log_file end if end try if (l_dest_invalid is false) then -- See if the item exists at the destination try set l_source_item to get item (name of l_destination_info) of l_source_folder on error l_error set l_delete_item to true end try -- If we need to delete the item... if (l_delete_item is true) then -- Log event log "----Deleting item " & l_destination_item as string if (class of m_log_file is file specification) then write "----Deleting item " & l_destination_item & " " to m_log_file end if -- Delete source try if (class of m_deleted_folder is alias) then move l_destination_item to m_deleted_folder with replacing else delete l_destination_item end if on error l_error log "****" & l_error if (class of m_log_file is file specification) then write "****" & l_error & " " to m_log_file end if end try end if -- If source item is a folder and wasn't deleted, add it to pending folders list if (l_delete_item is false and isFolder of l_destination_info is true) then -- We know l_source_item is a folder, not an application -- But it is a file specification, we need queue the actual item set l_pending_folders to l_pending_folders & {get folder l_destination_item as alias} end if end if end repeat end repeat -- Log end time log "=============================================================" log "Backup source: " & m_source_folder as string log "Backup destination: " & m_destination_folder as string log "Deleted folder: " & m_deleted_folder as string log "Copy only if source is newer: " & m_copy_newer_files_only log "Copy index.html to index2.html: " & m_create_index2_files log "Backup start time: " & l_start_time as string log "Backup delete time: " & l_delete_time as string log "Backup end time: " & (current date) log "=============================================================" if (class of m_log_file is file specification) then write "============================================================= " to m_log_file write "Backup source: " & m_source_folder & " " to m_log_file write "Backup destination: " & m_destination_folder & " " to m_log_file write "Deleted folder: " & m_deleted_folder & " " to m_log_file write "Copy only if source is newer: " & m_copy_newer_files_only & " " to m_log_file write "Copy index.html to index2.html: " & m_create_index2_files & " " to m_log_file write "Backup start time: " & l_start_time & " " to m_log_file write "Backup delete time: " & l_delete_time & " " to m_log_file write "Backup end time: " & (current date) & " " to m_log_file write "============================================================= " to m_log_file close access m_log_file end if end if end tell
on addIsFolderAttribute(l_record) if (class of l_record is record) then -- Add isFolder attribute so we can refer to it instead of folder set l_return to l_record & {isFolder:(folder of l_record)} -- Add dummy file type if there is none try file type of l_return on error l_error set l_return to l_return & {file type:false} end try -- Check to see if this an application, in which case treat it as a non-folder if (name of l_return ends with ".app") then set isFolder of l_return to false end if return l_return else return l_record end if end addIsFolderAttribute
|
|