aboutsummaryrefslogtreecommitdiffstats
path: root/build/scripts/make_container.py
blob: 2c07177fdb95cf1990919e5173ea1977693597f7 (plain) (blame)
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
import os
import shutil
import stat
import struct
import subprocess
import sys

import container  # 1


def main(output_path, entry_path, input_paths, squashfs_path):
    output_tmp_path = output_path + '.tmp'
    shutil.copy2(entry_path, output_tmp_path)
    st = os.stat(output_tmp_path)
    os.chmod(output_tmp_path, st.st_mode | stat.S_IWUSR)

    layer_paths = []
    other_paths = []
    for input_path in input_paths:
        (layer_paths if input_path.endswith('.container_layer') else other_paths).append(input_path)

    if len(other_paths) == 0:
        raise Exception('No program in container dependencies')

    if len(other_paths) > 1:
        raise Exception('Multiple non-layer inputs')

    program_path = other_paths[0]
    program_container_path = os.path.basename(program_path)

    os.symlink(program_container_path, 'entry')
    add_cmd = [os.path.join(squashfs_path, 'mksquashfs')]
    add_cmd.extend([program_path, 'entry', 'program_layer'])
    subprocess.run(add_cmd)

    layer_paths.append('program_layer')

    container.join_layers(layer_paths, 'container_data', squashfs_path)

    size = 0
    block_size = 1024 * 1024

    with open(output_tmp_path, 'ab') as output:
        with open('container_data', 'rb') as input_:
            while True:
                data = input_.read(block_size)
                output.write(data)
                size += len(data)

                if len(data) < block_size:
                    break

        with open(os.path.join(squashfs_path, 'unsquashfs'), 'rb') as input_:
            while True:
                data = input_.read(block_size)
                output.write(data)
                size += len(data)

                if len(data) == 0:
                    break

        output.write(struct.pack('<Q', size))

    os.rename(output_tmp_path, output_path)


def entry():
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--output', required=True)
    parser.add_argument('-s', '--squashfs-path', required=True)
    parser.add_argument('input', nargs='*')

    args = parser.parse_args()

    def is_container_entry(path):
        return os.path.basename(path) == '_container_entry'

    input_paths = []
    entry_paths = []

    for input_path in args.input:
        (entry_paths if is_container_entry(input_path) else input_paths).append(input_path)

    if len(entry_paths) != 1:
        raise Exception('Could not select container entry from {}'.format(entry_paths))

    return main(args.output, entry_paths[0], input_paths, args.squashfs_path)


if __name__ == '__main__':
    sys.exit(entry())