summaryrefslogtreecommitdiff
path: root/scripts/build-config
blob: fa0b351281fc6640082bbbb91c74931e42c50c64 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python3
#
# Copyright (C) 2019, VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# 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/>.
#
# File: build-config
# Purpose:
#  This script serves the same purpose as ./configure in traditional
#   autoconf setups.
#  It takes build configuration options from command line, checks them,
#  builds a config dictionary, augments it with some default and/or
#  computed values and saves it to build/build-config.json
#  for other build scripts to read.

import argparse
import re
import sys
import os
import getpass
import platform
import json

import defaults

# argparse converts hyphens to underscores,
# so for lookups in the original options hash we have to
# convert them back
def field_to_option(s):
    return re.sub(r'_', '-', s)

def get_default_build_by():
    return "{user}@{host}".format(user= getpass.getuser(), host=platform.node())

def get_validator(optdict, name):
    try:
        return optdict[name][2]
    except KeyError:
        return None


# Load the build flavor file
build_flavor = os.getenv('VYOS_BUILD_FLAVOR')
if build_flavor is None:
    build_flavor = defaults.DEFAULT_BUILD_FLAVOR
try:
    with open(build_flavor, 'r') as f:
        build_defaults = json.load(f)
except Exception as e:
    print("Failed to open the build flavor file {0}: {1}".format(build_flavor, e))
    sys.exit(1)


# Options dict format:
# '$option_name_without_leading_dashes': { ('$help_string', $default_value_generator_thunk, $value_checker_thunk) }
options = {
   'architecture': ('Image target architecture (amd64 or i386 or armhf or arm64)', lambda: build_defaults['architecture'], lambda x: x in ['amd64', 'i386', 'armhf', 'arm64']),
   'build-by': ('Builder identifier (e.g. jrandomhacker@example.net)', get_default_build_by, None),
   'debian-mirror': ('Debian repository mirror for ISO build', lambda: build_defaults['debian_mirror'], None),
   'debian-security-mirror': ('Debian security updates mirror', lambda: build_defaults['debian_security_mirror'], None),
   'pbuilder-debian-mirror': ('Debian repository mirror for pbuilder env bootstrap', lambda: build_defaults['debian_mirror'], None),
   'vyos-mirror': ('VyOS package mirror', lambda: build_defaults["vyos_mirror"], None),
   'build-type': ('Build type, release or development', lambda: 'development', lambda x: x in ['release', 'development']),
   'version': ('Version number (release builds only)', None, None),
   'build-comment': ('Optional build comment', lambda: '', None)
}

# Create the option parser
parser = argparse.ArgumentParser()
for k, v in options.items():
    help_string, default_value_thunk = v[0], v[1]
    if default_value_thunk is None:
        parser.add_argument('--' + k, type=str, help=help_string)
    else:
        parser.add_argument('--' + k, type=str, help=help_string, default=default_value_thunk())

# The debug option is a bit special since it's different type
parser.add_argument('--debug', help="Enable debug output", action='store_true')

# Custom APT entry and APT key options can be used multiple times
parser.add_argument('--custom-apt-entry', help="Custom APT entry", action='append')
parser.add_argument('--custom-apt-key', help="Custom APT key file", action='append')
parser.add_argument('--custom-package', help="Custom package to install from repositories", action='append')

args = vars(parser.parse_args())

# Validate options
for k, v in args.items():
    key = field_to_option(k)
    func = get_validator(options, k)
    if func is not None:
        if not func(v):
            print("{v} is not a valid value for --{o} option".format(o=key, v=v))
            sys.exit(1)

# Some fixup for mirror settings.
# The idea is: if --debian-mirror is specified but --pbuilder-debian-mirror is not,
# use the --debian-mirror value for both lb and pbuilder bootstrap
if (args['debian_mirror'] != build_defaults["debian_mirror"]) and \
   (args['pbuilder_debian_mirror'] == build_defaults["debian_mirror"]):
    args['pbuilder_debian_mirror'] = args['debian_mirror']

# Version can only be set for release builds,
# for dev builds it hardly makes any sense
if args['build_type'] == 'development':
    if args['version'] is not None:
        print("Version can only be set for release builds")
        print("Use --build-type=release option if you want to set version number")
        sys.exit(1)

# Populate some defaults that are not configurable,
# but that are handy to have in the options hash
args['distribution'] = build_defaults["debian_distribution"]
args['build_dir'] = defaults.BUILD_DIR
args['pbuilder_config'] = defaults.PBUILDER_CONFIG
args['vyos_branch'] = build_defaults["vyos_branch"]
args['release_train'] = build_defaults["release_train"]

# Add custom packages from build defaults
if not args['custom_package']:
    args['custom_package'] = []
args['custom_package'] = args['custom_package'] + build_defaults['custom_packages']

if not args['custom_apt_entry']:
    args['custom_apt_entry'] = []
args['custom_apt_entry'] = args['custom_apt_entry'] + build_defaults['additional_repositories']


# Check the build environment and dependencies
env_check_retval = os.system("scripts/check-build-env")
if env_check_retval > 0:
    print("Build environment check failed, fix the issues and retry")

args['kernel_version'] = build_defaults['kernel_version']
args['kernel_flavor'] = build_defaults['kernel_flavor']


# Save to file
os.makedirs(defaults.BUILD_DIR, exist_ok=True)
print("Saving the build config to {0}".format(defaults.BUILD_CONFIG))
with open(defaults.BUILD_CONFIG, 'w') as f:
    json.dump(args, f, indent=4, sort_keys=True)
    print("\n", file=f)