blob: bc05da21b8c6a4899eab37abe18f2a4cf4b9ed87 [file] [log] [blame]
Chris Kay32d73bc2021-12-09 14:37:06 +00001#!/usr/bin/env bash
2
Jimmy Brissonc7e28f52021-01-21 16:23:21 -06003#
Chris Kay32d73bc2021-12-09 14:37:06 +00004# Copyright (c) 2021-2022 Arm Limited. All rights reserved.
Jimmy Brissonc7e28f52021-01-21 16:23:21 -06005#
6# SPDX-License-Identifier: BSD-3-Clause
7#
Chris Kay32d73bc2021-12-09 14:37:06 +00008
Jimmy Brissonc7e28f52021-01-21 16:23:21 -06009set -euo pipefail
10
11# Overview
12# ========
13#
14# This script generates source lines of code as a tab separated values (TSV)
15# file and a stacked bar chart. It uses `tokei` for gathering the data, and
16# `gnuplot` for generating the plot. The data is available on stderr and the
17# plot will be put in stdout.
18#
19# This script generates information about the directory that it's run in,
20# aggregated by subdirectory.
Chris Kay32d73bc2021-12-09 14:37:06 +000021#
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060022# It is recommended that you run it from within the TF-A root directory for
23# best results.
24
Chris Kay32d73bc2021-12-09 14:37:06 +000025# Functions
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060026# =========
27
Chris Kay32d73bc2021-12-09 14:37:06 +000028# Convert newlines to tabs
29n2t() {
30 tr "\n" "\t"
31}
32
33# Strip trailing tabs
34strip() {
35 sed 's/\t$//'
36}
37
38# Variables
39# =========
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060040
41# We will build the final data file incrementally throughout the script. We need
42# A place to store this data, temporarily, so mktemp fills the role.
43data=$(mktemp XXXXXX-sloc.tsv)
44
Chris Kay32d73bc2021-12-09 14:37:06 +000045# Subdirectories that we will analyze
46analyze=("${@:-"." "./drivers" "./plat" "./tools"}")
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060047
Chris Kay32d73bc2021-12-09 14:37:06 +000048# Top-level directories that we will analyze
49readarray -t dirs < <(find ${analyze[@]} -maxdepth 1 -type d -not -path '*/\.*' | sort -u)
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060050
51# We want to be sure that we always put the data in the same order, with the
52# same keys in the resulting TSV file. To ensure this, we keep a json-encoded
53# array of the categories we would like to show in the graph.
Chris Kay32d73bc2021-12-09 14:37:06 +000054#
55# This was generated by taking the output of `tokei --output json | jq keys` and
56# trimming out things that we don't really need like "Svg"
57categories=$(tokei --output json | jq 'keys - ["Total", "Autoconf", "CSS", "JSON", "Module-Definition", "Plain Text", "SVG", "SWIG", "XML" ]')
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060058
59# Data File Generation
60# ====================
61#
Chris Kay32d73bc2021-12-09 14:37:06 +000062# Below we generate the data file used for the graph. The table is a tab
63# separated value (TSV) matrix with columns of code language (Bash, C, etc.),
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060064# and rows of subdirectories of TF-A that contain the code.
65
66# Column headers
67# --------------
Chris Kay32d73bc2021-12-09 14:37:06 +000068(echo "Module"; echo ${categories} | jq ".[]" ) | n2t > "${data}"
69echo >> "${data}"
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060070
71# Build Each Row
72# --------------
Chris Kay32d73bc2021-12-09 14:37:06 +000073for dir in "${dirs[@]}"; do
74 # Don't process directories that are ignored by Git
75 if git check-ignore -q "${dir}"; then
76 continue
77 fi
78
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060079 # Gnuplot likes to treat underscores as a syntax for subscripts. This
80 # looks weird, as module names are not named with this syntax in mind.
Chris Kay32d73bc2021-12-09 14:37:06 +000081 # Further, it turns out that we go through 3 expansions, so we need 8
82 # (2^3) backslashes.
83 echo "${dir}" | sed -e "s/_/\\\\\\\\_/g" | n2t >> "${data}"
84
85 # Additional arguments to Tokei
86 args=()
87
88 # Don't include the statistics of this directory's children in its own
89 # statistics if they are going to be analyzed separately.
90 readarray -t excludes < <(printf '%s\n' "${dirs[@]}" | grep "${dir}/")
91
92 for exclude in "${excludes[@]}"; do
93 # Tokei uses gitignore syntax, so we need to strip the leading
94 # period.
95 args+=(--exclude "${exclude#.}")
96 done
97
Jimmy Brissonc7e28f52021-01-21 16:23:21 -060098 # This is the heart of the implementation, and probably the most
99 # complicated line in this script. First, we generate the subdirectory
Chris Kay32d73bc2021-12-09 14:37:06 +0000100 # sloc with tokei, in JSON format. We then filter it with jq. The jq
Weronika Wiesiolek88b24012021-09-08 12:31:51 +0100101 # filter iterates over the column names as saved in the categories
102 # variable. Each iteration through the loop, we print out the code
103 # value, when it exists, or null + 0. This takes advantage of the
Chris Kay32d73bc2021-12-09 14:37:06 +0000104 # property of null:
105 #
106 # > null can be added to any value, and returns the other value
107 # > unchanged.
108 tokei "${dir}" --output json "${args[@]}" \
109 | jq " .[${categories}[]].code + 0" \
110 | n2t | strip >> "${data}"
111
112 echo >> "${data}"
Jimmy Brissonc7e28f52021-01-21 16:23:21 -0600113done
114
Chris Kay32d73bc2021-12-09 14:37:06 +0000115cat "${data}" 1>&2
116gnuplot -c "${0%bash}plot" "${data}"
Jimmy Brissonc7e28f52021-01-21 16:23:21 -0600117
Chris Kay32d73bc2021-12-09 14:37:06 +0000118rm "${data}"