generic.py 5.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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; either version 3
# of the License, or (at your option) any later version.
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################
import logging
import os
import sys
import inspect
31 32 33
import re
import urllib
import urlparse
34 35 36 37 38

import pkg_resources
import zc.buildout

class GenericBaseRecipe(object):
39 40 41 42
  """Boilerplate class for all Buildout recipes providing helpful methods like
     creating configuration file, creating wrappers, generating passwords, etc.
     Can be extended in SlapOS recipes to ease development.
  """
43 44

  TRUE_VALUES = ['y', 'yes', '1', 'true']
45
  FALSE_VALUES = ['n', 'no', '0', 'false']
46 47 48 49 50 51 52

  def __init__(self, buildout, name, options):
    """Recipe initialisation"""
    self.name = name
    self.buildout = buildout
    self.logger = logging.getLogger(name)

53
    self.options = options.copy() # If _options use self.optionIsTrue
54
    self._options(options) # Options Hook
55
    self.options = options.copy() # Updated options dict
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

    self._ws = self.getWorkingSet()

  def update(self):
    """By default update method does the same thing than install"""
    return self.install()

  def install(self):
    """Install method of the recipe. This must be overriden in child
    classes """
    raise NotImplementedError("install method is not implemented.")

  def getWorkingSet(self):
    """If you want do override the default working set"""
    egg = zc.recipe.egg.Egg(self.buildout, 'slapos.cookbook',
                                  self.options.copy())
    requirements, ws = egg.working_set()
    return ws

  def _options(self, options):
    """Options Hook method. This method can be overriden in child classes"""
    return

  def createFile(self, name, content, mode=0600):
    """Create a file with content

    The parent directory should exists, else it would raise IOError"""
    with open(name, 'w') as fileobject:
      fileobject.write(content)
      os.chmod(fileobject.name, mode)
    return os.path.abspath(name)

  def createExecutable(self, name, content, mode=0700):
    return self.createFile(name, content, mode)

  def createPythonScript(self, name, absolute_function, arguments=''):
    """Create a python script using zc.buildout.easy_install.scripts

     * function should look like 'module.function', or only 'function'
       if it is a builtin function."""
    absolute_function = tuple(absolute_function.rsplit('.', 1))
    if len(absolute_function) == 1:
      absolute_function = ('__builtin__',) + absolute_function
    if len(absolute_function) != 2:
      raise ValueError("A non valid function was given")

    module, function = absolute_function
    path, filename = os.path.split(os.path.abspath(name))

    script = zc.buildout.easy_install.scripts(
      [(filename, module, function)], self._ws, sys.executable,
      path, arguments=arguments)[0]
    return script

110 111 112 113 114 115 116 117
  def createDirectory(self, parent, name, mode=0700):
    path = os.path.join(parent, name)
    if not os.path.exists(path):
      os.mkdir(path, mode)
    elif not os.path.isdir(path):
      raise OSError("%r exists but is not a directory." % name)
    return path

118 119
  def substituteTemplate(self, template_location, mapping_dict):
    """Read from file template_location an substitute content with
Antoine Catton's avatar
Antoine Catton committed
120
       mapping_dict doing a dummy python format."""
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    with open(template_location, 'r') as template:
      return template.read() % mapping_dict

  def getTemplateFilename(self, template_name):
    caller = inspect.stack()[1]
    caller_frame = caller[0]
    name = caller_frame.f_globals['__name__']
    return pkg_resources.resource_filename(name,
        'template/%s' % template_name)

  def generatePassword(self, len_=32):
    # TODO: implement a real password generator which remember the last
    # call.
    return "insecure"

  def isTrueValue(self, value):
    return str(value).lower() in GenericBaseRecipe.TRUE_VALUES

  def optionIsTrue(self, optionname, default=None):
140 141
    if default is not None and optionname not in self.options:
      return default
142
    return self.isTrueValue(self.options[optionname])
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

  def unparseUrl(self, scheme, host, path='', params='', query='',
                 fragment='', port=None, auth=None):
    """Join a url with auth, host, and port.

    * auth can be either a login string or a tuple (login, password).
    * if the host is an ipv6 address, brackets will be added to surround it.

    """
    netloc = ''
    if auth is not None:
      auth = tuple(auth)
      netloc = urllib.quote(str(auth[0])) # Login
      if len(auth) > 1:
        netloc += ':%s' % urllib.quote(auth[1]) # Password
      netloc += '@'

    # host is an ipv6 address whithout brackets
    if ':' in host and not re.match(r'^\[.*\]$', host):
      netloc += '[%s]' % host
    else:
      netloc += str(host)

    if port is not None:
      netloc += ':%s' % port

    url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))

    return url