4

The Mac OS X Finder uses the concept of "packages" to make the contents of certain folders opaque to the user. I'm using os.walk() to enumerate a directory tree and I want to skip enumeration on packages such as application bundles.

The mdls commandline utility can be used to check whether com.apple.package is in the kMDItemContentTypeTree attribute. Is the only/best way to detect whether a folder is a package to drop into os.system and use mdls after detecting that the OS is indeed darwin?

As an aside, this solution seems to depend on Spotlight metadata which I understand is populated from the files/directories themselves. This makes me wonder whether there is a method to check whether a directory is a package outside of mdls. Perhaps I'm missing something.

Dean Stamler
  • 382
  • 4
  • 13
  • 1
    If you decide to go with `mdls`, call it with the [subprocess module](http://docs.python.org/2.7/library/subprocess.html#replacing-os-system) instead of `os.system`. – nofinator Jul 23 '13 at 20:45

1 Answers1

2

OS X packages (and bundles) are usually defined by their extension. Simply create a directory with an .app extension to see it be presented as a (broken) application in the Finder.

The official documentation lists the following ways to define bundles:

The Finder considers a directory to be a package if any of the following conditions are true:

  • The directory has a known filename extension: .app, .bundle, .framework, .plugin, .kext, and so on.
  • The directory has an extension that some other application claims represents a package type; see “Document Packages.”
  • The directory has its package bit set.

The preferred way to specify a package is to give the package directory a known filename extension. For the most part, Xcode takes care of this for you by providing templates that apply the correct extension. All you have to do is create an Xcode project of the appropriate type.

The simplest way to detect packages then is to detect those extensions. The quick and dirty way is to simply look for a hard-coded list of extensions, using the above documentation as your guide.

The next step up is to query the OS if a given extension has been registered as a Document Package. See How to check whether directories with a given extension are shown by the Finder as a package?

To detect the package bit on directories, you'll have to use the xattr library to retrieve the u'com.apple.FinderInfo' key and then use the Finder.h header info to decode the binary data returned; the kHasBundle flag is 0x2000:

attrs = xattr.getxattr('/path/to/dir', u'com.apple.FinderInfo')
ispackage = bool(ord(attrs[8]) & 0x20)  # I *think* this is correct; works for hidden dirs and & 0x40
Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • The crux of the issue (and the way to have an efficient implementation) requires the ability to query the system _once_ for a list of all extensions which should be treated as document packages and there doesn't seem to be an easy way to do this even in the link you provided to the other question unless I'm missing something. That link outlines a method of testing individual extensions against the system which is kind of like shooting in the dark. Nonetheless, you've helped me quite a bit with your xattr code and the kHasBundle bit. – Dean Stamler Jul 24 '13 at 03:24
  • I've re-read that link you provided and there doesn't seem to be an elegant way to do this in Objective-C let alone Python! – Dean Stamler Jul 24 '13 at 03:50
  • 1
    Nope, I haven't been able to find a better method either. Looks like the `mdls` tool is just easier. – Martijn Pieters Jul 24 '13 at 07:25