summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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