summaryrefslogtreecommitdiff
path: root/morphlib/defaults.py
blob: 9e695a9040275b77b09575572873b16ccdcb9a5d (plain)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
# Copyright (C) 2015  Codethink Limited
#
# 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; version 2 of the License.
#
# 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/>.
#
# =*= License: GPL-2 =*=


import cliapp
import jsonschema
import yaml

import os

import morphlib


class Defaults(object):
    '''Represents predefined default values specific to Baserock definitions.

    The DEFAULTS file was added in definitions format version 7, which lets
    users set these defaults. The text of DEFAULTS file can be passed in as
    'text', and will be validated and parsed if definitions_version >= 7.

    Prior to version 7, the defaults were hardcoded in Morph. These defaults
    will be returned if definitions_version < 7.

    '''
    def __init__(self, definitions_version, text=None):
        self._build_systems = {}
        self._split_rules = {}

        schema_path = os.path.join(morphlib.util.schemas_directory(),
                                   'defaults.json-schema')
        with open(schema_path) as f:
            self.schema = yaml.load(f)

        if definitions_version >= 7:
            if text:
                self._build_systems, self._split_rules = self._parse(text)
        else:
            self._build_systems, self._split_rules = self._builtins()

    def _parse(self, text):
        build_systems = {}
        split_rules = {}

        # This reports errors against <string> rather than the actual filename,
        # which is sad.
        data = yaml.safe_load(text)

        if data is None:
            # It's OK to be empty, I guess.
            return build_systems, split_rules

        try:
            # It would be nice if this could give line numbers when it spotted
            # errors. Seems tricky.
            jsonschema.validate(data, self.schema)
        except jsonschema.ValidationError as e:
            raise cliapp.AppException('Invalid DEFAULTS file: %s' % e.message)

        build_system_data = data.get('build-systems', {})
        for name, commands in build_system_data.items():
            build_system = morphlib.buildsystem.BuildSystem()
            build_system.from_dict(name, commands)
            build_systems[name] = build_system

        # It would make sense to create artifactsplitrule.SplitRule instances
        # here, instead of an unlabelled data structure. That would need some
        # changes to source.make_sources() and the 'artifactsplitrule' module.
        split_rules_data = data.get('split-rules', {})
        for kind, rules in split_rules_data.items():
            split_rules[kind] = []
            for rule in rules:
                rule_unlabelled = (rule['artifact'], rule['include'])
                split_rules[kind].append(rule_unlabelled)

        return build_systems, split_rules

    def _builtins(self):
        build_systems = {}
        split_rules = {}

        for build_system in morphlib.buildsystem.build_systems:
            build_systems[build_system.name] = build_system

        split_rules['chunk'] = \
            morphlib.artifactsplitrule.DEFAULT_CHUNK_RULES
        split_rules['stratum'] = \
            morphlib.artifactsplitrule.DEFAULT_STRATUM_RULES

        return build_systems, split_rules

    def build_systems(self):
        return self._build_systems

    def split_rules(self):
        return self._split_rules