~jcsackett/charmworld/bac-tag-constraints

« back to all changes in this revision

Viewing changes to charmworld/lib/deployer.py

  • Committer: Rick Harding
  • Date: 2013-10-31 17:27:29 UTC
  • mfrom: (435 trunk)
  • mto: (436.1.2 api-doc-updates)
  • mto: This revision was merged to the branch mainline in revision 437.
  • Revision ID: rick.harding@canonical.com-20131031172729-u7cxl8ox3awl2o55
Update deployer version and it's deps, make that work

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Helpers for dealing with deployer files."""
 
2
from copy import deepcopy
 
3
import yaml
 
4
 
 
5
from charmworld.lib.proof import ProofError
 
6
 
 
7
 
 
8
def parse_deployer(data, format='yaml'):
 
9
    try:
 
10
        return yaml.safe_load(data)
 
11
    except yaml.YAMLError, exc:
 
12
        raise ProofError(
 
13
            [
 
14
                data,
 
15
                str(exc)
 
16
            ],
 
17
            'Could not parse the yaml provided.'
 
18
        )
 
19
 
 
20
 
 
21
class CycleDetected(Exception):
 
22
    """An inheritance cycle was detected in a deployment config."""
 
23
 
 
24
    def __init__(self, key):
 
25
        super(CycleDetected, self).__init__(
 
26
            'An inheritance cycle was detected involving deployment "%s"'
 
27
            % key)
 
28
 
 
29
 
 
30
# Utils from deployer 1
 
31
def relations_combine(onto, source):
 
32
    target = deepcopy(onto)
 
33
    # Support list of relations targets
 
34
    if isinstance(onto, list) and isinstance(source, list):
 
35
        target.extend(source)
 
36
        return target
 
37
    for (key, value) in source.items():
 
38
        if key in target:
 
39
            if isinstance(target[key], dict) and isinstance(value, dict):
 
40
                target[key] = relations_combine(target[key], value)
 
41
            elif isinstance(target[key], list) and isinstance(value, list):
 
42
                target[key] = list(set(target[key] + value))
 
43
        else:
 
44
            target[key] = value
 
45
    return target
 
46
 
 
47
 
 
48
def dict_merge(onto, source):
 
49
    target = deepcopy(onto)
 
50
    for (key, value) in source.items():
 
51
        if key == 'relations' and key in target:
 
52
            target[key] = relations_combine(target[key], value)
 
53
        elif (key in target and isinstance(target[key], dict) and
 
54
                isinstance(value, dict)):
 
55
            target[key] = dict_merge(target[key], value)
 
56
        else:
 
57
            target[key] = value
 
58
    return target
 
59
 
 
60
 
 
61
def inherits(d):
 
62
    parents = d.get('inherits', ())
 
63
    if isinstance(parents, basestring):
 
64
        parents = [parents]
 
65
    return parents
 
66
 
 
67
 
 
68
def get_flattened_deployment(data, key, seen=None):
 
69
    """This flattens the inheritance hierarchy.
 
70
 
 
71
    This is provided as a public API for tools, such as Charmworld, that need
 
72
    to parse deployment configs.
 
73
    """
 
74
    if seen is None:
 
75
        seen = set()
 
76
    elif key in seen:
 
77
        raise CycleDetected(key)
 
78
    deploy_data = data[key]
 
79
    if not 'inherits' in deploy_data:
 
80
        return deploy_data
 
81
    parents = inherits(deploy_data)
 
82
    for parent_name in parents:
 
83
        parent_data = get_flattened_deployment(
 
84
            data, parent_name, seen | set([key]))
 
85
        parents.extend(inherits(parent_data))
 
86
        deploy_data = dict_merge(deploy_data, parent_data)
 
87
    deploy_data['inherits'] = parents
 
88
    return deploy_data