How to trigger a script after duplicating/copying a directory in Mac OSX/Finder
In Snow Leopard, I want to trigger a script/code whenever a user duplicates a directory in Finder. How can I do that?
I've been hunting around the docs, but I'm a little too new this type of work to recognize the right approach.
Motivation: If a directory is under version control, say with git or hg or svn, and the user duplicates that dir, then I want to run a script that searches for the original dir and then makes a 'tag' in version control. If the user renames the dir, say within 10 seconds, then the rename would be part of that tag comment. I'd eventually like to throw on some overlay icons to indicate the version control state of the dir, too.
Expanded Motivation: The problem that I face is that that version control software, like git, and hg, in my opinion is too complicated namely because it is too disconnected from the file system and acts as sort of a shadow-filesystem. I'm a big fan of version control and have used it for many years - but I have also seen the limits of deployment because of its complexity. The reality is that a lot more code would be under version control if it were easier to use.
I'm investigating the feasibility of creating an easier to use VCS system that doesn't require terminal access. Imagine what version control (for code) would look like if Apple were to make it part of finder and/or iLife - simple, but good-enough. In reality, I'm obviously not going to re-invent a vcs, but I'm hoping that building a module/plugin for something like hg, and coupling that with a re-envisioning of how vcs works for a finder-centric UI a - all to create a simpler, but good enough, VCS for the more casual programm开发者_如何学Goer.
The first technical hurdle detecting directory copies and renames - and hence this question.
Number of Files: Since the primary motivation of this project is for source code version control, I only need to match the number of directories matching the number of projects you are working on. So, if you are working on two distinct projects, then, I think, that I only need to track two directories - the root of each project. Now, I fully admit that I may, at this point be mis-characterizing the need, so maybe I need to track all of the directories in the projects, or maybe even all of files in those projects, too, so lets say, for the sake of argument, that a typically project has 1,000 files in it. So, basically, maybe only a few directories, or a few hundred directories, or maybe a few thousand files. Importantly, I think 50,000 files would be at the higher end of the spectrum.
User duplicates the dir 'trunk' from within finder
trunk --> trunk copy
If the user renames 'trunk copy' to 'trunk copy fixed #255 per colors' the trunk dir (not the copy) would be tagged with the comment 'fixed #255 per colors'
References:
File System Event Programming
- Get notified, upon start-up, if something in a registered dir changed - if any one file in a large dir changes. It won't tell you, I don't think, what got changed.
Kernel Queues
- You can register to be notified of things at the individual file level. You're options are (at least) the following: NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE This could maybe be used to detect a directory rename (will it work for dirs?), but apparently not a dir copy.
Slightly related question:
- How to write finder plugin
Thanks, JJ
The original post suggested a really large project, with a lot of unspecified features. Your 'expanded motivation' ending with '... detecting directory copies and renames ...' was helpful.
First, you pretty much answered your own post with the references to File System Events and Kernel Queues. You were correct to dismiss Folder Actions, but for the wrong reason. You seemed concerned with activating FAs for a large number of folders. That is not a problem, because it could be automated. The reason FAs won't work is that they can't detect a file rename. Also, there is a huge problem with overhead and concurrency because the actions are AppleScript.
And you were correct about FS Events: (from Darwin Docs)
The important point to take away is that the granularity of notifications is at a directory level. It tells you only that something in the directory has changed, but does not tell you what changed.
So it seems you are left with Kernel Queues. They do everything. Note that you will have to be clever to use Kernel Queues- you have to know the name of a flie to monitor it. So as new files/folders are created, you will have to interpret the events, and open (O_EVTONLY) the new files. However, there is a problem: (more Darwin Docs)
If you are monitoring a large hierarchy of content, you should use file system events instead, however, because kernel queues are somewhat more complex than kernel events, and can be more resource intensive because of the additional user-kernel communication involved.
Another reply had mentioned that TimeMachine used FS Events. I doubt that because of the noted 'coarse granularity'. I suspect that there is a special hook in the kernel 'close file' code. At least, that is what it seems you need if you want to monitor many files. How many are you considering?
It sounds like file system events is what you want. Maybe you're shying away from it because it seems complicated, but I think that what you're trying to do is complicated in general.
Spotlight and Time Machine use file system events in order to determine what's changed in the file system and therefore what files need to be indexed or backed up. Your requirement is similar, only instead of backing up, you want to check if the updated directories exist in source control, and if not, determine if something (either the new directories or a tag or whatever) should be added to source control.
There's probably a way to do this just within the Finder, but you probably also want to know if a user copies a directory from the command line or from some other program.
Could you go into some more detail about your motivation for this feature? It sounds like you're trying to enable users to "use" source control without actually having to learn it. "Just copy the directory and the integration code will take care of everything." But I think that you'll run into problems trying to do interpret very general filesystem changes as implicit source control commands.
If all you want is to trigger this script on some folders, then you should use what Apple calls "Folder Action" you can attach to whichever folder you like an apple script.
I don't know what the exact even the Finder will trigger but if I had my mac with me know I would open automater and look under "Files and Folders" I am 100% you will find an event for duplication or copying there.
there are no "on duplicate" and "on rename" events from the finder/system in automator scripts, so exactly what you are asking for requires using filesystem events (which I'm not going to get in to) but the following quick applescript
- catches all items added to the folder (including those added by duplication)
- asks the user to provide a tag name
- runs a bash script with this info
which should enable you to build a good solution
- place additem.scpt in /Library/Scripts/Folder Action Scripts
- fixup.sh in the folder containing trunk (or adjust and put where you like)
- on the containing folder, right click and select "Folder Action Setup..."
- connect the folder with the new script
- edit fixup.sh to suit your needs
additem.scpt
on adding folder items to this_folder after receiving added_items
try
tell application "Finder"
set the folder_name to the name of this_folder
end tell
set the item_count to the number of items in the added_items
repeat with an_added_item in added_items
tell application "Finder"
set item_name to name of an_added_item
end tell
set new_name to text returned of (display dialog "Please enter tag name " default answer item_name buttons {"Continue…"} default button 1)
set the scriptcode to "\"" & POSIX path of this_folder & "fixup.sh\" \"" & POSIX path of an_added_item & "\" \"" & new_name & "\""
display dialog scriptcode
do shell script scriptcode
end repeat
end try
end adding folder items to
fixup.sh
#!/bin/bash
if [ -d "$1" ]
then
echo asked to fixup \"$1\" >> /tmp/fixup.log
fi
精彩评论