summaryrefslogtreecommitdiff
path: root/morphlib/extensions.py
diff options
context:
space:
mode:
authorMark Doffman <mark.doffman@codethink.co.uk>2014-02-21 18:58:56 +0000
committerMark Doffman <mark.doffman@codethink.co.uk>2014-02-21 20:10:50 +0000
commitab0a83a09a93ca33aa402d9c4d3b916a48a1a882 (patch)
treeaa1ecd5d599c3b941ee735b2819968e31802038f /morphlib/extensions.py
parenta72c8dca6965d1ac239e4f0102f08fbf7fe59ac7 (diff)
downloadmorph-ab0a83a09a93ca33aa402d9c4d3b916a48a1a882.tar.gz
Add utilities for listing and finding extensions.
Diffstat (limited to 'morphlib/extensions.py')
-rw-r--r--morphlib/extensions.py143
1 files changed, 143 insertions, 0 deletions
diff --git a/morphlib/extensions.py b/morphlib/extensions.py
new file mode 100644
index 00000000..57649cf1
--- /dev/null
+++ b/morphlib/extensions.py
@@ -0,0 +1,143 @@
+# Copyright (C) 2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import cliapp
+import morphlib
+import glob
+import os
+import sysbranchdir
+import stat
+import tempfile
+
+def _get_root_repo(build_ref_prefix):
+ system_branch = morphlib.sysbranchdir.open_from_within('.')
+ root_repo_dir = morphlib.gitdir.GitDirectory(
+ system_branch.get_git_directory_name(
+ system_branch.root_repository_url))
+ build_branch = morphlib.buildbranch.BuildBranch(system_branch,
+ build_ref_prefix,
+ push_temporary=False)
+ ref = build_branch.root_ref
+
+ return (build_branch.root_ref, root_repo_dir)
+
+def _get_morph_extension_directory():
+ code_dir = os.path.dirname(morphlib.__file__)
+ return os.path.join(code_dir, 'exts')
+
+def _list_repo_extension_filenames(build_ref_prefix,
+ kind): #pragma: no cover
+ (ref, repo_dir) = _get_root_repo(build_ref_prefix)
+ files = repo_dir.list_files(ref)
+ return (f for f in files if os.path.splitext(f)[1] == kind)
+
+def _list_morph_extension_filenames(kind):
+ return glob.glob(os.path.join(_get_morph_extension_directory(),
+ '*' + kind))
+
+def _get_extension_name(filename):
+ return os.path.basename(filename)
+
+def _get_repo_extension_contents(build_ref_prefix, name, kind):
+ (ref, repo_dir) = _get_root_repo(build_ref_prefix)
+ return repo_dir.get_file_from_ref(ref, name + kind)
+
+def _get_morph_extension_filename(name, kind):
+ return os.path.join(_get_morph_extension_directory(), name + kind)
+
+def _is_executable(filename):
+ st = os.stat(filename)
+ mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
+ return (stat.S_IMODE(st.st_mode) & mask) != 0
+
+def _list_extensions(build_ref_prefix, kind):
+ repo_extension_filenames = []
+ try:
+ repo_extension_filenames = \
+ _list_repo_extension_filenames(build_ref_prefix, kind)
+ except (sysbranchdir.NotInSystemBranch):
+ # Squash this and just return no system branch extensions
+ pass
+ morph_extension_filenames = _list_morph_extension_filenames(kind)
+
+ repo_extension_names = \
+ (_get_extension_name(f) for f in repo_extension_filenames)
+ morph_extension_names = \
+ (_get_extension_name(f) for f in morph_extension_filenames)
+
+ extension_names = set(repo_extension_names)
+ extension_names.update(set(morph_extension_names))
+ return list(extension_names)
+
+def list_extensions(build_ref_prefix, kind=None):
+ """
+ List all available extensions by 'kind'.
+
+ 'kind' should be one of '.write' or '.configure'.
+ If 'kind' is not provided available extensions of both
+ types will be returned.
+ """
+ if kind:
+ return _list_extensions(build_ref_prefix, kind)
+ else:
+ configure_extensions = _list_extensions(build_ref_prefix, '.configure')
+ write_extensions = _list_extensions(build_ref_prefix, '.write')
+
+ return configure_extensions + write_extensions
+
+class get_extension_filename():
+ """
+ Find the filename of an extension by its 'name' and 'kind'.
+
+ 'kind' should be one of '.configure' or '.write'.
+
+ If the extension is in the build repository then a temporary
+ file will be created, which will be deleted on exting the with block.
+ """
+ def __init__(self, build_ref_prefix, name, kind):
+ self.build_ref_prefix = build_ref_prefix
+ self.name = name
+ self.kind = kind
+ self.delete = False
+
+ def __enter__(self):
+ ext_filename = None
+ try:
+ ext_contents = _get_repo_extension_contents(self.build_ref_prefix,
+ self.name,
+ self.kind)
+ except cliapp.AppException, sysbranchdir.NotInSystemBranch:
+ # Not found: look for it in the Morph code.
+ ext_filename = _get_morph_extension_filename(self.name, self.kind)
+ if not os.path.exists(ext_filename):
+ raise morphlib.Error(
+ 'Could not find extension %s%s' % (self.name, self.kind))
+ if not _is_executable(ext_filename):
+ raise morphlib.Error(
+ 'Extension not executable: %s' % ext_filename)
+ else:
+ # Found it in the system morphology's repository.
+ fd, ext_filename = tempfile.mkstemp()
+ os.write(fd, ext_contents)
+ os.close(fd)
+ os.chmod(ext_filename, 0700)
+ self.delete = True
+
+ self.ext_filename = ext_filename
+ return ext_filename
+
+ def __exit__(self, type, value, trace):
+ if self.delete:
+ os.remove(self.ext_filename)