diff options
Diffstat (limited to 'scripts/contrib')
23 files changed, 3978 insertions, 393 deletions
diff --git a/scripts/contrib/bb-perf/bb-matrix-plot.sh b/scripts/contrib/bb-perf/bb-matrix-plot.sh new file mode 100755 index 0000000000..136a25570d --- /dev/null +++ b/scripts/contrib/bb-perf/bb-matrix-plot.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# +# Copyright (c) 2011, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# DESCRIPTION +# This script operates on the .dat file generated by bb-matrix.sh. It tolerates +# the header by skipping the first line, but error messages and bad data records +# need to be removed first. It will generate three views of the plot, and leave +# an interactive view open for further analysis. +# +# AUTHORS +# Darren Hart <dvhart@linux.intel.com> +# + +# Setup the defaults +DATFILE="bb-matrix.dat" +XLABEL="BB_NUMBER_THREADS" +YLABEL="PARALLEL_MAKE" +FIELD=3 +DEF_TITLE="Elapsed Time (seconds)" +PM3D_FRAGMENT="unset surface; set pm3d at s hidden3d 100" +SIZE="640,480" + +function usage { +CMD=$(basename $0) +cat <<EOM +Usage: $CMD [-d datfile] [-f field] [-h] [-t title] [-w] + -d datfile The data file generated by bb-matrix.sh (default: $DATFILE) + -f field The field index to plot as the Z axis from the data file + (default: $FIELD, "$DEF_TITLE") + -h Display this help message + -s W,H PNG and window size in pixels (default: $SIZE) + -t title The title to display, should describe the field (-f) and units + (default: "$DEF_TITLE") + -w Render the plot as wireframe with a 2D colormap projected on the + XY plane rather than as the texture for the surface +EOM +} + +# Parse and validate arguments +while getopts "d:f:hs:t:w" OPT; do + case $OPT in + d) + DATFILE="$OPTARG" + ;; + f) + FIELD="$OPTARG" + ;; + h) + usage + exit 0 + ;; + s) + SIZE="$OPTARG" + ;; + t) + TITLE="$OPTARG" + ;; + w) + PM3D_FRAGMENT="set pm3d at b" + W="-w" + ;; + *) + usage + exit 1 + ;; + esac +done + +# Ensure the data file exists +if [ ! -f "$DATFILE" ]; then + echo "ERROR: $DATFILE does not exist" + usage + exit 1 +fi +PLOT_BASENAME=${DATFILE%.*}-f$FIELD$W + +# Set a sane title +# TODO: parse the header and define titles for each format parameter for TIME(1) +if [ -z "$TITLE" ]; then + if [ ! "$FIELD" == "3" ]; then + TITLE="Field $FIELD" + else + TITLE="$DEF_TITLE" + fi +fi + +# Determine the dgrid3d mesh dimensions size +MIN=$(tail -n +2 "$DATFILE" | cut -d ' ' -f 1 | sed 's/^0*//' | sort -n | uniq | head -n1) +MAX=$(tail -n +2 "$DATFILE" | cut -d ' ' -f 1 | sed 's/^0*//' | sort -n | uniq | tail -n1) +BB_CNT=$[${MAX} - $MIN + 1] +MIN=$(tail -n +2 "$DATFILE" | cut -d ' ' -f 2 | sed 's/^0*//' | sort -n | uniq | head -n1) +MAX=$(tail -n +2 "$DATFILE" | cut -d ' ' -f 2 | sed 's/^0*//' | sort -n | uniq | tail -n1) +PM_CNT=$[${MAX} - $MIN + 1] + + +(cat <<EOF +set title "$TITLE" +set xlabel "$XLABEL" +set ylabel "$YLABEL" +set style line 100 lt 5 lw 1.5 +$PM3D_FRAGMENT +set dgrid3d $PM_CNT,$BB_CNT splines +set ticslevel 0.2 + +set term png size $SIZE +set output "$PLOT_BASENAME.png" +splot "$DATFILE" every ::1 using 1:2:$FIELD with lines ls 100 + +set view 90,0 +set output "$PLOT_BASENAME-bb.png" +replot + +set view 90,90 +set output "$PLOT_BASENAME-pm.png" +replot + +set view 60,30 +set term wxt size $SIZE +replot +EOF +) | gnuplot --persist diff --git a/scripts/contrib/bb-perf/bb-matrix.sh b/scripts/contrib/bb-perf/bb-matrix.sh new file mode 100755 index 0000000000..106456584d --- /dev/null +++ b/scripts/contrib/bb-perf/bb-matrix.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# +# Copyright (c) 2011, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# DESCRIPTION +# This script runs BB_CMD (typically building core-image-sato) for all +# combincations of BB_RANGE and PM_RANGE values. It saves off all the console +# logs, the buildstats directories, and creates a bb-pm-runtime.dat file which +# can be used to postprocess the results with a plotting tool, spreadsheet, etc. +# Before running this script, it is recommended that you pre-download all the +# necessary sources by performing the BB_CMD once manually. It is also a good +# idea to disable cron to avoid runtime variations caused by things like the +# locate process. Be sure to sanitize the dat file prior to post-processing as +# it may contain error messages or bad runs that should be removed. +# +# AUTHORS +# Darren Hart <dvhart@linux.intel.com> +# + +# The following ranges are appropriate for a 4 core system with 8 logical units +# Use leading 0s to ensure all digits are the same string length, this results +# in nice log file names and columnar dat files. +BB_RANGE="04 05 06 07 08 09 10 11 12 13 14 15 16" +PM_RANGE="04 05 06 07 08 09 10 11 12 13 14 15 16" + +DATADIR="bb-matrix-$$" +BB_CMD="bitbake core-image-minimal" +RUNTIME_LOG="$DATADIR/bb-matrix.dat" + +# See TIME(1) for a description of the time format parameters +# The following all report 0: W K r s t w +TIME_STR="%e %S %U %P %c %w %R %F %M %x" + +# Prepare the DATADIR +mkdir $DATADIR +if [ $? -ne 0 ]; then + echo "Failed to create $DATADIR." + exit 1 +fi + +# Add a simple header +echo "BB PM $TIME_STR" > $RUNTIME_LOG +for BB in $BB_RANGE; do + for PM in $PM_RANGE; do + RUNDIR="$DATADIR/$BB-$PM-build" + mkdir $RUNDIR + BB_LOG=$RUNDIR/$BB-$PM-bitbake.log + date + echo "BB=$BB PM=$PM Logging to $BB_LOG" + + echo -n " Preparing the work directory... " + rm -rf pseudodone tmp sstate-cache tmp-eglibc &> /dev/null + echo "done" + + # Export the variables under test and run the bitbake command + # Strip any leading zeroes before passing to bitbake + export BB_NUMBER_THREADS=$(echo $BB | sed 's/^0*//') + export PARALLEL_MAKE="-j $(echo $PM | sed 's/^0*//')" + /usr/bin/time -f "$BB $PM $TIME_STR" -a -o $RUNTIME_LOG $BB_CMD &> $BB_LOG + + echo " $(tail -n1 $RUNTIME_LOG)" + cp -a tmp/buildstats $RUNDIR/$BB-$PM-buildstats + done +done diff --git a/scripts/contrib/bb-perf/buildstats-plot.sh b/scripts/contrib/bb-perf/buildstats-plot.sh new file mode 100755 index 0000000000..7e8ae0410e --- /dev/null +++ b/scripts/contrib/bb-perf/buildstats-plot.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2011, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# DESCRIPTION +# +# Produces script data to be consumed by gnuplot. There are two possible plots +# depending if either the -S parameter is present or not: +# +# * without -S: Produces a histogram listing top N recipes/tasks versus +# stats. The first stat defined in the -s parameter is the one taken +# into account for ranking +# * -S: Produces a histogram listing tasks versus stats. In this case, +# the value of each stat is the sum for that particular stat in all recipes found. +# Stats values are in descending order defined by the first stat defined on -s +# +# EXAMPLES +# +# 1. Top recipes' tasks taking into account utime +# +# $ buildstats-plot.sh -s utime | gnuplot -p +# +# 2. Tasks versus utime:stime +# +# $ buildstats-plot.sh -s utime:stime -S | gnuplot -p +# +# 3. Tasks versus IO write_bytes:IO read_bytes +# +# $ buildstats-plot.sh -s 'IO write_bytes:IO read_bytes' -S | gnuplot -p +# +# AUTHORS +# Leonardo Sandoval <leonardo.sandoval.gonzalez@linux.intel.com> +# + +set -o nounset +set -o errexit + +BS_DIR="tmp/buildstats" +N=10 +STATS="utime" +SUM="" +OUTDATA_FILE="$PWD/buildstats-plot.out" + +function usage { + CMD=$(basename $0) + cat <<EOM +Usage: $CMD [-b buildstats_dir] [-t do_task] + -b buildstats The path where the folder resides + (default: "$BS_DIR") + -n N Top N recipes to display. Ignored if -S is present + (default: "$N") + -s stats The stats to be matched. If more that one stat, units + should be the same because data is plot as histogram. + (see buildstats.sh -h for all options) or any other defined + (build)stat separated by colons, i.e. stime:utime + (default: "$STATS") + -S Sum values for a particular stat for found recipes + -o Output data file. + (default: "$OUTDATA_FILE") + -h Display this help message +EOM +} + +# Parse and validate arguments +while getopts "b:n:s:o:Sh" OPT; do + case $OPT in + b) + BS_DIR="$OPTARG" + ;; + n) + N="$OPTARG" + ;; + s) + STATS="$OPTARG" + ;; + S) + SUM="y" + ;; + o) + OUTDATA_FILE="$OPTARG" + ;; + h) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; + esac +done + +# Get number of stats +IFS=':'; statsarray=(${STATS}); unset IFS +nstats=${#statsarray[@]} + +# Get script folder, use to run buildstats.sh +CD=$(dirname $0) + +# Parse buildstats recipes to produce a single table +OUTBUILDSTATS="$PWD/buildstats.log" +$CD/buildstats.sh -H -s "$STATS" -H > $OUTBUILDSTATS + +# Get headers +HEADERS=$(cat $OUTBUILDSTATS | sed -n -e '1s/ /-/g' -e '1s/:/ /gp') + +echo -e "set boxwidth 0.9 relative" +echo -e "set style data histograms" +echo -e "set style fill solid 1.0 border lt -1" +echo -e "set xtics rotate by 45 right" + +# Get output data +if [ -z "$SUM" ]; then + cat $OUTBUILDSTATS | sed -e '1d' | sort -k3 -n -r | head -$N > $OUTDATA_FILE + # include task at recipe column + sed -i -e "1i\ +${HEADERS}" $OUTDATA_FILE + echo -e "set title \"Top task/recipes\"" + echo -e "plot for [COL=3:`expr 3 + ${nstats} - 1`] '${OUTDATA_FILE}' using COL:xtic(stringcolumn(1).' '.stringcolumn(2)) title columnheader(COL)" +else + + # Construct datatamash sum argument (sum 3 sum 4 ...) + declare -a sumargs + j=0 + for i in `seq $nstats`; do + sumargs[j]=sum; j=$(( $j + 1 )) + sumargs[j]=`expr 3 + $i - 1`; j=$(( $j + 1 )) + done + + # Do the processing with datamash + cat $OUTBUILDSTATS | sed -e '1d' | datamash -t ' ' -g1 ${sumargs[*]} | sort -k2 -n -r > $OUTDATA_FILE + + # Include headers into resulted file, so we can include gnuplot xtics + HEADERS=$(echo $HEADERS | sed -e 's/recipe//1') + sed -i -e "1i\ +${HEADERS}" $OUTDATA_FILE + + # Plot + echo -e "set title \"Sum stats values per task for all recipes\"" + echo -e "plot for [COL=2:`expr 2 + ${nstats} - 1`] '${OUTDATA_FILE}' using COL:xtic(1) title columnheader(COL)" +fi + diff --git a/scripts/contrib/bb-perf/buildstats.sh b/scripts/contrib/bb-perf/buildstats.sh new file mode 100755 index 0000000000..8d7e2488f0 --- /dev/null +++ b/scripts/contrib/bb-perf/buildstats.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# +# Copyright (c) 2011, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# DESCRIPTION +# Given 'buildstats' data (generate by bitbake when setting +# USER_CLASSES ?= "buildstats" on local.conf), task names and a stats values +# (these are the ones preset on the buildstats files), outputs +# '<task> <recipe> <value_1> <value_2> ... <value_n>'. The units are the ones +# defined at buildstats, which in turn takes data from /proc/[pid] files +# +# Some useful pipelines +# +# 1. Tasks with largest stime (Amount of time that this process has been scheduled +# in kernel mode) values +# $ buildstats.sh -b <buildstats> -s stime | sort -k3 -n -r | head +# +# 2. Min, max, sum utime (Amount of time that this process has been scheduled +# in user mode) per task (in needs GNU datamash) +# $ buildstats.sh -b <buildstats> -s utime | datamash -t' ' -g1 min 3 max 3 sum 3 | sort -k4 -n -r +# +# AUTHORS +# Leonardo Sandoval <leonardo.sandoval.gonzalez@linux.intel.com> +# + +# Stats, by type +TIME="utime:stime:cutime:cstime" +IO="IO wchar:IO write_bytes:IO syscr:IO read_bytes:IO rchar:IO syscw:IO cancelled_write_bytes" +RUSAGE="rusage ru_utime:rusage ru_stime:rusage ru_maxrss:rusage ru_minflt:rusage ru_majflt:\ +rusage ru_inblock:rusage ru_oublock:rusage ru_nvcsw:rusage ru_nivcsw" + +CHILD_RUSAGE="Child rusage ru_utime:Child rusage ru_stime:Child rusage ru_maxrss:Child rusage ru_minflt:\ +Child rusage ru_majflt:Child rusage ru_inblock:Child rusage ru_oublock:Child rusage ru_nvcsw:\ +Child rusage ru_nivcsw" + +BS_DIR="tmp/buildstats" +TASKS="compile:configure:fetch:install:patch:populate_lic:populate_sysroot:unpack" +STATS="$TIME" +HEADER="" # No header by default + +function usage { +CMD=$(basename $0) +cat <<EOM +Usage: $CMD [-b buildstats_dir] [-t do_task] + -b buildstats The path where the folder resides + (default: "$BS_DIR") + -t tasks The tasks to be computed + (default: "$TASKS") + -s stats The stats to be matched. Options: TIME, IO, RUSAGE, CHILD_RUSAGE + or any other defined buildstat separated by colons, i.e. stime:utime + (default: "$STATS") + Default stat sets: + TIME=$TIME + IO=$IO + RUSAGE=$RUSAGE + CHILD_RUSAGE=$CHILD_RUSAGE + -h Display this help message +EOM +} + +# Parse and validate arguments +while getopts "b:t:s:Hh" OPT; do + case $OPT in + b) + BS_DIR="$OPTARG" + ;; + t) + TASKS="$OPTARG" + ;; + s) + STATS="$OPTARG" + ;; + H) + HEADER="y" + ;; + h) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; + esac +done + +# Ensure the buildstats folder exists +if [ ! -d "$BS_DIR" ]; then + echo "ERROR: $BS_DIR does not exist" + usage + exit 1 +fi + +stats="" +IFS=":" +for stat in ${STATS}; do + case $stat in + TIME) + stats="${stats}:${TIME}" + ;; + IO) + stats="${stats}:${IO}" + ;; + RUSAGE) + stats="${stats}:${RUSAGE}" + ;; + CHILD_RUSAGE) + stats="${stats}:${CHILD_RUSAGE}" + ;; + *) + stats="${STATS}" + esac +done + +# remove possible colon at the beginning +stats="$(echo "$stats" | sed -e 's/^://1')" + +# Provide a header if required by the user +[ -n "$HEADER" ] && { echo "task:recipe:$stats"; } + +for task in ${TASKS}; do + task="do_${task}" + for file in $(find ${BS_DIR} -type f -name ${task} | awk 'BEGIN{ ORS=""; OFS=":" } { print $0,"" }'); do + recipe="$(basename $(dirname $file))" + times="" + for stat in ${stats}; do + [ -z "$stat" ] && { echo "empty stats"; } + time=$(sed -n -e "s/^\($stat\): \\(.*\\)/\\2/p" $file) + # in case the stat is not present, set the value as NA + [ -z "$time" ] && { time="NA"; } + # Append it to times + if [ -z "$times" ]; then + times="${time}" + else + times="${times} ${time}" + fi + done + echo "${task} ${recipe} ${times}" + done +done diff --git a/scripts/contrib/bbvars.py b/scripts/contrib/bbvars.py index 0896d64445..d8d0594776 100755 --- a/scripts/contrib/bbvars.py +++ b/scripts/contrib/bbvars.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ import os.path import re def usage(): - print 'Usage: %s -d FILENAME [-d FILENAME]* -m METADIR [-m MATADIR]*' % os.path.basename(sys.argv[0]) - print ' -d FILENAME documentation file to search' - print ' -h, --help display this help and exit' - print ' -m METADIR meta directory to search for recipes' - print ' -t FILENAME documentation config file (for doc tags)' - print ' -T Only display variables with doc tags (requires -t)' + print('Usage: %s -d FILENAME [-d FILENAME]* -m METADIR [-m MATADIR]*' % os.path.basename(sys.argv[0])) + print(' -d FILENAME documentation file to search') + print(' -h, --help display this help and exit') + print(' -m METADIR meta directory to search for recipes') + print(' -t FILENAME documentation config file (for doc tags)') + print(' -T Only display variables with doc tags (requires -t)') def recipe_bbvars(recipe): ''' Return a unique set of every bbvar encountered in the recipe ''' @@ -37,9 +37,9 @@ def recipe_bbvars(recipe): vset = set() try: r = open(recipe) - except IOError as (errno, strerror): - print 'WARNING: Failed to open recipe ', recipe - print strerror + except IOError as err: + print('WARNING: Failed to open recipe ', recipe) + print(err.args[1]) for line in r: # Strip any comments from the line @@ -59,8 +59,8 @@ def collect_bbvars(metadir): for root,dirs,files in os.walk(metadir): for name in files: if name.find(".bb") >= 0: - for key in recipe_bbvars(os.path.join(root,name)).iterkeys(): - if bbvars.has_key(key): + for key in recipe_bbvars(os.path.join(root,name)).keys(): + if key in bbvars: bbvars[key] = bbvars[key] + 1 else: bbvars[key] = 1 @@ -71,9 +71,9 @@ def bbvar_is_documented(var, docfiles): for doc in docfiles: try: f = open(doc) - except IOError as (errno, strerror): - print 'WARNING: Failed to open doc ', doc - print strerror + except IOError as err: + print('WARNING: Failed to open doc ', doc) + print(err.args[1]) for line in f: if prog.match(line): return True @@ -87,8 +87,8 @@ def bbvar_doctag(var, docconf): try: f = open(docconf) - except IOError as (errno, strerror): - return strerror + except IOError as err: + return err.args[1] for line in f: m = prog.search(line) @@ -109,8 +109,8 @@ def main(): # Collect and validate input try: opts, args = getopt.getopt(sys.argv[1:], "d:hm:t:T", ["help"]) - except getopt.GetoptError, err: - print '%s' % str(err) + except getopt.GetoptError as err: + print('%s' % str(err)) usage() sys.exit(2) @@ -122,13 +122,13 @@ def main(): if os.path.isfile(a): docfiles.append(a) else: - print 'ERROR: documentation file %s is not a regular file' % (a) + print('ERROR: documentation file %s is not a regular file' % a) sys.exit(3) elif o == '-m': if os.path.isdir(a): metadirs.append(a) else: - print 'ERROR: meta directory %s is not a directory' % (a) + print('ERROR: meta directory %s is not a directory' % a) sys.exit(4) elif o == "-t": if os.path.isfile(a): @@ -139,31 +139,31 @@ def main(): assert False, "unhandled option" if len(docfiles) == 0: - print 'ERROR: no docfile specified' + print('ERROR: no docfile specified') usage() sys.exit(5) if len(metadirs) == 0: - print 'ERROR: no metadir specified' + print('ERROR: no metadir specified') usage() sys.exit(6) if onlydoctags and docconf == "": - print 'ERROR: no docconf specified' + print('ERROR: no docconf specified') usage() sys.exit(7) # Collect all the variable names from the recipes in the metadirs for m in metadirs: - for key,cnt in collect_bbvars(m).iteritems(): - if bbvars.has_key(key): + for key,cnt in collect_bbvars(m).items(): + if key in bbvars: bbvars[key] = bbvars[key] + cnt else: bbvars[key] = cnt # Check each var for documentation varlen = 0 - for v in bbvars.iterkeys(): + for v in bbvars.keys(): if len(v) > varlen: varlen = len(v) if not bbvar_is_documented(v, docfiles): @@ -172,14 +172,14 @@ def main(): varlen = varlen + 1 # Report all undocumented variables - print 'Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars)) + print('Found %d undocumented bb variables (out of %d):' % (len(undocumented), len(bbvars))) header = '%s%s%s' % (str("VARIABLE").ljust(varlen), str("COUNT").ljust(6), str("DOCTAG").ljust(7)) - print header - print str("").ljust(len(header), '=') + print(header) + print(str("").ljust(len(header), '=')) for v in undocumented: doctag = bbvar_doctag(v, docconf) if not onlydoctags or not doctag == "": - print '%s%s%s' % (v.ljust(varlen), str(bbvars[v]).ljust(6), doctag) + print('%s%s%s' % (v.ljust(varlen), str(bbvars[v]).ljust(6), doctag)) if __name__ == "__main__": diff --git a/scripts/contrib/build-perf-test-wrapper.sh b/scripts/contrib/build-perf-test-wrapper.sh new file mode 100755 index 0000000000..3da32532be --- /dev/null +++ b/scripts/contrib/build-perf-test-wrapper.sh @@ -0,0 +1,219 @@ +#!/bin/bash +# +# Build performance test script wrapper +# +# Copyright (c) 2016, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope 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. +# +# +# This script is a simple wrapper around the actual build performance tester +# script. This script initializes the build environment, runs +# oe-build-perf-test and archives the results. + +script=`basename $0` +script_dir=$(realpath $(dirname $0)) +archive_dir=~/perf-results/archives + +usage () { +cat << EOF +Usage: $script [-h] [-c COMMITISH] [-C GIT_REPO] + +Optional arguments: + -h show this help and exit. + -a ARCHIVE_DIR archive results tarball here, give an empty string to + disable tarball archiving (default: $archive_dir) + -c COMMITISH test (checkout) this commit, <branch>:<commit> can be + specified to test specific commit of certain branch + -C GIT_REPO commit results into Git + -E EMAIL_ADDR send email report + -P GIT_REMOTE push results to a remote Git repository + -w WORK_DIR work dir for this script + (default: GIT_TOP_DIR/build-perf-test) + -x create xml report (instead of json) +EOF +} + +get_os_release_var () { + ( source /etc/os-release; eval echo '$'$1 ) +} + + +# Parse command line arguments +commitish="" +oe_build_perf_test_extra_opts=() +oe_git_archive_extra_opts=() +while getopts "ha:c:C:E:P:w:x" opt; do + case $opt in + h) usage + exit 0 + ;; + a) archive_dir=`realpath -s "$OPTARG"` + ;; + c) commitish=$OPTARG + ;; + C) results_repo=`realpath -s "$OPTARG"` + ;; + E) email_to="$OPTARG" + ;; + P) oe_git_archive_extra_opts+=("--push" "$OPTARG") + ;; + w) base_dir=`realpath -s "$OPTARG"` + ;; + x) oe_build_perf_test_extra_opts+=("--xml") + ;; + *) usage + exit 1 + ;; + esac +done + +# Check positional args +shift "$((OPTIND - 1))" +if [ $# -ne 0 ]; then + echo "ERROR: No positional args are accepted." + usage + exit 1 +fi + +# Open a file descriptor for flock and acquire lock +LOCK_FILE="/tmp/oe-build-perf-test-wrapper.lock" +if ! exec 3> "$LOCK_FILE"; then + echo "ERROR: Unable to open lock file" + exit 1 +fi +if ! flock -n 3; then + echo "ERROR: Another instance of this script is running" + exit 1 +fi + +echo "Running on `uname -n`" +if ! git_topdir=$(git rev-parse --show-toplevel); then + echo "The current working dir doesn't seem to be a git clone. Please cd there before running `basename $0`" + exit 1 +fi + +cd "$git_topdir" + +if [ -n "$commitish" ]; then + echo "Running git fetch" + git fetch &> /dev/null + git checkout HEAD^0 &> /dev/null + + # Handle <branch>:<commit> format + if echo "$commitish" | grep -q ":"; then + commit=`echo "$commitish" | cut -d":" -f2` + branch=`echo "$commitish" | cut -d":" -f1` + else + commit="$commitish" + branch="$commitish" + fi + + echo "Checking out $commitish" + git branch -D $branch &> /dev/null + if ! git checkout -f $branch &> /dev/null; then + echo "ERROR: Git checkout failed" + exit 1 + fi + + # Check that the specified branch really contains the commit + commit_hash=`git rev-parse --revs-only $commit --` + if [ -z "$commit_hash" -o "`git merge-base $branch $commit`" != "$commit_hash" ]; then + echo "ERROR: branch $branch does not contain commit $commit" + exit 1 + fi + git reset --hard $commit > /dev/null +fi + +# Setup build environment +if [ -z "$base_dir" ]; then + base_dir="$git_topdir/build-perf-test" +fi +echo "Using working dir $base_dir" + +timestamp=`date "+%Y%m%d%H%M%S"` +git_rev=$(git rev-parse --short HEAD) || exit 1 +build_dir="$base_dir/build-$git_rev-$timestamp" +results_dir="$base_dir/results-$git_rev-$timestamp" +globalres_log="$base_dir/globalres.log" +machine="qemux86" + +mkdir -p "$base_dir" +source ./oe-init-build-env $build_dir >/dev/null || exit 1 + +# Additional config +auto_conf="$build_dir/conf/auto.conf" +echo "MACHINE = \"$machine\"" > "$auto_conf" +echo 'BB_NUMBER_THREADS = "8"' >> "$auto_conf" +echo 'PARALLEL_MAKE = "-j 8"' >> "$auto_conf" +echo "DL_DIR = \"$base_dir/downloads\"" >> "$auto_conf" +# Disabling network sanity check slightly reduces the variance of timing results +echo 'CONNECTIVITY_CHECK_URIS = ""' >> "$auto_conf" +# Possibility to define extra settings +if [ -f "$base_dir/auto.conf.extra" ]; then + cat "$base_dir/auto.conf.extra" >> "$auto_conf" +fi + +# Run actual test script +oe-build-perf-test --out-dir "$results_dir" \ + --globalres-file "$globalres_log" \ + "${oe_build_perf_test_extra_opts[@]}" \ + --lock-file "$base_dir/oe-build-perf.lock" + +case $? in + 1) echo "ERROR: oe-build-perf-test script failed!" + exit 1 + ;; + 2) echo "NOTE: some tests failed!" + ;; +esac + +# Commit results to git +if [ -n "$results_repo" ]; then + echo -e "\nArchiving results in $results_repo" + oe-git-archive \ + --git-dir "$results_repo" \ + --branch-name "{hostname}/{branch}/{machine}" \ + --tag-name "{hostname}/{branch}/{machine}/{commit_count}-g{commit}/{tag_number}" \ + --exclude "buildstats.json" \ + --notes "buildstats/{branch_name}" "$results_dir/buildstats.json" \ + "${oe_git_archive_extra_opts[@]}" \ + "$results_dir" + + # Send email report + if [ -n "$email_to" ]; then + echo -e "\nEmailing test report" + os_name=`get_os_release_var PRETTY_NAME` + oe-build-perf-report -r "$results_repo" > report.txt + oe-build-perf-report -r "$results_repo" --html > report.html + "$script_dir"/oe-build-perf-report-email.py --to "$email_to" --subject "Build Perf Test Report for $os_name" --text report.txt --html report.html "${OE_BUILD_PERF_REPORT_EMAIL_EXTRA_ARGS[@]}" + fi +fi + + +echo -ne "\n\n-----------------\n" +echo "Global results file:" +echo -ne "\n" + +cat "$globalres_log" + +if [ -n "$archive_dir" ]; then + echo -ne "\n\n-----------------\n" + echo "Archiving results in $archive_dir" + mkdir -p "$archive_dir" + results_basename=`basename "$results_dir"` + results_dirname=`dirname "$results_dir"` + tar -czf "$archive_dir/`uname -n`-${results_basename}.tar.gz" -C "$results_dirname" "$results_basename" +fi + +rm -rf "$build_dir" +rm -rf "$results_dir" + +echo "DONE" diff --git a/scripts/contrib/build-perf-test.sh b/scripts/contrib/build-perf-test.sh new file mode 100755 index 0000000000..7d99228c73 --- /dev/null +++ b/scripts/contrib/build-perf-test.sh @@ -0,0 +1,400 @@ +#!/bin/bash +# +# This script runs a series of tests (with and without sstate) and reports build time (and tmp/ size) +# +# Build performance test script +# +# Copyright 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# AUTHORS: +# Stefan Stanacar <stefanx.stanacar@intel.com> + + +ME=$(basename $0) + +# +# usage and setup +# + +usage () { +cat << EOT +Usage: $ME [-h] + $ME [-c <commit>] [-v] [-m <val>] [-j <val>] [-t <val>] [-i <image-name>] [-d <path>] +Options: + -h + Display this help and exit. + -c <commit> + git checkout <commit> before anything else + -v + Show bitbake output, don't redirect it to a log. + -m <machine> + Value for MACHINE. Default is qemux86. + -j <val> + Value for PARALLEL_MAKE. Default is 8. + -t <val> + Value for BB_NUMBER_THREADS. Default is 8. + -i <image-name> + Instead of timing against core-image-sato, use <image-name> + -d <path> + Use <path> as DL_DIR + -p <githash> + Cherry pick githash onto the commit + +Note: current working directory must be inside a poky git clone. + +EOT +} + + +if clonedir=$(git rev-parse --show-toplevel); then + cd $clonedir +else + echo "The current working dir doesn't seem to be a poky git clone. Please cd there before running $ME" + exit 1 +fi + +IMAGE="core-image-sato" +verbose=0 +dldir= +commit= +pmake= +cherrypicks= +while getopts "hvc:m:j:t:i:d:p:" opt; do + case $opt in + h) usage + exit 0 + ;; + v) verbose=1 + ;; + c) commit=$OPTARG + ;; + m) export MACHINE=$OPTARG + ;; + j) pmake=$OPTARG + ;; + t) export BB_NUMBER_THREADS=$OPTARG + ;; + i) IMAGE=$OPTARG + ;; + d) dldir=$OPTARG + ;; + p) cherrypicks="$cherrypicks $OPTARG" + ;; + *) usage + exit 1 + ;; + esac +done + + +#drop cached credentials and test for sudo access without a password +sudo -k -n ls > /dev/null 2>&1 +reqpass=$? +if [ $reqpass -ne 0 ]; then + echo "The script requires sudo access to drop caches between builds (echo 3 > /proc/sys/vm/drop_caches)" + read -s -p "Please enter your sudo password: " pass + echo +fi + +if [ -n "$commit" ]; then + echo "git checkout -f $commit" + git pull > /dev/null 2>&1 + git checkout -f $commit || exit 1 + git pull > /dev/null 2>&1 +fi + +if [ -n "$cherrypicks" ]; then + for c in $cherrypicks; do + git cherry-pick $c + done +fi + +rev=$(git rev-parse --short HEAD) || exit 1 +OUTDIR="$clonedir/build-perf-test/results-$rev-`date "+%Y%m%d%H%M%S"`" +BUILDDIR="$OUTDIR/build" +resultsfile="$OUTDIR/results.log" +cmdoutput="$OUTDIR/commands.log" +myoutput="$OUTDIR/output.log" +globalres="$clonedir/build-perf-test/globalres.log" + +mkdir -p $OUTDIR || exit 1 + +log () { + local msg="$1" + echo "`date`: $msg" | tee -a $myoutput +} + + +# +# Config stuff +# + +branch=`git branch 2>&1 | grep "^* " | tr -d "* "` +gitcommit=$(git rev-parse HEAD) || exit 1 +log "Running on $branch:$gitcommit" + +source ./oe-init-build-env $OUTDIR/build >/dev/null || exit 1 +cd $OUTDIR/build + +[ -n "$MACHINE" ] || export MACHINE="qemux86" +[ -n "$BB_NUMBER_THREADS" ] || export BB_NUMBER_THREADS="8" + +if [ -n "$pmake" ]; then + export PARALLEL_MAKE="-j $pmake" +else + export PARALLEL_MAKE="-j 8" +fi + +if [ -n "$dldir" ]; then + echo "DL_DIR = \"$dldir\"" >> conf/local.conf +else + echo "DL_DIR = \"$clonedir/build-perf-test/downloads\"" >> conf/local.conf +fi + +# Sometimes I've noticed big differences in timings for the same commit, on the same machine +# Disabling the network sanity check helps a bit (because of my crappy network connection and/or proxy) +echo "CONNECTIVITY_CHECK_URIS =\"\"" >> conf/local.conf + + +# +# Functions +# + +declare -a TIMES +time_count=0 +declare -a SIZES +size_count=0 + +time_cmd () { + log " Timing: $*" + + if [ $verbose -eq 0 ]; then + /usr/bin/time -v -o $resultsfile "$@" >> $cmdoutput + else + /usr/bin/time -v -o $resultsfile "$@" + fi + ret=$? + if [ $ret -eq 0 ]; then + t=`grep wall $resultsfile | sed 's/.*m:ss): //'` + log " TIME: $t" + TIMES[(( time_count++ ))]="$t" + else + log "ERROR: exit status was non-zero, will report time as 0." + TIMES[(( time_count++ ))]="0" + fi + + #time by default overwrites the output file and we want to keep the results + #it has an append option but I don't want to clobber the results in the same file + i=`ls $OUTDIR/results.log* |wc -l` + mv $resultsfile "${resultsfile}.${i}" + log "More stats can be found in ${resultsfile}.${i}" +} + +bbtime () { + time_cmd bitbake "$@" +} + +#we don't time bitbake here +bbnotime () { + local arg="$@" + log " Running: bitbake ${arg}" + if [ $verbose -eq 0 ]; then + bitbake ${arg} >> $cmdoutput + else + bitbake ${arg} + fi + ret=$? + if [ $ret -eq 0 ]; then + log " Finished bitbake ${arg}" + else + log "ERROR: exit status was non-zero. Exit.." + exit $ret + fi + +} + +do_rmtmp() { + log " Removing tmp" + rm -rf bitbake.lock pseudodone conf/sanity_info cache tmp +} +do_rmsstate () { + log " Removing sstate-cache" + rm -rf sstate-cache +} +do_sync () { + log " Syncing and dropping caches" + sync; sync + if [ $reqpass -eq 0 ]; then + sudo sh -c "echo 3 > /proc/sys/vm/drop_caches" + else + echo "$pass" | sudo -S sh -c "echo 3 > /proc/sys/vm/drop_caches" + echo + fi + sleep 3 +} + +write_results() { + echo -n "`uname -n`,$branch:$gitcommit,`git describe`," >> $globalres + for i in "${TIMES[@]}"; do + echo -n "$i," >> $globalres + done + for i in "${SIZES[@]}"; do + echo -n "$i," >> $globalres + done + echo >> $globalres + sed -i '$ s/,$//' $globalres +} + +#### + +# +# Test 1 +# Measure: Wall clock of "bitbake core-image-sato" and size of tmp/dir (w/o rm_work and w/ rm_work) +# Pre: Downloaded sources, no sstate +# Steps: +# Part1: +# - fetchall +# - clean build dir +# - time bitbake core-image-sato +# - collect data +# Part2: +# - bitbake virtual/kernel -c cleansstate +# - time bitbake virtual/kernel +# Part3: +# - add INHERIT to local.conf +# - clean build dir +# - build +# - report size, remove INHERIT + +test1_p1 () { + log "Running Test 1, part 1/3: Measure wall clock of bitbake $IMAGE and size of tmp/ dir" + bbnotime $IMAGE -c fetchall + do_rmtmp + do_rmsstate + do_sync + bbtime $IMAGE + s=`du -s tmp | sed 's/tmp//' | sed 's/[ \t]*$//'` + SIZES[(( size_count++ ))]="$s" + log "SIZE of tmp dir is: $s" + log "Buildstats are saved in $OUTDIR/buildstats-test1" + mv tmp/buildstats $OUTDIR/buildstats-test1 +} + + +test1_p2 () { + log "Running Test 1, part 2/3: bitbake virtual/kernel -c cleansstate and time bitbake virtual/kernel" + bbnotime virtual/kernel -c cleansstate + do_sync + bbtime virtual/kernel +} + +test1_p3 () { + log "Running Test 1, part 3/3: Build $IMAGE w/o sstate and report size of tmp/dir with rm_work enabled" + echo "INHERIT += \"rm_work\"" >> conf/local.conf + do_rmtmp + do_rmsstate + do_sync + bbtime $IMAGE + sed -i 's/INHERIT += \"rm_work\"//' conf/local.conf + s=`du -s tmp | sed 's/tmp//' | sed 's/[ \t]*$//'` + SIZES[(( size_count++ ))]="$s" + log "SIZE of tmp dir is: $s" + log "Buildstats are saved in $OUTDIR/buildstats-test13" + mv tmp/buildstats $OUTDIR/buildstats-test13 +} + + +# +# Test 2 +# Measure: Wall clock of "bitbake core-image-sato" and size of tmp/dir +# Pre: populated sstate cache + +test2 () { + # Assuming test 1 has run + log "Running Test 2: Measure wall clock of bitbake $IMAGE -c rootfs with sstate" + do_rmtmp + do_sync + bbtime $IMAGE -c rootfs +} + + +# Test 3 +# parsing time metrics +# +# Start with +# i) "rm -rf tmp/cache; time bitbake -p" +# ii) "rm -rf tmp/cache/default-glibc/; time bitbake -p" +# iii) "time bitbake -p" + + +test3 () { + log "Running Test 3: Parsing time metrics (bitbake -p)" + log " Removing tmp/cache && cache" + rm -rf tmp/cache cache + bbtime -p + log " Removing tmp/cache/default-glibc/" + rm -rf tmp/cache/default-glibc/ + bbtime -p + bbtime -p +} + +# +# Test 4 - eSDK +# Measure: eSDK size and installation time +test4 () { + log "Running Test 4: eSDK size and installation time" + bbnotime $IMAGE -c do_populate_sdk_ext + + esdk_installer=(tmp/deploy/sdk/*-toolchain-ext-*.sh) + + if [ ${#esdk_installer[*]} -eq 1 ]; then + s=$((`stat -c %s "$esdk_installer"` / 1024)) + SIZES[(( size_count++ ))]="$s" + log "Download SIZE of eSDK is: $s kB" + + do_sync + time_cmd "$esdk_installer" -y -d "tmp/esdk-deploy" + + s=$((`du -sb "tmp/esdk-deploy" | cut -f1` / 1024)) + SIZES[(( size_count++ ))]="$s" + log "Install SIZE of eSDK is: $s kB" + else + log "ERROR: other than one sdk found (${esdk_installer[*]}), reporting size and time as 0." + SIZES[(( size_count++ ))]="0" + TIMES[(( time_count++ ))]="0" + fi + +} + + +# RUN! + +test1_p1 +test1_p2 +test1_p3 +test2 +test3 +test4 + +# if we got til here write to global results +write_results + +log "All done, cleaning up..." + +do_rmtmp +do_rmsstate diff --git a/scripts/contrib/ddimage b/scripts/contrib/ddimage new file mode 100755 index 0000000000..ab929957a5 --- /dev/null +++ b/scripts/contrib/ddimage @@ -0,0 +1,108 @@ +#!/bin/sh + +# Default to avoiding the first two disks on typical Linux and Mac OS installs +# Better safe than sorry :-) +BLACKLIST_DEVICES="/dev/sda /dev/sdb /dev/disk1 /dev/disk2" + +# 1MB blocksize +BLOCKSIZE=1048576 + +usage() { + echo "Usage: $(basename $0) IMAGE DEVICE" +} + +image_details() { + IMG=$1 + echo "Image details" + echo "=============" + echo " image: $(basename $IMG)" + # stat format is different on Mac OS and Linux + if [ "$(uname)" = "Darwin" ]; then + echo " size: $(stat -L -f '%z bytes' $IMG)" + echo " modified: $(stat -L -f '%Sm' $IMG)" + else + echo " size: $(stat -L -c '%s bytes' $IMG)" + echo " modified: $(stat -L -c '%y' $IMG)" + fi + echo " type: $(file -L -b $IMG)" + echo "" +} + +device_details() { + DEV=$1 + BLOCK_SIZE=512 + + echo "Device details" + echo "==============" + + # Collect disk info using diskutil on Mac OS + if [ "$(uname)" = "Darwin" ]; then + diskutil info $DEVICE | egrep "(Device Node|Media Name|Total Size)" + return + fi + + # Default / Linux information collection + echo " device: $DEVICE" + if [ -f "/sys/class/block/$DEV/device/vendor" ]; then + echo " vendor: $(cat /sys/class/block/$DEV/device/vendor)" + else + echo " vendor: UNKOWN" + fi + if [ -f "/sys/class/block/$DEV/device/model" ]; then + echo " model: $(cat /sys/class/block/$DEV/device/model)" + else + echo " model: UNKNOWN" + fi + if [ -f "/sys/class/block/$DEV/size" ]; then + echo " size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes" + else + echo " size: UNKNOWN" + fi + echo "" +} + +if [ $# -ne 2 ]; then + usage + exit 1 +fi + +IMAGE=$1 +DEVICE=$2 + +if [ ! -e "$IMAGE" ]; then + echo "ERROR: Image $IMAGE does not exist" + usage + exit 1 +fi + + +for i in ${BLACKLIST_DEVICES}; do + if [ "$i" = "$DEVICE" ]; then + echo "ERROR: Device $DEVICE is blacklisted" + exit 1 + fi +done + +if [ ! -w "$DEVICE" ]; then + echo "ERROR: Device $DEVICE does not exist or is not writable" + usage + exit 1 +fi + +image_details $IMAGE +device_details $(basename $DEVICE) + +printf "Write $IMAGE to $DEVICE [y/N]? " +read RESPONSE +if [ "$RESPONSE" != "y" ]; then + echo "Write aborted" + exit 0 +fi + +echo "Writing image..." +if which pv >/dev/null 2>&1; then + pv "$IMAGE" | dd of="$DEVICE" bs="$BLOCKSIZE" +else + dd if="$IMAGE" of="$DEVICE" bs="$BLOCKSIZE" +fi +sync diff --git a/scripts/contrib/devtool-stress.py b/scripts/contrib/devtool-stress.py new file mode 100755 index 0000000000..d555c51a65 --- /dev/null +++ b/scripts/contrib/devtool-stress.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 + +# devtool stress tester +# +# Written by: Paul Eggleton <paul.eggleton@linux.intel.com> +# +# Copyright 2015 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import sys +import os +import os.path +import subprocess +import re +import argparse +import logging +import tempfile +import shutil +import signal +import fnmatch + +scripts_lib_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'lib')) +sys.path.insert(0, scripts_lib_path) +import scriptutils +import argparse_oe +logger = scriptutils.logger_create('devtool-stress') + +def select_recipes(args): + import bb.tinfoil + tinfoil = bb.tinfoil.Tinfoil() + tinfoil.prepare(False) + + pkg_pn = tinfoil.cooker.recipecaches[''].pkg_pn + (latest_versions, preferred_versions) = bb.providers.findProviders(tinfoil.config_data, tinfoil.cooker.recipecaches[''], pkg_pn) + + skip_classes = args.skip_classes.split(',') + + recipelist = [] + for pn in sorted(pkg_pn): + pref = preferred_versions[pn] + inherits = [os.path.splitext(os.path.basename(f))[0] for f in tinfoil.cooker.recipecaches[''].inherits[pref[1]]] + for cls in skip_classes: + if cls in inherits: + break + else: + recipelist.append(pn) + + tinfoil.shutdown() + + resume_from = args.resume_from + if resume_from: + if not resume_from in recipelist: + print('%s is not a testable recipe' % resume_from) + return 1 + if args.only: + only = args.only.split(',') + for onlyitem in only: + for pn in recipelist: + if fnmatch.fnmatch(pn, onlyitem): + break + else: + print('%s does not match any testable recipe' % onlyitem) + return 1 + else: + only = None + if args.skip: + skip = args.skip.split(',') + else: + skip = [] + + recipes = [] + for pn in recipelist: + if resume_from: + if pn == resume_from: + resume_from = None + else: + continue + + if args.only: + for item in only: + if fnmatch.fnmatch(pn, item): + break + else: + continue + + skipit = False + for item in skip: + if fnmatch.fnmatch(pn, item): + skipit = True + if skipit: + continue + + recipes.append(pn) + + return recipes + + +def stress_extract(args): + import bb.process + + recipes = select_recipes(args) + + failures = 0 + tmpdir = tempfile.mkdtemp() + os.setpgrp() + try: + for pn in recipes: + sys.stdout.write('Testing %s ' % (pn + ' ').ljust(40, '.')) + sys.stdout.flush() + failed = False + skipped = None + + srctree = os.path.join(tmpdir, pn) + try: + bb.process.run('devtool extract %s %s' % (pn, srctree)) + except bb.process.ExecutionError as exc: + if exc.exitcode == 4: + skipped = 'incompatible' + else: + failed = True + with open('stress_%s_extract.log' % pn, 'w') as f: + f.write(str(exc)) + + if os.path.exists(srctree): + shutil.rmtree(srctree) + + if failed: + print('failed') + failures += 1 + elif skipped: + print('skipped (%s)' % skipped) + else: + print('ok') + except KeyboardInterrupt: + # We want any child processes killed. This is crude, but effective. + os.killpg(0, signal.SIGTERM) + + if failures: + return 1 + else: + return 0 + + +def stress_modify(args): + import bb.process + + recipes = select_recipes(args) + + failures = 0 + tmpdir = tempfile.mkdtemp() + os.setpgrp() + try: + for pn in recipes: + sys.stdout.write('Testing %s ' % (pn + ' ').ljust(40, '.')) + sys.stdout.flush() + failed = False + reset = True + skipped = None + + srctree = os.path.join(tmpdir, pn) + try: + bb.process.run('devtool modify -x %s %s' % (pn, srctree)) + except bb.process.ExecutionError as exc: + if exc.exitcode == 4: + skipped = 'incompatible' + else: + with open('stress_%s_modify.log' % pn, 'w') as f: + f.write(str(exc)) + failed = 'modify' + reset = False + + if not skipped: + if not failed: + try: + bb.process.run('bitbake -c install %s' % pn) + except bb.process.CmdError as exc: + with open('stress_%s_install.log' % pn, 'w') as f: + f.write(str(exc)) + failed = 'build' + if reset: + try: + bb.process.run('devtool reset %s' % pn) + except bb.process.CmdError as exc: + print('devtool reset failed: %s' % str(exc)) + break + + if os.path.exists(srctree): + shutil.rmtree(srctree) + + if failed: + print('failed (%s)' % failed) + failures += 1 + elif skipped: + print('skipped (%s)' % skipped) + else: + print('ok') + except KeyboardInterrupt: + # We want any child processes killed. This is crude, but effective. + os.killpg(0, signal.SIGTERM) + + if failures: + return 1 + else: + return 0 + + +def main(): + parser = argparse_oe.ArgumentParser(description="devtool stress tester", + epilog="Use %(prog)s <subcommand> --help to get help on a specific command") + parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true') + parser.add_argument('-r', '--resume-from', help='Resume from specified recipe', metavar='PN') + parser.add_argument('-o', '--only', help='Only test specified recipes (comma-separated without spaces, wildcards allowed)', metavar='PNLIST') + parser.add_argument('-s', '--skip', help='Skip specified recipes (comma-separated without spaces, wildcards allowed)', metavar='PNLIST', default='gcc-source-*,kernel-devsrc,package-index,perf,meta-world-pkgdata,glibc-locale,glibc-mtrace,glibc-scripts,os-release') + parser.add_argument('-c', '--skip-classes', help='Skip recipes inheriting specified classes (comma-separated) - default %(default)s', metavar='CLASSLIST', default='native,nativesdk,cross,cross-canadian,image,populate_sdk,meta,packagegroup') + subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>') + subparsers.required = True + + parser_modify = subparsers.add_parser('modify', + help='Run "devtool modify" followed by a build with bitbake on matching recipes', + description='Runs "devtool modify" followed by a build with bitbake on matching recipes') + parser_modify.set_defaults(func=stress_modify) + + parser_extract = subparsers.add_parser('extract', + help='Run "devtool extract" on matching recipes', + description='Runs "devtool extract" on matching recipes') + parser_extract.set_defaults(func=stress_extract) + + args = parser.parse_args() + + if args.debug: + logger.setLevel(logging.DEBUG) + + import scriptpath + bitbakepath = scriptpath.add_bitbake_lib_path() + if not bitbakepath: + logger.error("Unable to find bitbake by searching parent directory of this script or PATH") + return 1 + logger.debug('Found bitbake path: %s' % bitbakepath) + + ret = args.func(args) + +if __name__ == "__main__": + main() diff --git a/scripts/contrib/dialog-power-control b/scripts/contrib/dialog-power-control new file mode 100755 index 0000000000..7550ea53be --- /dev/null +++ b/scripts/contrib/dialog-power-control @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Simple script to show a manual power prompt for when you want to use +# automated hardware testing with testimage.bbclass but you don't have a +# web-enabled power strip or similar to do the power on/off/cycle. +# +# You can enable it by enabling testimage (see the Yocto Project +# Development manual "Performing Automated Runtime Testing" section) +# and setting the following in your local.conf: +# +# TEST_POWERCONTROL_CMD = "${COREBASE}/scripts/contrib/dialog-power-control" +# + +PROMPT="" +while true; do + case $1 in + on) + PROMPT="Please turn device power on";; + off) + PROMPT="Please turn device power off";; + cycle) + PROMPT="Please click Done, then turn the device power off then on";; + "") + break;; + esac + shift +done + +if [ "$PROMPT" = "" ] ; then + echo "ERROR: no power action specified on command line" + exit 2 +fi + +if [ "`which kdialog 2>/dev/null`" != "" ] ; then + DIALOGUTIL="kdialog" +elif [ "`which zenity 2>/dev/null`" != "" ] ; then + DIALOGUTIL="zenity" +else + echo "ERROR: couldn't find program to display a message, install kdialog or zenity" + exit 3 +fi + +if [ "$DIALOGUTIL" = "kdialog" ] ; then + kdialog --yesno "$PROMPT" --title "TestImage Power Control" --yes-label "Done" --no-label "Cancel test" +elif [ "$DIALOGUTIL" = "zenity" ] ; then + zenity --question --text="$PROMPT" --title="TestImage Power Control" --ok-label="Done" --cancel-label="Cancel test" +fi + +if [ "$?" != "0" ] ; then + echo "User cancelled test at power prompt" + exit 1 +fi + diff --git a/scripts/contrib/documentation-audit.sh b/scripts/contrib/documentation-audit.sh new file mode 100755 index 0000000000..2144aac936 --- /dev/null +++ b/scripts/contrib/documentation-audit.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# +# Perform an audit of which packages provide documentation and which +# are missing -doc packages. +# +# Setup requirements: be sure to be building for MACHINE=qemux86. Run +# this script after source'ing the build environment script, so you're +# running it from build/ directory. +# +# Maintainer: Scott Garman <scott.a.garman@intel.com> + +REPORT_DOC_SIMPLE="documentation_exists.txt" +REPORT_DOC_DETAIL="documentation_exists_detail.txt" +REPORT_MISSING_SIMPLE="documentation_missing.txt" +REPORT_MISSING_DETAIL="documentation_missing_detail.txt" +REPORT_BUILD_ERRORS="build_errors.txt" + +rm -rf $REPORT_DOC_SIMPLE $REPORT_DOC_DETAIL $REPORT_MISSING_SIMPLE $REPORT_MISSING_DETAIL + +BITBAKE=`which bitbake` +if [ -z "$BITBAKE" ]; then + echo "Error: bitbake command not found." + echo "Did you forget to source the build environment script?" + exit 1 +fi + +echo "REMINDER: you need to build for MACHINE=qemux86 or you won't get useful results" +echo "REMINDER: you need to set LICENSE_FLAGS_WHITELIST appropriately in local.conf or " +echo " you'll get false positives. For example, LICENSE_FLAGS_WHITELIST = \"Commercial\"" + +for pkg in `bitbake -s | awk '{ print \$1 }'`; do + if [[ "$pkg" == "Loading" || "$pkg" == "Loaded" || + "$pkg" == "Recipe" || + "$pkg" == "Parsing" || "$pkg" == "Package" || + "$pkg" == "NOTE:" || "$pkg" == "WARNING:" || + "$pkg" == "done." || "$pkg" == "===========" ]] + then + # Skip initial bitbake output + continue + fi + if [[ "$pkg" =~ -native$ || "$pkg" =~ -nativesdk$ || + "$pkg" =~ -cross-canadian ]]; then + # Skip native/nativesdk/cross-canadian recipes + continue + fi + if [[ "$pkg" =~ ^meta- || "$pkg" =~ ^packagegroup- || "$pkg" =~ -image ]]; then + # Skip meta, task and image recipes + continue + fi + if [[ "$pkg" =~ ^glibc- || "$pkg" =~ ^libiconv$ || + "$pkg" =~ -toolchain$ || "$pkg" =~ ^package-index$ || + "$pkg" =~ ^linux- || "$pkg" =~ ^adt-installer$ || + "$pkg" =~ ^eds-tools$ || "$pkg" =~ ^external-python-tarball$ || + "$pkg" =~ ^qt4-embedded$ || "$pkg" =~ ^qt-mobility ]]; then + # Skip glibc, libiconv, -toolchain, and other recipes known + # to cause build conflicts or trigger false positives. + continue + fi + + echo "Building package $pkg..." + bitbake $pkg > /dev/null + if [ $? -ne 0 ]; then + echo "There was an error building package $pkg" >> "$REPORT_MISSING_DETAIL" + echo "$pkg" >> $REPORT_BUILD_ERRORS + + # Do not skip the remaining tests, as sometimes the + # exit status is 1 due to QA errors, and we can still + # perform the -doc checks. + fi + + echo "$pkg built successfully, checking for a documentation package..." + WORKDIR=`bitbake -e $pkg | grep ^WORKDIR | awk -F '=' '{ print \$2 }' | awk -F '"' '{ print \$2 }'` + FIND_DOC_PKG=`find $WORKDIR/packages-split/*-doc -maxdepth 0 -type d` + if [ -z "$FIND_DOC_PKG" ]; then + # No -doc package was generated: + echo "No -doc package: $pkg" >> "$REPORT_MISSING_DETAIL" + echo "$pkg" >> $REPORT_MISSING_SIMPLE + continue + fi + + FIND_DOC_FILES=`find $FIND_DOC_PKG -type f` + if [ -z "$FIND_DOC_FILES" ]; then + # No files shipped with the -doc package: + echo "No files shipped with the -doc package: $pkg" >> "$REPORT_MISSING_DETAIL" + echo "$pkg" >> $REPORT_MISSING_SIMPLE + continue + fi + + echo "Documentation shipped with $pkg:" >> "$REPORT_DOC_DETAIL" + echo "$FIND_DOC_FILES" >> "$REPORT_DOC_DETAIL" + echo "" >> "$REPORT_DOC_DETAIL" + + echo "$pkg" >> "$REPORT_DOC_SIMPLE" +done diff --git a/scripts/contrib/graph-tool b/scripts/contrib/graph-tool new file mode 100755 index 0000000000..1df5b8c345 --- /dev/null +++ b/scripts/contrib/graph-tool @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 + +# Simple graph query utility +# useful for getting answers from .dot files produced by bitbake -g +# +# Written by: Paul Eggleton <paul.eggleton@linux.intel.com> +# +# Copyright 2013 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import sys + +def get_path_networkx(dotfile, fromnode, tonode): + try: + import networkx + except ImportError: + print('ERROR: Please install the networkx python module') + sys.exit(1) + + graph = networkx.DiGraph(networkx.nx_pydot.read_dot(dotfile)) + def node_missing(node): + import difflib + close_matches = difflib.get_close_matches(node, graph.nodes(), cutoff=0.7) + if close_matches: + print('ERROR: no node "%s" in graph. Close matches:\n %s' % (node, '\n '.join(close_matches))) + sys.exit(1) + + if not fromnode in graph: + node_missing(fromnode) + if not tonode in graph: + node_missing(tonode) + return networkx.all_simple_paths(graph, source=fromnode, target=tonode) + + +def find_paths(args, usage): + if len(args) < 3: + usage() + sys.exit(1) + + fromnode = args[1] + tonode = args[2] + + path = None + for path in get_path_networkx(args[0], fromnode, tonode): + print(" -> ".join(map(str, path))) + if not path: + print("ERROR: no path from %s to %s in graph" % (fromnode, tonode)) + sys.exit(1) + +def main(): + import optparse + parser = optparse.OptionParser( + usage = '''%prog [options] <command> <arguments> + +Available commands: + find-paths <dotfile> <from> <to> + Find all of the paths between two nodes in a dot graph''') + + #parser.add_option("-d", "--debug", + # help = "Report all SRCREV values, not just ones where AUTOREV has been used", + # action="store_true", dest="debug", default=False) + + options, args = parser.parse_args(sys.argv) + args = args[1:] + + if len(args) < 1: + parser.print_help() + sys.exit(1) + + if args[0] == "find-paths": + find_paths(args[1:], parser.print_help) + else: + parser.print_help() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/contrib/list-packageconfig-flags.py b/scripts/contrib/list-packageconfig-flags.py new file mode 100755 index 0000000000..7ce718624a --- /dev/null +++ b/scripts/contrib/list-packageconfig-flags.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation. +# +# Copyright (C) 2013 Wind River Systems, Inc. +# Copyright (C) 2014 Intel Corporation +# +# - list available recipes which have PACKAGECONFIG flags +# - list available PACKAGECONFIG flags and all affected recipes +# - list all recipes and PACKAGECONFIG information + +import sys +import optparse +import os + + +scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0]))) +lib_path = os.path.abspath(scripts_path + '/../lib') +sys.path = sys.path + [lib_path] + +import scriptpath + +# For importing the following modules +bitbakepath = scriptpath.add_bitbake_lib_path() +if not bitbakepath: + sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n") + sys.exit(1) + +import bb.cooker +import bb.providers +import bb.tinfoil + +def get_fnlist(bbhandler, pkg_pn, preferred): + ''' Get all recipe file names ''' + if preferred: + (latest_versions, preferred_versions) = bb.providers.findProviders(bbhandler.config_data, bbhandler.cooker.recipecaches[''], pkg_pn) + + fn_list = [] + for pn in sorted(pkg_pn): + if preferred: + fn_list.append(preferred_versions[pn][1]) + else: + fn_list.extend(pkg_pn[pn]) + + return fn_list + +def get_recipesdata(bbhandler, preferred): + ''' Get data of all available recipes which have PACKAGECONFIG flags ''' + pkg_pn = bbhandler.cooker.recipecaches[''].pkg_pn + + data_dict = {} + for fn in get_fnlist(bbhandler, pkg_pn, preferred): + data = bbhandler.parse_recipe_file(fn) + flags = data.getVarFlags("PACKAGECONFIG") + flags.pop('doc', None) + if flags: + data_dict[fn] = data + + return data_dict + +def collect_pkgs(data_dict): + ''' Collect available pkgs in which have PACKAGECONFIG flags ''' + # pkg_dict = {'pkg1': ['flag1', 'flag2',...]} + pkg_dict = {} + for fn in data_dict: + pkgconfigflags = data_dict[fn].getVarFlags("PACKAGECONFIG") + pkgconfigflags.pop('doc', None) + pkgname = data_dict[fn].getVar("P") + pkg_dict[pkgname] = sorted(pkgconfigflags.keys()) + + return pkg_dict + +def collect_flags(pkg_dict): + ''' Collect available PACKAGECONFIG flags and all affected pkgs ''' + # flag_dict = {'flag': ['pkg1', 'pkg2',...]} + flag_dict = {} + for pkgname, flaglist in pkg_dict.items(): + for flag in flaglist: + if flag in flag_dict: + flag_dict[flag].append(pkgname) + else: + flag_dict[flag] = [pkgname] + + return flag_dict + +def display_pkgs(pkg_dict): + ''' Display available pkgs which have PACKAGECONFIG flags ''' + pkgname_len = len("RECIPE NAME") + 1 + for pkgname in pkg_dict: + if pkgname_len < len(pkgname): + pkgname_len = len(pkgname) + pkgname_len += 1 + + header = '%-*s%s' % (pkgname_len, str("RECIPE NAME"), str("PACKAGECONFIG FLAGS")) + print(header) + print(str("").ljust(len(header), '=')) + for pkgname in sorted(pkg_dict): + print('%-*s%s' % (pkgname_len, pkgname, ' '.join(pkg_dict[pkgname]))) + + +def display_flags(flag_dict): + ''' Display available PACKAGECONFIG flags and all affected pkgs ''' + flag_len = len("PACKAGECONFIG FLAG") + 5 + + header = '%-*s%s' % (flag_len, str("PACKAGECONFIG FLAG"), str("RECIPE NAMES")) + print(header) + print(str("").ljust(len(header), '=')) + + for flag in sorted(flag_dict): + print('%-*s%s' % (flag_len, flag, ' '.join(sorted(flag_dict[flag])))) + +def display_all(data_dict): + ''' Display all pkgs and PACKAGECONFIG information ''' + print(str("").ljust(50, '=')) + for fn in data_dict: + print('%s' % data_dict[fn].getVar("P")) + print(fn) + packageconfig = data_dict[fn].getVar("PACKAGECONFIG") or '' + if packageconfig.strip() == '': + packageconfig = 'None' + print('PACKAGECONFIG %s' % packageconfig) + + for flag,flag_val in data_dict[fn].getVarFlags("PACKAGECONFIG").items(): + if flag == "doc": + continue + print('PACKAGECONFIG[%s] %s' % (flag, flag_val)) + print('') + +def main(): + pkg_dict = {} + flag_dict = {} + + # Collect and validate input + parser = optparse.OptionParser( + description = "Lists recipes and PACKAGECONFIG flags. Without -a or -f, recipes and their available PACKAGECONFIG flags are listed.", + usage = """ + %prog [options]""") + + parser.add_option("-f", "--flags", + help = "list available PACKAGECONFIG flags and affected recipes", + action="store_const", dest="listtype", const="flags", default="recipes") + parser.add_option("-a", "--all", + help = "list all recipes and PACKAGECONFIG information", + action="store_const", dest="listtype", const="all") + parser.add_option("-p", "--preferred-only", + help = "where multiple recipe versions are available, list only the preferred version", + action="store_true", dest="preferred", default=False) + + options, args = parser.parse_args(sys.argv) + + with bb.tinfoil.Tinfoil() as bbhandler: + bbhandler.prepare() + print("Gathering recipe data...") + data_dict = get_recipesdata(bbhandler, options.preferred) + + if options.listtype == 'flags': + pkg_dict = collect_pkgs(data_dict) + flag_dict = collect_flags(pkg_dict) + display_flags(flag_dict) + elif options.listtype == 'recipes': + pkg_dict = collect_pkgs(data_dict) + display_pkgs(pkg_dict) + elif options.listtype == 'all': + display_all(data_dict) + +if __name__ == "__main__": + main() diff --git a/scripts/contrib/mkefidisk.sh b/scripts/contrib/mkefidisk.sh new file mode 100755 index 0000000000..800733f0af --- /dev/null +++ b/scripts/contrib/mkefidisk.sh @@ -0,0 +1,464 @@ +#!/bin/sh +# +# Copyright (c) 2012, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +LANG=C + +echo +echo "WARNING: This script is deprecated and will be removed soon." +echo "Please consider using wic EFI images instead." +echo + +# Set to 1 to enable additional output +DEBUG=0 +OUT="/dev/null" + +# +# Defaults +# +# 20 Mb for the boot partition +BOOT_SIZE=20 +# 5% for swap +SWAP_RATIO=5 + +# Cleanup after die() +cleanup() { + debug "Syncing and unmounting devices" + # Unmount anything we mounted + unmount $ROOTFS_MNT || error "Failed to unmount $ROOTFS_MNT" + unmount $BOOTFS_MNT || error "Failed to unmount $BOOTFS_MNT" + unmount $HDDIMG_ROOTFS_MNT || error "Failed to unmount $HDDIMG_ROOTFS_MNT" + unmount $HDDIMG_MNT || error "Failed to unmount $HDDIMG_MNT" + + # Remove the TMPDIR + debug "Removing temporary files" + if [ -d "$TMPDIR" ]; then + rm -rf $TMPDIR || error "Failed to remove $TMPDIR" + fi +} + +trap 'die "Signal Received, Aborting..."' HUP INT TERM + +# Logging routines +WARNINGS=0 +ERRORS=0 +CLEAR="$(tput sgr0)" +INFO="$(tput bold)" +RED="$(tput setaf 1)$(tput bold)" +GREEN="$(tput setaf 2)$(tput bold)" +YELLOW="$(tput setaf 3)$(tput bold)" +info() { + echo "${INFO}$1${CLEAR}" +} +error() { + ERRORS=$((ERRORS+1)) + echo "${RED}$1${CLEAR}" +} +warn() { + WARNINGS=$((WARNINGS+1)) + echo "${YELLOW}$1${CLEAR}" +} +success() { + echo "${GREEN}$1${CLEAR}" +} +die() { + error "$1" + cleanup + exit 1 +} +debug() { + if [ $DEBUG -eq 1 ]; then + echo "$1" + fi +} + +usage() { + echo "Usage: $(basename $0) [-v] DEVICE HDDIMG TARGET_DEVICE" + echo " -v: Verbose debug" + echo " DEVICE: The device to write the image to, e.g. /dev/sdh" + echo " HDDIMG: The hddimg file to generate the efi disk from" + echo " TARGET_DEVICE: The device the target will boot from, e.g. /dev/mmcblk0" +} + +image_details() { + IMG=$1 + info "Image details" + echo " image: $(stat --printf '%N\n' $IMG)" + echo " size: $(stat -L --printf '%s bytes\n' $IMG)" + echo " modified: $(stat -L --printf '%y\n' $IMG)" + echo " type: $(file -L -b $IMG)" + echo "" +} + +device_details() { + DEV=$1 + BLOCK_SIZE=512 + + info "Device details" + echo " device: $DEVICE" + if [ -f "/sys/class/block/$DEV/device/vendor" ]; then + echo " vendor: $(cat /sys/class/block/$DEV/device/vendor)" + else + echo " vendor: UNKOWN" + fi + if [ -f "/sys/class/block/$DEV/device/model" ]; then + echo " model: $(cat /sys/class/block/$DEV/device/model)" + else + echo " model: UNKNOWN" + fi + if [ -f "/sys/class/block/$DEV/size" ]; then + echo " size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes" + else + echo " size: UNKNOWN" + fi + echo "" +} + +unmount_device() { + grep -q $DEVICE /proc/mounts + if [ $? -eq 0 ]; then + warn "$DEVICE listed in /proc/mounts, attempting to unmount" + umount $DEVICE* 2>/dev/null + return $? + fi + return 0 +} + +unmount() { + if [ "$1" = "" ] ; then + return 0 + fi + grep -q $1 /proc/mounts + if [ $? -eq 0 ]; then + debug "Unmounting $1" + umount $1 + return $? + fi + return 0 +} + +# +# Parse and validate arguments +# +if [ $# -lt 3 ] || [ $# -gt 4 ]; then + if [ $# -eq 1 ]; then + AVAILABLE_DISK=`lsblk | grep "disk" | cut -f 1 -d " "` + X=0 + for disk in `echo $AVAILABLE_DISK`; do + mounted=`lsblk /dev/$disk | awk {'print $7'} | sed "s/MOUNTPOINT//"` + if [ -z "$mounted" ]; then + UNMOUNTED_AVAILABLES="$UNMOUNTED_AVAILABLES /dev/$disk" + info "$X - /dev/$disk" + X=`expr $X + 1` + fi + done + if [ $X -eq 0 ]; then + die "No unmounted device found." + fi + read -p "Choose unmounted device number: " DISK_NUMBER + X=0 + for line in `echo $UNMOUNTED_AVAILABLES`; do + if [ $DISK_NUMBER -eq $X ]; then + DISK_TO_BE_FLASHED=$line + break + else + X=`expr $X + 1` + fi + done + if [ -z "$DISK_TO_BE_FLASHED" ]; then + die "Option \"$DISK_NUMBER\" is invalid. Choose a valid option" + else + if [ -z `echo $DISK_TO_BE_FLASHED | grep "mmc"` ]; then + TARGET_TO_BE_BOOT="/dev/sda" + else + TARGET_TO_BE_BOOT="/dev/mmcblk0" + fi + fi + echo "" + echo "Choose a name of the device that will be boot from" + echo -n "Recommended name is: " + info "$TARGET_TO_BE_BOOT" + read -p "Is target device okay? [y/N]: " RESPONSE + if [ "$RESPONSE" != "y" ]; then + read -p "Choose target device name: " TARGET_TO_BE_BOOT + fi + echo "" + if [ -z "$TARGET_TO_BE_BOOT" ]; then + die "Error: choose a valid target name" + fi + else + usage + exit 1 + fi +fi + +if [ "$1" = "-v" ]; then + DEBUG=1 + OUT="1" + shift +fi + +if [ -z "$AVAILABLE_DISK" ]; then + DEVICE=$1 + HDDIMG=$2 + TARGET_DEVICE=$3 +else + DEVICE=$DISK_TO_BE_FLASHED + HDDIMG=$1 + TARGET_DEVICE=$TARGET_TO_BE_BOOT +fi + +LINK=$(readlink $DEVICE) +if [ $? -eq 0 ]; then + DEVICE="$LINK" +fi + +if [ ! -w "$DEVICE" ]; then + usage + if [ ! -e "${DEVICE}" ] ; then + die "Device $DEVICE cannot be found" + else + die "Device $DEVICE is not writable (need to run under sudo?)" + fi +fi + +if [ ! -e "$HDDIMG" ]; then + usage + die "HDDIMG $HDDIMG does not exist" +fi + +# +# Ensure the hddimg is not mounted +# +unmount "$HDDIMG" || die "Failed to unmount $HDDIMG" + +# +# Check if any $DEVICE partitions are mounted +# +unmount_device || die "Failed to unmount $DEVICE" + +# +# Confirm device with user +# +image_details $HDDIMG +device_details $(basename $DEVICE) +echo -n "${INFO}Prepare EFI image on $DEVICE [y/N]?${CLEAR} " +read RESPONSE +if [ "$RESPONSE" != "y" ]; then + echo "Image creation aborted" + exit 0 +fi + + +# +# Prepare the temporary working space +# +TMPDIR=$(mktemp -d mkefidisk-XXX) || die "Failed to create temporary mounting directory." +HDDIMG_MNT=$TMPDIR/hddimg +HDDIMG_ROOTFS_MNT=$TMPDIR/hddimg_rootfs +ROOTFS_MNT=$TMPDIR/rootfs +BOOTFS_MNT=$TMPDIR/bootfs +mkdir $HDDIMG_MNT || die "Failed to create $HDDIMG_MNT" +mkdir $HDDIMG_ROOTFS_MNT || die "Failed to create $HDDIMG_ROOTFS_MNT" +mkdir $ROOTFS_MNT || die "Failed to create $ROOTFS_MNT" +mkdir $BOOTFS_MNT || die "Failed to create $BOOTFS_MNT" + + +# +# Partition $DEVICE +# +DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//") +# If the device size is not reported there may not be a valid label +if [ "$DEVICE_SIZE" = "" ] ; then + parted -s $DEVICE mklabel msdos || die "Failed to create MSDOS partition table" + DEVICE_SIZE=$(parted -s $DEVICE unit mb print | grep ^Disk | cut -d" " -f 3 | sed -e "s/MB//") +fi +SWAP_SIZE=$((DEVICE_SIZE*SWAP_RATIO/100)) +ROOTFS_SIZE=$((DEVICE_SIZE-BOOT_SIZE-SWAP_SIZE)) +ROOTFS_START=$((BOOT_SIZE)) +ROOTFS_END=$((ROOTFS_START+ROOTFS_SIZE)) +SWAP_START=$((ROOTFS_END)) + +# MMC devices use a partition prefix character 'p' +PART_PREFIX="" +if [ ! "${DEVICE#/dev/mmcblk}" = "${DEVICE}" ] || [ ! "${DEVICE#/dev/loop}" = "${DEVICE}" ]; then + PART_PREFIX="p" +fi +BOOTFS=$DEVICE${PART_PREFIX}1 +ROOTFS=$DEVICE${PART_PREFIX}2 +SWAP=$DEVICE${PART_PREFIX}3 + +TARGET_PART_PREFIX="" +if [ ! "${TARGET_DEVICE#/dev/mmcblk}" = "${TARGET_DEVICE}" ]; then + TARGET_PART_PREFIX="p" +fi +TARGET_ROOTFS=$TARGET_DEVICE${TARGET_PART_PREFIX}2 +TARGET_SWAP=$TARGET_DEVICE${TARGET_PART_PREFIX}3 + +echo "" +info "Boot partition size: $BOOT_SIZE MB ($BOOTFS)" +info "ROOTFS partition size: $ROOTFS_SIZE MB ($ROOTFS)" +info "Swap partition size: $SWAP_SIZE MB ($SWAP)" +echo "" + +# Use MSDOS by default as GPT cannot be reliably distributed in disk image form +# as it requires the backup table to be on the last block of the device, which +# of course varies from device to device. + +info "Partitioning installation media ($DEVICE)" + +debug "Deleting partition table on $DEVICE" +dd if=/dev/zero of=$DEVICE bs=512 count=2 >$OUT 2>&1 || die "Failed to zero beginning of $DEVICE" + +debug "Creating new partition table (MSDOS) on $DEVICE" +parted -s $DEVICE mklabel msdos >$OUT 2>&1 || die "Failed to create MSDOS partition table" + +debug "Creating boot partition on $BOOTFS" +parted -s $DEVICE mkpart primary 0% $BOOT_SIZE >$OUT 2>&1 || die "Failed to create BOOT partition" + +debug "Enabling boot flag on $BOOTFS" +parted -s $DEVICE set 1 boot on >$OUT 2>&1 || die "Failed to enable boot flag" + +debug "Creating ROOTFS partition on $ROOTFS" +parted -s $DEVICE mkpart primary $ROOTFS_START $ROOTFS_END >$OUT 2>&1 || die "Failed to create ROOTFS partition" + +debug "Creating swap partition on $SWAP" +parted -s $DEVICE mkpart primary $SWAP_START 100% >$OUT 2>&1 || die "Failed to create SWAP partition" + +if [ $DEBUG -eq 1 ]; then + parted -s $DEVICE print +fi + + +# +# Check if any $DEVICE partitions are mounted after partitioning +# +unmount_device || die "Failed to unmount $DEVICE partitions" + + +# +# Format $DEVICE partitions +# +info "Formatting partitions" +debug "Formatting $BOOTFS as vfat" +if [ ! "${DEVICE#/dev/loop}" = "${DEVICE}" ]; then + mkfs.vfat -I $BOOTFS -n "EFI" >$OUT 2>&1 || die "Failed to format $BOOTFS" +else + mkfs.vfat $BOOTFS -n "EFI" >$OUT 2>&1 || die "Failed to format $BOOTFS" +fi + +debug "Formatting $ROOTFS as ext3" +mkfs.ext3 -F $ROOTFS -L "ROOT" >$OUT 2>&1 || die "Failed to format $ROOTFS" + +debug "Formatting swap partition ($SWAP)" +mkswap $SWAP >$OUT 2>&1 || die "Failed to prepare swap" + + +# +# Installing to $DEVICE +# +debug "Mounting images and device in preparation for installation" +mount -o ro,loop $HDDIMG $HDDIMG_MNT >$OUT 2>&1 || error "Failed to mount $HDDIMG" +mount -o ro,loop $HDDIMG_MNT/rootfs.img $HDDIMG_ROOTFS_MNT >$OUT 2>&1 || error "Failed to mount rootfs.img" +mount $ROOTFS $ROOTFS_MNT >$OUT 2>&1 || error "Failed to mount $ROOTFS on $ROOTFS_MNT" +mount $BOOTFS $BOOTFS_MNT >$OUT 2>&1 || error "Failed to mount $BOOTFS on $BOOTFS_MNT" + +info "Preparing boot partition" +EFIDIR="$BOOTFS_MNT/EFI/BOOT" +cp $HDDIMG_MNT/vmlinuz $BOOTFS_MNT >$OUT 2>&1 || error "Failed to copy vmlinuz" +# Copy the efi loader and configs (booti*.efi and grub.cfg if it exists) +cp -r $HDDIMG_MNT/EFI $BOOTFS_MNT >$OUT 2>&1 || error "Failed to copy EFI dir" +# Silently ignore a missing systemd-boot loader dir (we might just be a GRUB image) +cp -r $HDDIMG_MNT/loader $BOOTFS_MNT >$OUT 2>&1 + +# Update the boot loaders configurations for an installed image +# Remove any existing root= kernel parameters and: +# o Add a root= parameter with the target rootfs +# o Specify ro so fsck can be run during boot +# o Specify rootwait in case the target media is an asyncronous block device +# such as MMC or USB disks +# o Specify "quiet" to minimize boot time when using slow serial consoles + +# Look for a GRUB installation +GRUB_CFG="$EFIDIR/grub.cfg" +if [ -e "$GRUB_CFG" ]; then + info "Configuring GRUB" + # Delete the install entry + sed -i "/menuentry 'install'/,/^}/d" $GRUB_CFG + # Delete the initrd lines + sed -i "/initrd /d" $GRUB_CFG + # Delete any LABEL= strings + sed -i "s/ LABEL=[^ ]*/ /" $GRUB_CFG + + sed -i "s@ root=[^ ]*@ @" $GRUB_CFG + sed -i "s@vmlinuz @vmlinuz root=$TARGET_ROOTFS ro rootwait console=ttyS0 console=tty0 @" $GRUB_CFG +fi + +# Look for a systemd-boot installation +SYSTEMD_BOOT_ENTRIES="$BOOTFS_MNT/loader/entries" +SYSTEMD_BOOT_CFG="$SYSTEMD_BOOT_ENTRIES/boot.conf" +if [ -d "$SYSTEMD_BOOT_ENTRIES" ]; then + info "Configuring SystemD-boot" + # remove the install target if it exists + rm $SYSTEMD_BOOT_ENTRIES/install.conf >$OUT 2>&1 + + if [ ! -e "$SYSTEMD_BOOT_CFG" ]; then + echo "ERROR: $SYSTEMD_BOOT_CFG not found" + fi + + sed -i "/initrd /d" $SYSTEMD_BOOT_CFG + sed -i "s@ root=[^ ]*@ @" $SYSTEMD_BOOT_CFG + sed -i "s@options *LABEL=boot @options LABEL=Boot root=$TARGET_ROOTFS ro rootwait console=ttyS0 console=tty0 @" $SYSTEMD_BOOT_CFG +fi + +# Ensure we have at least one EFI bootloader configured +if [ ! -e $GRUB_CFG ] && [ ! -e $SYSTEMD_BOOT_CFG ]; then + die "No EFI bootloader configuration found" +fi + + +info "Copying ROOTFS files (this may take a while)" +cp -a $HDDIMG_ROOTFS_MNT/* $ROOTFS_MNT >$OUT 2>&1 || die "Root FS copy failed" + +echo "$TARGET_SWAP swap swap defaults 0 0" >> $ROOTFS_MNT/etc/fstab + +# We dont want udev to mount our root device while we're booting... +if [ -d $ROOTFS_MNT/etc/udev/ ] ; then + echo "$TARGET_DEVICE" >> $ROOTFS_MNT/etc/udev/mount.blacklist +fi + +# Add startup.nsh script for automated boot +echo "fs0:\EFI\BOOT\bootx64.efi" > $BOOTFS_MNT/startup.nsh + + +# Call cleanup to unmount devices and images and remove the TMPDIR +cleanup + +echo "" +if [ $WARNINGS -ne 0 ] && [ $ERRORS -eq 0 ]; then + echo "${YELLOW}Installation completed with warnings${CLEAR}" + echo "${YELLOW}Warnings: $WARNINGS${CLEAR}" +elif [ $ERRORS -ne 0 ]; then + echo "${RED}Installation encountered errors${CLEAR}" + echo "${RED}Errors: $ERRORS${CLEAR}" + echo "${YELLOW}Warnings: $WARNINGS${CLEAR}" +else + success "Installation completed successfully" +fi +echo "" diff --git a/scripts/contrib/oe-build-perf-report-email.py b/scripts/contrib/oe-build-perf-report-email.py new file mode 100755 index 0000000000..261ca514e5 --- /dev/null +++ b/scripts/contrib/oe-build-perf-report-email.py @@ -0,0 +1,269 @@ +#!/usr/bin/python3 +# +# Send build performance test report emails +# +# Copyright (c) 2017, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope 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. +# +import argparse +import base64 +import logging +import os +import pwd +import re +import shutil +import smtplib +import socket +import subprocess +import sys +import tempfile +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + + +# Setup logging +logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") +log = logging.getLogger('oe-build-perf-report') + + +# Find js scaper script +SCRAPE_JS = os.path.join(os.path.dirname(__file__), '..', 'lib', 'build_perf', + 'scrape-html-report.js') +if not os.path.isfile(SCRAPE_JS): + log.error("Unableto find oe-build-perf-report-scrape.js") + sys.exit(1) + + +class ReportError(Exception): + """Local errors""" + pass + + +def check_utils(): + """Check that all needed utils are installed in the system""" + missing = [] + for cmd in ('phantomjs', 'optipng'): + if not shutil.which(cmd): + missing.append(cmd) + if missing: + log.error("The following tools are missing: %s", ' '.join(missing)) + sys.exit(1) + + +def parse_args(argv): + """Parse command line arguments""" + description = """Email build perf test report""" + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description=description) + + parser.add_argument('--debug', '-d', action='store_true', + help="Verbose logging") + parser.add_argument('--quiet', '-q', action='store_true', + help="Only print errors") + parser.add_argument('--to', action='append', + help="Recipients of the email") + parser.add_argument('--subject', default="Yocto build perf test report", + help="Email subject") + parser.add_argument('--outdir', '-o', + help="Store files in OUTDIR. Can be used to preserve " + "the email parts") + parser.add_argument('--text', + help="Plain text message") + parser.add_argument('--html', + help="HTML peport generated by oe-build-perf-report") + parser.add_argument('--phantomjs-args', action='append', + help="Extra command line arguments passed to PhantomJS") + + args = parser.parse_args(argv) + + if not args.html and not args.text: + parser.error("Please specify --html and/or --text") + + return args + + +def decode_png(infile, outfile): + """Parse/decode/optimize png data from a html element""" + with open(infile) as f: + raw_data = f.read() + + # Grab raw base64 data + b64_data = re.sub('^.*href="data:image/png;base64,', '', raw_data, 1) + b64_data = re.sub('">.+$', '', b64_data, 1) + + # Replace file with proper decoded png + with open(outfile, 'wb') as f: + f.write(base64.b64decode(b64_data)) + + subprocess.check_output(['optipng', outfile], stderr=subprocess.STDOUT) + + +def encode_png(pngfile): + """Encode png into a <img> html element""" + with open(pngfile, 'rb') as f: + data = f.read() + + b64_data = base64.b64encode(data) + return '<img src="data:image/png;base64,' + b64_data.decode('utf-8') + '">\n' + + +def mangle_html_report(infile, outfile, pngs): + """Mangle html file into a email compatible format""" + paste = True + png_dir = os.path.dirname(outfile) + with open(infile) as f_in: + with open(outfile, 'w') as f_out: + for line in f_in.readlines(): + stripped = line.strip() + # Strip out scripts + if stripped == '<!--START-OF-SCRIPTS-->': + paste = False + elif stripped == '<!--END-OF-SCRIPTS-->': + paste = True + elif paste: + if re.match('^.+href="data:image/png;base64', stripped): + # Strip out encoded pngs (as they're huge in size) + continue + elif 'www.gstatic.com' in stripped: + # HACK: drop references to external static pages + continue + + # Replace charts with <img> elements + match = re.match('<div id="(?P<id>\w+)"', stripped) + if match and match.group('id') in pngs: + #f_out.write('<img src="{}">\n'.format(match.group('id') + '.png')) + png_file = os.path.join(png_dir, match.group('id') + '.png') + f_out.write(encode_png(png_file)) + else: + f_out.write(line) + + +def scrape_html_report(report, outdir, phantomjs_extra_args=None): + """Scrape html report into a format sendable by email""" + tmpdir = tempfile.mkdtemp(dir='.') + log.debug("Using tmpdir %s for phantomjs output", tmpdir) + + if not os.path.isdir(outdir): + os.mkdir(outdir) + if os.path.splitext(report)[1] not in ('.html', '.htm'): + raise ReportError("Invalid file extension for report, needs to be " + "'.html' or '.htm'") + + try: + log.info("Scraping HTML report with PhangomJS") + extra_args = phantomjs_extra_args if phantomjs_extra_args else [] + subprocess.check_output(['phantomjs', '--debug=true'] + extra_args + + [SCRAPE_JS, report, tmpdir], + stderr=subprocess.STDOUT) + + pngs = [] + attachments = [] + for fname in os.listdir(tmpdir): + base, ext = os.path.splitext(fname) + if ext == '.png': + log.debug("Decoding %s", fname) + decode_png(os.path.join(tmpdir, fname), + os.path.join(outdir, fname)) + pngs.append(base) + attachments.append(fname) + elif ext in ('.html', '.htm'): + report_file = fname + else: + log.warning("Unknown file extension: '%s'", ext) + #shutil.move(os.path.join(tmpdir, fname), outdir) + + log.debug("Mangling html report file %s", report_file) + mangle_html_report(os.path.join(tmpdir, report_file), + os.path.join(outdir, report_file), pngs) + return report_file, attachments + finally: + shutil.rmtree(tmpdir) + +def send_email(text_fn, html_fn, subject, recipients): + """Send email""" + # Generate email message + text_msg = html_msg = None + if text_fn: + with open(text_fn) as f: + text_msg = MIMEText("Yocto build performance test report.\n" + + f.read(), 'plain') + if html_fn: + with open(html_fn) as f: + html_msg = MIMEText(f.read(), 'html') + + if text_msg and html_msg: + msg = MIMEMultipart('alternative') + msg.attach(text_msg) + msg.attach(html_msg) + elif text_msg: + msg = text_msg + elif html_msg: + msg = html_msg + else: + raise ReportError("Neither plain text nor html body specified") + + pw_data = pwd.getpwuid(os.getuid()) + full_name = pw_data.pw_gecos.split(',')[0] + email = os.environ.get('EMAIL', + '{}@{}'.format(pw_data.pw_name, socket.getfqdn())) + msg['From'] = "{} <{}>".format(full_name, email) + msg['To'] = ', '.join(recipients) + msg['Subject'] = subject + + # Send email + with smtplib.SMTP('localhost') as smtp: + smtp.send_message(msg) + + +def main(argv=None): + """Script entry point""" + args = parse_args(argv) + if args.quiet: + log.setLevel(logging.ERROR) + if args.debug: + log.setLevel(logging.DEBUG) + + check_utils() + + if args.outdir: + outdir = args.outdir + if not os.path.exists(outdir): + os.mkdir(outdir) + else: + outdir = tempfile.mkdtemp(dir='.') + + try: + log.debug("Storing email parts in %s", outdir) + html_report = None + if args.html: + scrape_html_report(args.html, outdir, args.phantomjs_args) + html_report = os.path.join(outdir, os.path.basename(args.html)) + + if args.to: + log.info("Sending email to %s", ', '.join(args.to)) + send_email(args.text, html_report, args.subject, args.to) + except subprocess.CalledProcessError as err: + log.error("%s, with output:\n%s", str(err), err.output.decode()) + return 1 + except ReportError as err: + log.error(err) + return 1 + finally: + if not args.outdir: + log.debug("Wiping %s", outdir) + shutil.rmtree(outdir) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/contrib/python/generate-manifest-2.6.py b/scripts/contrib/python/generate-manifest-2.6.py deleted file mode 100755 index 1b11266edf..0000000000 --- a/scripts/contrib/python/generate-manifest-2.6.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env python - -# generate Python Manifest for the OpenEmbedded build system -# (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> -# (C) 2007 Jeremy Laine -# licensed under MIT, see COPYING.MIT - -import os -import sys -import time - -VERSION = "2.6.6" - -__author__ = "Michael 'Mickey' Lauer <mlauer@vanille-media.de>" -__version__ = "20110222" - -class MakefileMaker: - - def __init__( self, outfile ): - """initialize""" - self.packages = {} - self.targetPrefix = "${libdir}/python%s/" % VERSION[:3] - self.output = outfile - self.out( """ -# WARNING: This file is AUTO GENERATED: Manual edits will be lost next time I regenerate the file. -# Generator: '%s' Version %s (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> -# Visit the Python for Embedded Systems Site => http://www.Vanille.de/projects/python.spy -""" % ( sys.argv[0], __version__ ) ) - - # - # helper functions - # - - def out( self, data ): - """print a line to the output file""" - self.output.write( "%s\n" % data ) - - def setPrefix( self, targetPrefix ): - """set a file prefix for addPackage files""" - self.targetPrefix = targetPrefix - - def doProlog( self ): - self.out( """ """ ) - self.out( "" ) - - def addPackage( self, name, description, dependencies, filenames ): - """add a package to the Makefile""" - if type( filenames ) == type( "" ): - filenames = filenames.split() - fullFilenames = [] - for filename in filenames: - if filename[0] != "$": - fullFilenames.append( "%s%s" % ( self.targetPrefix, filename ) ) - else: - fullFilenames.append( filename ) - self.packages[name] = description, dependencies, fullFilenames - - def doBody( self ): - """generate body of Makefile""" - - global VERSION - - # - # generate provides line - # - - provideLine = 'PROVIDES+="' - for name in sorted(self.packages): - provideLine += "%s " % name - provideLine += '"' - - self.out( provideLine ) - self.out( "" ) - - # - # generate package line - # - - packageLine = 'PACKAGES="${PN}-core-dbg ' - for name in sorted(self.packages): - if name != '${PN}-core-dbg': - packageLine += "%s " % name - packageLine += '${PN}-modules"' - - self.out( packageLine ) - self.out( "" ) - - # - # generate package variables - # - - for name, data in sorted(self.packages.iteritems()): - desc, deps, files = data - - # - # write out the description, revision and dependencies - # - self.out( 'DESCRIPTION_%s="%s"' % ( name, desc ) ) - self.out( 'RDEPENDS_%s="%s"' % ( name, deps ) ) - - line = 'FILES_%s="' % name - - # - # check which directories to make in the temporary directory - # - - dirset = {} # if python had a set-datatype this would be sufficient. for now, we're using a dict instead. - for target in files: - dirset[os.path.dirname( target )] = True - - # - # generate which files to copy for the target (-dfR because whole directories are also allowed) - # - - for target in files: - line += "%s " % target - - line += '"' - self.out( line ) - self.out( "" ) - - self.out( 'DESCRIPTION_${PN}-modules="All Python modules"' ) - line = 'RDEPENDS_${PN}-modules="' - - for name, data in sorted(self.packages.iteritems()): - if name not in ['${PN}-core-dbg', '${PN}-dev']: - line += "%s " % name - - self.out( "%s \"" % line ) - self.out( 'ALLOW_EMPTY_${PN}-modules = "1"' ) - - def doEpilog( self ): - self.out( """""" ) - self.out( "" ) - - def make( self ): - self.doProlog() - self.doBody() - self.doEpilog() - -if __name__ == "__main__": - - if len( sys.argv ) > 1: - os.popen( "rm -f ./%s" % sys.argv[1] ) - outfile = file( sys.argv[1], "w" ) - else: - outfile = sys.stdout - - m = MakefileMaker( outfile ) - - # Add packages here. Only specify dlopen-style library dependencies here, no ldd-style dependencies! - # Parameters: revision, name, description, dependencies, filenames - # - - m.addPackage( "${PN}-core", "Python Interpreter and core modules (needed!)", "", - "__future__.* _abcoll.* abc.* copy.* copy_reg.* ConfigParser.* " + - "genericpath.* getopt.* linecache.* new.* " + - "os.* posixpath.* struct.* " + - "warnings.* site.* stat.* " + - "UserDict.* UserList.* UserString.* " + - "lib-dynload/binascii.so lib-dynload/_struct.so lib-dynload/time.so " + - "lib-dynload/xreadlines.so types.* platform.* ${bindir}/python*" ) - - m.addPackage( "${PN}-core-dbg", "Python core module debug information", "${PN}-core", - "config/.debug lib-dynload/.debug ${bindir}/.debug ${libdir}/.debug" ) - - m.addPackage( "${PN}-dev", "Python Development Package", "${PN}-core", - "${includedir} ${libdir}/libpython2.6.so" ) # package - - m.addPackage( "${PN}-idle", "Python Integrated Development Environment", "${PN}-core ${PN}-tkinter", - "${bindir}/idle idlelib" ) # package - - m.addPackage( "${PN}-pydoc", "Python Interactive Help Support", "${PN}-core ${PN}-lang ${PN}-stringold ${PN}-re", - "${bindir}/pydoc pydoc.*" ) - - m.addPackage( "${PN}-smtpd", "Python Simple Mail Transport Daemon", "${PN}-core ${PN}-netserver ${PN}-email ${PN}-mime", - "${bindir}/smtpd.*" ) - - m.addPackage( "${PN}-audio", "Python Audio Handling", "${PN}-core", - "wave.* chunk.* sndhdr.* lib-dynload/ossaudiodev.so lib-dynload/audioop.so" ) - - m.addPackage( "${PN}-bsddb", "Python Berkeley Database Bindings", "${PN}-core", - "bsddb lib-dynload/_bsddb.so" ) # package - - m.addPackage( "${PN}-codecs", "Python Codecs, Encodings & i18n Support", "${PN}-core ${PN}-lang", - "codecs.* encodings gettext.* locale.* lib-dynload/_locale.so lib-dynload/unicodedata.so stringprep.* xdrlib.*" ) - - m.addPackage( "${PN}-compile", "Python Bytecode Compilation Support", "${PN}-core", - "py_compile.* compileall.*" ) - - m.addPackage( "${PN}-compiler", "Python Compiler Support", "${PN}-core", - "compiler" ) # package - - m.addPackage( "${PN}-compression", "Python High Level Compression Support", "${PN}-core ${PN}-zlib", - "gzip.* zipfile.* tarfile.* lib-dynload/bz2.so" ) - - m.addPackage( "${PN}-crypt", "Python Basic Cryptographic and Hashing Support", "${PN}-core", - "hashlib.* md5.* sha.* lib-dynload/crypt.so lib-dynload/_hashlib.so lib-dynload/_sha256.so lib-dynload/_sha512.so" ) - - m.addPackage( "${PN}-textutils", "Python Option Parsing, Text Wrapping and Comma-Separated-Value Support", "${PN}-core ${PN}-io ${PN}-re ${PN}-stringold", - "lib-dynload/_csv.so csv.* optparse.* textwrap.*" ) - - m.addPackage( "${PN}-curses", "Python Curses Support", "${PN}-core", - "curses lib-dynload/_curses.so lib-dynload/_curses_panel.so" ) # directory + low level module - - m.addPackage( "${PN}-ctypes", "Python C Types Support", "${PN}-core", - "ctypes lib-dynload/_ctypes.so" ) # directory + low level module - - m.addPackage( "${PN}-datetime", "Python Calendar and Time support", "${PN}-core ${PN}-codecs", - "_strptime.* calendar.* lib-dynload/datetime.so" ) - - m.addPackage( "${PN}-db", "Python File-Based Database Support", "${PN}-core", - "anydbm.* dumbdbm.* whichdb.* " ) - - m.addPackage( "${PN}-debugger", "Python Debugger", "${PN}-core ${PN}-io ${PN}-lang ${PN}-re ${PN}-stringold ${PN}-shell ${PN}-pprint", - "bdb.* pdb.*" ) - - m.addPackage( "${PN}-difflib", "Python helpers for computing deltas between objects.", "${PN}-lang ${PN}-re", - "difflib.*" ) - - m.addPackage( "${PN}-distutils", "Python Distribution Utilities", "${PN}-core", - "config distutils" ) # package - - m.addPackage( "${PN}-doctest", "Python framework for running examples in docstrings.", "${PN}-core ${PN}-lang ${PN}-io ${PN}-re ${PN}-unittest ${PN}-debugger ${PN}-difflib", - "doctest.*" ) - - # FIXME consider adding to some higher level package - m.addPackage( "${PN}-elementtree", "Python elementree", "${PN}-core", - "lib-dynload/_elementtree.so" ) - - m.addPackage( "${PN}-email", "Python Email Support", "${PN}-core ${PN}-io ${PN}-re ${PN}-mime ${PN}-audio ${PN}-image ${PN}-netclient", - "imaplib.* email" ) # package - - m.addPackage( "${PN}-fcntl", "Python's fcntl Interface", "${PN}-core", - "lib-dynload/fcntl.so" ) - - m.addPackage( "${PN}-hotshot", "Python Hotshot Profiler", "${PN}-core", - "hotshot lib-dynload/_hotshot.so" ) - - m.addPackage( "${PN}-html", "Python HTML Processing", "${PN}-core", - "formatter.* htmlentitydefs.* htmllib.* markupbase.* sgmllib.* " ) - - m.addPackage( "${PN}-gdbm", "Python GNU Database Support", "${PN}-core", - "lib-dynload/gdbm.so" ) - - m.addPackage( "${PN}-image", "Python Graphical Image Handling", "${PN}-core", - "colorsys.* imghdr.* lib-dynload/imageop.so lib-dynload/rgbimg.so" ) - - m.addPackage( "${PN}-io", "Python Low-Level I/O", "${PN}-core ${PN}-math", - "lib-dynload/_socket.so lib-dynload/_ssl.so lib-dynload/select.so lib-dynload/termios.so lib-dynload/cStringIO.so " + - "pipes.* socket.* ssl.* tempfile.* StringIO.* " ) - - m.addPackage( "${PN}-json", "Python JSON Support", "${PN}-core ${PN}-math ${PN}-re", - "json" ) # package - - m.addPackage( "${PN}-lang", "Python Low-Level Language Support", "${PN}-core", - "lib-dynload/_bisect.so lib-dynload/_collections.so lib-dynload/_heapq.so lib-dynload/_weakref.so lib-dynload/_functools.so " + - "lib-dynload/array.so lib-dynload/itertools.so lib-dynload/operator.so lib-dynload/parser.so " + - "atexit.* bisect.* code.* codeop.* collections.* dis.* functools.* heapq.* inspect.* keyword.* opcode.* symbol.* repr.* token.* " + - "tokenize.* traceback.* weakref.*" ) - - m.addPackage( "${PN}-logging", "Python Logging Support", "${PN}-core ${PN}-io ${PN}-lang ${PN}-pickle ${PN}-stringold", - "logging" ) # package - - m.addPackage( "${PN}-mailbox", "Python Mailbox Format Support", "${PN}-core ${PN}-mime", - "mailbox.*" ) - - m.addPackage( "${PN}-math", "Python Math Support", "${PN}-core", - "lib-dynload/cmath.so lib-dynload/math.so lib-dynload/_random.so random.* sets.*" ) - - m.addPackage( "${PN}-mime", "Python MIME Handling APIs", "${PN}-core ${PN}-io", - "mimetools.* uu.* quopri.* rfc822.*" ) - - m.addPackage( "${PN}-mmap", "Python Memory-Mapped-File Support", "${PN}-core ${PN}-io", - "lib-dynload/mmap.so " ) - - m.addPackage( "${PN}-multiprocessing", "Python Multiprocessing Support", "${PN}-core ${PN}-io ${PN}-lang", - "lib-dynload/_multiprocessing.so multiprocessing" ) # package - - m.addPackage( "${PN}-netclient", "Python Internet Protocol Clients", "${PN}-core ${PN}-crypt ${PN}-datetime ${PN}-io ${PN}-lang ${PN}-logging ${PN}-mime", - "*Cookie*.* " + - "base64.* cookielib.* ftplib.* gopherlib.* hmac.* httplib.* mimetypes.* nntplib.* poplib.* smtplib.* telnetlib.* urllib.* urllib2.* urlparse.* uuid.* rfc822.* mimetools.*" ) - - m.addPackage( "${PN}-netserver", "Python Internet Protocol Servers", "${PN}-core ${PN}-netclient", - "cgi.* *HTTPServer.* SocketServer.*" ) - - m.addPackage( "${PN}-numbers", "Python Number APIs", "${PN}-core ${PN}-lang ${PN}-re", - "decimal.* numbers.*" ) - - m.addPackage( "${PN}-pickle", "Python Persistence Support", "${PN}-core ${PN}-codecs ${PN}-io ${PN}-re", - "pickle.* shelve.* lib-dynload/cPickle.so" ) - - m.addPackage( "${PN}-pkgutil", "Python Package Extension Utility Support", "${PN}-core", - "pkgutil.*") - - m.addPackage( "${PN}-pprint", "Python Pretty-Print Support", "${PN}-core", - "pprint.*" ) - - m.addPackage( "${PN}-profile", "Python Basic Profiling Support", "${PN}-core ${PN}-textutils", - "profile.* pstats.* cProfile.* lib-dynload/_lsprof.so" ) - - m.addPackage( "${PN}-re", "Python Regular Expression APIs", "${PN}-core", - "re.* sre.* sre_compile.* sre_constants* sre_parse.*" ) # _sre is builtin - - m.addPackage( "${PN}-readline", "Python Readline Support", "${PN}-core", - "lib-dynload/readline.so rlcompleter.*" ) - - m.addPackage( "${PN}-resource", "Python Resource Control Interface", "${PN}-core", - "lib-dynload/resource.so" ) - - m.addPackage( "${PN}-shell", "Python Shell-Like Functionality", "${PN}-core ${PN}-re", - "cmd.* commands.* dircache.* fnmatch.* glob.* popen2.* shlex.* shutil.*" ) - - m.addPackage( "${PN}-robotparser", "Python robots.txt parser", "${PN}-core ${PN}-netclient", - "robotparser.*") - - m.addPackage( "${PN}-subprocess", "Python Subprocess Support", "${PN}-core ${PN}-io ${PN}-re ${PN}-fcntl ${PN}-pickle", - "subprocess.*" ) - - m.addPackage( "${PN}-sqlite3", "Python Sqlite3 Database Support", "${PN}-core ${PN}-datetime ${PN}-lang ${PN}-crypt ${PN}-io ${PN}-threading ${PN}-zlib", - "lib-dynload/_sqlite3.so sqlite3/dbapi2.* sqlite3/__init__.* sqlite3/dump.*" ) - - m.addPackage( "${PN}-sqlite3-tests", "Python Sqlite3 Database Support Tests", "${PN}-core ${PN}-sqlite3", - "sqlite3/test" ) - - m.addPackage( "${PN}-stringold", "Python String APIs [deprecated]", "${PN}-core ${PN}-re", - "lib-dynload/strop.so string.*" ) - - m.addPackage( "${PN}-syslog", "Python Syslog Interface", "${PN}-core", - "lib-dynload/syslog.so" ) - - m.addPackage( "${PN}-terminal", "Python Terminal Controlling Support", "${PN}-core ${PN}-io", - "pty.* tty.*" ) - - m.addPackage( "${PN}-tests", "Python Tests", "${PN}-core", - "test" ) # package - - m.addPackage( "${PN}-threading", "Python Threading & Synchronization Support", "${PN}-core ${PN}-lang", - "_threading_local.* dummy_thread.* dummy_threading.* mutex.* threading.* Queue.*" ) - - m.addPackage( "${PN}-tkinter", "Python Tcl/Tk Bindings", "${PN}-core", - "lib-dynload/_tkinter.so lib-tk" ) # package - - m.addPackage( "${PN}-unittest", "Python Unit Testing Framework", "${PN}-core ${PN}-stringold ${PN}-lang", - "unittest.*" ) - - m.addPackage( "${PN}-unixadmin", "Python Unix Administration Support", "${PN}-core", - "lib-dynload/nis.so lib-dynload/grp.so lib-dynload/pwd.so getpass.*" ) - - m.addPackage( "${PN}-xml", "Python basic XML support.", "${PN}-core ${PN}-elementtree ${PN}-re", - "lib-dynload/pyexpat.so xml xmllib.*" ) # package - - m.addPackage( "${PN}-xmlrpc", "Python XMLRPC Support", "${PN}-core ${PN}-xml ${PN}-netserver ${PN}-lang", - "xmlrpclib.* SimpleXMLRPCServer.*" ) - - m.addPackage( "${PN}-zlib", "Python zlib Support.", "${PN}-core", - "lib-dynload/zlib.so" ) - - m.addPackage( "${PN}-mailbox", "Python Mailbox Format Support", "${PN}-core ${PN}-mime", - "mailbox.*" ) - - m.make() diff --git a/scripts/contrib/python/generate-manifest-2.7.py b/scripts/contrib/python/generate-manifest-2.7.py new file mode 100755 index 0000000000..8c3655d395 --- /dev/null +++ b/scripts/contrib/python/generate-manifest-2.7.py @@ -0,0 +1,420 @@ +#!/usr/bin/env python + +# generate Python Manifest for the OpenEmbedded build system +# (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> +# (C) 2007 Jeremy Laine +# licensed under MIT, see COPYING.MIT +# +# June 22, 2011 -- Mark Hatle <mark.hatle@windriver.com> +# * Updated to no longer generate special -dbg package, instead use the +# single system -dbg +# * Update version with ".1" to indicate this change +# +# February 26, 2017 -- Ming Liu <peter.x.liu@external.atlascopco.com> +# * Updated to support generating manifest for native python + +import os +import sys +import time +import argparse + +VERSION = "2.7.2" + +__author__ = "Michael 'Mickey' Lauer <mlauer@vanille-media.de>" +__version__ = "20110222.2" + +class MakefileMaker: + + def __init__( self, outfile, isNative ): + """initialize""" + self.packages = {} + self.targetPrefix = "${libdir}/python%s/" % VERSION[:3] + self.isNative = isNative + self.output = outfile + self.out( """ +# WARNING: This file is AUTO GENERATED: Manual edits will be lost next time I regenerate the file. +# Generator: '%s%s' Version %s (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> +""" % ( sys.argv[0], ' --native' if isNative else '', __version__ ) ) + + # + # helper functions + # + + def out( self, data ): + """print a line to the output file""" + self.output.write( "%s\n" % data ) + + def setPrefix( self, targetPrefix ): + """set a file prefix for addPackage files""" + self.targetPrefix = targetPrefix + + def doProlog( self ): + self.out( """ """ ) + self.out( "" ) + + def addPackage( self, name, description, dependencies, filenames ): + """add a package to the Makefile""" + if type( filenames ) == type( "" ): + filenames = filenames.split() + fullFilenames = [] + for filename in filenames: + if filename[0] != "$": + fullFilenames.append( "%s%s" % ( self.targetPrefix, filename ) ) + else: + fullFilenames.append( filename ) + self.packages[name] = description, dependencies, fullFilenames + + def doBody( self ): + """generate body of Makefile""" + + global VERSION + + # + # generate rprovides line for native + # + + if self.isNative: + rprovideLine = 'RPROVIDES+="' + for name in sorted(self.packages): + rprovideLine += "%s-native " % name.replace( '${PN}', 'python' ) + rprovideLine += '"' + + self.out( rprovideLine ) + self.out( "" ) + return + + # + # generate provides line + # + + provideLine = 'PROVIDES+="' + for name in sorted(self.packages): + provideLine += "%s " % name + provideLine += '"' + + self.out( provideLine ) + self.out( "" ) + + # + # generate package line + # + + packageLine = 'PACKAGES="${PN}-dbg ' + for name in sorted(self.packages): + if name.startswith("${PN}-distutils"): + if name == "${PN}-distutils": + packageLine += "%s-staticdev %s " % (name, name) + elif name != '${PN}-dbg': + packageLine += "%s " % name + packageLine += '${PN}-modules"' + + self.out( packageLine ) + self.out( "" ) + + # + # generate package variables + # + + for name, data in sorted(self.packages.items()): + desc, deps, files = data + + # + # write out the description, revision and dependencies + # + self.out( 'SUMMARY_%s="%s"' % ( name, desc ) ) + self.out( 'RDEPENDS_%s="%s"' % ( name, deps ) ) + + line = 'FILES_%s="' % name + + # + # check which directories to make in the temporary directory + # + + dirset = {} # if python had a set-datatype this would be sufficient. for now, we're using a dict instead. + for target in files: + dirset[os.path.dirname( target )] = True + + # + # generate which files to copy for the target (-dfR because whole directories are also allowed) + # + + for target in files: + line += "%s " % target + + line += '"' + self.out( line ) + self.out( "" ) + + self.out( 'SUMMARY_${PN}-modules="All Python modules"' ) + line = 'RDEPENDS_${PN}-modules="' + + for name, data in sorted(self.packages.items()): + if name not in ['${PN}-dev', '${PN}-distutils-staticdev']: + line += "%s " % name + + self.out( "%s \"" % line ) + self.out( 'ALLOW_EMPTY_${PN}-modules = "1"' ) + + def doEpilog( self ): + self.out( """""" ) + self.out( "" ) + + def make( self ): + self.doProlog() + self.doBody() + self.doEpilog() + +if __name__ == "__main__": + parser = argparse.ArgumentParser( description='generate python manifest' ) + parser.add_argument( '-n', '--native', help='generate manifest for native python', action='store_true' ) + parser.add_argument( 'outfile', metavar='OUTPUT_FILE', nargs='?', default='', help='Output file (defaults to stdout)' ) + args = parser.parse_args() + + if args.outfile: + try: + os.unlink( args.outfile ) + except Exception: + sys.exc_clear() + outfile = open( args.outfile, "w" ) + else: + outfile = sys.stdout + + m = MakefileMaker( outfile, args.native ) + + # Add packages here. Only specify dlopen-style library dependencies here, no ldd-style dependencies! + # Parameters: revision, name, description, dependencies, filenames + # + + m.addPackage( "${PN}-core", "Python interpreter and core modules", "${PN}-lang ${PN}-re", + "__future__.* _abcoll.* abc.* ast.* copy.* copy_reg.* ConfigParser.* " + + "genericpath.* getopt.* linecache.* new.* " + + "os.* posixpath.* struct.* " + + "warnings.* site.* stat.* " + + "UserDict.* UserList.* UserString.* " + + "lib-dynload/binascii.so lib-dynload/_struct.so lib-dynload/time.so " + + "lib-dynload/xreadlines.so types.* platform.* ${bindir}/python* " + + "_weakrefset.* sysconfig.* _sysconfigdata.* " + + "${includedir}/python${PYTHON_MAJMIN}/pyconfig*.h " + + "${libdir}/python${PYTHON_MAJMIN}/sitecustomize.py ") + + m.addPackage( "${PN}-dev", "Python development package", "${PN}-core", + "${includedir} " + + "${libdir}/lib*${SOLIBSDEV} " + + "${libdir}/*.la " + + "${libdir}/*.a " + + "${libdir}/*.o " + + "${libdir}/pkgconfig " + + "${base_libdir}/*.a " + + "${base_libdir}/*.o " + + "${datadir}/aclocal " + + "${datadir}/pkgconfig " + + "config/Makefile ") + + m.addPackage( "${PN}-2to3", "Python automated Python 2 to 3 code translator", "${PN}-core", + "${bindir}/2to3 lib2to3" ) # package + + m.addPackage( "${PN}-idle", "Python Integrated Development Environment", "${PN}-core ${PN}-tkinter", + "${bindir}/idle idlelib" ) # package + + m.addPackage( "${PN}-pydoc", "Python interactive help support", "${PN}-core ${PN}-lang ${PN}-stringold ${PN}-re", + "${bindir}/pydoc pydoc.* pydoc_data" ) + + m.addPackage( "${PN}-smtpd", "Python Simple Mail Transport Daemon", "${PN}-core ${PN}-netserver ${PN}-email ${PN}-mime", + "${bindir}/smtpd.* smtpd.*" ) + + m.addPackage( "${PN}-audio", "Python Audio Handling", "${PN}-core", + "wave.* chunk.* sndhdr.* lib-dynload/ossaudiodev.so lib-dynload/audioop.so audiodev.* sunaudio.* sunau.* toaiff.*" ) + + m.addPackage( "${PN}-bsddb", "Python bindings for the Berkeley Database", "${PN}-core", + "bsddb lib-dynload/_bsddb.so" ) # package + + m.addPackage( "${PN}-codecs", "Python codecs, encodings & i18n support", "${PN}-core ${PN}-lang", + "codecs.* encodings gettext.* locale.* lib-dynload/_locale.so lib-dynload/_codecs* lib-dynload/_multibytecodec.so lib-dynload/unicodedata.so stringprep.* xdrlib.*" ) + + m.addPackage( "${PN}-compile", "Python bytecode compilation support", "${PN}-core", + "py_compile.* compileall.*" ) + + m.addPackage( "${PN}-compiler", "Python compiler support", "${PN}-core", + "compiler" ) # package + + m.addPackage( "${PN}-compression", "Python high-level compression support", "${PN}-core ${PN}-zlib", + "gzip.* zipfile.* tarfile.* lib-dynload/bz2.so" ) + + m.addPackage( "${PN}-crypt", "Python basic cryptographic and hashing support", "${PN}-core", + "hashlib.* md5.* sha.* lib-dynload/crypt.so lib-dynload/_hashlib.so lib-dynload/_sha256.so lib-dynload/_sha512.so" ) + + m.addPackage( "${PN}-textutils", "Python option parsing, text wrapping and CSV support", "${PN}-core ${PN}-io ${PN}-re ${PN}-stringold", + "lib-dynload/_csv.so csv.* optparse.* textwrap.*" ) + + m.addPackage( "${PN}-curses", "Python curses support", "${PN}-core", + "curses lib-dynload/_curses.so lib-dynload/_curses_panel.so" ) # directory + low level module + + m.addPackage( "${PN}-ctypes", "Python C types support", "${PN}-core", + "ctypes lib-dynload/_ctypes.so lib-dynload/_ctypes_test.so" ) # directory + low level module + + m.addPackage( "${PN}-datetime", "Python calendar and time support", "${PN}-core ${PN}-codecs", + "_strptime.* calendar.* lib-dynload/datetime.so" ) + + m.addPackage( "${PN}-db", "Python file-based database support", "${PN}-core", + "anydbm.* dumbdbm.* whichdb.* " ) + + m.addPackage( "${PN}-debugger", "Python debugger", "${PN}-core ${PN}-io ${PN}-lang ${PN}-re ${PN}-stringold ${PN}-shell ${PN}-pprint", + "bdb.* pdb.*" ) + + m.addPackage( "${PN}-difflib", "Python helpers for computing deltas between objects", "${PN}-lang ${PN}-re", + "difflib.*" ) + + m.addPackage( "${PN}-distutils-staticdev", "Python distribution utilities (static libraries)", "${PN}-distutils", + "config/lib*.a" ) # package + + m.addPackage( "${PN}-distutils", "Python Distribution Utilities", "${PN}-core ${PN}-email", + "config distutils" ) # package + + m.addPackage( "${PN}-doctest", "Python framework for running examples in docstrings", "${PN}-core ${PN}-lang ${PN}-io ${PN}-re ${PN}-unittest ${PN}-debugger ${PN}-difflib", + "doctest.*" ) + + m.addPackage( "${PN}-email", "Python email support", "${PN}-core ${PN}-io ${PN}-re ${PN}-mime ${PN}-audio ${PN}-image ${PN}-netclient", + "imaplib.* email" ) # package + + m.addPackage( "${PN}-fcntl", "Python's fcntl interface", "${PN}-core", + "lib-dynload/fcntl.so" ) + + m.addPackage( "${PN}-hotshot", "Python hotshot performance profiler", "${PN}-core", + "hotshot lib-dynload/_hotshot.so" ) + + m.addPackage( "${PN}-html", "Python HTML processing support", "${PN}-core", + "formatter.* htmlentitydefs.* htmllib.* markupbase.* sgmllib.* HTMLParser.* " ) + + m.addPackage( "${PN}-importlib", "Python import implementation library", "${PN}-core", + "importlib" ) + + m.addPackage( "${PN}-gdbm", "Python GNU database support", "${PN}-core", + "lib-dynload/gdbm.so" ) + + m.addPackage( "${PN}-image", "Python graphical image handling", "${PN}-core", + "colorsys.* imghdr.* lib-dynload/imageop.so lib-dynload/rgbimg.so" ) + + m.addPackage( "${PN}-io", "Python low-level I/O", "${PN}-core ${PN}-math ${PN}-textutils ${PN}-netclient ${PN}-contextlib", + "lib-dynload/_socket.so lib-dynload/_io.so lib-dynload/_ssl.so lib-dynload/select.so lib-dynload/termios.so lib-dynload/cStringIO.so " + + "pipes.* socket.* ssl.* tempfile.* StringIO.* io.* _pyio.*" ) + + m.addPackage( "${PN}-json", "Python JSON support", "${PN}-core ${PN}-math ${PN}-re ${PN}-codecs", + "json lib-dynload/_json.so" ) # package + + m.addPackage( "${PN}-lang", "Python low-level language support", "${PN}-core", + "lib-dynload/_bisect.so lib-dynload/_collections.so lib-dynload/_heapq.so lib-dynload/_weakref.so lib-dynload/_functools.so " + + "lib-dynload/array.so lib-dynload/itertools.so lib-dynload/operator.so lib-dynload/parser.so " + + "atexit.* bisect.* code.* codeop.* collections.* dis.* functools.* heapq.* inspect.* keyword.* opcode.* symbol.* repr.* token.* " + + "tokenize.* traceback.* weakref.*" ) + + m.addPackage( "${PN}-logging", "Python logging support", "${PN}-core ${PN}-io ${PN}-lang ${PN}-pickle ${PN}-stringold", + "logging" ) # package + + m.addPackage( "${PN}-mailbox", "Python mailbox format support", "${PN}-core ${PN}-mime", + "mailbox.*" ) + + m.addPackage( "${PN}-math", "Python math support", "${PN}-core ${PN}-crypt", + "lib-dynload/cmath.so lib-dynload/math.so lib-dynload/_random.so random.* sets.*" ) + + m.addPackage( "${PN}-mime", "Python MIME handling APIs", "${PN}-core ${PN}-io", + "mimetools.* uu.* quopri.* rfc822.* MimeWriter.*" ) + + m.addPackage( "${PN}-mmap", "Python memory-mapped file support", "${PN}-core ${PN}-io", + "lib-dynload/mmap.so " ) + + m.addPackage( "${PN}-multiprocessing", "Python multiprocessing support", "${PN}-core ${PN}-io ${PN}-lang ${PN}-pickle ${PN}-threading ${PN}-ctypes ${PN}-mmap", + "lib-dynload/_multiprocessing.so multiprocessing" ) # package + + m.addPackage( "${PN}-netclient", "Python Internet Protocol clients", "${PN}-core ${PN}-crypt ${PN}-datetime ${PN}-io ${PN}-lang ${PN}-logging ${PN}-mime", + "*Cookie*.* " + + "base64.* cookielib.* ftplib.* gopherlib.* hmac.* httplib.* mimetypes.* nntplib.* poplib.* smtplib.* telnetlib.* urllib.* urllib2.* urlparse.* uuid.* rfc822.* mimetools.*" ) + + m.addPackage( "${PN}-netserver", "Python Internet Protocol servers", "${PN}-core ${PN}-netclient ${PN}-shell ${PN}-threading", + "cgi.* *HTTPServer.* SocketServer.*" ) + + m.addPackage( "${PN}-numbers", "Python number APIs", "${PN}-core ${PN}-lang ${PN}-re", + "decimal.* fractions.* numbers.*" ) + + m.addPackage( "${PN}-pickle", "Python serialisation/persistence support", "${PN}-core ${PN}-codecs ${PN}-io ${PN}-re", + "pickle.* shelve.* lib-dynload/cPickle.so pickletools.*" ) + + m.addPackage( "${PN}-pkgutil", "Python package extension utility support", "${PN}-core", + "pkgutil.*") + + m.addPackage( "${PN}-plistlib", "Generate and parse Mac OS X .plist files", "${PN}-core ${PN}-datetime ${PN}-io", + "plistlib.*") + + m.addPackage( "${PN}-pprint", "Python pretty-print support", "${PN}-core ${PN}-io", + "pprint.*" ) + + m.addPackage( "${PN}-profile", "Python basic performance profiling support", "${PN}-core ${PN}-textutils", + "profile.* pstats.* cProfile.* lib-dynload/_lsprof.so" ) + + m.addPackage( "${PN}-re", "Python Regular Expression APIs", "${PN}-core", + "re.* sre.* sre_compile.* sre_constants* sre_parse.*" ) # _sre is builtin + + m.addPackage( "${PN}-readline", "Python readline support", "${PN}-core", + "lib-dynload/readline.so rlcompleter.*" ) + + m.addPackage( "${PN}-resource", "Python resource control interface", "${PN}-core", + "lib-dynload/resource.so" ) + + m.addPackage( "${PN}-shell", "Python shell-like functionality", "${PN}-core ${PN}-re", + "cmd.* commands.* dircache.* fnmatch.* glob.* popen2.* shlex.* shutil.*" ) + + m.addPackage( "${PN}-robotparser", "Python robots.txt parser", "${PN}-core ${PN}-netclient", + "robotparser.*") + + m.addPackage( "${PN}-subprocess", "Python subprocess support", "${PN}-core ${PN}-io ${PN}-re ${PN}-fcntl ${PN}-pickle", + "subprocess.*" ) + + m.addPackage( "${PN}-sqlite3", "Python Sqlite3 database support", "${PN}-core ${PN}-datetime ${PN}-lang ${PN}-crypt ${PN}-io ${PN}-threading ${PN}-zlib", + "lib-dynload/_sqlite3.so sqlite3/dbapi2.* sqlite3/__init__.* sqlite3/dump.*" ) + + m.addPackage( "${PN}-sqlite3-tests", "Python Sqlite3 database support tests", "${PN}-core ${PN}-sqlite3", + "sqlite3/test" ) + + m.addPackage( "${PN}-stringold", "Python string APIs [deprecated]", "${PN}-core ${PN}-re", + "lib-dynload/strop.so string.* stringold.*" ) + + m.addPackage( "${PN}-syslog", "Python syslog interface", "${PN}-core", + "lib-dynload/syslog.so" ) + + m.addPackage( "${PN}-terminal", "Python terminal controlling support", "${PN}-core ${PN}-io", + "pty.* tty.*" ) + + m.addPackage( "${PN}-tests", "Python tests", "${PN}-core ${PN}-modules", + "test" ) # package + + m.addPackage( "${PN}-threading", "Python threading & synchronization support", "${PN}-core ${PN}-lang", + "_threading_local.* dummy_thread.* dummy_threading.* mutex.* threading.* Queue.*" ) + + m.addPackage( "${PN}-tkinter", "Python Tcl/Tk bindings", "${PN}-core", + "lib-dynload/_tkinter.so lib-tk" ) # package + + m.addPackage( "${PN}-unittest", "Python unit testing framework", "${PN}-core ${PN}-stringold ${PN}-lang ${PN}-io ${PN}-difflib ${PN}-pprint ${PN}-shell", + "unittest/" ) + + m.addPackage( "${PN}-unixadmin", "Python Unix administration support", "${PN}-core", + "lib-dynload/nis.so lib-dynload/grp.so lib-dynload/pwd.so getpass.*" ) + + m.addPackage( "${PN}-xml", "Python basic XML support", "${PN}-core ${PN}-re", + "lib-dynload/_elementtree.so lib-dynload/pyexpat.so xml xmllib.*" ) # package + + m.addPackage( "${PN}-xmlrpc", "Python XML-RPC support", "${PN}-core ${PN}-xml ${PN}-netserver ${PN}-lang", + "xmlrpclib.* SimpleXMLRPCServer.* DocXMLRPCServer.*" ) + + m.addPackage( "${PN}-zlib", "Python zlib compression support", "${PN}-core", + "lib-dynload/zlib.so" ) + + m.addPackage( "${PN}-mailbox", "Python mailbox format support", "${PN}-core ${PN}-mime", + "mailbox.*" ) + + m.addPackage( "${PN}-argparse", "Python command line argument parser", "${PN}-core ${PN}-codecs ${PN}-textutils", + "argparse.*" ) + + m.addPackage( "${PN}-contextlib", "Python utilities for with-statement" + + "contexts.", "${PN}-core", + "${libdir}/python${PYTHON_MAJMIN}/contextlib.*" ) + + m.make() diff --git a/scripts/contrib/python/generate-manifest-3.5.py b/scripts/contrib/python/generate-manifest-3.5.py new file mode 100755 index 0000000000..075860c418 --- /dev/null +++ b/scripts/contrib/python/generate-manifest-3.5.py @@ -0,0 +1,432 @@ +#!/usr/bin/env python + +# generate Python Manifest for the OpenEmbedded build system +# (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> +# (C) 2007 Jeremy Laine +# licensed under MIT, see COPYING.MIT +# +# June 22, 2011 -- Mark Hatle <mark.hatle@windriver.com> +# * Updated to no longer generate special -dbg package, instead use the +# single system -dbg +# * Update version with ".1" to indicate this change +# +# 2014 Khem Raj <raj.khem@gmail.com> +# Added python3 support +# +# February 26, 2017 -- Ming Liu <peter.x.liu@external.atlascopco.com> +# * Updated to support generating manifest for native python3 + +import os +import sys +import time +import argparse + +VERSION = "3.5.0" + +__author__ = "Michael 'Mickey' Lauer <mlauer@vanille-media.de>" +__version__ = "20140131" + +class MakefileMaker: + + def __init__( self, outfile, isNative ): + """initialize""" + self.packages = {} + self.targetPrefix = "${libdir}/python%s/" % VERSION[:3] + self.isNative = isNative + self.output = outfile + self.out( """ +# WARNING: This file is AUTO GENERATED: Manual edits will be lost next time I regenerate the file. +# Generator: '%s%s' Version %s (C) 2002-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de> +""" % ( sys.argv[0], ' --native' if isNative else '', __version__ ) ) + + # + # helper functions + # + + def out( self, data ): + """print a line to the output file""" + self.output.write( "%s\n" % data ) + + def setPrefix( self, targetPrefix ): + """set a file prefix for addPackage files""" + self.targetPrefix = targetPrefix + + def doProlog( self ): + self.out( """ """ ) + self.out( "" ) + + def addPackage( self, name, description, dependencies, filenames ): + """add a package to the Makefile""" + if type( filenames ) == type( "" ): + filenames = filenames.split() + fullFilenames = [] + for filename in filenames: + if filename[0] != "$": + fullFilenames.append( "%s%s" % ( self.targetPrefix, filename ) ) + fullFilenames.append( "%s%s" % ( self.targetPrefix, + self.pycachePath( filename ) ) ) + else: + fullFilenames.append( filename ) + self.packages[name] = description, dependencies, fullFilenames + + def pycachePath( self, filename ): + dirname = os.path.dirname( filename ) + basename = os.path.basename( filename ) + if '.' in basename: + return os.path.join( dirname, '__pycache__', basename ) + else: + return os.path.join( dirname, basename, '__pycache__' ) + + def doBody( self ): + """generate body of Makefile""" + + global VERSION + + # + # generate rprovides line for native + # + + if self.isNative: + rprovideLine = 'RPROVIDES+="' + for name in sorted(self.packages): + rprovideLine += "%s-native " % name.replace( '${PN}', 'python3' ) + rprovideLine += '"' + + self.out( rprovideLine ) + self.out( "" ) + return + + # + # generate provides line + # + + provideLine = 'PROVIDES+="' + for name in sorted(self.packages): + provideLine += "%s " % name + provideLine += '"' + + self.out( provideLine ) + self.out( "" ) + + # + # generate package line + # + + packageLine = 'PACKAGES="${PN}-dbg ' + for name in sorted(self.packages): + if name.startswith("${PN}-distutils"): + if name == "${PN}-distutils": + packageLine += "%s-staticdev %s " % (name, name) + elif name != '${PN}-dbg': + packageLine += "%s " % name + packageLine += '${PN}-modules"' + + self.out( packageLine ) + self.out( "" ) + + # + # generate package variables + # + + for name, data in sorted(self.packages.items()): + desc, deps, files = data + + # + # write out the description, revision and dependencies + # + self.out( 'SUMMARY_%s="%s"' % ( name, desc ) ) + self.out( 'RDEPENDS_%s="%s"' % ( name, deps ) ) + + line = 'FILES_%s="' % name + + # + # check which directories to make in the temporary directory + # + + dirset = {} # if python had a set-datatype this would be sufficient. for now, we're using a dict instead. + for target in files: + dirset[os.path.dirname( target )] = True + + # + # generate which files to copy for the target (-dfR because whole directories are also allowed) + # + + for target in files: + line += "%s " % target + + line += '"' + self.out( line ) + self.out( "" ) + + self.out( 'SUMMARY_${PN}-modules="All Python modules"' ) + line = 'RDEPENDS_${PN}-modules="' + + for name, data in sorted(self.packages.items()): + if name not in ['${PN}-dev', '${PN}-distutils-staticdev']: + line += "%s " % name + + self.out( "%s \"" % line ) + self.out( 'ALLOW_EMPTY_${PN}-modules = "1"' ) + + def doEpilog( self ): + self.out( """""" ) + self.out( "" ) + + def make( self ): + self.doProlog() + self.doBody() + self.doEpilog() + +if __name__ == "__main__": + parser = argparse.ArgumentParser( description='generate python3 manifest' ) + parser.add_argument( '-n', '--native', help='generate manifest for native python3', action='store_true' ) + parser.add_argument( 'outfile', metavar='OUTPUT_FILE', nargs='?', default='', help='Output file (defaults to stdout)' ) + args = parser.parse_args() + + if args.outfile: + try: + os.unlink( args.outfile ) + except Exception: + sys.exc_clear() + outfile = open( args.outfile, "w" ) + else: + outfile = sys.stdout + + m = MakefileMaker( outfile, args.native ) + + # Add packages here. Only specify dlopen-style library dependencies here, no ldd-style dependencies! + # Parameters: revision, name, description, dependencies, filenames + # + + m.addPackage( "${PN}-core", "Python interpreter and core modules", "${PN}-lang ${PN}-re ${PN}-reprlib ${PN}-codecs ${PN}-io ${PN}-math", + "__future__.* _abcoll.* abc.* ast.* copy.* copyreg.* configparser.* " + + "genericpath.* getopt.* linecache.* new.* " + + "os.* posixpath.* struct.* " + + "warnings.* site.* stat.* " + + "UserDict.* UserList.* UserString.* " + + "lib-dynload/binascii.*.so lib-dynload/_struct.*.so lib-dynload/time.*.so " + + "lib-dynload/xreadlines.*.so types.* platform.* ${bindir}/python* " + + "_weakrefset.* sysconfig.* _sysconfigdata.* " + + "${includedir}/python${PYTHON_BINABI}/pyconfig*.h " + + "${libdir}/python${PYTHON_MAJMIN}/collections " + + "${libdir}/python${PYTHON_MAJMIN}/_collections_abc.* " + + "${libdir}/python${PYTHON_MAJMIN}/_sitebuiltins.* " + + "${libdir}/python${PYTHON_MAJMIN}/sitecustomize.py ") + + m.addPackage( "${PN}-dev", "Python development package", "${PN}-core", + "${includedir} " + + "${libdir}/lib*${SOLIBSDEV} " + + "${libdir}/*.la " + + "${libdir}/*.a " + + "${libdir}/*.o " + + "${libdir}/pkgconfig " + + "${base_libdir}/*.a " + + "${base_libdir}/*.o " + + "${datadir}/aclocal " + + "${datadir}/pkgconfig " + + "config/Makefile ") + + m.addPackage( "${PN}-2to3", "Python automated Python 2 to 3 code translator", "${PN}-core", + "lib2to3" ) # package + + m.addPackage( "${PN}-idle", "Python Integrated Development Environment", "${PN}-core ${PN}-tkinter", + "${bindir}/idle idlelib" ) # package + + m.addPackage( "${PN}-pydoc", "Python interactive help support", "${PN}-core ${PN}-lang ${PN}-stringold ${PN}-re", + "${bindir}/pydoc pydoc.* pydoc_data" ) + + m.addPackage( "${PN}-smtpd", "Python Simple Mail Transport Daemon", "${PN}-core ${PN}-netserver ${PN}-email ${PN}-mime", + "${bindir}/smtpd.* smtpd.*" ) + + m.addPackage( "${PN}-audio", "Python Audio Handling", "${PN}-core", + "wave.* chunk.* sndhdr.* lib-dynload/ossaudiodev.*.so lib-dynload/audioop.*.so audiodev.* sunaudio.* sunau.* toaiff.*" ) + + m.addPackage( "${PN}-argparse", "Python command line argument parser", "${PN}-core ${PN}-codecs ${PN}-textutils", + "argparse.*" ) + + m.addPackage( "${PN}-asyncio", "Python Asynchronous I/O, event loop, coroutines and tasks", "${PN}-core", + "asyncio" ) + + m.addPackage( "${PN}-codecs", "Python codecs, encodings & i18n support", "${PN}-core ${PN}-lang", + "codecs.* encodings gettext.* locale.* lib-dynload/_locale.*.so lib-dynload/_codecs* lib-dynload/_multibytecodec.*.so lib-dynload/unicodedata.*.so stringprep.* xdrlib.*" ) + + m.addPackage( "${PN}-compile", "Python bytecode compilation support", "${PN}-core", + "py_compile.* compileall.*" ) + + m.addPackage( "${PN}-compression", "Python high-level compression support", "${PN}-core ${PN}-codecs ${PN}-importlib ${PN}-threading ${PN}-shell", + "gzip.* zipfile.* tarfile.* lib-dynload/bz2.*.so lib-dynload/zlib.*.so" ) + + m.addPackage( "${PN}-crypt", "Python basic cryptographic and hashing support", "${PN}-core", + "hashlib.* md5.* sha.* lib-dynload/crypt.*.so lib-dynload/_hashlib.*.so lib-dynload/_sha256.*.so lib-dynload/_sha512.*.so" ) + + m.addPackage( "${PN}-textutils", "Python option parsing, text wrapping and CSV support", "${PN}-core ${PN}-io ${PN}-re ${PN}-stringold", + "lib-dynload/_csv.*.so csv.* optparse.* textwrap.*" ) + + m.addPackage( "${PN}-curses", "Python curses support", "${PN}-core", + "curses lib-dynload/_curses.*.so lib-dynload/_curses_panel.*.so" ) # directory + low level module + + m.addPackage( "${PN}-ctypes", "Python C types support", "${PN}-core ${PN}-subprocess", + "ctypes lib-dynload/_ctypes.*.so lib-dynload/_ctypes_test.*.so" ) # directory + low level module + + m.addPackage( "${PN}-datetime", "Python calendar and time support", "${PN}-core ${PN}-codecs", + "_strptime.* calendar.* datetime.* lib-dynload/_datetime.*.so" ) + + m.addPackage( "${PN}-db", "Python file-based database support", "${PN}-core", + "anydbm.* dumbdbm.* whichdb.* dbm lib-dynload/_dbm.*.so" ) + + m.addPackage( "${PN}-debugger", "Python debugger", "${PN}-core ${PN}-io ${PN}-lang ${PN}-re ${PN}-stringold ${PN}-shell ${PN}-pprint ${PN}-importlib ${PN}-pkgutil", + "bdb.* pdb.*" ) + + m.addPackage( "${PN}-difflib", "Python helpers for computing deltas between objects", "${PN}-lang ${PN}-re", + "difflib.*" ) + + m.addPackage( "${PN}-distutils-staticdev", "Python distribution utilities (static libraries)", "${PN}-distutils", + "config/lib*.a" ) # package + + m.addPackage( "${PN}-distutils", "Python Distribution Utilities", "${PN}-core ${PN}-email", + "config distutils" ) # package + + m.addPackage( "${PN}-doctest", "Python framework for running examples in docstrings", "${PN}-core ${PN}-lang ${PN}-io ${PN}-re ${PN}-unittest ${PN}-debugger ${PN}-difflib", + "doctest.*" ) + + m.addPackage( "${PN}-email", "Python email support", "${PN}-core ${PN}-io ${PN}-re ${PN}-mime ${PN}-audio ${PN}-image ${PN}-netclient", + "imaplib.* email" ) # package + + m.addPackage( "${PN}-enum", "Python support for enumerations", "${PN}-core", + "enum.*" ) + + m.addPackage( "${PN}-fcntl", "Python's fcntl interface", "${PN}-core", + "lib-dynload/fcntl.*.so" ) + + m.addPackage( "${PN}-html", "Python HTML processing support", "${PN}-core", + "formatter.* htmlentitydefs.* html htmllib.* markupbase.* sgmllib.* HTMLParser.* " ) + + m.addPackage( "${PN}-importlib", "Python import implementation library", "${PN}-core ${PN}-lang", + "importlib imp.*" ) + + m.addPackage( "${PN}-gdbm", "Python GNU database support", "${PN}-core", + "lib-dynload/_gdbm.*.so" ) + + m.addPackage( "${PN}-image", "Python graphical image handling", "${PN}-core", + "colorsys.* imghdr.* lib-dynload/imageop.*.so lib-dynload/rgbimg.*.so" ) + + m.addPackage( "${PN}-io", "Python low-level I/O", "${PN}-core ${PN}-math", + "lib-dynload/_socket.*.so lib-dynload/_io.*.so lib-dynload/_ssl.*.so lib-dynload/select.*.so lib-dynload/termios.*.so lib-dynload/cStringIO.*.so " + + "ipaddress.* pipes.* socket.* ssl.* tempfile.* StringIO.* io.* _pyio.*" ) + + m.addPackage( "${PN}-json", "Python JSON support", "${PN}-core ${PN}-math ${PN}-re", + "json lib-dynload/_json.*.so" ) # package + + m.addPackage( "${PN}-lang", "Python low-level language support", "${PN}-core ${PN}-importlib", + "lib-dynload/_bisect.*.so lib-dynload/_collections.*.so lib-dynload/_heapq.*.so lib-dynload/_weakref.*.so lib-dynload/_functools.*.so " + + "lib-dynload/array.*.so lib-dynload/itertools.*.so lib-dynload/operator.*.so lib-dynload/parser.*.so " + + "atexit.* bisect.* code.* codeop.* collections.* _collections_abc.* contextlib.* dis.* functools.* heapq.* inspect.* keyword.* opcode.* operator.* symbol.* repr.* token.* " + + "tokenize.* traceback.* weakref.*" ) + + m.addPackage( "${PN}-logging", "Python logging support", "${PN}-core ${PN}-io ${PN}-lang ${PN}-pickle ${PN}-stringold", + "logging" ) # package + + m.addPackage( "${PN}-mailbox", "Python mailbox format support", "${PN}-core ${PN}-mime", + "mailbox.*" ) + + m.addPackage( "${PN}-math", "Python math support", "${PN}-core ${PN}-crypt", + "lib-dynload/cmath.*.so lib-dynload/math.*.so lib-dynload/_random.*.so random.* sets.*" ) + + m.addPackage( "${PN}-mime", "Python MIME handling APIs", "${PN}-core ${PN}-io", + "mimetools.* uu.* quopri.* rfc822.* MimeWriter.*" ) + + m.addPackage( "${PN}-mmap", "Python memory-mapped file support", "${PN}-core ${PN}-io", + "lib-dynload/mmap.*.so " ) + + m.addPackage( "${PN}-multiprocessing", "Python multiprocessing support", "${PN}-core ${PN}-io ${PN}-lang ${PN}-pickle ${PN}-threading ${PN}-ctypes ${PN}-mmap", + "lib-dynload/_multiprocessing.*.so multiprocessing" ) # package + + m.addPackage( "${PN}-netclient", "Python Internet Protocol clients", "${PN}-argparse ${PN}-core ${PN}-crypt ${PN}-datetime ${PN}-io ${PN}-lang ${PN}-logging ${PN}-mime ${PN}-html", + "*Cookie*.* " + + "base64.* cookielib.* ftplib.* gopherlib.* hmac.* http* httplib.* mimetypes.* nntplib.* poplib.* smtplib.* telnetlib.* urllib uuid.* rfc822.* mimetools.*" ) + + m.addPackage( "${PN}-netserver", "Python Internet Protocol servers", "${PN}-core ${PN}-netclient ${PN}-shell ${PN}-threading", + "cgi.* socketserver.* *HTTPServer.* SocketServer.*" ) + + m.addPackage( "${PN}-numbers", "Python number APIs", "${PN}-core ${PN}-lang ${PN}-re", + "decimal.* fractions.* numbers.*" ) + + m.addPackage( "${PN}-pickle", "Python serialisation/persistence support", "${PN}-core ${PN}-codecs ${PN}-io ${PN}-re", + "_compat_pickle.* pickle.* shelve.* lib-dynload/cPickle.*.so pickletools.*" ) + + m.addPackage( "${PN}-pkgutil", "Python package extension utility support", "${PN}-core", + "pkgutil.*") + + m.addPackage( "${PN}-pprint", "Python pretty-print support", "${PN}-core ${PN}-io", + "pprint.*" ) + + m.addPackage( "${PN}-profile", "Python basic performance profiling support", "${PN}-core ${PN}-textutils", + "profile.* pstats.* cProfile.* lib-dynload/_lsprof.*.so" ) + + m.addPackage( "${PN}-re", "Python Regular Expression APIs", "${PN}-core", + "re.* sre.* sre_compile.* sre_constants* sre_parse.*" ) # _sre is builtin + + m.addPackage( "${PN}-readline", "Python readline support", "${PN}-core", + "lib-dynload/readline.*.so rlcompleter.*" ) + + m.addPackage( "${PN}-reprlib", "Python alternate repr() implementation", "${PN}-core", + "reprlib.py" ) + + m.addPackage( "${PN}-resource", "Python resource control interface", "${PN}-core", + "lib-dynload/resource.*.so" ) + + m.addPackage( "${PN}-selectors", "Python High-level I/O multiplexing", "${PN}-core", + "selectors.*" ) + + m.addPackage( "${PN}-shell", "Python shell-like functionality", "${PN}-core ${PN}-re ${PN}-compression", + "cmd.* commands.* dircache.* fnmatch.* glob.* popen2.* shlex.* shutil.*" ) + + m.addPackage( "${PN}-signal", "Python set handlers for asynchronous events support", "${PN}-core ${PN}-enum", + "signal.*" ) + + m.addPackage( "${PN}-subprocess", "Python subprocess support", "${PN}-core ${PN}-io ${PN}-re ${PN}-fcntl ${PN}-pickle ${PN}-threading ${PN}-signal ${PN}-selectors", + "subprocess.* lib-dynload/_posixsubprocess.*.so" ) + + m.addPackage( "${PN}-sqlite3", "Python Sqlite3 database support", "${PN}-core ${PN}-datetime ${PN}-lang ${PN}-crypt ${PN}-io ${PN}-threading", + "lib-dynload/_sqlite3.*.so sqlite3/dbapi2.* sqlite3/__init__.* sqlite3/dump.*" ) + + m.addPackage( "${PN}-sqlite3-tests", "Python Sqlite3 database support tests", "${PN}-core ${PN}-sqlite3", + "sqlite3/test" ) + + m.addPackage( "${PN}-stringold", "Python string APIs [deprecated]", "${PN}-core ${PN}-re", + "lib-dynload/strop.*.so string.* stringold.*" ) + + m.addPackage( "${PN}-syslog", "Python syslog interface", "${PN}-core", + "lib-dynload/syslog.*.so" ) + + m.addPackage( "${PN}-terminal", "Python terminal controlling support", "${PN}-core ${PN}-io", + "pty.* tty.*" ) + + m.addPackage( "${PN}-tests", "Python tests", "${PN}-core", + "test" ) # package + + m.addPackage( "${PN}-threading", "Python threading & synchronization support", "${PN}-core ${PN}-lang", + "_threading_local.* dummy_thread.* dummy_threading.* mutex.* threading.* queue.*" ) + + m.addPackage( "${PN}-tkinter", "Python Tcl/Tk bindings", "${PN}-core", + "lib-dynload/_tkinter.*.so lib-tk tkinter" ) # package + + m.addPackage( "${PN}-typing", "Python typing support", "${PN}-core", + "typing.*" ) + + m.addPackage( "${PN}-unittest", "Python unit testing framework", "${PN}-core ${PN}-stringold ${PN}-lang ${PN}-io ${PN}-difflib ${PN}-pprint ${PN}-shell", + "unittest/" ) + + m.addPackage( "${PN}-unixadmin", "Python Unix administration support", "${PN}-core", + "lib-dynload/nis.*.so lib-dynload/grp.*.so lib-dynload/pwd.*.so getpass.*" ) + + m.addPackage( "${PN}-xml", "Python basic XML support", "${PN}-core ${PN}-re", + "lib-dynload/_elementtree.*.so lib-dynload/pyexpat.*.so xml xmllib.*" ) # package + + m.addPackage( "${PN}-xmlrpc", "Python XML-RPC support", "${PN}-core ${PN}-xml ${PN}-netserver ${PN}-lang ${PN}-pydoc", + "xmlrpclib.* SimpleXMLRPCServer.* DocXMLRPCServer.* xmlrpc" ) + + m.addPackage( "${PN}-mailbox", "Python mailbox format support", "${PN}-core ${PN}-mime", + "mailbox.*" ) + + m.make() diff --git a/scripts/contrib/serdevtry b/scripts/contrib/serdevtry new file mode 100755 index 0000000000..74bd7b7161 --- /dev/null +++ b/scripts/contrib/serdevtry @@ -0,0 +1,60 @@ +#!/bin/sh + +# Copyright (C) 2014 Intel Corporation +# +# Released under the MIT license (see COPYING.MIT) + +if [ "$1" = "" -o "$1" = "--help" ] ; then + echo "Usage: $0 <serial terminal command>" + echo + echo "Simple script to handle maintaining a terminal for serial devices that" + echo "disappear when a device is powered down or reset, such as the USB" + echo "serial console on the original BeagleBone (white version)." + echo + echo "e.g. $0 picocom -b 115200 /dev/ttyUSB0" + echo + exit +fi + +args="$@" +DEVICE="" +while [ "$1" != "" ]; do + case "$1" in + /dev/*) + DEVICE=$1 + break;; + esac + shift +done + +if [ "$DEVICE" != "" ] ; then + while true; do + if [ ! -e $DEVICE ] ; then + echo "serdevtry: waiting for $DEVICE to exist..." + while [ ! -e $DEVICE ]; do + sleep 0.1 + done + fi + if [ ! -w $DEVICE ] ; then + # Sometimes (presumably because of a race with udev) we get to + # the device before its permissions have been set up + RETRYNUM=0 + while [ ! -w $DEVICE ]; do + if [ "$RETRYNUM" = "2" ] ; then + echo "Device $DEVICE exists but is not writable!" + exit 1 + fi + RETRYNUM=$((RETRYNUM+1)) + sleep 0.1 + done + fi + $args + if [ -e $DEVICE ] ; then + break + fi + done +else + echo "Unable to determine device node from command: $args" + exit 1 +fi + diff --git a/scripts/contrib/test_build_time.sh b/scripts/contrib/test_build_time.sh new file mode 100755 index 0000000000..9e5725ae54 --- /dev/null +++ b/scripts/contrib/test_build_time.sh @@ -0,0 +1,237 @@ +#!/bin/bash + +# Build performance regression test script +# +# Copyright 2011 Intel Corporation +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# DESCRIPTION +# This script is intended to be used in conjunction with "git bisect run" +# in order to find regressions in build time, however it can also be used +# independently. It cleans out the build output directories, runs a +# specified worker script (an example is test_build_time_worker.sh) under +# TIME(1), logs the results to TEST_LOGDIR (default /tmp) and returns a +# value telling "git bisect run" whether the build time is good (under +# the specified threshold) or bad (over it). There is also a tolerance +# option but it is not particularly useful as it only subtracts the +# tolerance from the given threshold and uses it as the actual threshold. +# +# It is also capable of taking a file listing git revision hashes to be +# test-applied to the repository in order to get past build failures that +# would otherwise cause certain revisions to have to be skipped; if a +# revision does not apply cleanly then the script assumes it does not +# need to be applied and ignores it. +# +# Please see the help output (syntax below) for some important setup +# instructions. +# +# AUTHORS +# Paul Eggleton <paul.eggleton@linux.intel.com> + + +syntax() { + echo "syntax: $0 <script> <time> <tolerance> [patchrevlist]" + echo "" + echo " script - worker script file (if in current dir, prefix with ./)" + echo " time - time threshold (in seconds, suffix m for minutes)" + echo " tolerance - tolerance (in seconds, suffix m for minutes or % for" + echo " percentage, can be 0)" + echo " patchrevlist - optional file listing revisions to apply as patches on top" + echo "" + echo "You must set TEST_BUILDDIR to point to a previously created build directory," + echo "however please note that this script will wipe out the TMPDIR defined in" + echo "TEST_BUILDDIR/conf/local.conf as part of its initial setup (as well as your" + echo "~/.ccache)" + echo "" + echo "To get rid of the sudo prompt, please add the following line to /etc/sudoers" + echo "(use 'visudo' to edit this; also it is assumed that the user you are running" + echo "as is a member of the 'wheel' group):" + echo "" + echo "%wheel ALL=(ALL) NOPASSWD: /sbin/sysctl -w vm.drop_caches=[1-3]" + echo "" + echo "Note: it is recommended that you disable crond and any other process that" + echo "may cause significant CPU or I/O usage during build performance tests." +} + +# Note - we exit with 250 here because that will tell git bisect run that +# something bad happened and stop +if [ "$1" = "" ] ; then + syntax + exit 250 +fi + +if [ "$2" = "" ] ; then + syntax + exit 250 +fi + +if [ "$3" = "" ] ; then + syntax + exit 250 +fi + +if ! [[ "$2" =~ ^[0-9][0-9m.]*$ ]] ; then + echo "'$2' is not a valid number for threshold" + exit 250 +fi + +if ! [[ "$3" =~ ^[0-9][0-9m.%]*$ ]] ; then + echo "'$3' is not a valid number for tolerance" + exit 250 +fi + +if [ "$TEST_BUILDDIR" = "" ] ; then + echo "Please set TEST_BUILDDIR to a previously created build directory" + exit 250 +fi + +if [ ! -d "$TEST_BUILDDIR" ] ; then + echo "TEST_BUILDDIR $TEST_BUILDDIR not found" + exit 250 +fi + +git diff --quiet +if [ $? != 0 ] ; then + echo "Working tree is dirty, cannot proceed" + exit 251 +fi + +if [ "$BB_ENV_EXTRAWHITE" != "" ] ; then + echo "WARNING: you are running after sourcing the build environment script, this is not recommended" +fi + +runscript=$1 +timethreshold=$2 +tolerance=$3 + +if [ "$4" != "" ] ; then + patchrevlist=`cat $4` +else + patchrevlist="" +fi + +if [[ timethreshold == *m* ]] ; then + timethreshold=`echo $timethreshold | sed s/m/*60/ | bc` +fi + +if [[ $tolerance == *m* ]] ; then + tolerance=`echo $tolerance | sed s/m/*60/ | bc` +elif [[ $tolerance == *%* ]] ; then + tolerance=`echo $tolerance | sed s/%//` + tolerance=`echo "scale = 2; (($tolerance * $timethreshold) / 100)" | bc` +fi + +tmpdir=`grep "^TMPDIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/TMPDIR[ \t]*=[ \t\?]*"//' -e 's/"//'` +if [ "x$tmpdir" = "x" ]; then + echo "Unable to determine TMPDIR from $TEST_BUILDDIR/conf/local.conf, bailing out" + exit 250 +fi +sstatedir=`grep "^SSTATE_DIR" $TEST_BUILDDIR/conf/local.conf | sed -e 's/SSTATE_DIR[ \t\?]*=[ \t]*"//' -e 's/"//'` +if [ "x$sstatedir" = "x" ]; then + echo "Unable to determine SSTATE_DIR from $TEST_BUILDDIR/conf/local.conf, bailing out" + exit 250 +fi + +if [ `expr length $tmpdir` -lt 4 ] ; then + echo "TMPDIR $tmpdir is less than 4 characters, bailing out" + exit 250 +fi + +if [ `expr length $sstatedir` -lt 4 ] ; then + echo "SSTATE_DIR $sstatedir is less than 4 characters, bailing out" + exit 250 +fi + +echo -n "About to wipe out TMPDIR $tmpdir, press Ctrl+C to break out... " +for i in 9 8 7 6 5 4 3 2 1 +do + echo -ne "\x08$i" + sleep 1 +done +echo + +pushd . > /dev/null + +rm -f pseudodone +echo "Removing TMPDIR $tmpdir..." +rm -rf $tmpdir +echo "Removing TMPDIR $tmpdir-*libc..." +rm -rf $tmpdir-*libc +echo "Removing SSTATE_DIR $sstatedir..." +rm -rf $sstatedir +echo "Removing ~/.ccache..." +rm -rf ~/.ccache + +echo "Syncing..." +sync +sync +echo "Dropping VM cache..." +#echo 3 > /proc/sys/vm/drop_caches +sudo /sbin/sysctl -w vm.drop_caches=3 > /dev/null + +if [ "$TEST_LOGDIR" = "" ] ; then + logdir="/tmp" +else + logdir="$TEST_LOGDIR" +fi +rev=`git rev-parse HEAD` +logfile="$logdir/timelog_$rev.log" +echo -n > $logfile + +gitroot=`git rev-parse --show-toplevel` +cd $gitroot +for patchrev in $patchrevlist ; do + echo "Applying $patchrev" + patchfile=`mktemp` + git show $patchrev > $patchfile + git apply --check $patchfile &> /dev/null + if [ $? != 0 ] ; then + echo " ... patch does not apply without errors, ignoring" + else + echo "Applied $patchrev" >> $logfile + git apply $patchfile &> /dev/null + fi + rm $patchfile +done + +sync +echo "Quiescing for 5s..." +sleep 5 + +echo "Running $runscript at $rev..." +timeoutfile=`mktemp` +/usr/bin/time -o $timeoutfile -f "%e\nreal\t%E\nuser\t%Us\nsys\t%Ss\nmaxm\t%Mk" $runscript 2>&1 | tee -a $logfile +exitstatus=$PIPESTATUS + +git reset --hard HEAD > /dev/null +popd > /dev/null + +timeresult=`head -n1 $timeoutfile` +cat $timeoutfile | tee -a $logfile +rm $timeoutfile + +if [ $exitstatus != 0 ] ; then + # Build failed, exit with 125 to tell git bisect run to skip this rev + echo "*** Build failed (exit code $exitstatus), skipping..." | tee -a $logfile + exit 125 +fi + +ret=`echo "scale = 2; $timeresult > $timethreshold - $tolerance" | bc` +echo "Returning $ret" | tee -a $logfile +exit $ret + diff --git a/scripts/contrib/test_build_time_worker.sh b/scripts/contrib/test_build_time_worker.sh new file mode 100755 index 0000000000..8e20a9ea7d --- /dev/null +++ b/scripts/contrib/test_build_time_worker.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# This is an example script to be used in conjunction with test_build_time.sh + +if [ "$TEST_BUILDDIR" = "" ] ; then + echo "TEST_BUILDDIR is not set" + exit 1 +fi + +buildsubdir=`basename $TEST_BUILDDIR` +if [ ! -d $buildsubdir ] ; then + echo "Unable to find build subdir $buildsubdir in current directory" + exit 1 +fi + +if [ -f oe-init-build-env ] ; then + . ./oe-init-build-env $buildsubdir +elif [ -f poky-init-build-env ] ; then + . ./poky-init-build-env $buildsubdir +else + echo "Unable to find build environment setup script" + exit 1 +fi + +if [ -f ../meta/recipes-sato/images/core-image-sato.bb ] ; then + target="core-image-sato" +else + target="poky-image-sato" +fi + +echo "Build started at `date "+%Y-%m-%d %H:%M:%S"`" +echo "bitbake $target" +bitbake $target +ret=$? +echo "Build finished at `date "+%Y-%m-%d %H:%M:%S"`" +exit $ret + diff --git a/scripts/contrib/uncovered b/scripts/contrib/uncovered new file mode 100755 index 0000000000..a8399ad170 --- /dev/null +++ b/scripts/contrib/uncovered @@ -0,0 +1,39 @@ +#!/bin/bash -eur +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +# +# Find python modules uncovered by oe-seltest +# +# Copyright (c) 2016, Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Author: Ed Bartosh <ed.bartosh@linux.intel.com> +# + +if [ ! "$#" -eq 1 -o -t 0 ] ; then + echo 'Usage: coverage report | ./scripts/contrib/uncovered <dir>' 1>&2 + exit 1 +fi + +path=$(readlink -ev $1) + +if [ ! -d "$path" ] ; then + echo "directory $1 doesn't exist" 1>&2 + exit 1 +fi + +diff -u <(grep "$path" | grep -v '0%$' | cut -f1 -d: | sort) \ + <(find $path | xargs file | grep 'Python script' | cut -f1 -d:| sort) | \ + grep "^+$path" | cut -c2- diff --git a/scripts/contrib/verify-homepage.py b/scripts/contrib/verify-homepage.py new file mode 100755 index 0000000000..76f1749cfa --- /dev/null +++ b/scripts/contrib/verify-homepage.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +# This script can be used to verify HOMEPAGE values for all recipes in +# the current configuration. +# The result is influenced by network environment, since the timeout of connect url is 5 seconds as default. + +import sys +import os +import subprocess +import urllib.request + + +# Allow importing scripts/lib modules +scripts_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/..') +lib_path = scripts_path + '/lib' +sys.path = sys.path + [lib_path] +import scriptpath +import scriptutils + +# Allow importing bitbake modules +bitbakepath = scriptpath.add_bitbake_lib_path() + +import bb.tinfoil + +logger = scriptutils.logger_create('verify_homepage') + +def wgetHomepage(pn, homepage): + result = subprocess.call('wget ' + '-q -T 5 -t 1 --spider ' + homepage, shell = True) + if result: + logger.warn("%s: failed to verify HOMEPAGE: %s " % (pn, homepage)) + return 1 + else: + return 0 + +def verifyHomepage(bbhandler): + pkg_pn = bbhandler.cooker.recipecaches[''].pkg_pn + pnlist = sorted(pkg_pn) + count = 0 + checked = [] + for pn in pnlist: + for fn in pkg_pn[pn]: + # There's no point checking multiple BBCLASSEXTENDed variants of the same recipe + realfn, _, _ = bb.cache.virtualfn2realfn(fn) + if realfn in checked: + continue + data = bbhandler.parse_recipe_file(realfn) + homepage = data.getVar("HOMEPAGE") + if homepage: + try: + urllib.request.urlopen(homepage, timeout=5) + except Exception: + count = count + wgetHomepage(os.path.basename(realfn), homepage) + checked.append(realfn) + return count + +if __name__=='__main__': + with bb.tinfoil.Tinfoil() as bbhandler: + bbhandler.prepare() + logger.info("Start verifying HOMEPAGE:") + failcount = verifyHomepage(bbhandler) + logger.info("Finished verifying HOMEPAGE.") + logger.info("Summary: %s failed" % failcount) |
