1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2022 Intel Corporation.
5#
6# SPDX-License-Identifier: BSD-3-Clause
7#
8
9import sys
10import os
11import json
12import shlex
13import shutil
14import subprocess
15import argparse
16import re
17
18from pathlib import Path
19
20DEBUG = False
21
22
23def run_command(cmd, path):
24    if DEBUG:
25        print("cmd = %s, path = %s" % (cmd, path))
26    cmd_proc = subprocess.Popen(
27        shlex.split(cmd),
28        cwd=path,
29        stdout=sys.stdout,
30        stderr=sys.stderr,
31        universal_newlines=True
32    )
33    while True:
34        ret_code = cmd_proc.poll()
35        if ret_code is not None:
36            break
37    return ret_code
38
39
40def add_cmd_list(cmd_list, cmd_str, dir_str):
41    cmd = {
42        'cmd': cmd_str,
43        'dir': dir_str
44    }
45    cmd_list.append(cmd)
46
47
48def run_cmd_list(cmd_list):
49    for cmd in cmd_list:
50        ret = run_command(cmd['cmd'], cmd['dir'])
51        if ret != 0:
52            print("cmd(%s) run in dir(%s) failed and exit" % (cmd['cmd'], cmd['dir']))
53            exit(-1)
54    return
55
56
57def create_acrn_deb(board, scenario, version, build_dir):
58    cur_dir = build_dir + '/../'
59    deb_dir = build_dir + '/acrn_release_deb/'
60    cmd_list = []
61    if os.path.exists(deb_dir):
62        add_cmd_list(cmd_list, 'rm -rf acrn_release_deb', build_dir)
63    add_cmd_list(cmd_list, 'mkdir -p acrn_release_deb', build_dir)
64    add_cmd_list(cmd_list, 'mkdir -p acrn_release_deb/boot', build_dir)
65    add_cmd_list(cmd_list, 'mkdir DEBIAN', deb_dir)
66    add_cmd_list(cmd_list, 'touch DEBIAN/control', deb_dir)
67    deb_bin_name = 'acrn.%s.%s.bin' % (scenario, board)
68    deb_out_name = 'acrn.%s.%s.32.out' % (scenario, board)
69    build_bin_name = build_dir + '/hypervisor/acrn.bin'
70    build_out_name = build_dir + '/hypervisor/acrn.32.out'
71    add_cmd_list(cmd_list, 'cp %s acrn_release_deb/boot/%s' % (build_bin_name, deb_bin_name), build_dir)
72    add_cmd_list(cmd_list, 'cp %s acrn_release_deb/boot/%s' % (build_out_name, deb_out_name), build_dir)
73    run_cmd_list(cmd_list)
74
75    lines = []
76    f = open(cur_dir + "/misc/packaging/acrn-hypervisor.postinst", 'r')
77    for line in f:
78        lines.append(line)
79    f.close()
80    start = lines.index('#Build info Start\n')
81    end = lines.index('#Build info End\n')
82    del lines[(start + 1):(end - 1)]
83    lines.insert(start + 1, "\nSCENARIO=(%s)\n" % scenario)
84    lines.insert(start + 2, "\nBOARD=(%s)\n" % board)
85
86    a_f = open(build_dir + "/hypervisor/.scenario.xml", 'r')
87    for a_line in a_f:
88        l = re.search(r"<CPU_PERFORMANCE_POLICY>(\w*)</CPU_PERFORMANCE_POLICY>", a_line)
89        if l != None:
90            break;
91    start = lines.index('#ACRN parameters Start\n')
92    end = lines.index('#ACRN parameters End\n')
93    del lines[(start + 1):(end - 1)]
94    if l == None:
95        lines.insert(start + 1, "\nGENERATED_PARAMS=(cpu_perf_policy=%s)\n" % "Performance")
96    else:
97        lines.insert(start + 1, "\nGENERATED_PARAMS=(cpu_perf_policy=%s)\n" % l.group(1))
98
99    with open(cur_dir + "/misc/packaging/acrn-hypervisor.postinst", "w") as f:
100        for line in lines:
101            f.write(line)
102    f.close()
103
104    listcontrol = [
105        'Package: acrn-hypervisor\n',
106        'version: %s \n' % version,
107        'Depends: libcjson1\n',
108        'Pre-Depends: libsdl2-2.0-0\n',
109        'Section: free \n',
110        'Priority: optional \n',
111        'Architecture: amd64 \n',
112        'Maintainer: acrn-dev@lists.projectacrn.org \n',
113        'Description: ACRN Hypervisor for IoT \n',
114        '\n'
115    ]
116    with open(deb_dir + '/DEBIAN/control', 'w', encoding='utf-8') as fr:
117        fr.writelines(listcontrol)
118
119    # design in acrn_data
120    with open(cur_dir + "/.deb.conf", "r") as load_deb:
121        deb_info = json.load(load_deb)
122    load_deb.close()
123
124    deb_info_list = list(deb_info)
125    run_command('rm -rf acrn_release_img/usr/*', build_dir)
126
127    for i in deb_info_list:
128        source = deb_info[i]['source']
129        target = deb_info[i]['target']
130        if target == 'boot/':
131            continue
132        source = cur_dir + source
133        target = deb_dir + target
134        if os.path.exists(source):
135            if os.path.exists(target):
136                run_command('cp %s %s' % (source, target), cur_dir)
137            else:
138                run_command('mkdir -p %s' % target, cur_dir)
139                run_command('cp %s %s' % (source, target), cur_dir)
140
141    run_command('cp ./misc/packaging/acrn-hypervisor.postinst ./build/acrn_release_deb/DEBIAN/postinst', cur_dir)
142    run_command('chmod +x ./build/acrn_release_deb/etc/grub.d/100_ACRN', cur_dir)
143    run_command('chmod +x ./build/acrn_release_deb/DEBIAN/postinst', cur_dir)
144    run_command('sed -i \'s/\r//\' ./build/acrn_release_deb/DEBIAN/postinst', cur_dir)
145    if os.path.exists('./build/acrn_release_deb/DEBIAN/preinst'):
146        run_command('chmod +x ./build/acrn_release_deb/DEBIAN/preinst', cur_dir)
147        run_command('sed -i \'s/\r//\' ./build/acrn_release_deb/DEBIAN/preinst', cur_dir)
148
149    ret = run_command('dpkg -b acrn_release_deb acrn-%s-%s-%s.deb' % (board, scenario, version), build_dir)
150    if ret != 0:
151        print("ERROR : generate ACRN debian package acrn-{}-{}-{}.deb failed! \
152Please check all the files in {}/acrn_release_deb".format(board, scenario, version, build_dir))
153    else:
154        print(
155            "ACRN debian package acrn-{}-{}-{}.deb was successfully created in the {}.".format(board, scenario, version,
156                                                                                               build_dir))
157    return
158
159
160def create_acrn_board_inspector_deb(version, build_dir):
161    cur_dir = build_dir + '/../'
162    deb_dir = build_dir + '/acrn_board_inspector_deb/'
163    cmd_list = []
164    if os.path.exists(deb_dir):
165        add_cmd_list(cmd_list, 'rm -rf acrn_board_inspector_deb', build_dir)
166    add_cmd_list(cmd_list, 'mkdir -p acrn_board_inspector_deb', build_dir)
167    add_cmd_list(cmd_list, 'mkdir DEBIAN', deb_dir)
168    add_cmd_list(cmd_list, 'touch DEBIAN/control', deb_dir)
169    run_cmd_list(cmd_list)
170
171    # control file description
172    listcontrol = [
173        'Package: acrn-board-inspector\n',
174        'version: %s \n' % version,
175        'Section: free \n',
176        'Priority: optional \n',
177        'Architecture: amd64 \n',
178        'Maintainer: acrn-dev@lists.projectacrn.org \n',
179        'Description: ACRN board inspector tools \n',
180        'Depends: cpuid, msr-tools, pciutils, dmidecode, python3, python3-pip, python3-lxml, python3-tqdm \n',
181        '\n'
182    ]
183    with open(deb_dir + '/DEBIAN/control', 'w', encoding='utf-8') as fr:
184        fr.writelines(listcontrol)
185    run_command('cp -r ./misc/config_tools/board_inspector/ ./build/acrn_board_inspector_deb/bin/', cur_dir)
186    run_command('cp ./misc/packaging/acrn-board-inspector.postinst ./build/acrn_board_inspector_deb/DEBIAN/postinst',
187                cur_dir)
188    run_command('chmod +x ./build/acrn_board_inspector_deb/DEBIAN/postinst', cur_dir)
189    run_command('sed -i \'s/\r//\' ./build/acrn_board_inspector_deb/DEBIAN/postinst', cur_dir)
190    run_command('cp ./misc/packaging/acrn-board-inspector.prerm ./build/acrn_board_inspector_deb/DEBIAN/prerm', cur_dir)
191    run_command('chmod +x ./build/acrn_board_inspector_deb/DEBIAN/prerm', cur_dir)
192    run_command('sed -i \'s/\r//\' ./build/acrn_board_inspector_deb/DEBIAN/prerm', cur_dir)
193
194    ret = run_command('dpkg -b acrn_board_inspector_deb acrn-board-inspector-%s.deb' % version, build_dir)
195    if ret != 0:
196        print(
197            "ERROR : generate board_inspector debian package acrn-board-inspector-{}.deb failed! "
198            "Please check all the files in {}/acrn_board_inspector_deb".format(version, build_dir)
199        )
200    else:
201        print(
202            "board_inspector debian package acrn-board-inspector-{}.deb"
203            " was successfully created in the {}.".format(version, build_dir)
204        )
205    return
206
207
208def create_configurator_deb(version, build_dir):
209    cmd_list = []
210
211    # get folder path
212    project_base = Path(__file__).parent.parent.parent
213    config_tools_path = Path(__file__).parent.parent / 'config_tools'
214    configurator_path = config_tools_path / 'configurator'
215    scenario_config_path = project_base / "misc" / "config_tools" / "scenario_config"
216    deb_dir = configurator_path / 'packages' / 'configurator' / 'src-tauri' / 'target' / 'release' / 'bundle' / 'deb'
217
218    # clean old directory
219    if os.path.isdir(deb_dir):
220        shutil.rmtree(deb_dir)
221
222    # build command, if you update this, please update misc/config_tools/configurator/README.md#L55
223    add_cmd_list(cmd_list, 'python3 schema_slicer.py', scenario_config_path)
224    add_cmd_list(cmd_list, 'python3 converter.py', scenario_config_path / "jsonschema")
225    add_cmd_list(cmd_list, 'bash -c "xmllint --xinclude schema/datachecks.xsd > schema/allchecks.xsd"', config_tools_path)
226    add_cmd_list(cmd_list, 'python3 -m build', config_tools_path)
227    add_cmd_list(cmd_list, 'bash -c "rm -f ./configurator/packages/configurator/thirdLib/acrn_config_tools-3.0-py3-none-any.whl"', config_tools_path)
228    add_cmd_list(cmd_list, 'python3 packages/configurator/thirdLib/manager.py install', configurator_path)
229    add_cmd_list(cmd_list, 'yarn', configurator_path)
230    add_cmd_list(cmd_list, 'yarn build', configurator_path)
231    run_cmd_list(cmd_list)
232
233    orig_deb_name = [x for x in os.listdir(deb_dir) if x.endswith('.deb')]
234    if not orig_deb_name:
235        print('ERROR! No acrn-configurator deb found!')
236        return
237    orig_deb_name = orig_deb_name[0]
238    dist_deb_name = 'acrn-configurator-{ver}.deb'.format(ver=version)
239    with open(deb_dir / orig_deb_name, 'rb') as src:
240        with open(os.path.join(build_dir, dist_deb_name), 'wb') as dest:
241            dest.write(src.read())
242    return
243
244def clean_configurator_deb(version, build_dir):
245    cmd_list = []
246
247    # get folder path
248    project_base = Path(__file__).parent.parent.parent
249    config_tools_path = Path(__file__).parent.parent / 'config_tools'
250
251    add_cmd_list(cmd_list, 'bash -c "find -name "*.log" -delete"', config_tools_path)
252    add_cmd_list(cmd_list, 'bash -c "find -name "*.whl" -delete"', config_tools_path)
253    add_cmd_list(cmd_list, 'bash -c "find -name "*.egg-info" -prune -exec rm -rf {} \\;"', config_tools_path)
254    add_cmd_list(cmd_list, 'bash -c "find -name "node_modules" -prune -exec rm -rf {} \\;"', config_tools_path)
255    add_cmd_list(cmd_list, 'bash -c "find -name "build" -prune -exec rm -rf {} \\;"', config_tools_path)
256    add_cmd_list(cmd_list, 'bash -c "find -name "target" -prune -exec rm -rf {} \\;"', config_tools_path)
257    add_cmd_list(cmd_list, 'bash -c "rm -rf dist"', config_tools_path)
258    add_cmd_list(cmd_list, 'bash -c "rm -rf schema/sliced.xsd"', config_tools_path)
259    add_cmd_list(cmd_list, 'bash -c "rm -rf schema/allchecks.xsd"', config_tools_path)
260    add_cmd_list(cmd_list, 'bash -c "python3 ./configurator/packages/configurator/thirdLib/manager.py clean"', config_tools_path)
261    run_cmd_list(cmd_list)
262    return
263
264if __name__ == "__main__":
265    parser = argparse.ArgumentParser()
266    parser.add_argument("deb_mode", help="choose deb mode, e.g. acrn_all, board_inspector, configurator or clean")
267    parser.add_argument("build_dir", help="the absolute address of the acrn-hypervisor build directory")
268    parser.add_argument("--version", default="1.0", help="the acrn-hypervisor version")
269    parser.add_argument("--board_name", default="board", help="the name of the board that runs the ACRN hypervisor")
270    parser.add_argument("--scenario", default="scenario", help="the acrn hypervisor scenario setting")
271    parser.add_argument("--debug", default=False, help="debug mode")
272    args = parser.parse_args()
273
274    DEBUG = args.debug
275
276    if args.deb_mode == 'board_inspector':
277        create_acrn_board_inspector_deb(args.version, args.build_dir)
278    elif args.deb_mode == 'acrn_all':
279        create_acrn_deb(args.board_name, args.scenario, args.version, args.build_dir)
280    elif args.deb_mode == 'configurator':
281        create_configurator_deb(args.version, args.build_dir)
282    elif args.deb_mode == 'clean':
283        clean_configurator_deb(args.version, args.build_dir)
284    else:
285        print("ERROR: Please check the value of the first argument: the value shall be acrn_all, board_inspector, configurator or clean.")
286