From eaef567cabc5c0dda9706faa0e17e20909131ade Mon Sep 17 00:00:00 2001 From: simpoir Date: Fri, 30 Jan 2009 04:14:48 +0000 Subject: ajout initial du tree jhbuild [jhbuild base] --- (limited to 'src/sugar/bundle/bundle.py') diff --git a/src/sugar/bundle/bundle.py b/src/sugar/bundle/bundle.py new file mode 100644 index 0000000..a1b2686 --- /dev/null +++ b/src/sugar/bundle/bundle.py @@ -0,0 +1,199 @@ +# Copyright (C) 2007, Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +"""Sugar bundle file handler + +UNSTABLE. +""" + +import os +import logging +import shutil +import StringIO +import zipfile + +class AlreadyInstalledException(Exception): + pass + +class NotInstalledException(Exception): + pass + +class InvalidPathException(Exception): + pass + +class ZipExtractException(Exception): + pass + +class RegistrationException(Exception): + pass + +class MalformedBundleException(Exception): + pass + +class Bundle(object): + """A Sugar activity, content module, etc. + + The bundle itself may be either a zip file or a directory + hierarchy, with metadata about the bundle stored various files + inside it. + + This is an abstract base class. See ActivityBundle and + ContentBundle for more details on those bundle types. + """ + + _zipped_extension = None + _unzipped_extension = None + + def __init__(self, path): + self._path = path + self._zip_root_dir = None + + if os.path.isdir(self._path): + self._zip_file = None + else: + self._zip_file = zipfile.ZipFile(self._path) + self._check_zip_bundle() + + # manifest = self._get_file(self._infodir + '/contents') + # if manifest is None: + # raise MalformedBundleException('No manifest file') + # + # signature = self._get_file(self._infodir + '/contents.sig') + # if signature is None: + # raise MalformedBundleException('No signature file') + + def __del__(self): + if self._zip_file is not None: + self._zip_file.close() + + def _check_zip_bundle(self): + file_names = self._zip_file.namelist() + if len(file_names) == 0: + raise MalformedBundleException('Empty zip file') + + if file_names[0] == 'mimetype': + del file_names[0] + + self._zip_root_dir = file_names[0].split('/')[0] + if self._zip_root_dir.startswith('.'): + raise MalformedBundleException( + 'root directory starts with .') + if self._unzipped_extension is not None: + (name_, ext) = os.path.splitext(self._zip_root_dir) + if ext != self._unzipped_extension: + raise MalformedBundleException( + 'All files in the bundle must be inside a single ' + + 'directory whose name ends with "%s"' % + self._unzipped_extension) + + for file_name in file_names: + if not file_name.startswith(self._zip_root_dir): + raise MalformedBundleException( + 'All files in the bundle must be inside a single ' + + 'top-level directory') + + def get_file(self, filename): + f = None + + if self._zip_file is None: + path = os.path.join(self._path, filename) + try: + f = open(path,"rb") + except IOError: + return None + else: + path = os.path.join(self._zip_root_dir, filename) + try: + data = self._zip_file.read(path) + f = StringIO.StringIO(data) + except KeyError: + logging.debug('%s not found.' % filename) + + return f + + def is_file(self, filename): + if self._zip_file is None: + path = os.path.join(self._path, filename) + return os.path.isfile(path) + else: + path = os.path.join(self._zip_root_dir, filename) + try: + self._zip_file.getinfo(path) + except KeyError: + return False + + return True + + def is_dir(self, filename): + if self._zip_file is None: + path = os.path.join(self._path, filename) + return os.path.isdir(path) + else: + path = os.path.join(self._zip_root_dir, filename, "") + for f in self._zip_file.namelist(): + if f.startswith(path): + return True + return False + + def get_path(self): + """Get the bundle path.""" + return self._path + + def _unzip(self, install_dir): + if self._zip_file is None: + raise AlreadyInstalledException + + if not os.path.isdir(install_dir): + os.mkdir(install_dir, 0775) + + # zipfile provides API that in theory would let us do this + # correctly by hand, but handling all the oddities of + # Windows/UNIX mappings, extension attributes, deprecated + # features, etc makes it impractical. + # FIXME: use manifest + if os.spawnlp(os.P_WAIT, 'unzip', 'unzip', '-o', self._path, + '-x', 'mimetype', '-d', install_dir): + # clean up install dir after failure + shutil.rmtree(os.path.join(install_dir, self._zip_root_dir), + ignore_errors=True) + # indicate failure. + raise ZipExtractException + + def _zip(self, bundle_path): + if self._zip_file is not None: + raise NotInstalledException + + raise NotImplementedError + + def _uninstall(self, install_path): + if not os.path.isdir(install_path): + raise InvalidPathException + if self._unzipped_extension is not None: + (name_, ext) = os.path.splitext(install_path) + if ext != self._unzipped_extension: + raise InvalidPathException + + for root, dirs, files in os.walk(install_path, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + path = os.path.join(root, name) + if os.path.islink(path): + os.remove(path) + else: + os.rmdir(path) + os.rmdir(install_path) -- cgit v0.9.1