xref: /OK3568_Linux_fs/yocto/poky/scripts/lib/devtool/export.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun# Development tool - export command plugin
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright (C) 2014-2017 Intel Corporation
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun"""Devtool export plugin"""
8*4882a593Smuzhiyun
9*4882a593Smuzhiyunimport os
10*4882a593Smuzhiyunimport argparse
11*4882a593Smuzhiyunimport tarfile
12*4882a593Smuzhiyunimport logging
13*4882a593Smuzhiyunimport datetime
14*4882a593Smuzhiyunimport json
15*4882a593Smuzhiyun
16*4882a593Smuzhiyunlogger = logging.getLogger('devtool')
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun# output files
19*4882a593Smuzhiyundefault_arcname_prefix = "workspace-export"
20*4882a593Smuzhiyunmetadata = '.export_metadata'
21*4882a593Smuzhiyun
22*4882a593Smuzhiyundef export(args, config, basepath, workspace):
23*4882a593Smuzhiyun    """Entry point for the devtool 'export' subcommand"""
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun    def add_metadata(tar):
26*4882a593Smuzhiyun        """Archive the workspace object"""
27*4882a593Smuzhiyun        # finally store the workspace metadata
28*4882a593Smuzhiyun        with open(metadata, 'w') as fd:
29*4882a593Smuzhiyun            fd.write(json.dumps((config.workspace_path, workspace)))
30*4882a593Smuzhiyun        tar.add(metadata)
31*4882a593Smuzhiyun        os.unlink(metadata)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun    def add_recipe(tar, recipe, data):
34*4882a593Smuzhiyun        """Archive recipe with proper arcname"""
35*4882a593Smuzhiyun        # Create a map of name/arcnames
36*4882a593Smuzhiyun        arcnames = []
37*4882a593Smuzhiyun        for key, name in data.items():
38*4882a593Smuzhiyun            if name:
39*4882a593Smuzhiyun                if key == 'srctree':
40*4882a593Smuzhiyun                    # all sources, no matter where are located, goes into the sources directory
41*4882a593Smuzhiyun                    arcname = 'sources/%s' % recipe
42*4882a593Smuzhiyun                else:
43*4882a593Smuzhiyun                    arcname = name.replace(config.workspace_path, '')
44*4882a593Smuzhiyun                arcnames.append((name, arcname))
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun        for name, arcname in arcnames:
47*4882a593Smuzhiyun            tar.add(name, arcname=arcname)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun    # Make sure workspace is non-empty and possible listed include/excluded recipes are in workspace
51*4882a593Smuzhiyun    if not workspace:
52*4882a593Smuzhiyun        logger.info('Workspace contains no recipes, nothing to export')
53*4882a593Smuzhiyun        return 0
54*4882a593Smuzhiyun    else:
55*4882a593Smuzhiyun        for param, recipes in {'include':args.include,'exclude':args.exclude}.items():
56*4882a593Smuzhiyun            for recipe in recipes:
57*4882a593Smuzhiyun                if recipe not in workspace:
58*4882a593Smuzhiyun                    logger.error('Recipe (%s) on %s argument not in the current workspace' % (recipe, param))
59*4882a593Smuzhiyun                    return 1
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun    name = args.file
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun    default_name = "%s-%s.tar.gz" % (default_arcname_prefix, datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
64*4882a593Smuzhiyun    if not name:
65*4882a593Smuzhiyun        name = default_name
66*4882a593Smuzhiyun    else:
67*4882a593Smuzhiyun        # if name is a directory, append the default name
68*4882a593Smuzhiyun        if os.path.isdir(name):
69*4882a593Smuzhiyun            name = os.path.join(name, default_name)
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun    if os.path.exists(name) and not args.overwrite:
72*4882a593Smuzhiyun        logger.error('Tar archive %s exists. Use --overwrite/-o to overwrite it')
73*4882a593Smuzhiyun        return 1
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun    # if all workspace is excluded, quit
76*4882a593Smuzhiyun    if not len(set(workspace.keys()).difference(set(args.exclude))):
77*4882a593Smuzhiyun        logger.warning('All recipes in workspace excluded, nothing to export')
78*4882a593Smuzhiyun        return 0
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun    exported = []
81*4882a593Smuzhiyun    with tarfile.open(name, 'w:gz') as tar:
82*4882a593Smuzhiyun        if args.include:
83*4882a593Smuzhiyun            for recipe in args.include:
84*4882a593Smuzhiyun                add_recipe(tar, recipe, workspace[recipe])
85*4882a593Smuzhiyun                exported.append(recipe)
86*4882a593Smuzhiyun        else:
87*4882a593Smuzhiyun            for recipe, data in workspace.items():
88*4882a593Smuzhiyun                if recipe not in args.exclude:
89*4882a593Smuzhiyun                    add_recipe(tar, recipe, data)
90*4882a593Smuzhiyun                    exported.append(recipe)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun        add_metadata(tar)
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun    logger.info('Tar archive created at %s with the following recipes: %s' % (name, ', '.join(exported)))
95*4882a593Smuzhiyun    return 0
96*4882a593Smuzhiyun
97*4882a593Smuzhiyundef register_commands(subparsers, context):
98*4882a593Smuzhiyun    """Register devtool export subcommands"""
99*4882a593Smuzhiyun    parser = subparsers.add_parser('export',
100*4882a593Smuzhiyun                                   help='Export workspace into a tar archive',
101*4882a593Smuzhiyun                                   description='Export one or more recipes from current workspace into a tar archive',
102*4882a593Smuzhiyun                                   group='advanced')
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun    parser.add_argument('--file', '-f', help='Output archive file name')
105*4882a593Smuzhiyun    parser.add_argument('--overwrite', '-o', action="store_true", help='Overwrite previous export tar archive')
106*4882a593Smuzhiyun    group = parser.add_mutually_exclusive_group()
107*4882a593Smuzhiyun    group.add_argument('--include', '-i', nargs='+', default=[], help='Include recipes into the tar archive')
108*4882a593Smuzhiyun    group.add_argument('--exclude', '-e', nargs='+', default=[], help='Exclude recipes into the tar archive')
109*4882a593Smuzhiyun    parser.set_defaults(func=export)
110