Re: Mysterious Preferences File Again
Re: Mysterious Preferences File Again
- Subject: Re: Mysterious Preferences File Again
- From: Matt Deatherage <email@hidden>
- Date: Sun, 14 May 2006 15:14:25 -0500
On 5/14/06 at 1:29 PM, Luther Fuller <email@hidden> wrote:
> I have not yet found a fix for the original problem where an unwanted
> prefs file is created for applications that don't use a prefs file,
> but do use 'choose ...'. If anyone has additional insight into this
> problem, please let us know.
What we have here is a failure to communicate.
You see the system creating a ".plist" file for an application's bundle
ID even when that application does not explicitly use the CFPreference
or NSUserDefaults system to store or retrieve preferences.
You view this as a problem. What I was trying to tell you is that the
system does not view this as a problem, but as a feature. It's not a
bug, and it's not going to be fixed, but you can actually leverage this
to have shorter code with fewer problems.
The issue:
CFPreferences and NSUserDefaults are abstract preference systems.
Applications read, write, and synchronize preferences "on disk" by using
the supplied APIs, but the documentation does not guarantee *how* these
preferences are stored on disk. In fact, as most of us know, they're
generally stored in property list files named after the application's
bundle, like "com.gcsf.wonderapp.plist".
Mac OS X itself maintains certain per-application preference
information. The OS uses its own routines (CFPreferences or
NSUserDefaults) to store that information, and if the domain and user
and privileges are all normal, they wind up stored in the same place as
the application's own preferences.
*This is not a bug.* When the OS stores keys in an application's
preferences table, it does so with keys reserved for Apple that do not
conflict with anything your application will read or write. Applications
using the preference system neither know nor care that the OS has stored
extra keys in their files for things like Navigation Services window
locations and sizes. (Developers would only hear about if it *didn't*
do this, because then users would complain, "The open dialog box doesn't
stay where I put it!")
> perhaps 'choose folder' has already created a bogus prefs file without
> the key value my script expects to read. If an uncorrupted prefs file
> already exists, there appears to be no problem.
You're dealing with OS-managed preference files, and you need to
gracefully handle the situation where the preference file exists but the
key you want isn't in it.
If I had to guess, I'd say the real trouble step is this one:
> On 5/12/06 at 6:45 PM, Luther Fuller <email@hidden> wrote:
>
> > When my application needs to create a new preferences file, it first
> > reads the value of CFBundleIdentifier in its info.plist file, then
> > appends '.plist' to get the prefs file name. Next it copies a
> > default .plist file, containing some default preferences, from
> > Contents/Resources, into the preferences folder and renames it with
> > the proper prefs file name.
No matter how cleanly you think you're doing this, what you're doing is
creating a file that the OS expects or wants in a specific format. If
it finds *any* trouble with it, it would not shock me in the slightest
for it to empty out the file and rewrite its contents to suit itself.
As far as the OS is concerned, *it* owns the [bundlename].plist file,
and will enforce whatever standards of orthodoxy on it that it wants.
Because you are manipulating the plist file directly, something that
Apple would tell developers *not* to do for preferences, you wind up
fighting with CFPreferences (upon which NSUserDefaults is built) over
the content and format of the file. And the OS wins, because it's
bigger and stronger.
The underlying problem is that AppleScript has no real access to the
system's preference routines, so you have to rely upon the
*implementation detail* that the preferences are stored in a property
list file. If you were using real preferences APIs to read and write
your keys, then whatever else was in the file wouldn't matter, nor would
the OS tinkering with it make any difference.
The fix:
The solution may be the only real supported way to access CFPreferences
from AppleScript: the "defaults" command-line tool. When you use
"defaults write", you let the system store the data in the right place,
and it fetches it for you when you use "defaults read". It will never
conflict with the system's usage by default, since the system is what's
reading and writing it.
So, all that given, here's what I'd recommend.
Take your default plist file and copy it into your ~/Library/Preferences
folder for the moment. I'll assume it's named
"com.luther.niftyapp.plist" so I have a name. When the file is in
place, go to terminal and type:
defaults read com.luther.niftyapp
(or whatever your bundle name is, of course). "defaults" responds with
all of the keys in your plist file, formatted as an old-school, pre-XML
property list.
Copy all of that text, and remove the line endings, so it's just a bunch
of key-value pairs in braces, like:
{ WebKitDefaultFixedFontSize = 10; WebKitDefaultFontSize = 12;
WebKitFixedFont = Monaco; }
If the key has a space in it, the results will be quoted for you; if
it's a dictionary, it will be formatted properly, or in hex if no
formatting makes sense, etc.
Now get rid of the copy of com.luther.niftyapp.plist that you put in
"~/Library/Preferences", empty the trash, and in terminal, type:
defaults write com.luther.niftyapp -plist [data]
...except replace "[data]" with your plist-formatted string. The system
will write a preferences file for you with all that data. Now here's
the fun part: do "defaults read com.luther.niftyapp" *again*, and you
should find that the new preference file's contents exactly match the
one you created by hand.
That's how you get around this problem now and forever: use "defaults"
to do the dirty work for you. If your preferences are small, just build
them into the application in a variable. If they're large, store the
formatted plist from "defaults read" in a text file in your bundle, find
the filename, and use it with piping so the shell reads the file instead
of input.
Then, instead of manipulating the plist file directly, use "defaults
read com.luther.niftyapp" to get at any preference you want, and
"defaults write com.luther.niftyapp" to save any preference you want. It
works with any plist format, it works if Apple changes preferences to
use some other storage format, it just *works* because you're working
with the system instead of fighting it.
By the way, this presumes that the preferences in question are *yours*.
If you're trying to read or write the preferences of another application
while it's running, the application probably won't see your changes, and
may very well overwrite them with its own in-RAM values. That's
documented and also unlikely to change.
So, yeah, use "defaults" to manage prefs instead of rolling your own
property lists and the system will stop pissing in your Post Toasties.
--Matt
--
Matt Deatherage <email@hidden>
GCSF, Incorporated <http://www.macjournals.com>
" 'Sorry' isn't an excuse when you do something stupid on purpose."
-- <http://bash.org/?623457>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Applescript-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden