Friday, July 20, 2012

plistbuddy and defaults on OS X

I use defaults to read most plists on OS X, but it has an annoying habit of being very chatty in the logs. If you want to write code to query for a value that may or may not be present, it ends up being very noisy. e.g. even if you suppress stderr like this:
defaults read /Library/Preferences/com.apple.CrashReporter.plist DOESNT_EXIST 2> /dev/null
For some reason the defaults tool thinks the failure to read the value is really important and writes a log line like:
defaults[34157]: The domain/default pair of (com.apple.CrashReporter.plist, DOESNT_EXIST) does not exist
So if you don't want the spurious logs, you can use plist buddy to do the same thing:
/usr/local/bin/PlistBuddy -c Print:DOESNT_EXIST /Library/Preferences/com.apple.CrashReporter.plist

Monday, July 2, 2012

Mox: stub out a python builtin method like 'exit' or 'open'

Occasionally you need to stub out a part of core python for a test to work. In my case it was 'exit', another example is 'open'. This is what your test code will look like:
import __builtin__

m = mox.Mox()
m.StubOutWithMock(__builtin__, 'exit')
exit(my_module.EXIT_ERROR)

m.ReplayAll()
my_module.myfunction()
m.VerifyAll()

Friday, June 29, 2012

JAVA CA store on OS X

To get the list of CAs trusted by Java on OS X:
keytool -v -list -keystore /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts
The default password is 'changeit'.

Thursday, June 28, 2012

Ruby foo: flatten a hash into a string

Flatten a ruby hash into a string. In this case the comma is the key value delimiter and the semicolon is the entry delimiter.
irb(main):016:0> a={'sdfs'=>['aaa','bbb'], 'ppp'=>['aa','a']}
=> {"ppp"=>["aa", "a"], "sdfs"=>["aaa", "bbb"]}
=> ["ppp:aa,a", "sdfs:aaa,bbb"]
irb(main):018:0> b=a.map { |k, v| "#{k}:#{v.join(',')}" }.join(";")
=> "ppp:aa,a;sdfs:aaa,bbb"

Tuesday, June 26, 2012

Ruby Dir.glob to provides some of the python os.walk functionality

The ruby Dir.glob command is pretty nice. It provides some of what os.walk provides for python and is a reasonable choice for working with files and directories. Double * gets you recursion. Quick and dirty way to list user home directories and user-level global environment file:
Dir.glob("/Users/**/.MacOSX/environment")
More comprehensive is to use dscl, but it is more work, first get a list of users:
dscl . -list /Users
Then iterate over each of those:
dscl . -read /Users/myuser NFSHomeDirectory
To get a rough list of Applications and their plists (note getting a list of everything installed is more complicated):
Dir.glob("/Applications/**/**app/Contents/Info.plist")

Thursday, June 21, 2012

Ruby string manipulation: struct, split, join

Every time I write ruby it seems like I have to re-learn everything. To shortcut the process for next time here is a snippet that demonstrates some string handling by parsing the output of lsof (OS X format). Ruby structs are the equivalent of python namedtuple, very handy for splitting up strings in a sane way.
def parse_lsof(lsof_out)
  net_listener = Struct.new(:command, :pid, :user, :fd, :type, :device, :size, :node, :name, :status)
  output = []

  # strip header line
  lsof_lines = lsof_out.split("\n")[1..-1]

  lsof_lines.each {
    |line|

    line_array = line.split("\s")
    listener_o = net_listener.new(*line_array)
    output.push("#{listener_o.command},#{listener_o.user},#{listener_o.type},#{listener_o.node},#{listener_o.name}")
  }
  return output.join("    ")
end

Thursday, June 14, 2012

Adjust log level of python logger in a library (pyactiveresource)

My logging was being polluted by pyactiveresource that was writing a lot of useless logs at the 'INFO' level. I wanted my own logging set at INFO, so how can you change pyactiveresource? As described in the python doco, you can access the logger with getLogger and adjust the level like this:
  noisy_logger = logging.getLogger('pyactiveresource')
  noisy_logger.setLevel(logging.WARN)
Then just set your own logger as normal, something like:
  syslog = logging.handlers.SysLogHandler('/var/run/syslog')
  syslog.setFormatter(logging.Formatter('%(name)s: %(message)s'))
  syslog.setLevel(logging.INFO)
  logging.getLogger().addHandler(syslog)