| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- #!/usr/bin/env python
- # Licensed to Cloudera, Inc. under one
- # or more contributor license agreements. See the NOTICE file
- # distributed with this work for additional information
- # regarding copyright ownership. Cloudera, Inc. licenses this file
- # to you under the Apache License, Version 2.0 (the
- # "License"); you may not use this file except in compliance
- # with the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """
- Registry for the applications
- """
- import glob
- import logging
- import os
- try:
- import json
- except ImportError:
- import simplejson as json
- import common
- LOG = logging.getLogger(__name__)
- class AppRegistry(object):
- """
- Represents a registry.
- """
- def __init__(self):
- """Open the existing registry"""
- self._reg_path = os.path.join(os.environ.get("HUE_APP_REG_DIR", common.INSTALL_ROOT), 'app.reg')
- self._initialized = False
- self._apps = { } # Map of name -> HueApp
- self._open()
- def _open(self):
- """Open the registry file. May raise OSError"""
- if os.path.exists(self._reg_path):
- reg_file = file(self._reg_path)
- app_list = json.load(reg_file)
- reg_file.close()
- for app_json in app_list:
- app_json.setdefault('author', 'Unknown') # Added after 0.9
- app = HueApp.create(app_json)
- self._apps[app.name] = app
- self._initialized = True
- def _write(self, path):
- """Write out the registry to the given path"""
- outfile = file(path, 'w')
- json.dump(self._apps.values(), outfile, cls=AppJsonEncoder, indent=2)
- outfile.close()
- def contains(self, app):
- """Returns whether the app (of the same version) is in the registry"""
- try:
- existing = self._apps[app.name]
- return existing.version == app.version
- except KeyError:
- return False
- def register(self, app):
- """register(app) -> True/False"""
- assert self._initialized, "Registry not yet initialized"
- try:
- existing = self._apps[app.name]
- version_diff = common.cmp_version(existing.version, app.version)
- if version_diff == 0:
- LOG.warn('%s is already registered' % (app,))
- return False
- elif version_diff < 0:
- LOG.info('Upgrading %s from version %s' % (app, existing.version))
- elif version_diff > 0:
- LOG.error('A newer version (%s) of %s is already installed' % (existing.version, app))
- return False
- except KeyError:
- pass
- LOG.info('Updating registry with %s' % (app,))
- self._apps[app.name] = app
- return True
- def unregister(self, app_name):
- """unregister(app_Name) -> HueApp. May raise KeyError"""
- assert self._initialized, "Registry not yet initialized"
- app = self._apps[app_name]
- del self._apps[app_name]
- return app
- def get_all_apps(self):
- """get_all_apps() -> List of HueApp"""
- return self._apps.values()
- def save(self):
- """Save and write out the registry"""
- assert self._initialized, "Registry not yet initialized"
- tmp_path = self._reg_path + '.new'
- self._write(tmp_path)
- os.rename(tmp_path, self._reg_path)
- LOG.info('=== Saved registry at %s' % (self._reg_path,))
- class HueApp(object):
- """
- Represents an app.
- """
- @staticmethod
- def create(json):
- return HueApp(json['name'], json['version'], json['path'], json['desc'], json['author'])
- def __init__(self, name, version, path, desc, author):
- self.name = name
- self.version = version
- self.path = path
- self.desc = desc
- self.author = author
- def __str__(self):
- return "%s v.%s" % (self.name, self.version)
- def __cmp__(self, other):
- if not isinstance(other, HueApp):
- raise TypeError
- return cmp((self.name, self.version), (other.name, other.version))
- def jsonable(self):
- return dict(name=self.name, version=self.version, path=self.path,
- desc=self.desc, author=self.author)
- def find_ext_pys(self):
- """find_ext_pys() -> A list of paths for all ext-py packages"""
- return glob.glob(os.path.join(self.path, 'ext-py', '*'))
- def get_conffiles(self):
- """get_conffiles() -> A list of config (.ini) files"""
- ini_files = glob.glob(os.path.join(self.path, 'conf', '*.ini'))
- return [ os.path.abspath(ini) for ini in ini_files ]
- def install_conf(self):
- """
- install_conf() -> True/False
- Symlink the app's conf/*.ini files into the conf directory.
- """
- installed = [ ]
- for target in self.get_conffiles():
- link_name = os.path.join(common.HUE_CONF_DIR, os.path.basename(target))
- # Does the link already exists?
- if os.path.islink(link_name):
- try:
- cur = os.readlink(link_name)
- if cur == target:
- LOG.warn("Symlink for configuration already exists: %s" % (link_name,))
- installed.append(link_name)
- continue
- # Remove broken link
- if not os.path.exists(cur):
- os.unlink(link_name)
- LOG.warn("Removing broken link: %s" % (link_name,))
- except OSError, ex:
- LOG.warn("Error checking for existing link %s: %s" % (link_name, ex))
- # Actually install the link
- try:
- os.symlink(target, link_name)
- LOG.info('Symlink config %s -> %s' % (link_name, target))
- installed.append(link_name)
- except OSError, ex:
- LOG.error("Failed to symlink %s to %s: %s" % (target, link_name, ex))
- for lnk in installed:
- try:
- os.unlink(lnk)
- except OSError, ex2:
- LOG.error("Failed to cleanup link %s: %s" % (link_name, ex2))
- return False
- return True
- def uninstall_conf(self):
- """uninstall_conf() -> True/False"""
- app_conf_dir = os.path.abspath(os.path.join(self.path, 'conf'))
- if not os.path.isdir(app_conf_dir):
- return True
- # Check all symlink in the conf dir and remove any that point to this app
- for name in os.listdir(common.HUE_CONF_DIR):
- path = os.path.join(common.HUE_CONF_DIR, name)
- if not os.path.islink(path):
- continue
- target = os.readlink(path)
- target_dir = os.path.abspath(os.path.dirname(target))
- if target_dir == app_conf_dir:
- try:
- os.unlink(path)
- LOG.info('Remove config symlink %s -> %s' % (path, target))
- except OSError, ex:
- LOG.error("Failed to remove configuration link %s: %s" % (path, ex))
- return False
- return True
- class AppJsonEncoder(json.JSONEncoder):
- def __init__(self, **kwargs):
- json.JSONEncoder.__init__(self, **kwargs)
- def default(self, obj):
- if isinstance(obj, HueApp):
- return obj.jsonable()
- return json.JSONEncoder.default(self, obj)
|