kcw | journal | 2001 << Previous Page | Next Page >>
set m_source_folder to ""
set m_destination_folder to ""
set m_deleted_folder to true

set m_log_file to false
set m_log_errors to false
set m_log_actions to false
set m_log_decisions to false
set m_log_folder_trace to false
set m_log_file_trace to false

set m_diff_sec to 0
set m_copy_newer_files_only to false
set m_filter_files to "/.DS_Store/Desktop DB/Desktop DF/
.FBCLockFolder/.FBCIndex/Network Trash Folder/" & Â
"TheVolumeSettingsFolder/AppleShare PDS/Trash/.Trash/.Trashes/Temporary Items/"

set m_create_index2_files to false -- !!! EXTRA !!!

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_diff_sec = 0) then
try
set l_record to display dialog Â
"Source/Destination with modification dates within these number of
seconds are considered the same (Cancel to quit):" default answer 60
set m_diff_sec to text returned of l_record as integer
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 l_choices to ""
set l_choices_string to ""

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.txt"

set l_options to {"Errors", "Actions", "Decisions", "Folder Trace", "File Trace"}
set l_defaults to {"Errors", "Actions"}

set l_choices to choose from list l_options with prompt Â
"Select activities to log:" default items l_defaults
with multiple selections allowed and empty selection allowed

if ("Errors" is in l_choices) then
set m_log_errors to true
set l_choices_string to "Errors"
end if
if ("Actions" is in l_choices) then
set m_log_actions to true
if (l_choices_string is equal to "") then
set l_choices_string to "Actions"
else
set l_choices_string to l_choices_string & ", Actions"
end if
end if
if ("Decisions" is in l_choices) then
set m_log_decisions to true
if (l_choices_string is equal to "") then
set l_choices_string to "Decisions"
else
set l_choices_string to l_choices_string & ", Decisions"
end if
end if
if ("Folder Trace" is in l_choices) then
set m_log_folder_trace to true
if (l_choices_string is equal to "") then
set l_choices_string to "Folder Trace"
else
set l_choices_string to l_choices_string & ", Folder Trace"
end if
end if
if ("File Trace" is in l_choices) then
set m_log_file_trace to true
if (l_choices_string is equal to "") then
set l_choices_string to "File Trace"
else
set l_choices_string to l_choices_string & ", File Trace"
end if
end if
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

-- Should we copy system files?
set l_record to display dialog "Copy system files?" buttons {"yes", "no"}
if (button returned of l_record is "yes") then
set m_filter_files to ""
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 "Log file: " & m_log_file
log "Log options: " & l_choices_string
log "Copy only if source is newer: " & m_copy_newer_files_only
log "Filter files: " & m_filter_files
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 not boolean) 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 "Log file: " & m_log_file & "
" to m_log_file
write "Log options: " & l_choices_string & "
" to m_log_file
write "Copy only if source is newer: " & m_copy_newer_files_only & "
" to m_log_file
write "Filter files: " & m_filter_files & "
" 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
if (m_log_folder_trace is true) then
log "Checking folder for copy: " & l_current_folder as string
if (class of m_log_file is not boolean) then
write "Checking folder for copy: " & l_current_folder & "
" to m_log_file
end if
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

try
-- Determine destination folder.
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
on error l_error
-- If there's an error, chances are dest folder doesn't exist.
-- Occurs when copying from Mac OS X to Mac OS 9 and file name
-- of source folder is illegal in Mac OS 9.
set l_dest_folder to ""
set l_items to {}

if (m_log_errors is true) then
log "*****Error getting destination folder " & l_string
log "*****" & l_error
if (class of m_log_file is not boolean) then
write "*****Error getting destination folder " & l_string & "
" to m_log_file
write "*****" & l_error & "
" to m_log_file
end if
end if
end try

-- l_temp_folders keeps track of folder list, so that we can
-- prepend it to l_pending_folders and do a depth-first search.
set l_temp_folders to {}

repeat with l_source_item_name in l_items

if (m_log_file_trace is true) then
log "....Checking file " & l_current_folder & l_source_item_name
if (class of m_log_file is not boolean) then
write "....Checking file " & l_current_folder & l_source_item_name & "
" to m_log_file
end if
end if

set l_source_invalid to false

try
set l_source_item to (get item l_source_item_name of l_current_folder)
set l_copy_item to false
set l_dest_item to ""
on error l_error
set l_source_invalid to true

if (m_log_errors is true) then
log "*****Error processing source item " & l_current_folder & l_source_item_name
log "*****" & l_error
if (class of m_log_file is not boolean) 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 if
end try

if ("/" & l_source_item_name & "/" is in m_filter_files) then
-- Check to see if this is a file we should skip
set l_source_invalid to true

if (m_log_decisions is true) then
log "////Skipping filtered file " & l_current_folder & l_source_item_name
if (class of m_log_file is not boolean) then
write "////Skipping filtered file " & l_current_folder & l_source_item_name & "
" to m_log_file
end if
end if
end if

if (l_source_invalid is false) then

set l_source_kind to (get kind of l_source_item)

if (l_source_kind is "Application") then
set l_source_date to (get creation date of l_source_item)
else
set l_source_date to (get modification date of l_source_item)
end if

-- See if the item exists at the destination
try
set l_dest_item to (get item l_source_item_name of l_dest_folder)

set l_dest_kind to (get kind of l_dest_item)

if (l_source_kind is "Application") then
set l_dest_date to (get creation date of l_dest_item)
else
set l_dest_date to (get modification date of l_dest_item)
end if
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 (l_source_kind is not equal to l_dest_kind) then
-- First check class of items
set l_copy_item to true

if (m_log_decisions is true) then
log "////Source kind (" & l_source_kind & ")
differs from destination kind (" & l_dest_kind & ")"
if (class of m_log_file is not boolean) then
write "////Source kind (" & l_source_kind & ")
differs from destination kind (" & l_dest_kind & ")
" to m_log_file
end if
end if

else if (m_copy_newer_files_only is true and Â
l_source_kind is not "Folder" and Â
((l_source_date - l_dest_date) - m_diff_sec) > 0) then
-- Second, check source item is newer than destination. Only for non-folders
set l_copy_item to true

if (m_log_decisions is true) then
log "////Source date (" & l_source_date & ")
is newer than destination date (" & l_dest_date & ")"
if (class of m_log_file is not boolean) then
write "////Source date (" & l_source_date & ")
is newer than destination date (" & l_dest_date & ")
" to m_log_file
end if
end if

else if (m_copy_newer_files_only is false and Â
l_source_kind is not "Folder" and Â
(((l_source_date - l_dest_date) - m_diff_sec) > 0 or Â
((l_dest_date - l_source_date) - m_diff_sec) > 0)) then
-- Or, check date of source item is different than destination.
Only for non-folders
set l_copy_item to true

if (m_log_decisions is true) then
log "////Source date (" & l_source_date & ") is different
than destination date (" & l_dest_date & ")"
if (class of m_log_file is not boolean) then
write "////Source date (" & l_source_date & ") is different
than destination date (" & l_dest_date & ")
" to m_log_file
end if
end if

end if
end if

-- If we need to copy the item...
if (l_copy_item is true) then

-- Log event
if (m_log_actions is true) then
log "++++Copying item " & l_source_item as string
if (class of m_log_file is not boolean) then
write "++++Copying item " & l_source_item & "
" to m_log_file
end if
end if

-- Copy source to destination
if (l_source_kind is not "Folder") 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
if (m_log_errors is true) then
log "****" & l_error
if (class of m_log_file is not boolean) then
write "****" & l_error & "
" to m_log_file
end if
end if
end try
end timeout
else
try
-- move or delete non-folder item
if (class of l_dest_item is not string and l_dest_kind is not "Folder") 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 (l_source_item_name)
on error l_error
if (m_log_errors is true) then
log "****" & l_error
if (class of m_log_file is not boolean) then
write "****" & l_error & "
" to m_log_file
end if
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 l_source_item_name is "index.html") then
try
delete file "index2.html" of l_current_folder
set l_dup to (duplicate l_source_item)
set name of l_dup to "index2.html"
on error l_error
end try

if (m_log_actions is true) then
log "++++Copying item index2.html"
if (class of m_log_file is not boolean) then
write "++++Copying item index2.html
" to m_log_file
end if
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
if (m_log_errors is true) then
log "****" & l_error
if (class of m_log_file is not boolean) then
write "****" & l_error & "
" to m_log_file
end if
end if
end try
end timeout
end if

end if

-- If source item is a folder, add it to pending folders list
if (l_source_kind is "Folder") then
set l_temp_folders to l_temp_folders & {l_source_item as alias}
end if
end if
end repeat

-- Prepend new folders to l_pending_folders
if ((count of l_temp_folders) > 0) then
set l_pending_folders to l_temp_folders & l_pending_folders
end if

-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-- Delete Destination Files Not In Source
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

if (class of l_dest_folder is not string) then

-- Log current folder
if (m_log_folder_trace is true) then
log "Checking folder for delete: " & l_dest_folder as string
if (class of m_log_file is not boolean) then
write "Checking folder delete: " & l_dest_folder & "
" to m_log_file
end if
end if

-- Cycle through items in the current folder and process each item
set l_items to list folder of (l_dest_folder as alias)

repeat with l_destination_item_name in l_items

if (m_log_file_trace is true) then
log "....Checking file " & l_dest_folder & l_destination_item_name
if (class of m_log_file is not boolean) then
write "....Checking file " & l_dest_folder & l_destination_item_name & "
" to m_log_file
end if
end if

set l_dest_invalid to false

try
set l_destination_item to (get item l_destination_item_name of l_dest_folder)
set l_delete_item to false
set l_source_item to ""
on error l_error
set l_dest_invalid to true
if (m_log_errors is true) then
log "*****Error processing destination item " & l_dest_folder & l_destination_item_name
log "*****" & l_error
if (class of m_log_file is not boolean) then
write "*****Error processing destination item " & l_dest_folder
& l_destination_item_name & "
" to m_log_file
write "*****" & l_error & "
" to m_log_file
end if
end if
end try

if ("/" & l_destination_item_name & "/" is in m_filter_files) then
-- Check to see if this is a file we should skip
set l_dest_invalid to true

if (m_log_decisions is true) then
log "////Skipping filtered file " & l_dest_folder & l_destination_item_name
if (class of m_log_file is not boolean) then
write "////Skipping filtered file " & l_dest_folder & l_destination_item_name & "
" to m_log_file
end if
end if
end if

if (l_dest_invalid is false) then
-- See if the item exists at the destination
try
set l_source_item to (get item l_destination_item_name of l_current_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
if (m_log_actions is true) then
log "----Deleting item " & l_destination_item as string
if (class of m_log_file is not boolean) then
write "----Deleting item " & l_destination_item & "
" to m_log_file
end if
end if

-- Delete destination
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
if (m_log_errors is true) then
log "****" & l_error
if (class of m_log_file is not boolean) then
write "****" & l_error & "
" to m_log_file
end if
end if
end try

end if

end if
end repeat
end if
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 "Log file: " & m_log_file
log "Log options: " & l_choices_string
log "Copy only if source is newer: " & m_copy_newer_files_only
log "Filter files: " & m_filter_files
log "Copy index.html to index2.html: " & m_create_index2_files
log "Backup start time: " & l_start_time as string
log "Backup end time: " & (current date)
log "============================================================="
if (class of m_log_file is not boolean) 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 "Log file: " & m_log_file & "
" to m_log_file
write "Log options: " & l_choices_string & "
" to m_log_file
write "Copy only if source is newer: " & m_copy_newer_files_only & "
" to m_log_file
write "Filter files: " & m_filter_files & "
" 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 end time: " & (current date) & "
" to m_log_file
write "=============================================================
" to m_log_file
close access m_log_file
end if
end if

end tell

Copyright (c) 2001 Kevin C. Wong
Page Created: August 20, 2004
Page Last Updated: August 20, 2004