How to make Smart folder like physical folder with the combined contents of two folders
I have an application which looks for its data (*.txt) files in a folder. I have two folders containing text data that I need to keep separate, but it would be useful to have the application see the text data files as residing in one folder (containing the two sets of files).
I can create a script that maintains symbolic links to the files in the two folders in a third combined folder.
Rather than reinventing the wheel, I'd like to use a proven solution if possible.
The solution would have to deal with the case of file name clashes in a sensible way.
You could use launchd
.
launchd
lets you manage daemons and agents according to certain conditions.
What are daemons and agents?
From man launchd
:
A "daemon" is, by definition, a system-wide service of which there is one instance for all clients. An "agent" is a service that runs on a per-user basis. Daemons should not attempt to display UI or interact directly with a user's login session. Any and all work that involves interacting with a user should be done through agents.
From http://developer.apple.com/library/mac/#technotes/tn2083/_index.html:
Daemons and agents, collectively known as background programs, are programs that operate without any graphical user interface. As a developer, you can use background programs to perform actions without user interaction, and also to manage a shared state between multiple other programs.
The difference between an agent and a daemon is that an agent can display GUI if it wants to, while a daemon can't. The difference between an agent and a regular application is that an agent typically displays no GUI (or a very limited GUI).
The daemon/agent is described in an XML file with extension plist. One of the conditions that can be monitored is changes in a folder. This will come in handy.
OK, let's get our hands dirty:
Let's say these are the 2 folders where you and your friend keep your files:
/tmp/folderstuart
/tmp/folderstuartsfriend
and this is the common folder for the application:
/tmp/folder
We want to monitor the two paths above and synchronize their contents with /tmp/folder
.
This is the plist that does what we need:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>notesfoldersync</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/rsync</string>
<string>-aE</string>
<string>--delete</string>
<string>--exclude='.*'</string>
<string>/tmp/folderstuart/</string>
<string>/tmp/folderstuartsfriend/</string>
<string>/tmp/folder</string>
</array>
<key>WatchPaths</key>
<array>
<string>/tmp/folderstuart</string>
<string>/tmp/folderstuartsfriend</string>
</array>
<key>ThrottleInterval</key>
<integer>10</integer>
</dict>
</plist>
The plist monitors the two folders with key WatchPaths
(see http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html#//apple_ref/doc/uid/10000172i-SW7-SW8).
I suggest the program rsync
for synchronizing folders. Option --delete
ensures that files deleted in the monitored folders are also deleted in /tmp/folder
. Other options are -aE
to copy standard and extended HFS+ attributes, and --exclude='.*'
to skip .localized
, .DS_Store
and other hidden files.
I added ThrottleInterval
in case you want to set the minimum interval a job can be spawned. Default value is 10 s, that is, jobs will not be spawned more than once every 10 seconds.
Save the plist (see man launchd
for a list of possible paths) as:
/System/Library/LaunchDaemons/notesfoldersync.plist
Create:
/tmp/folderstuart
/tmp/folderstuartsfriend
/tmp/folder
and load (that is, enable) the plist:
sudo launchctl load /System/Library/LaunchDaemons/notesfoldersync.plist
Now create a file in /tmp/folderstuart
:
touch /tmp/folderstuart/file.txt
and watch the magic happen: file.txt
will be created within seconds in /tmp/folder
. Delete it and it will disappear from /tmp/folder
. It will also synchronize files created or deleted in /tmp/folderstuartsfriend
.
Notice that this solution doesn't handle name collisions! If you can't ensure that files will be named differently substitute rsync with a script that rsyncs and does file name checking to avoid data loss.
If copying files is not an option, substitute rsync
with a script that creates hardlinks (if both files are in the same filesystem I'd recommend hardlinks instead of symlinks). Before changing the plist unload it:
sudo launchctl unload /System/Library/LaunchDaemons/notesfoldersync.plist
When you're done, load it again.
Why not use a keyword or Spotlight Comment to tag the files in each folder, and then a Smart Folder to show them together?