From 72e2d820516ef534c5b557703a973e0499ac398a Mon Sep 17 00:00:00 2001 From: Jonathan Maw Date: Thu, 6 Jun 2013 11:14:21 +0100 Subject: Add the install-files extension to morph --- install-files.configure | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100755 install-files.configure (limited to 'install-files.configure') diff --git a/install-files.configure b/install-files.configure new file mode 100755 index 00000000..669fc518 --- /dev/null +++ b/install-files.configure @@ -0,0 +1,112 @@ +#!/usr/bin/python +# Copyright (C) 2013 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. + + +''' A Morph configuration extension for adding arbitrary files to a system + +It will read the manifest files specified in the environment variable +INSTALL_FILES, then use the contens of those files to determine which files +to install into the target system. + +''' + +import cliapp +import os +import re +import sys +import shlex +import shutil +import stat + +class InstallFilesConfigureExtension(cliapp.Application): + + '''Install the files specified in the manifests listed in INSTALL_FILES + + The manifest is formatted as: + + + + Where the filename is how the file is found inside whatever directory + the manifest is stored in, and also the path within the system to + install to. + + Directories on the target must be created if they do not exist. + + This extension supports files, symlinks and directories. + + ''' + + def process_args(self, args): + if not 'INSTALL_FILES' in os.environ: + return + target_root = args[0] + manifests = shlex.split(os.environ['INSTALL_FILES']) + for manifest in manifests: + self.install_manifest(manifest, target_root) + + def install_manifest(self, manifest, target_root): + manifest_dir = os.path.dirname(manifest) + with open(manifest) as f: + entries = f.readlines() + for entry in entries: + self.install_entry(entry, manifest_dir, target_root) + + def install_entry(self, entry, manifest_root, target_root): + entry_data = re.split('\W+', entry.strip(), maxsplit=3) + mode = int(entry_data[0], 8) + uid = int(entry_data[1]) + gid = int(entry_data[2]) + path = entry_data[3] + dest_path = os.path.join(target_root, './' + path) + if stat.S_ISDIR(mode): + if os.path.exists(dest_path): + dest_stat = os.stat(dest_path) + if (mode != dest_stat.st_mode + or uid != dest_stat.st_uid + or gid != dest_stat.st_gid): + raise cliapp.AppException('"%s" exists and is not ' + 'identical to directory ' + '"%s"' % (dest_path, entry)) + else: + os.mkdir(dest_path, mode) + os.chown(dest_path, uid, gid) + os.chmod(dest_path, mode) + + elif stat.S_ISLNK(mode): + if os.path.lexists(dest_path): + raise cliapp.AppException('Symlink already exists at %s' + % dest_path) + else: + linkdest = os.readlink(os.path.join(manifest_root, + './' + path)) + os.symlink(linkdest, dest_path) + os.lchown(dest_path, uid, gid) + + elif stat.S_ISREG(mode): + if os.path.lexists(dest_path): + raise cliapp.AppException('File already exists at %s' + % dest_path) + else: + shutil.copyfile(os.path.join(manifest_root, './' + path), + dest_path) + os.chown(dest_path, uid, gid) + os.chmod(dest_path, mode) + + else: + raise cliapp.AppException('Mode given in "%s" is not a file,' + ' symlink or directory' % entry) + +InstallFilesConfigureExtension().run() -- cgit v1.2.1