summaryrefslogtreecommitdiff
path: root/cloudinit/mergers
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/mergers')
-rw-r--r--cloudinit/mergers/__init__.py166
-rw-r--r--cloudinit/mergers/m_dict.py88
-rw-r--r--cloudinit/mergers/m_list.py89
-rw-r--r--cloudinit/mergers/m_str.py46
4 files changed, 0 insertions, 389 deletions
diff --git a/cloudinit/mergers/__init__.py b/cloudinit/mergers/__init__.py
deleted file mode 100644
index e13f55ac..00000000
--- a/cloudinit/mergers/__init__.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2012 Yahoo! Inc.
-#
-# Author: Joshua Harlow <harlowja@yahoo-inc.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import re
-
-import six
-
-from cloudinit import importer
-from cloudinit import log as logging
-from cloudinit import type_utils
-
-NAME_MTCH = re.compile(r"(^[a-zA-Z_][A-Za-z0-9_]*)\((.*?)\)$")
-
-LOG = logging.getLogger(__name__)
-DEF_MERGE_TYPE = "list()+dict()+str()"
-MERGER_PREFIX = 'm_'
-MERGER_ATTR = 'Merger'
-
-
-class UnknownMerger(object):
- # Named differently so auto-method finding
- # doesn't pick this up if there is ever a type
- # named "unknown"
- def _handle_unknown(self, _meth_wanted, value, _merge_with):
- return value
-
- # This merging will attempt to look for a '_on_X' method
- # in our own object for a given object Y with type X,
- # if found it will be called to perform the merge of a source
- # object and a object to merge_with.
- #
- # If not found the merge will be given to a '_handle_unknown'
- # function which can decide what to do wit the 2 values.
- def merge(self, source, merge_with):
- type_name = type_utils.obj_name(source)
- type_name = type_name.lower()
- method_name = "_on_%s" % (type_name)
- meth = None
- args = [source, merge_with]
- if hasattr(self, method_name):
- meth = getattr(self, method_name)
- if not meth:
- meth = self._handle_unknown
- args.insert(0, method_name)
- return meth(*args)
-
-
-class LookupMerger(UnknownMerger):
- def __init__(self, lookups=None):
- UnknownMerger.__init__(self)
- if lookups is None:
- self._lookups = []
- else:
- self._lookups = lookups
-
- def __str__(self):
- return 'LookupMerger: (%s)' % (len(self._lookups))
-
- # For items which can not be merged by the parent this object
- # will lookup in a internally maintained set of objects and
- # find which one of those objects can perform the merge. If
- # any of the contained objects have the needed method, they
- # will be called to perform the merge.
- def _handle_unknown(self, meth_wanted, value, merge_with):
- meth = None
- for merger in self._lookups:
- if hasattr(merger, meth_wanted):
- # First one that has that method/attr gets to be
- # the one that will be called
- meth = getattr(merger, meth_wanted)
- break
- if not meth:
- return UnknownMerger._handle_unknown(self, meth_wanted,
- value, merge_with)
- return meth(value, merge_with)
-
-
-def dict_extract_mergers(config):
- parsed_mergers = []
- raw_mergers = config.pop('merge_how', None)
- if raw_mergers is None:
- raw_mergers = config.pop('merge_type', None)
- if raw_mergers is None:
- return parsed_mergers
- if isinstance(raw_mergers, six.string_types):
- return string_extract_mergers(raw_mergers)
- for m in raw_mergers:
- if isinstance(m, (dict)):
- name = m['name']
- name = name.replace("-", "_").strip()
- opts = m['settings']
- else:
- name = m[0]
- if len(m) >= 2:
- opts = m[1:]
- else:
- opts = []
- if name:
- parsed_mergers.append((name, opts))
- return parsed_mergers
-
-
-def string_extract_mergers(merge_how):
- parsed_mergers = []
- for m_name in merge_how.split("+"):
- # Canonicalize the name (so that it can be found
- # even when users alter it in various ways)
- m_name = m_name.lower().strip()
- m_name = m_name.replace("-", "_")
- if not m_name:
- continue
- match = NAME_MTCH.match(m_name)
- if not match:
- msg = ("Matcher identifer '%s' is not in the right format" %
- (m_name))
- raise ValueError(msg)
- (m_name, m_ops) = match.groups()
- m_ops = m_ops.strip().split(",")
- m_ops = [m.strip().lower() for m in m_ops if m.strip()]
- parsed_mergers.append((m_name, m_ops))
- return parsed_mergers
-
-
-def default_mergers():
- return tuple(string_extract_mergers(DEF_MERGE_TYPE))
-
-
-def construct(parsed_mergers):
- mergers_to_be = []
- for (m_name, m_ops) in parsed_mergers:
- if not m_name.startswith(MERGER_PREFIX):
- m_name = MERGER_PREFIX + str(m_name)
- merger_locs, looked_locs = importer.find_module(m_name,
- [__name__],
- [MERGER_ATTR])
- if not merger_locs:
- msg = ("Could not find merger module named '%s' "
- "with attribute '%s' (searched %s)") % (m_name,
- MERGER_ATTR,
- looked_locs)
- raise ImportError(msg)
- else:
- mod = importer.import_module(merger_locs[0])
- mod_attr = getattr(mod, MERGER_ATTR)
- mergers_to_be.append((mod_attr, m_ops))
- # Now form them...
- mergers = []
- root = LookupMerger(mergers)
- for (attr, opts) in mergers_to_be:
- mergers.append(attr(root, opts))
- return root
diff --git a/cloudinit/mergers/m_dict.py b/cloudinit/mergers/m_dict.py
deleted file mode 100644
index 87cf1a72..00000000
--- a/cloudinit/mergers/m_dict.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2012 Yahoo! Inc.
-#
-# Author: Joshua Harlow <harlowja@yahoo-inc.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import six
-
-DEF_MERGE_TYPE = 'no_replace'
-MERGE_TYPES = ('replace', DEF_MERGE_TYPE,)
-
-
-def _has_any(what, *keys):
- for k in keys:
- if k in what:
- return True
- return False
-
-
-class Merger(object):
- def __init__(self, merger, opts):
- self._merger = merger
- # Affects merging behavior...
- self._method = DEF_MERGE_TYPE
- for m in MERGE_TYPES:
- if m in opts:
- self._method = m
- break
- # Affect how recursive merging is done on other primitives.
- self._recurse_str = 'recurse_str' in opts
- self._recurse_array = _has_any(opts, 'recurse_array', 'recurse_list')
- self._allow_delete = 'allow_delete' in opts
- # Backwards compat require this to be on.
- self._recurse_dict = True
-
- def __str__(self):
- s = ('DictMerger: (method=%s,recurse_str=%s,'
- 'recurse_dict=%s,recurse_array=%s,allow_delete=%s)')
- s = s % (self._method, self._recurse_str,
- self._recurse_dict, self._recurse_array, self._allow_delete)
- return s
-
- def _do_dict_replace(self, value, merge_with, do_replace):
-
- def merge_same_key(old_v, new_v):
- if do_replace:
- return new_v
- if isinstance(new_v, (list, tuple)) and self._recurse_array:
- return self._merger.merge(old_v, new_v)
- if isinstance(new_v, six.string_types) and self._recurse_str:
- return self._merger.merge(old_v, new_v)
- if isinstance(new_v, (dict)) and self._recurse_dict:
- return self._merger.merge(old_v, new_v)
- # Otherwise leave it be...
- return old_v
-
- for (k, v) in merge_with.items():
- if k in value:
- if v is None and self._allow_delete:
- value.pop(k)
- else:
- value[k] = merge_same_key(value[k], v)
- else:
- value[k] = v
- return value
-
- def _on_dict(self, value, merge_with):
- if not isinstance(merge_with, (dict)):
- return value
- if self._method == 'replace':
- merged = self._do_dict_replace(dict(value), merge_with, True)
- elif self._method == 'no_replace':
- merged = self._do_dict_replace(dict(value), merge_with, False)
- else:
- raise NotImplementedError("Unknown merge type %s" % (self._method))
- return merged
diff --git a/cloudinit/mergers/m_list.py b/cloudinit/mergers/m_list.py
deleted file mode 100644
index 81e5c580..00000000
--- a/cloudinit/mergers/m_list.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2012 Yahoo! Inc.
-#
-# Author: Joshua Harlow <harlowja@yahoo-inc.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import six
-
-DEF_MERGE_TYPE = 'replace'
-MERGE_TYPES = ('append', 'prepend', DEF_MERGE_TYPE, 'no_replace')
-
-
-def _has_any(what, *keys):
- for k in keys:
- if k in what:
- return True
- return False
-
-
-class Merger(object):
- def __init__(self, merger, opts):
- self._merger = merger
- # Affects merging behavior...
- self._method = DEF_MERGE_TYPE
- for m in MERGE_TYPES:
- if m in opts:
- self._method = m
- break
- # Affect how recursive merging is done on other primitives
- self._recurse_str = _has_any(opts, 'recurse_str')
- self._recurse_dict = _has_any(opts, 'recurse_dict')
- self._recurse_array = _has_any(opts, 'recurse_array', 'recurse_list')
-
- def __str__(self):
- return ('ListMerger: (method=%s,recurse_str=%s,'
- 'recurse_dict=%s,recurse_array=%s)') % (self._method,
- self._recurse_str,
- self._recurse_dict,
- self._recurse_array)
-
- def _on_tuple(self, value, merge_with):
- return tuple(self._on_list(list(value), merge_with))
-
- def _on_list(self, value, merge_with):
- if (self._method == 'replace' and
- not isinstance(merge_with, (tuple, list))):
- return merge_with
-
- # Ok we now know that what we are merging with is a list or tuple.
- merged_list = []
- if self._method == 'prepend':
- merged_list.extend(merge_with)
- merged_list.extend(value)
- return merged_list
- elif self._method == 'append':
- merged_list.extend(value)
- merged_list.extend(merge_with)
- return merged_list
-
- def merge_same_index(old_v, new_v):
- if self._method == 'no_replace':
- # Leave it be...
- return old_v
- if isinstance(new_v, (list, tuple)) and self._recurse_array:
- return self._merger.merge(old_v, new_v)
- if isinstance(new_v, six.string_types) and self._recurse_str:
- return self._merger.merge(old_v, new_v)
- if isinstance(new_v, (dict)) and self._recurse_dict:
- return self._merger.merge(old_v, new_v)
- return new_v
-
- # Ok now we are replacing same indexes
- merged_list.extend(value)
- common_len = min(len(merged_list), len(merge_with))
- for i in range(0, common_len):
- merged_list[i] = merge_same_index(merged_list[i], merge_with[i])
- return merged_list
diff --git a/cloudinit/mergers/m_str.py b/cloudinit/mergers/m_str.py
deleted file mode 100644
index b00c4bf3..00000000
--- a/cloudinit/mergers/m_str.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2012 Yahoo! Inc.
-#
-# Author: Joshua Harlow <harlowja@yahoo-inc.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import six
-
-
-class Merger(object):
- def __init__(self, _merger, opts):
- self._append = 'append' in opts
-
- def __str__(self):
- return 'StringMerger: (append=%s)' % (self._append)
-
- # On encountering a unicode object to merge value with
- # we will for now just proxy into the string method to let it handle it.
- def _on_unicode(self, value, merge_with):
- return self._on_str(value, merge_with)
-
- # On encountering a string object to merge with we will
- # perform the following action, if appending we will
- # merge them together, otherwise we will just return value.
- def _on_str(self, value, merge_with):
- if not isinstance(value, six.string_types):
- return merge_with
- if not self._append:
- return merge_with
- if isinstance(value, six.text_type):
- return value + six.text_type(merge_with)
- else:
- return value + six.binary_type(merge_with)