Last active
October 9, 2024 15:59
-
-
Save gregneagle/010b369e86410a2f279ff8e980585c68 to your computer and use it in GitHub Desktop.
fancy_defaults_read.py: Reads a preference, prints its value, type, and where it is defined.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import os | |
import sys | |
from CoreFoundation import (CFPreferencesAppValueIsForced, | |
CFPreferencesCopyAppValue, | |
CFPreferencesCopyValue, | |
kCFPreferencesAnyUser, | |
kCFPreferencesAnyHost, | |
kCFPreferencesCurrentUser, | |
kCFPreferencesCurrentHost) | |
def get_type(value): | |
'''Returns type of pref value''' | |
if value is None: | |
return 'null' | |
type_name = type(value).__name__ | |
if type_name == '__NSCFDictionary': | |
return 'dictionary' | |
if type_name == '__NSCFArray': | |
return 'array' | |
if type_name in ('pyobjc_unicode', '__NSCFString'): | |
return 'string' | |
if type_name in ('bool', '__NSCFBoolean'): | |
return 'boolean' | |
if type_name == '__NSCFData': | |
return 'data' | |
if type_name == '__NSDate': | |
return 'date' | |
if type_name == 'OC_PythonLong': | |
return 'integer' | |
if type_name == 'OC_PythonFloat': | |
return 'real' | |
return type(value).__name__ | |
def get_config_level(bundle_id, pref_name, value): | |
'''Returns a string indicating where the given preference is defined''' | |
if value is None: | |
return 'not set' | |
if CFPreferencesAppValueIsForced(pref_name, bundle_id): | |
return 'MANAGED' | |
home_dir = os.path.expanduser('~') | |
# define all the places we need to search, in priority order | |
levels = [ | |
{'file': os.path.join(home_dir, 'Library/Preferences/ByHost', | |
bundle_id + '.xxxx.plist'), | |
'domain': bundle_id, | |
'user': kCFPreferencesCurrentUser, | |
'host': kCFPreferencesCurrentHost | |
}, | |
{'file': os.path.join(home_dir, 'Library/Preferences/', | |
bundle_id + '.plist'), | |
'domain': bundle_id, | |
'user': kCFPreferencesCurrentUser, | |
'host': kCFPreferencesAnyHost | |
}, | |
{'file': os.path.join(home_dir, 'Library/Preferences/ByHost', | |
'.GlobalPreferences.xxxx.plist'), | |
'domain': '.GlobalPreferences', | |
'user': kCFPreferencesCurrentUser, | |
'host': kCFPreferencesCurrentHost | |
}, | |
{'file': os.path.join(home_dir, 'Library/Preferences', | |
'.GlobalPreferences.plist'), | |
'domain': '.GlobalPreferences', | |
'user': kCFPreferencesCurrentUser, | |
'host': kCFPreferencesAnyHost | |
}, | |
{'file': os.path.join('/Library/Preferences', bundle_id +'.plist'), | |
'domain': bundle_id, | |
'user': kCFPreferencesAnyUser, | |
'host': kCFPreferencesCurrentHost | |
}, | |
{'file': '/Library/Preferences/.GlobalPreferences.plist', | |
'domain': '.GlobalPreferences', | |
'user': kCFPreferencesAnyUser, | |
'host': kCFPreferencesCurrentHost | |
}, | |
] | |
for level in levels: | |
if (value == CFPreferencesCopyValue( | |
pref_name, level['domain'], level['user'], level['host'])): | |
return level['file'] | |
if value == DEFAULT_PREFS.get(pref_name): | |
return 'default' | |
return 'unknown' | |
def get_pref_value(bundle_id, pref_name): | |
'''Returns the effective value of a preference''' | |
return CFPreferencesCopyAppValue(pref_name, bundle_id) | |
def main(): | |
try: | |
domain = sys.argv[1] | |
key = sys.argv[2] | |
except IndexError: | |
print >> sys.stderr, "Usage: %s <domain> <key>" % sys.argv[0] | |
sys.exit(-1) | |
value = get_pref_value(domain, key) | |
kind = get_type(value) | |
where = get_config_level(domain, key, value) | |
print '%s: %s' % (key, repr(value)) | |
print 'Type: %s' % kind | |
print 'Defined: %s' % where | |
if __name__ == '__main__': | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Examples of the use of fancy_defaults_read.py: | |
$ ./fancy_defaults_read.py com.apple.finder AppleShowAllExtensions | |
AppleShowAllExtensions: False | |
Type: boolean | |
Defined: /Users/gneagle/Library/Preferences/com.apple.finder.plist | |
$ ./fancy_defaults_read.py com.apple.SoftwareUpdate CatalogURL | |
CatalogURL: u'http://su.mycorp.com/index_testing.sucatalog' | |
Type: string | |
Defined: /Library/Preferences/com.apple.SoftwareUpdate.plist | |
$ ./fancy_defaults_read.py com.apple.screensaver askForPassword | |
askForPassword: True | |
Type: boolean | |
Defined: MANAGED | |
$ ./fancy_defaults_read.py com.apple.screensaver moduleDict | |
moduleDict: { | |
moduleName = iLifeSlideshows; | |
path = "/System/Library/Frameworks/ScreenSaver.framework/Resources/iLifeSlideshows.saver"; | |
type = 0; | |
} | |
Type: dictionary | |
Defined: /Users/gneagle/Library/Preferences/ByHost/com.apple.screensaver.xxxx.plist | |
Suggested improvements left for the reader: | |
1) Instead of '/Library/Preferences/ByHost/com.apple.screensaver.xxxx.plist', print the actual filename. | |
2) Add support for sandboxed applications that store their preferences in ~/Library/Containers/<identifier>/Data/Library/Preferences/<identifier>.plist |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment