Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 3 | # |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 4 | # Copyright (c) 2021-2022 Arm Limited. All rights reserved. |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 5 | # |
| 6 | # SPDX-License-Identifier: BSD-3-Clause |
| 7 | # |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 8 | |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 9 | set -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 Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 21 | # |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 22 | # It is recommended that you run it from within the TF-A root directory for |
| 23 | # best results. |
| 24 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 25 | # Functions |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 26 | # ========= |
| 27 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 28 | # Convert newlines to tabs |
| 29 | n2t() { |
| 30 | tr "\n" "\t" |
| 31 | } |
| 32 | |
| 33 | # Strip trailing tabs |
| 34 | strip() { |
| 35 | sed 's/\t$//' |
| 36 | } |
| 37 | |
| 38 | # Variables |
| 39 | # ========= |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 40 | |
| 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. |
| 43 | data=$(mktemp XXXXXX-sloc.tsv) |
| 44 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 45 | # Subdirectories that we will analyze |
| 46 | analyze=("${@:-"." "./drivers" "./plat" "./tools"}") |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 47 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 48 | # Top-level directories that we will analyze |
| 49 | readarray -t dirs < <(find ${analyze[@]} -maxdepth 1 -type d -not -path '*/\.*' | sort -u) |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 50 | |
| 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 Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 54 | # |
| 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" |
| 57 | categories=$(tokei --output json | jq 'keys - ["Total", "Autoconf", "CSS", "JSON", "Module-Definition", "Plain Text", "SVG", "SWIG", "XML" ]') |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 58 | |
| 59 | # Data File Generation |
| 60 | # ==================== |
| 61 | # |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 62 | # 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 Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 64 | # and rows of subdirectories of TF-A that contain the code. |
| 65 | |
| 66 | # Column headers |
| 67 | # -------------- |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 68 | (echo "Module"; echo ${categories} | jq ".[]" ) | n2t > "${data}" |
| 69 | echo >> "${data}" |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 70 | |
| 71 | # Build Each Row |
| 72 | # -------------- |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 73 | for 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 Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 79 | # 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 Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 81 | # 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 Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 98 | # This is the heart of the implementation, and probably the most |
| 99 | # complicated line in this script. First, we generate the subdirectory |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 100 | # sloc with tokei, in JSON format. We then filter it with jq. The jq |
Weronika Wiesiolek | 88b2401 | 2021-09-08 12:31:51 +0100 | [diff] [blame] | 101 | # 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 Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 104 | # 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 Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 113 | done |
| 114 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 115 | cat "${data}" 1>&2 |
| 116 | gnuplot -c "${0%bash}plot" "${data}" |
Jimmy Brisson | c7e28f5 | 2021-01-21 16:23:21 -0600 | [diff] [blame] | 117 | |
Chris Kay | 32d73bc | 2021-12-09 14:37:06 +0000 | [diff] [blame] | 118 | rm "${data}" |