DRAFT mcf: Recognize "-f CONFIGFILE" option, v2 of CONFIGFILE, and more (v7.0.0)
- Also allow CONFIGFILE to have a ".mcf" extension. - Drop support for broken tags= - Support CONFIGFILE version 2 (McfFileVersion = 2) - Rename "webos_layers" to "Layers", but continue to recognize old name. - Recognize dict-s for fetch and options, but continue to recognize file version 1 strings. - Recognize an optional BblayersConfExtraLines variable in CONFIGFILE that contains a list of strings to be appended as separate lines to the generated conf/bblayers.conf . - Rename "submission" item to "fetch". - Fix error message to mention conf/layer.conf instead of incorrect local.conf . - Correct/improve messages - Requires Python 3.5 => major version bump.
This commit is contained in:
parent
f586a9cd53
commit
e23d42f253
134
scripts/mcf
134
scripts/mcf
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2008-2017 LG Electronics, Inc.
|
# Copyright (c) 2008-2019 LG Electronics, Inc.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +13,6 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import errno
|
import errno
|
||||||
import logging
|
import logging
|
||||||
|
@ -24,8 +23,10 @@ import re
|
||||||
from time import gmtime, strftime, sleep
|
from time import gmtime, strftime, sleep
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
import glob
|
||||||
|
import importlib.util
|
||||||
|
import importlib.machinery
|
||||||
|
|
||||||
__version__ = "6.2.3"
|
__version__ = "7.0.0"
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ TRACE = False
|
||||||
REMOTE = "origin"
|
REMOTE = "origin"
|
||||||
SSTATE_MIRRORS = ''
|
SSTATE_MIRRORS = ''
|
||||||
LAYERS = {}
|
LAYERS = {}
|
||||||
|
MCFFILEVERSION = None
|
||||||
DISTRO = None
|
DISTRO = None
|
||||||
SUPPORTED_MACHINES = []
|
SUPPORTED_MACHINES = []
|
||||||
|
|
||||||
|
@ -116,14 +118,16 @@ def getopts():
|
||||||
general.add_argument(mcfcommand_option, dest=mcfcommand_dest, choices=mcfcommand_choices, default=mcfcommand_default,
|
general.add_argument(mcfcommand_option, dest=mcfcommand_dest, choices=mcfcommand_choices, default=mcfcommand_default,
|
||||||
help='command to mcf; if update is given, none of the remaining options nor MACHINE can be specified (default: %(default)s)')
|
help='command to mcf; if update is given, none of the remaining options nor MACHINE can be specified (default: %(default)s)')
|
||||||
|
|
||||||
|
general.add_argument('-f', '--config-file', dest='configfile', help='.mcf/.py file specifying the build configuration (default: weboslayers.py in same directory as this script)')
|
||||||
|
|
||||||
if mcfcommand in ('configure','update+configure'):
|
if mcfcommand in ('configure','update+configure'):
|
||||||
variations = parser.add_argument_group('Build Instructions')
|
variations = parser.add_argument_group('Build Instructions')
|
||||||
|
|
||||||
variations.add_argument('-p', '--enable-parallel-make', dest='parallel_make', type=int, default=0,
|
variations.add_argument('-p', '--enable-parallel-make', dest='parallel_make', type=int, default=0,
|
||||||
help='maximum number of parallel tasks each submake of bitbake should spawn (default: 0 = 2x the number of processor cores)')
|
help='maximum number of parallel tasks each submake of bitbake should spawn (default: 0 means 2x the number of processor cores)')
|
||||||
|
|
||||||
variations.add_argument('-b', '--enable-bb-number-threads', dest='bb_number_threads', type=int, default=0,
|
variations.add_argument('-b', '--enable-bb-number-threads', dest='bb_number_threads', type=int, default=0,
|
||||||
help='maximum number of bitbake tasks to spawn (default: 0 = 2x the number of processor cores))')
|
help='maximum number of bitbake tasks to spawn (default: 0 means 2x the number of processor cores))')
|
||||||
|
|
||||||
icecc = parser.add_argument_group('ICECC Configuration')
|
icecc = parser.add_argument_group('ICECC Configuration')
|
||||||
|
|
||||||
|
@ -263,35 +267,77 @@ def location_to_dirname(location):
|
||||||
str1 = location.split('/')
|
str1 = location.split('/')
|
||||||
return os.path.splitext(str1[len(str1)-1])[0]
|
return os.path.splitext(str1[len(str1)-1])[0]
|
||||||
|
|
||||||
def read_weboslayers(path):
|
def read_mcfconfigfile(configfile):
|
||||||
sys.path.insert(0,path)
|
if not os.path.isfile(configfile):
|
||||||
if not os.path.isfile(os.path.join(path,'weboslayers.py')):
|
raise Exception("Error: Configuration file %s does not exist!" % configfile)
|
||||||
raise Exception("Error: Configuration file %s does not exist!" % os.path.join(path,'weboslayers.py'))
|
|
||||||
|
|
||||||
from weboslayers import webos_layers
|
importlib.machinery.SOURCE_SUFFIXES.append(".mcf")
|
||||||
|
spec = importlib.util.spec_from_file_location("mcfconfigfile", configfile)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
sys.modules["mcfconfigfile"] = module
|
||||||
|
|
||||||
for p in webos_layers:
|
try:
|
||||||
layer = {"name":p[0], "priority":p[1], "url":p[2], "submission":p[3], "location":p[4]}
|
from mcfconfigfile import McfFileVersion
|
||||||
|
except ImportError:
|
||||||
|
McfFileVersion = 1
|
||||||
|
global MCFFILEVERSION
|
||||||
|
MCFFILEVERSION = McfFileVersion
|
||||||
|
logger.debug("Config file version: %d" % MCFFILEVERSION)
|
||||||
|
|
||||||
|
if MCFFILEVERSION > 1:
|
||||||
|
try:
|
||||||
|
from mcfconfigfile import Layers
|
||||||
|
except ImportError:
|
||||||
|
from mcfconfigfile import webos_layers
|
||||||
|
Layers = webos_layers
|
||||||
|
else:
|
||||||
|
from mcfconfigfile import webos_layers
|
||||||
|
Layers = webos_layers
|
||||||
|
|
||||||
|
for p in Layers:
|
||||||
|
if MCFFILEVERSION > 1 and isinstance(p[4], dict):
|
||||||
|
options = p[4]
|
||||||
|
try:
|
||||||
|
location = options["location"]
|
||||||
|
except KeyError:
|
||||||
|
location = ''
|
||||||
|
else:
|
||||||
|
# It's expected to be a string.
|
||||||
|
location = p[4]
|
||||||
|
|
||||||
|
layer = {"name":p[0], "priority":p[1], "url":p[2], "fetch":p[3], "location":location}
|
||||||
LAYERS[layer["name"]] = layer
|
LAYERS[layer["name"]] = layer
|
||||||
parsesubmissions(layer)
|
parsefetch(layer)
|
||||||
if not layer["url"] and not layer["location"]:
|
if not layer["url"] and not layer["location"]:
|
||||||
raise Exception("Error: Layer '%s' does not have either URL or alternative working-dir defined in weboslayers.py" % layer["name"])
|
raise Exception("Error: Layer '%s' does not have either URL or alternative working-dir defined in %s" % (layer["name"], configfile))
|
||||||
if not layer["location"]:
|
if not layer["location"]:
|
||||||
layer["location"] = location_to_dirname(layer["url"])
|
layer["location"] = location_to_dirname(layer["url"])
|
||||||
|
|
||||||
from weboslayers import Distribution
|
from mcfconfigfile import Distribution
|
||||||
global DISTRO
|
global DISTRO
|
||||||
DISTRO = Distribution
|
DISTRO = Distribution
|
||||||
|
|
||||||
from weboslayers import Machines
|
from mcfconfigfile import Machines
|
||||||
global SUPPORTED_MACHINES
|
global SUPPORTED_MACHINES
|
||||||
SUPPORTED_MACHINES = Machines
|
SUPPORTED_MACHINES = Machines
|
||||||
|
|
||||||
def parsesubmissions(layer):
|
def parsefetch(layer):
|
||||||
|
fetch = layer["fetch"]
|
||||||
branch = ''
|
branch = ''
|
||||||
commit = ''
|
commit = ''
|
||||||
tag = ''
|
if MCFFILEVERSION > 1 and isinstance(fetch, dict):
|
||||||
for vgit in layer["submission"].split(','):
|
try:
|
||||||
|
branch = fetch["branch"]
|
||||||
|
except KeyError:
|
||||||
|
branch = 'master'
|
||||||
|
try:
|
||||||
|
commit = fetch["commit"]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# It's expected to be a string.
|
||||||
|
for vgit in fetch.split(','):
|
||||||
if not vgit:
|
if not vgit:
|
||||||
continue
|
continue
|
||||||
str1, str2 = vgit.split('=')
|
str1, str2 = vgit.split('=')
|
||||||
|
@ -300,16 +346,12 @@ def parsesubmissions(layer):
|
||||||
commit = str2
|
commit = str2
|
||||||
elif str1.lower() == 'branch':
|
elif str1.lower() == 'branch':
|
||||||
branch = str2
|
branch = str2
|
||||||
elif str1.lower() == 'tag':
|
|
||||||
if not tag:
|
|
||||||
tag = str2
|
|
||||||
|
|
||||||
if not branch:
|
if not branch:
|
||||||
branch = 'master'
|
branch = 'master'
|
||||||
|
|
||||||
layer["branch_new"] = branch
|
layer["branch_new"] = branch
|
||||||
layer["commit_new"] = commit
|
layer["commit_new"] = commit
|
||||||
layer["tag_new"] = tag
|
|
||||||
|
|
||||||
def wait_for_git_mirror(newcommitid):
|
def wait_for_git_mirror(newcommitid):
|
||||||
repodir=os.getcwd()
|
repodir=os.getcwd()
|
||||||
|
@ -386,18 +428,6 @@ def downloadrepo(layer):
|
||||||
cmd ='git checkout %s' % newcommitid
|
cmd ='git checkout %s' % newcommitid
|
||||||
echo_check_call(cmd)
|
echo_check_call(cmd)
|
||||||
|
|
||||||
newtag = layer["tag_new"]
|
|
||||||
if newtag:
|
|
||||||
if newbranch and newbranch != currentbranch:
|
|
||||||
# older git doesn't allow to update reference on currently checked out branch
|
|
||||||
cmd ='git checkout -B %s %s' % (newbranch,newtag)
|
|
||||||
elif newbranch:
|
|
||||||
# we're already on requested branch
|
|
||||||
cmd ='git reset --hard %s' % newtag
|
|
||||||
else:
|
|
||||||
cmd ='git checkout %s' % newtag
|
|
||||||
echo_check_call(cmd)
|
|
||||||
|
|
||||||
os.chdir(olddir)
|
os.chdir(olddir)
|
||||||
|
|
||||||
def parselayerconffile(layer, layerconffile):
|
def parselayerconffile(layer, layerconffile):
|
||||||
|
@ -415,6 +445,7 @@ def traversedir(layer):
|
||||||
for path, dirs, files in os.walk(layer["location"]):
|
for path, dirs, files in os.walk(layer["location"]):
|
||||||
if os.path.basename(os.path.dirname(path)) == layer["name"]:
|
if os.path.basename(os.path.dirname(path)) == layer["name"]:
|
||||||
for filename in files:
|
for filename in files:
|
||||||
|
# XXX Should check that it's under a "conf" subdirectory.
|
||||||
if filename == 'layer.conf':
|
if filename == 'layer.conf':
|
||||||
layer["collection_path"] = os.path.relpath(os.path.dirname(path), os.path.dirname(layer["location"]))
|
layer["collection_path"] = os.path.relpath(os.path.dirname(path), os.path.dirname(layer["location"]))
|
||||||
logger.debug("traversedir(%s,%s) -> %s" % (layer["name"], layer["location"], layer["collection_path"]))
|
logger.debug("traversedir(%s,%s) -> %s" % (layer["name"], layer["location"], layer["collection_path"]))
|
||||||
|
@ -436,7 +467,7 @@ def write_bblayers_conf(sourcedir):
|
||||||
priorities = ""
|
priorities = ""
|
||||||
for layer in sorted(LAYERS.values(), key=lambda l: l["priority"], reverse=True):
|
for layer in sorted(LAYERS.values(), key=lambda l: l["priority"], reverse=True):
|
||||||
if layer["priority"] == -1:
|
if layer["priority"] == -1:
|
||||||
# bitbake is not metadata layer, skip it
|
# Layer is not metadata layer, skip it
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if os.path.isabs(layer["location"]):
|
if os.path.isabs(layer["location"]):
|
||||||
|
@ -446,7 +477,7 @@ def write_bblayers_conf(sourcedir):
|
||||||
layer_name = layer["name"].replace('-','_').upper()
|
layer_name = layer["name"].replace('-','_').upper()
|
||||||
|
|
||||||
if "collection_path" not in layer:
|
if "collection_path" not in layer:
|
||||||
logger.error("Layer %s doesn't exist at all or local.conf file wasn't found inside" % layer["name"])
|
logger.error("Layer %s doesn't exist or no conf/layer.conf file was found inside" % layer["name"])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
locations += "%s_LAYER ?= \"%s/%s\"\n" % (layer_name, topdir, layer["collection_path"])
|
locations += "%s_LAYER ?= \"%s/%s\"\n" % (layer_name, topdir, layer["collection_path"])
|
||||||
|
@ -462,13 +493,20 @@ def write_bblayers_conf(sourcedir):
|
||||||
f.write(bblayers)
|
f.write(bblayers)
|
||||||
f.write('"\n')
|
f.write('"\n')
|
||||||
f.write(priorities)
|
f.write(priorities)
|
||||||
|
try:
|
||||||
|
from mcfconfigfile import BblayersConfExtraLines
|
||||||
|
if BblayersConfExtraLines:
|
||||||
|
f.write('\n# Lines from the BblayersConfExtraLines setting:\n')
|
||||||
|
f.writelines('\n'.join(BblayersConfExtraLines) + '\n')
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
def update_layers(sourcedir):
|
def update_layers(sourcedir):
|
||||||
logger.info('MCF-%s: Updating build directory' % __version__)
|
logger.info('MCF-%s: Updating layers' % __version__)
|
||||||
layers_sanity = list()
|
layers_sanity = list()
|
||||||
update_location = list()
|
update_location = list()
|
||||||
for layer in sorted(LAYERS.values(), key=lambda l: l["priority"]):
|
for layer in sorted(LAYERS.values(), key=lambda l: l["priority"]):
|
||||||
if layer["submission"] and layer["location"] not in update_location:
|
if layer["fetch"] and layer["location"] not in update_location:
|
||||||
update_location.append(layer["location"])
|
update_location.append(layer["location"])
|
||||||
if not os.path.exists(os.path.abspath(layer["location"])):
|
if not os.path.exists(os.path.abspath(layer["location"])):
|
||||||
# downloadrepo
|
# downloadrepo
|
||||||
|
@ -838,6 +876,7 @@ def configure_build(srcdir, options):
|
||||||
['@prog@', progname],
|
['@prog@', progname],
|
||||||
['@srcdir@', srcdir],
|
['@srcdir@', srcdir],
|
||||||
['@abs_srcdir@', abs_srcdir],
|
['@abs_srcdir@', abs_srcdir],
|
||||||
|
['@configfileoption@', ('--config-file=%s' % options.configfile) if options.configfile else '' ],
|
||||||
]
|
]
|
||||||
|
|
||||||
# if icecc is not installed, or version does not match requirements, then disabling icecc is the correct action.
|
# if icecc is not installed, or version does not match requirements, then disabling icecc is the correct action.
|
||||||
|
@ -874,12 +913,25 @@ if __name__ == '__main__':
|
||||||
# NB. The exec done by mcf.status causes argv[0] to be an absolute pathname
|
# NB. The exec done by mcf.status causes argv[0] to be an absolute pathname
|
||||||
progname = sys.argv[0]
|
progname = sys.argv[0]
|
||||||
|
|
||||||
|
|
||||||
|
# Uses importlib.util.module_from_spec => requires Python 3.5 or later (see
|
||||||
|
# https://docs.python.org/3.5/library/importlib.html?highlight=importlib%20util%20module_from_spec#importlib.util.module_from_spec).
|
||||||
|
if sys.hexversion < 0x03050000:
|
||||||
|
logger.error("%s requires Python 3.5 or later" % progname)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Use the same timestamp for everything created by this invocation of mcf
|
# Use the same timestamp for everything created by this invocation of mcf
|
||||||
timestamp = strftime("%Y%m%d%H%M%S", gmtime())
|
timestamp = strftime("%Y%m%d%H%M%S", gmtime())
|
||||||
|
|
||||||
options = getopts()
|
options = getopts()
|
||||||
|
|
||||||
|
if options.configfile:
|
||||||
|
srcdir = "."
|
||||||
|
configfile = options.configfile
|
||||||
|
else:
|
||||||
srcdir = os.path.dirname(progname)
|
srcdir = os.path.dirname(progname)
|
||||||
|
configfile = os.path.join(srcdir, "weboslayers.py")
|
||||||
|
|
||||||
abs_srcdir = os.path.abspath(srcdir)
|
abs_srcdir = os.path.abspath(srcdir)
|
||||||
|
|
||||||
if options.mcfcommand == 'update':
|
if options.mcfcommand == 'update':
|
||||||
|
@ -891,10 +943,10 @@ if __name__ == '__main__':
|
||||||
if options.clean:
|
if options.clean:
|
||||||
enable_clean()
|
enable_clean()
|
||||||
|
|
||||||
read_weboslayers(srcdir)
|
read_mcfconfigfile(configfile)
|
||||||
for M in options.MACHINE:
|
for M in options.MACHINE:
|
||||||
if M not in SUPPORTED_MACHINES:
|
if M not in SUPPORTED_MACHINES:
|
||||||
logger.error("MACHINE argument '%s' isn't supported (does not appear in Machines in weboslayers.py '%s')" % (M, SUPPORTED_MACHINES))
|
logger.error("MACHINE argument '%s' isn't supported (does not appear in Machines in %s: '%s')" % (M, options.configfile, SUPPORTED_MACHINES))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if options.mcfcommand != 'configure':
|
if options.mcfcommand != 'configure':
|
||||||
|
|
Loading…
Reference in New Issue