I don’t need help here, because I eventually found the bug and a way to avoid it. I just wanted to document it, because to me, this is a pretty surprising bug.
I had this script to make an alias to a folder inside the user’s library script folder:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set newScriptsFolderAlias to choose folder with prompt "What folder do you want to alias to \"~/Library/Scripts/\""
set libraryScriptsAliasPath to (POSIX path of (path to home folder as text)) & "Library/Scripts/Scripts"
if check_file_exists(libraryScriptsAliasPath) is true then
do shell script "rm -r " & quoted form of libraryScriptsAliasPath
set repeatCount to 0
repeat until check_file_exists(libraryScriptsAliasPath) is false
delay 0.1
set repeatCount to repeatCount + 1
if repeatCount > 20 then
display dialog "Error deleting current directory at:" & return & libraryScriptsAliasPath
error -128
end if
end repeat
end if
tell application "Finder" to set createdAlias to make new alias to newScriptsFolderAlias at folder ((path to home folder as text) & "Library:Scripts:") with properties {name:"Scripts"}
on check_file_exists(filePath)
try
(POSIX file filePath as alias)
set fileExists to true
on error
set fileExists to false
end try
return fileExists
end check_file_exists
Running this, on repeated runs, I frequently end up with a Finder Alias that does not point to the directory selected by the user in the script - it points to the same directory as the prior alias that was already there.
All that code checking to see if it exists and all was an attempt to troubleshoot - was it not really deleting with the ‘rm’ command?
But no, the old Finder Alias really gets deleted reliably by the ‘rm’ command. And a new one gets made. And that new one somehow does not point to the directory the user selected, stored in the variable “newScriptsFolderAlias.”
Now, if you just use Finder to delete the old Finder Alias instead of a “do shell script” “rm” command, then it seems to work perfectly reliably. This works:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set newScriptsFolderAlias to choose folder with prompt "What folder do you want to alias to \"~/Library/Scripts/\""
set libraryScriptsAliasPath to (POSIX path of (path to home folder as text)) & "Library/Scripts/Scripts"
tell application "Finder"
try
delete ((POSIX file libraryScriptsAliasPath) as alias)
end try
set createdAlias to make new alias to newScriptsFolderAlias at folder ((path to home folder as text) & "Library:Scripts:") with properties {name:"Scripts"}
end tell
But I found the failure of the first script to be very surprising.
Interesting. I can’t repeat it here. However, there’s at least one other case where rm can be less than satisfactory: it doesn’t clean up the launch services database when you use it to delete an app.
Here’s an ASObjC alternative to try:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set newScriptsFolderAlias to choose folder with prompt "What folder do you want to alias to \"~/Library/Scripts/\""
set fileManager to current application's NSFileManager's defaultManager()
set sourceURL to current application's NSURL's fileURLWithPath:(POSIX path of newScriptsFolderAlias)
set libraryScriptsAliasPath to (POSIX path of (path to home folder as text)) & "Library/Scripts/Scripts"
set destURL to current application's NSURL's fileURLWithPath:libraryScriptsAliasPath
fileManager's removeItemAtURL:destURL |error|:(missing value)
set theData to (sourceURL's bookmarkDataWithOptions:(current application's NSURLBookmarkCreationSuitableForBookmarkFile) includingResourceValuesForKeys:{} relativeToURL:(missing value) |error|:(missing value))
current application's |NSURL|'s writeBookmarkData:theData toURL:destURL options:(current application's NSURLBookmarkCreationSuitableForBookmarkFile) |error|:(missing value)
t.spoon. I think this may be a timing issue. I ran your first script as written and observed the behavior you describe. I then inserted a 1-second delay just above the line that creates the alias and the first script worked as expected. I tested your second script and it works fine without the delay.
Shane - thanks for the AsObjC.
Peavine - yes, I had certainly expected it might be a timing issue. But I thought that if it was, then running a loop to check that the file does not exist before proceeding to make the new Finder Alias would effect whatever the necessary delay is - that is, once the system thinks the old one is gone, you’d think that would be sufficient to prevent whatever problems could have been caused by its existence when making the new one.
It seems the ‘rm’ works consistently, it doesn’t fail. And the “make new alias” code does fail if the existing alias is not deleted first. If you comment out the “rm” line, the script will reliably fail with an error when it tries to make the alias.
So the old alias really does get deleted, and a new one does get created by the script, yet the new one the script created does not point where the script says it should.
I’m super confused about how that’s possible. I’m willing to grant that it’s timing-related… but I would expect a “timing bug” in this scenario to mean that the “make new alias” command would over-run the effect of the “rm” (removing the old Finder Alias), in which case it should fail, because the path it’s trying to make the Finder Alias at already exists.
But it doesn’t… it makes a new Finder Alias that points to the wrong place… I find that an extremely unexpected failure mode.
I’m glad you could confirm the same error on your system.
Thanks,
t.spoon.
t.spoon. I agree with what you say. My guess is that this conundrum arises from the nature of aliases and how macOS keeps track of alias-referenced files, although I don’t know enough about the inner workings of macOS to say if that’s true.
Just out of curiosity, I spent some additional time on this topic and wrote the following script, which works by resetting the target of an existing alias file. I tested this under Catalina without issue but it may not work on computers running earlier versions of macOS.
set aliasName to "Script Alias"
set aliasFolder to (path to desktop as text)
set referencedFolder to (choose folder) as text
tell application "Finder"
try
make new alias file at folder aliasFolder to folder referencedFolder with properties {name:aliasName}
on error
set original item of alias file (aliasFolder & aliasName) to folder referencedFolder
end try
end tell
I’m not sure how much it affects the result, but t.spoon’s alias-creation line has ‘make new alias’. peavine’s last script above corrects this to ‘make new alias file’, but then makes the creation destination a string path.
Thanks Nigel. I revised my script as you suggest. Also, I modified t.spoon’s first script, changing “alias” to “alias file”, and it still did not work correctly. His second script always worked as expected.