1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import logging
8import os
9import json
10import stat
11
12logger = logging.getLogger('bitbake-layers')
13
14def plugin_init(plugins):
15    return OeSetupLayersWriter()
16
17class OeSetupLayersWriter():
18
19    def __str__(self):
20        return "oe-setup-layers"
21
22    def _write_python(self, input, output):
23        with open(input) as f:
24            script = f.read()
25        with open(output, 'w') as f:
26            f.write(script)
27        st = os.stat(output)
28        os.chmod(output, st.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
29
30    def _write_json(self, repos, output):
31        with open(output, 'w') as f:
32            json.dump(repos, f, sort_keys=True, indent=4)
33
34    def _read_repo_config(self, json_path):
35        with open(json_path) as f:
36            json_config = json.load(f)
37
38        supported_versions = ["1.0"]
39        if json_config["version"] not in supported_versions:
40            err = "File {} has version {}, which is not in supported versions: {}".format(json_path, json_config["version"], supported_versions)
41            logger.error(err)
42            raise Exception(err)
43
44        return json_config
45
46    def _modify_repo_config(self, json_config, args):
47        sources = json_config['sources']
48        for pair in args.custom_references:
49            try:
50                repo, rev = pair.split(':', maxsplit=1)
51            except ValueError:
52                err = "Invalid custom reference specified: '{}'. Provide one using 'REPOSITORY:REFERENCE'.".format(pair)
53                logger.error(err)
54                raise Exception(err)
55            if not repo in sources.keys():
56                err = "Repository {} does not exist in setup-layers config".format(repo)
57                logger.error(err)
58                raise Exception(err)
59
60            layer_remote = json_config['sources'][repo]['git-remote']
61            layer_remote['rev'] = rev
62            # Clear describe
63            layer_remote['describe'] = ''
64
65    def do_write(self, parent, args):
66        """ Writes out a python script and a json config that replicate the directory structure and revisions of the layers in a current build. """
67        output = args.output_prefix or "setup-layers"
68        output = os.path.join(os.path.abspath(args.destdir), output)
69
70        if args.update:
71            # Modify existing layers setup
72            if args.custom_references is None:
73                err = "No custom reference specified. Please provide one using '--use-custom-reference REPOSITORY:REFERENCE'."
74                logger.error(err)
75                raise Exception(err)
76
77            json = self._read_repo_config(output + ".json")
78            if not 'sources' in json.keys():
79                err = "File {}.json does not contain valid layer sources.".format(output)
80                logger.error(err)
81                raise Exception(err)
82
83        else:
84            # Create new layers setup
85            if not os.path.exists(args.destdir):
86                os.makedirs(args.destdir)
87            repos = parent.make_repo_config(args.destdir)
88            json = {"version":"1.0","sources":repos}
89            if not repos:
90                err = "Could not determine layer sources"
91                logger.error(err)
92                raise Exception(err)
93
94        if args.custom_references is not None:
95            self._modify_repo_config(json, args)
96
97        self._write_json(json, output + ".json")
98        logger.info('Created {}.json'.format(output))
99        if not args.json_only:
100            self._write_python(os.path.join(os.path.dirname(__file__),'../../../../scripts/oe-setup-layers'), output)
101            logger.info('Created {}'.format(output))
102
103    def register_arguments(self, parser):
104        parser.add_argument('--json-only', action='store_true',
105            help='When using the oe-setup-layers writer, write only the layer configuruation in json format. Otherwise, also a copy of scripts/oe-setup-layers (from oe-core or poky) is provided, which is a self contained python script that fetches all the needed layers and sets them to correct revisions using the data from the json.')
106
107        parser.add_argument('--update', '-u',
108            action='store_true',
109            help=("Instead of writing a new json file, update an existing layer setup json file with custom references provided via the '--use-custom-reference' option."
110                  "\nThis will only update repositories for which a custom reference is specified, all other repositores will be left unchanged."))
111        parser.add_argument('--use-custom-reference', '-r',
112            action='append',
113            dest='custom_references',
114            metavar='REPOSITORY:REFERENCE',
115            help=("A pair consisting of a repository and a custom reference to use for it (by default the currently checked out commit id would be written out)."
116                  "\nThis value can be any reference that 'git checkout' would accept, and is not checked for validity."
117                  "\nThis option can be used multiple times."))
118