summaryrefslogtreecommitdiff
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-03-31 21:33:22 +0000
commit8fb1dac02b0be1502fd7b19de981e2a81468ffe2 (patch)
treee2239babb6782d1ea869f43e18b6a59d59a3c326
parent20b4bf7dbf1b4950b82113f6ffdd2ef171cfc04e (diff)
downloadmorph-8fb1dac02b0be1502fd7b19de981e2a81468ffe2.tar.gz
Add utilities for listing and finding extensions.
Add a module to morphlib that can list all write and configuration extensions either in morph itself or the morphology repository. The module also contains methods to find an extension filename from the name and type.
-rw-r--r--morphlib/__init__.py1
-rw-r--r--morphlib/extensions.py159
-rw-r--r--morphlib/plugins/deploy_plugin.py59
-rw-r--r--without-test-modules1
4 files changed, 177 insertions, 43 deletions
diff --git a/morphlib/__init__.py b/morphlib/__init__.py
index f416ae0c..0c928fd3 100644
--- a/morphlib/__init__.py
+++ b/morphlib/__init__.py
@@ -59,6 +59,7 @@ import buildsystem
import builder2
import cachedrepo
import cachekeycomputer
+import extensions
import extractedtarball
import fsutils
import git
diff --git a/morphlib/extensions.py b/morphlib/extensions.py
new file mode 100644
index 00000000..be551fdd
--- /dev/null
+++ b/morphlib/extensions.py
@@ -0,0 +1,159 @@
+# 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
+
+class ExtensionError(morphlib.Error):
+ pass
+
+class ExtensionNotFoundError(ExtensionError):
+ pass
+
+class ExtensionNotExecutableError(ExtensionError):
+ pass
+
+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.
+
+ '.check' extensions are not listed here as they should
+ be associated with a '.write' extension of the same name.
+ """
+ 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', '.write' or '.check'.
+
+ '.help' files for the extensions may also be retrieved by
+ passing the kind as '.write.help' or '.configure.help'.
+
+ 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, executable=True):
+ self.build_ref_prefix = build_ref_prefix
+ self.name = name
+ self.kind = kind
+ self.executable = executable
+ 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 ExtensionNotFoundError(
+ 'Could not find extension %s%s' % (self.name, self.kind))
+ if self.executable and not _is_executable(ext_filename):
+ raise ExtensionNotExecutableError(
+ '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)
diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py
index ae62b75d..1d582949 100644
--- a/morphlib/plugins/deploy_plugin.py
+++ b/morphlib/plugins/deploy_plugin.py
@@ -26,11 +26,6 @@ import uuid
import morphlib
-
-class ExtensionNotFoundError(morphlib.Error):
- pass
-
-
class DeployPlugin(cliapp.Plugin):
def enable(self):
@@ -425,9 +420,9 @@ class DeployPlugin(cliapp.Plugin):
# extension itself has the chance to raise an error.
try:
self._run_extension(
- root_repo_dir, ref, deployment_type, '.check',
+ root_repo_dir, deployment_type, '.check',
[location], env)
- except ExtensionNotFoundError:
+ except morphlib.extensions.ExtensionNotFoundError:
pass
def setup_deploy(self, build_command, deploy_tempdir, root_repo_dir, ref,
@@ -485,7 +480,6 @@ class DeployPlugin(cliapp.Plugin):
for name in names:
self._run_extension(
root_repo_dir,
- ref,
name,
'.configure',
[system_tree],
@@ -495,7 +489,6 @@ class DeployPlugin(cliapp.Plugin):
self.app.status(msg='Writing to device')
self._run_extension(
root_repo_dir,
- ref,
deployment_type,
'.write',
[system_tree, location],
@@ -506,7 +499,7 @@ class DeployPlugin(cliapp.Plugin):
self.app.status(msg='Cleaning up')
shutil.rmtree(deploy_private_tempdir)
- def _run_extension(self, gd, ref, name, kind, args, env):
+ def _run_extension(self, gd, name, kind, args, env):
'''Run an extension.
The ``kind`` should be either ``.configure`` or ``.write``,
@@ -516,39 +509,19 @@ class DeployPlugin(cliapp.Plugin):
system morphology (repo, ref), or with the Morph code.
'''
-
- # Look for extension in the system morphology's repository.
- try:
- ext = gd.get_file_from_ref(ref, name + kind)
- except cliapp.AppException:
- # Not found: look for it in the Morph code.
- code_dir = os.path.dirname(morphlib.__file__)
- ext_filename = os.path.join(code_dir, 'exts', name + kind)
- if not os.path.exists(ext_filename):
- raise ExtensionNotFoundError(
- 'Could not find extension %s%s' % (name, kind))
- if not self._is_executable(ext_filename):
- raise morphlib.Error(
- 'Extension not executable: %s' % ext_filename)
- delete_ext = False
- else:
- # Found it in the system morphology's repository.
- fd, ext_filename = tempfile.mkstemp()
- os.write(fd, ext)
- os.close(fd)
- os.chmod(ext_filename, 0700)
- delete_ext = True
-
- self.app.status(msg='Running extension %(name)s%(kind)s',
- name=name, kind=kind)
- self.app.runcmd(
- [ext_filename] + args,
- ['sh', '-c', 'while read l; do echo `date "+%F %T"` "$1$l"; done',
- '-', '%s[%s]' % (self.app.status_prefix, name + kind)],
- cwd=gd.dirname, env=env, stdout=None, stderr=None)
-
- if delete_ext:
- os.remove(ext_filename)
+ build_ref_prefix = self.app.settings['build-ref-prefix']
+ with morphlib.extensions.get_extension_filename(
+ build_ref_prefix, name, kind) as ext_filename:
+ self.app.status(msg='Running extension %(name)s%(kind)s',
+ name=name, kind=kind)
+ self.app.runcmd(
+ [ext_filename] + args,
+ ['sh',
+ '-c',
+ 'while read l; do echo `date "+%F %T"` "$1$l"; done',
+ '-',
+ '%s[%s]' % (self.app.status_prefix, name + kind)],
+ cwd=gd.dirname, env=env, stdout=None, stderr=None)
def _is_executable(self, filename):
st = os.stat(filename)
diff --git a/without-test-modules b/without-test-modules
index 9b893300..a42cce97 100644
--- a/without-test-modules
+++ b/without-test-modules
@@ -6,6 +6,7 @@ morphlib/tester.py
morphlib/git.py
morphlib/app.py
morphlib/mountableimage.py
+morphlib/extensions.py
morphlib/extractedtarball.py
morphlib/plugins/artifact_inspection_plugin.py
morphlib/plugins/cross-bootstrap_plugin.py