blob: 135b4cf3553eb50995ea63dfa9b23599ae54e2a9 [file] [log] [blame]
Jimmy Brissonc7e28f52021-01-21 16:23:21 -06001#
2# Copyright (c) 2021 Arm Limited. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#!/usr/bin/env bash
7set -euo pipefail
8
9# Overview
10# ========
11#
12# This script generates source lines of code as a tab separated values (TSV)
13# file and a stacked bar chart. It uses `tokei` for gathering the data, and
14# `gnuplot` for generating the plot. The data is available on stderr and the
15# plot will be put in stdout.
16#
17# This script generates information about the directory that it's run in,
18# aggregated by subdirectory.
19# It is recommended that you run it from within the TF-A root directory for
20# best results.
21
22# Variables
23# =========
24
25# convert newlines to tabs
26n2t="tr \n \t"
27
28# We will build the final data file incrementally throughout the script. We need
29# A place to store this data, temporarily, so mktemp fills the role.
30data=$(mktemp XXXXXX-sloc.tsv)
31
32# Top level TF-A directories that we consider by themselves.
33toplevel=$(find -mindepth 1 -maxdepth 1 -type d -and ! -name ".*" | sed "s|./||g")
34
35# Second level TF-A directories that we consider separately.
36secondlevel=$(find drivers plat -mindepth 1 -maxdepth 1 -type d || true)
37
38# We want to be sure that we always put the data in the same order, with the
39# same keys in the resulting TSV file. To ensure this, we keep a json-encoded
40# array of the categories we would like to show in the graph.
41# This was generated by taking the output of `tokei --output json | jq keys`
42# and trimming out things that we don't really need like "Svg"
43categories='["AssemblyGAS", "C", "CHeader", "DeviceTree", "Makefile", "Python", "ReStructuredText"]'
44
45# Data File Generation
46# ====================
47#
48# Below we generate the data file used for the graph. The table is a
49# tab separated value(TSV) matrix with columns of code language (Bash, C, etc),
50# and rows of subdirectories of TF-A that contain the code.
51
52# Column headers
53# --------------
54(echo module; echo $categories | jq ".[]" ) | $n2t > $data
55# add a newline
56echo >> $data
57
58# Build Each Row
59# --------------
60for dir in $toplevel $secondlevel; do
61 # Gnuplot likes to treat underscores as a syntax for subscripts. This
62 # looks weird, as module names are not named with this syntax in mind.
63 # Further, it turns out that we go through 3 expansions, so we need 8 (2^3)
64 # backslashes.
65 echo $dir | sed -e "s/_/\\\\\\\\_/g" | $n2t >> $data
66 # This is the heart of the implementation, and probably the most
67 # complicated line in this script. First, we generate the subdirectory
68 # sloc with tokei, in json format. We then filter it with jq. The jq
69 # filter is a foreach loop where we iterate over $x = column name, as
70 # passed in as the first positional argument. Each interation through
71 # the loop, we print out the code value, when it exists, or null + 0.
72 # This takes advantage of the property of null:
73 # > null can be added to any value, and returns the other value
74 # > unchanged.
75 tokei --output json $dir \
76 | jq '$ARGS.positional[0][] as $x | .[$x].code + 0' \
77 --jsonargs "$categories" \
78 | $n2t >> $data
79 echo >> $data
80done
81
82cat $data 1>&2
83gnuplot -c ${0%bash}plot $data
84
85rm $data