Vor einiger Zeit hatte ich mich mal aufgemacht um meine Bash-Dateien, welche ich täglich verwende mal sauber zu dokumentieren. Dabei habe ich verschiedene Lösungen ausprobiert (von selbstgebauten bis zu kostenpflichtigen) und bin letztendlich bei Doxygen hängen geblieben. Doygen kann jedoch von Haus aus nicht mit bash Dateien umgehen. In diesem Beitrag zeige ich wie man das löst und Doxygen dafür vorbereitet.

Los geht es mit der Installation von Doxygen welche je nach Distro unterschiedlich ist. Ich bin mit der manuellen Kompilierung ganz gut gefahren, aber das kommt auf den Nutzer an ;) So habe ich zunächst hier die Anweisungen für die “Bleeding Edge” Version nachgesehen und durchgeführt.

1
2
3
4
5
6
7
git clone https://github.com/doxygen/doxygen.git
cd doxygen
mkdir build
cd build
cmake -G "Unix Makefiles" ..
make
make install

An dieser Stelle sollte sich unter:

1
doxygen -v

schon das binary melden können ;)

Nun geht es an die Einbindung des Bash Dokumentationsplugins. Dazu verwende ich bash-doxygen was ein Filter, in sed umgesetzt, ist und die Dateien von Bash auf C-Code (was doxygen versteht) umsetzt.

Zunächst muss man sich einen Ort raussuchen unter dem das Plugin zu finden ist. Der Author selbst hat das Plugin unter die WTFPL gestellt, wodurch es auch direkt im Sourcecode mitgeliefert werden kann. Ich habe das bei meinem Projekt so gelöst, dass ich den Filter in einem Unterordner gehalten habe. Um das einfach darzustellen zeige ich mal wie mein Projekt aufgebaut ist.

Zunächst habe ich ein Verzeichnis in dem eine bash-Datei liegt, die dokumentiert werden soll. Das ganze sieht dann so aus:

  • myfile.sh
    • docs
      • generate.sh
      • helpers
        • bash-doxygen
          • doxygen-bash.sed

Oder als Kommandos:

1
2
3
4
5
6
7
8
9
LOCALDIR=$(pwd)
mkdir -p $LOCALDIR/docs/helpers
cd $LOCALDIR/docs/helpers
git clone https://github.com/Anvil/bash-doxygen.git
cd $LOCALDIR/docs
wget https://wolf-u.li/upload/2016/06/5657-generate.txt -O generate.sh
doxygen -g
chmod +x generate.sh
cd $LOCALDIR

Nun steht die Struktur aber man muss noch das Konfigurationsfile für Doxygen unter docs/Doxyfile anpassen. Dazu editiert man dieses - im Nachfolgenden gebe ich die wichtigsten Änderungen an, welche ich durchgeführt habe:

  • PROJECT_NAME Hier habe ich den Namen meines Projektes eingetragen - dieser erscheint dann in der Titelzeile der Dokumentation.

  • PROJECT_NUMBER

    1
    
    PROJECT_NUMBER = $(PROJECT_NUMBER)
    

    Diese Projektnummer wird via Umgebungsvariable in der generate.sh gesetzt und kann beispielsweise ein git commit oder das aktuelle Datum sein.

  • PROJECT_BRIEF Ein schlagkräftiger Satz zur Beschreibung. Wird im Header der Dokumentation angezeigt.

  • EXTENSION_MAPPING

    1
    
    EXTENSION_MAPPING = sh=C
    

    um die sh Dateien parsen zu lassen

  • INPUT

    1
    
    INPUT = ../
    

    da der übergeordnete Ordner geparsed werden soll

  • FILE_PATTERNS Füge das Pattern

    1
    
    *.sh
    

    mit hinzu, damit Doxygen diese Files ansieht

  • RECURSIVE

    1
    
    RECURSIVE = YES
    

    da auch untergeordnete Ordner geparsed werden sollen

  • EXCLUDE_PATTERNS

    1
    
    EXCLUDE_PATTERNS = */docs/*
    

    Alle Ordner, die “docs” im Namen beinhalten sollen nicht geparsed werden

  • INPUT_FILTER

    1
    
    INPUT_FILTER = "sed -n -f helpers/bash-doxygen/doxygen-bash.sed -- "
    

Damit fehlt dann nur noch das myfile.sh. Hier ein Quickstarter als Template für bashfiles:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/bin/sh
## @file myfile.sh
## @brief Runs the cooles things in the world.
## @author Uli Wolf
## @date 2016-06-08
## @copyright Released under the WTFPL
## @details This script provides the required code to run code that is cooler than anybody elses code
#######################################################################################################################
## @mainpage MyFile Docs
## This line shows a quick overview of what the Project does
## @tableofcontents
## @section secoverview Overview
## Now this section shows really the details.
## @section secprerequisites Prerequisites
## This describes the minimum requirements to run this script
## @subsection subsecdatabase Prerequisites: Database
## * No database is required currently
## @subsection subsecagentversions Prerequisites: Minimum Version of the Agents
## The minimum level of the respective are:
## * What Agents?
## @section secintro Installation
## Here you could show how to install the script
## @section secexecution Execution
## The script is executed like this. The usage of the user root is forbidden.
## ```{.sh}
## myfile.sh
## ```
#######################################################################################################################
# Various Variable definitions
## @var V_INTERNALSTARTTIME
## @brief This holds the starttime
## @showinitializer
## @details Time is measured in seconds since 1st. of January 1970. The value will be used to later calculate the
## runtime of the script.
declare V_INTERNALSTARTTIME=$(date +%s);

## @var V_CURRENTTIMESTAMP
## @brief This holds the date in YYMMDD-HHMMSS format
## @showinitializer
declare V_CURRENTTIMESTAMP=$(date +%y%m%d-%H%M%S);

## @var V_HOSTNAME
## @brief This holds the hostname of the local system
## @showinitializer
declare V_HOSTNAME=$(hostname -s);

## @var D_SCRIPT
## @brief The local directory of the script
## @showinitializer
declare -x D_SCRIPT=$(cd $(dirname $0) && pwd);
export D_SCRIPT

## @fn func_check_user_root()
## @author Uli Wolf The Second
## @brief Check User root
## @retval 0 if the user is root
## @retval 1 if the user is not root
## @details Checks if the current user is root
func_check_user_root() {
 local CURRENTUSER=`whoami`;
 if [[ $CURRENTUSER != "root" ]]; then
 return 1;
 else
 return 0;
 fi
}

if [[ $(func_check_user_root) == 1 ]]; then
 echo "You are really not using root - awesome!";
fi

Wie man sehen (und der Doku entnehmen kann) müssen die Teile, welche an Doxygen weitergegeben werden, mit zwei Rauten versehen werden. Zudem werden Variablen mit “declare” versehen und Funktionen müssen ohne “function” keyword und mit der öffnenden Klammer in der ersten Zeile geschrieben und mit @fn versehen versehen werden. Die Hauptdatei kann man zusätzlich mit einer Beschreibung des Projekts (@mainpage) versehen werden. Dokumentation kann dann entweder regulär oder mit Markdown geschrieben werden. Und statt “@” kann man auch “" als keyword verwenden. Alle keywords sind hier beschrieben.

Eigentlich easy ;)