blob: 135b4cf3553eb50995ea63dfa9b23599ae54e2a9 [file] [log] [blame]
#
# Copyright (c) 2021 Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#!/usr/bin/env bash
set -euo pipefail
# Overview
# ========
#
# This script generates source lines of code as a tab separated values (TSV)
# file and a stacked bar chart. It uses `tokei` for gathering the data, and
# `gnuplot` for generating the plot. The data is available on stderr and the
# plot will be put in stdout.
#
# This script generates information about the directory that it's run in,
# aggregated by subdirectory.
# It is recommended that you run it from within the TF-A root directory for
# best results.
# Variables
# =========
# convert newlines to tabs
n2t="tr \n \t"
# We will build the final data file incrementally throughout the script. We need
# A place to store this data, temporarily, so mktemp fills the role.
data=$(mktemp XXXXXX-sloc.tsv)
# Top level TF-A directories that we consider by themselves.
toplevel=$(find -mindepth 1 -maxdepth 1 -type d -and ! -name ".*" | sed "s|./||g")
# Second level TF-A directories that we consider separately.
secondlevel=$(find drivers plat -mindepth 1 -maxdepth 1 -type d || true)
# We want to be sure that we always put the data in the same order, with the
# same keys in the resulting TSV file. To ensure this, we keep a json-encoded
# array of the categories we would like to show in the graph.
# This was generated by taking the output of `tokei --output json | jq keys`
# and trimming out things that we don't really need like "Svg"
categories='["AssemblyGAS", "C", "CHeader", "DeviceTree", "Makefile", "Python", "ReStructuredText"]'
# Data File Generation
# ====================
#
# Below we generate the data file used for the graph. The table is a
# tab separated value(TSV) matrix with columns of code language (Bash, C, etc),
# and rows of subdirectories of TF-A that contain the code.
# Column headers
# --------------
(echo module; echo $categories | jq ".[]" ) | $n2t > $data
# add a newline
echo >> $data
# Build Each Row
# --------------
for dir in $toplevel $secondlevel; do
# Gnuplot likes to treat underscores as a syntax for subscripts. This
# looks weird, as module names are not named with this syntax in mind.
# Further, it turns out that we go through 3 expansions, so we need 8 (2^3)
# backslashes.
echo $dir | sed -e "s/_/\\\\\\\\_/g" | $n2t >> $data
# This is the heart of the implementation, and probably the most
# complicated line in this script. First, we generate the subdirectory
# sloc with tokei, in json format. We then filter it with jq. The jq
# filter is a foreach loop where we iterate over $x = column name, as
# passed in as the first positional argument. Each interation through
# the loop, we print out the code value, when it exists, or null + 0.
# This takes advantage of the property of null:
# > null can be added to any value, and returns the other value
# > unchanged.
tokei --output json $dir \
| jq '$ARGS.positional[0][] as $x | .[$x].code + 0' \
--jsonargs "$categories" \
| $n2t >> $data
echo >> $data
done
cat $data 1>&2
gnuplot -c ${0%bash}plot $data
rm $data