This script has stopped working since updating to High Sierra (& presumably Mojave).
I use it to back up a website (though it works for any folder!): select the folder & it makes a time-stamped copy to the back up location.
It’s failing because Finder no longer finds the copy it makes once it renames it, so can’t move it. Any ideas how to fix?? Thanks.
--"Backup Site"
---------------------
(* ==== PROPERTIES ==== *)
global saveFolder
global saveFolderLocation
global myFolder
global theDuplicateAlias
property saveFolderName : "BACKUP" --!!
(* ==== HANDLERS ==== *)
--VERIFY FOLDER
on verifyFolder()
tell application "Finder"
try
--check backup folder
if not (exists folder saveFolderName of folder saveFolderLocation) then
make folder at folder saveFolderLocation with properties {name:saveFolderName}
end if
on error the error_message number the error_number
beep
display dialog "Error: " & the error_number & ". " & the error_message buttons {"Cancel"} default button 1 with icon 0
end try
end tell
end verifyFolder
--TIME STAMP DUPLICATE
--NB: for both files & folders
on timestampedduplicate(theItem)
tell application "Finder"
set folderCheck to theItem
if folder (folderCheck as text) exists then
else
set extensionhidden to extension hidden of theItem
set extension hidden of theItem to true
end if
set theItemName to displayed name of theItem
if folder (folderCheck as text) exists then
else
set theItemExtension to name extension of theItem
end if
set upOneLevelFolder to folder of theItem as alias
set {year:y, month:m, day:d, time string:t} to (current date)
set date_format to (y * 10000 + m * 100 + d) as string
set time_format to (t) as string
set t to (do shell script "echo " & "'" & t & "'" & " | sed 's/://g' ")
set thedate to date_format & " " & t as text
if folder (folderCheck as text) exists then
set theNewName to theItemName & " " & thedate as text
else
set theNewName to theItemName & " " & thedate & "." & theItemExtension as text
end if
log theNewName
set theDuplicate to duplicate theItem to upOneLevelFolder replacing no
set theDuplicateAlias to theDuplicate as alias
set name of theDuplicateAlias to theNewName
if folder (folderCheck as text) exists then
else
if extensionhidden then
set extension hidden of theDuplicateAlias to true
set extension hidden of theItem to true
else
set extension hidden of theDuplicateAlias to false
set extension hidden of theItem to false
end if
end if
end tell
end timestampedduplicate
(* ==== SCRIPT ==== *)
--initialise
set path2home to (path to home folder) as text
set saveFolderLocation to path2home & "Library:Application Support:"
set saveFolder to saveFolderLocation & saveFolderName & ":"
set defaultLocation to path2home & "Sites:"
my verifyFolder()
--dialog
display dialog "Backup site?" buttons {"Cancel", "View Backups", "Choose Site"} default button 3 with icon 1
set button_returned to button returned of the result
--view
if button_returned is "View Backups" then
tell application "Finder"
open folder saveFolder
end tell
--dialog
activate me
display dialog "Backup folder opened..." buttons {"Backup Site", "Done"} default button 2 with icon 1
set button_returned to button returned of the result
end if
--backup
if button_returned is in {"Choose Site", "Backup Site"} then
tell application "Finder"
set myFolder to choose folder default location defaultLocation as alias --choose site
end tell
my timestampedduplicate(myFolder) --make duplicate
tell application "Finder"
move folder theDuplicateAlias to folder saveFolder --move to backup folder
(*FAILING HERE!!*)
end tell
--dialog
activate me
display dialog "Site backed up." buttons {"Done"} default button 1 with icon 1
end if
(* ==== END ==== *)
I can’t test because I don’t use networks.
I just guess that the site is not aware of the new name when the Finder try to move the renamed folder.
For my own use I would not trigger Finder but would rely upon ASObjC which is more efficient but just to play I edited your script in a way which, I guess, would work.
It no longer use a renamed temporary folder but duplicate directly into the BACKUP folder then rename the replicate.
I changed also the structure so that there is no “living” global values which are stored on disk.
--"Backup Site"
---------------------
my germaine()
(* ==== HANDLERS ==== *)
--VERIFY FOLDER
on verifyFolder(saveFolderName, saveFolderLocation)
tell application "Finder"
try
--check backup folder
if not (exists folder saveFolderName of folder saveFolderLocation) then
make folder at folder saveFolderLocation with properties {name:saveFolderName}
end if
on error the error_message number the error_number
beep
display dialog "Error: " & the error_number & ". " & the error_message buttons {"Cancel"} default button 1 with icon 0
end try
end tell
end verifyFolder
on germaine()
--initialise
set saveFolderName to "BACKUP"
set path2home to (path to home folder) as text
set saveFolderLocation to path2home & "Library:Application Support:"
set saveFolder to saveFolderLocation & saveFolderName & ":"
set defaultLocation to path2home & "Sites:"
my verifyFolder(saveFolderName, saveFolderLocation)
--dialog
display dialog "Backup site?" buttons {"Cancel", "View Backups", "Choose Site"} default button 3 with icon 1
set button_returned to button returned of the result
--view
if button_returned is "View Backups" then
tell application "Finder"
open folder saveFolder
end tell
--dialog
activate me
display dialog "Backup folder opened..." buttons {"Backup Site", "Done"} default button 2 with icon 1
set button_returned to button returned of the result
end if
--backup
if button_returned is in {"Choose Site", "Backup Site"} then
tell application "Finder"
set myFolder to choose folder default location defaultLocation as alias --choose site
set replicate to duplicate myFolder to folder saveFolder
end tell
# As we want to rename a folder, no need to play with extension hidden
set {year:y, month:m, day:d, hours:h, minutes:mm, seconds:s} to (current date)
set date_format to (y * 10000 + m * 100 + d) as string
set time_format to (h * 10000 + mm * 100 + s) as string
set thedate to date_format & " " & time_format
tell application "Finder"
set newName to (name of myFolder) & " " & thedate
set name of replicate to newName
end tell
--dialog
activate me
display dialog "Site backed up." buttons {"Done"} default button 1 with icon 1
end if
end germaine
(* ==== END ==== *)
Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 11 février 2019 14:49:36
I’m seeing a bug in Mojave whereby theDuplicateAlias isn’t tracking the name change here. It seems workroundable:
set theNewName to "BACKUP"
tell application "Finder"
set upOneLevelFolder to container of theItem as alias -- 'folder of theItem' is incorrect.
set theDuplicate to duplicate theItem -- to upOneLevelFolder replacing no
set name of theDuplicate to theNewName -- Change the name before setting the alias.
set theDuplicateAlias to (item theNewName of upOneLevelFolder) as alias
end tell
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
my germaine()
#=====#=====#=====#=====#=====#=====
# Some handlers borrowed to Shane STANLEY
-- Creates a new folder. There is no error if the folder already exists, and it will also create intermediate folders if required
on createFolderNamed:proposedName inFolder:POSIXPath
local |⌘|, theFolderURL, theDestURL, theFileManager
set |⌘| to current application
set theFolderURL to |⌘|'s |NSURL|'s fileURLWithPath:POSIXPath
if class of proposedName is text then set proposedName to |⌘|'s NSString's stringWithString:proposedName
set proposedName to proposedName's stringByReplacingOccurrencesOfString:"/" withString:":"
set theDestURL to theFolderURL's URLByAppendingPathComponent:proposedName
set theFileManager to |⌘|'s NSFileManager's |defaultManager|()
-- set {theResult, theError} to theFileManager's createDirectoryAtURL:theDestURL withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
theFileManager's createDirectoryAtURL:theDestURL withIntermediateDirectories:true attributes:(missing value) |error|:(missing value)
-- if not (theResult as boolean) then error (theError's |localizedDescription|() as text)
return theDestURL's |path| as text
end createFolderNamed:inFolder:
#=====#=====#=====#=====#=====#=====
on copyThis:POSIXPath intoFolder:folderOrPath addingString:theStamp
local |⌘|, theSourceURL, destName, theFolderURL, theDestURL
set |⌘| to current application
set theSourceURL to |⌘|'s |NSURL|'s fileURLWithPath:POSIXPath
set destName to theSourceURL's |lastPathComponent|()
set destName to destName's stringByAppendingString:(space & theStamp)
set theFolderURL to |⌘|'s |NSURL|'s fileURLWithPath:folderOrPath
set theDestURL to theFolderURL's URLByAppendingPathComponent:destName
my copyFromURL:theSourceURL toURL:theDestURL withReplacing:true
end copyThis:intoFolder:addingString:
#=====
-- This handler is called by other handlers, and is not meant to called directly
on copyFromURL:sourceURL toURL:destinationURL withReplacing:replaceFlag
set |⌘| to current application
set theFileManager to |⌘|'s NSFileManager's |defaultManager|()
set {theResult, theError} to (theFileManager's copyItemAtURL:sourceURL toURL:destinationURL |error|:(reference))
if not theResult as boolean then
if replaceFlag and (theError's code() as integer = |⌘|'s NSFileWriteFileExistsError as integer) then -- it already exists, so try replacing
-- create suitable temporary directory in destinationURL's parent folder
set {tempFolderURL, theError} to theFileManager's URLForDirectory:(|⌘|'s NSItemReplacementDirectory) inDomain:(|⌘|'s NSUserDomainMask) appropriateForURL:(destinationURL's |URLByDeletingLastPathComponent|()) create:true |error|:(reference)
if tempFolderURL = missing value then error (theError's |localizedDescription|() as text) -- failed, so return error
-- copy sourceURL to temp directory
set tempDestURL to tempFolderURL's URLByAppendingPathComponent:(destinationURL's |lastPathComponent|())
set {theResult, theError} to theFileManager's copyItemAtURL:sourceURL toURL:tempDestURL |error|:(reference)
if not theResult as boolean then
-- copy failed, so delete temporary directory and return error
theFileManager's removeItemAtURL:tempFolderURL |error|:(missing value)
error (theError's |localizedDescription|() as text)
end if
-- replace existing file with temp file atomically, then delete temp directory
set {theResult, theError} to theFileManager's replaceItemAtURL:destinationURL withItemAtURL:tempDestURL backupItemName:(missing value) options:(|⌘|'s NSFileManagerItemReplacementUsingNewMetadataOnly) resultingItemURL:(missing value) |error|:(reference)
theFileManager's removeItemAtURL:tempFolderURL |error|:(missing value)
-- if replacement failed, return error
if not theResult as boolean then error (theError's |localizedDescription|() as text)
else -- replaceFlag is false or an error other than file already exists, so return error
error (theError's |localizedDescription|() as text)
end if
end if
end copyFromURL:toURL:withReplacing:
#=====#=====#=====#=====#=====#=====
on formatDate:theDate usingFormat:formatString
set theFormatter to current application's NSDateFormatter's new()
theFormatter's setDateFormat:formatString
set theString to theFormatter's stringFromDate:theDate
return theString as text
end formatDate:usingFormat:
#=====#=====#=====#=====#=====#=====
on germaine()
--initialise
set saveFolderName to "BACKUP"
set path2home to (path to home folder) as text
set saveFolderLocation to path2home & "Library:Application Support:"
set defaultLocation to path2home & "Sites:"
set POSIXSaveFolder to my createFolderNamed:saveFolderName inFolder:(POSIX path of saveFolderLocation)
--dialog
display dialog "Backup site?" buttons {"Cancel", "View Backups", "Choose Site"} default button 3 with icon 1
set button_returned to button returned of the result
--view
if button_returned is "View Backups" then
tell application "Finder"
open folder (POSIX file POSIXSaveFolder)
end tell
--dialog
activate me
display dialog "Backup folder opened..." buttons {"Backup Site", "Done"} default button 2 with icon 1
set button_returned to button returned of the result
end if
--backup
if button_returned is in {"Choose Site", "Backup Site"} then
set myFolder to choose folder default location defaultLocation as alias --choose site
# As we want to rename a folder, no need to play with extension hidden
set theStamp to my formatDate:(current date) usingFormat:"yyyyMMdd HHmmss"
# Copy myFolder into saveFolder adding theStamp to the final name
my copyThis:(POSIX path of myFolder) intoFolder:POSIXSaveFolder addingString:theStamp
--dialog
activate me
display dialog "Site backed up." buttons {"Done"} default button 1 with icon 1
end if
end germaine
(* ==== END ==== *)
This one creates the replicate directly with the stamped name.
Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 12 février 2019 12:13:46