Skip to content

Commit

Permalink
Merge branch 'version-plist'
Browse files Browse the repository at this point in the history
Version checks for some OS X applications that don't support a
--version option.  Andrew Walker confirmed that this found his Safari
version on OS X 10.6.8, but the code is otherwise untested [1].

[1]: https://github.com/swcarpentry/workshop-template/pull/108#issuecomment-71517251

* version-plist:
  Fix decorator in VersionPlistCommandDependency
  swc-installation-test-2.py: Convert PathCommandDependency to VersionPlistCommandDependency
  • Loading branch information
W. Trevor King committed Mar 5, 2015
2 parents d13b26c + 9bffbc2 commit 33574ab
Showing 1 changed file with 60 additions and 17 deletions.
77 changes: 60 additions & 17 deletions swc-installation-test-2.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def import_module(name):
import urllib.parse as _urllib_parse
except ImportError: # Python 2.x
import urllib as _urllib_parse # for quote()
import xml.etree.ElementTree as _element_tree


if not hasattr(_shlex, 'quote'): # Python versions older than 3.3
Expand Down Expand Up @@ -477,26 +478,62 @@ def _get_version(self):
return match.group(1)


class PathCommandDependency (CommandDependency):
class VersionPlistCommandDependency (CommandDependency):
"""A command that doesn't support --version or equivalent options
On some operating systems (e.g. OS X), a command's executable may
be hard to find, or not exist in the PATH. Work around that by
just checking for the existence of a characteristic file or
directory. Since the characteristic path may depend on OS,
installed version, etc., take a list of paths, and succeed if any
of them exists.
On OS X, a command's executable may be hard to find, or not exist
in the PATH. Work around that by looking up the version
information in the package's version.plist file.
"""
def __init__(self, key='CFBundleShortVersionString', **kwargs):
super(VersionPlistCommandDependency, self).__init__(**kwargs)
self.key = key

def _get_command_version_stream(self, *args, **kwargs):
raise NotImplementedError()

def _get_version_stream(self, *args, **kwargs):
raise NotImplementedError()

@staticmethod
def _get_parent(root, element):
"""Returns the parent of this element or None for the root element
"""
for node in root.iter():
if element in node:
return node
raise ValueError((root, element))

@classmethod
def _get_next(cls, root, element):
"""Returns the following sibling of this element or None
"""
parent = cls._get_parent(root=root, element=element)
siblings = iter(parent)
for node in siblings:
if node == element:
try:
return next(siblings)
except StopIteration:
return None
return None

def _get_version_from_plist(self, path):
"""Parse the plist and return the value string for self.key
"""
tree = _element_tree.parse(source=path)
data = {}
for key in tree.findall('.//key'):
value = self._get_next(root=tree, element=key)
if value.tag != 'string':
raise ValueError((tree, key, value))
data[key.text] = value.text
return data[self.key]

def _get_version(self):
for path in self.paths:
if _os.path.exists(path):
return None
return self._get_version_from_plist(path=path)
raise DependencyError(
checker=self,
message=(
Expand Down Expand Up @@ -746,23 +783,28 @@ def _program_files_paths(*args):


for paths,name,long_name in [
([_os.path.join(_ROOT_PATH, 'Applications', 'Sublime Text 2.app')],
([_os.path.join(_ROOT_PATH, 'Applications', 'Sublime Text 2.app',
'Contents', 'version.plist')],
'sublime-text', 'Sublime Text'),
([_os.path.join(_ROOT_PATH, 'Applications', 'TextMate.app')],
([_os.path.join(_ROOT_PATH, 'Applications', 'TextMate.app',
'Contents', 'version.plist')],
'textmate', 'TextMate'),
([_os.path.join(_ROOT_PATH, 'Applications', 'TextWrangler.app')],
([_os.path.join(_ROOT_PATH, 'Applications', 'TextWrangler.app',
'Contents', 'version.plist')],
'textwrangler', 'TextWrangler'),
([_os.path.join(_ROOT_PATH, 'Applications', 'Safari.app')],
([_os.path.join(_ROOT_PATH, 'Applications', 'Safari.app',
'Contents', 'version.plist')],
'safari', 'Safari'),
([_os.path.join(_ROOT_PATH, 'Applications', 'Xcode.app'), # OS X >=1.7
_os.path.join(_ROOT_PATH, 'Developer', 'Applications', 'Xcode.app'
) # OS X 1.6,
([_os.path.join(_ROOT_PATH, 'Applications', 'Xcode.app',
'Contents', 'version.plist'), # OS X >=1.7
_os.path.join(_ROOT_PATH, 'Developer', 'Applications', 'Xcode.app',
'Contents', 'version.plist'), # OS X 1.6,
],
'xcode', 'Xcode'),
]:
if not long_name:
long_name = name
CHECKER[name] = PathCommandDependency(
CHECKER[name] = VersionPlistCommandDependency(
command=None, paths=paths, name=name, long_name=long_name)
del paths, name, long_name # cleanup namespace

Expand Down Expand Up @@ -807,9 +849,10 @@ def _program_files_paths(*args):
long_name='{0} for IPython'.format(
CHECKER['chromium'].long_name),
minimum_version=(13, 0)),
PathCommandDependency(
VersionPlistCommandDependency(
command=CHECKER['safari'].command,
paths=CHECKER['safari'].paths,
key=CHECKER['safari'].key,
name='{0}-for-ipython'.format(
CHECKER['safari'].name),
long_name='{0} for IPython'.format(
Expand Down

0 comments on commit 33574ab

Please sign in to comment.