Usando opengrok con jetty

2020/04/29

Motivación

Revisando el código de qemu me encontré con que es bastante tedioso el buscar las definiciones de algunas funciones, por lo que pensé en utilizar opengrok para poder navegar de forma más fácil en el código. Ya que normalmente utilizo jetty como web server para aplicaciones java pensé en utilizarlo para ejecutar opengrok, en lugar de utilizar tomcat como es sugerido.

Instalación y configuración de opengrok

En la página web de opengrok se indica que se requiere un servlet container, por lo que jetty debería poder utilizarse, ya que en la descripción de la página web se indica:

Eclipse Jetty provides a Web server and javax.servlet container

Se comienza instalando las dependencias (o asegurandose que estén) a nivel de sistema:

sudo apt-get install -Vy default-jre-headless universal-ctags

Luego se crea la estructura de directorios que utilizará opengrok, para descargar y descomprimir jetty y opengrok:

WORKDIR=/path/to/opengrok
mkdir -p "$WORKDIR"/{src,data,dist,etc,log}
wget -P "$WORKDIR" 'https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.28.v20200408/jetty-distribution-9.4.28.v20200408.tar.gz'
mkdir "$WORKDIR"/jetty
tar --strip-components=1 -xzf jetty-distribution-9.4.28.v20200408.tar.gz -C "$WORKDIR"/jetty
wget -P "$WORKDIR" 'https://github.com/oracle/opengrok/releases/download/1.3.13/opengrok-1.3.13.tar.gz'
tar --strip-components=1 -xzf opengrok-1.3.13.tar.gz -C "$WORKDIR"/dist

Continuando con la documentación de instalación de opengrok se copia la configuración de logs a utilizar (se utiliza la configuración por defecto):

cp "$WORKDIR"/dist/doc/logging.properties "$WORKDIR"/etc
sed -i 's#^\(java.util.logging.FileHandler.pattern =\).*$#\1 '"$WORKDIR"'/log/opengrok%g.%u.log#' "$WORKDIR"/etc/logging.properties

Para el deploy de la aplicación web se crea un enlace simbólico del archivo source.war en dist al directorio jetty/webapps.

ln -s "$WORKDIR"/dist/lib/source.war "$WORKDIR"/jetty/webapps

Como se indica en la documentación respecto al deploy de la aplicación web, el archivo web.xml contiene el context-param CONFIGURATION cuyo valor por defecto es /opengrok/etc/configuration.xml (en realidad, para la versión 1.3.13 el valor es /var/opengrok/etc/configuration.xml). Para sobreescribir dicho valor podemos utilizar la opción override-web.xml de jetty que permite reescribir o agregar nuevos elementos al archivo web.xml.

Para esto se crea el archivo source.xml en la carpeta jetty/webapps indicando el archivo que tendrá la configuración que sobreescribirá el valor de CONFIGURATION:

cat <<END > "$WORKDIR"/jetty/webapps/source.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Set name="war">${WORKDIR}/jetty/webapps/source.war</Set>
    <Set name="overrideDescriptor">${WORKDIR}/override-web.xml</Set>
</Configure>
END

NOTA: Los detalles para configurar el archivo anterior se pueden encontrar en:

Obviamente, debe crearse el archivo override-web.xml que indica el valor de configuración a sobreescribir:

cat <<END > "$WORKDIR"/override-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--
        This web.xml format file is an override file that is applied to the
        opengrok webapp (source.war) AFTER it has been configured by the default
        descriptor and the WEB-INF/web.xml descriptor
    -->

    <!-- Override context init parameter CONFIGURATION -->
    <context-param>
        <param-name>CONFIGURATION</param-name>
        <param-value>${WORKDIR}/etc/configuration.xml</param-value>
    </context-param>
</web-app>
END

Ya creados los archivos anteriores se inicia jetty:

cd "$WORKDIR"/jetty
java -jar start.jar > /tmp/jetty.out 2>&1 &

Para corroborar que la configuración funciona correctamente y que el archivo web.xml fué escrito correctamente es busca por el error esperado de que no se encuentra el archivo $WORKDIR/etc/configuration.xml:

$ grep 'java.io.FileNotFoundException: .* (No such file or directory)' /tmp/jetty.out
java.io.FileNotFoundException: <<WORKDIR>>/etc/configuration.xml (No such file or directory)

(en la salida anterior se sustituyó el valor de la variable $WORKDIR por el texto <<WORKDIR>>.

Lo que queda es realizar la indexación inicial, la cual también crea el archivo faltante configuration.xml.

En mi caso, el código de qemu ya fué descargado en el directorio QEMUDIR:

QEMUDIR=/path/to/qemu
cd "$QEMUDIR"/..
git clone https://git.qemu.org/git/qemu.git
cd qemu
git submodule init
git submodule update --recursive

Se utiliza un enlace simbólico para que opengrok tenga acceso al código:

ln -s "$QEMUDIR" "$WORKDIR"/src

Y se pasa a indexar el código del repositorio de qemu:

java \
    -Djava.util.logging.config.file="$WORKDIR"/etc/logging.properties \
    -jar "$WORKDIR"/dist/lib/opengrok.jar \
    -c /usr/bin/ctags-universal \
    -s "$WORKDIR"/src \
    -d "$WORKDIR"/data -H -P -S -G \
    -W "$WORKDIR"/etc/configuration.xml \
    -U http://localhost:8080/source

El comando anterior genera además el archivo "$WORKDIR"/etc/configuration.xml que será utilizado por el archivo war de opengrok al ser deployado.

Por último, se reinicia jetty y ya se puede acceder a opengrok.

Script para instalación y configuración de opengrok con jetty

Se crea el script install-opengrok-using-jetty.sh utilizando los comandos de la parte anterior.

Este script utilizará dos parámetros, el primero la ruta donde se desea realizar la instalación de opengrok. El segundo, la rutas donde se encuentra el código fuente a indexar.

También se agrega el directorio bin con los scripts reindex y up para facilitar la administración y no tener que estar recordando los comandos utilizados luego de un tiempo.

Conclusiones

Sin duda que opengrok es una herramienta útil a la hora de recorrer el código fuente de un proyecto. Como ejemplo, la definición de type_init en el código de qemu, que resultó ser una macro (y el motivo de porqué pensé en instalar opengrok), lo encontré al momento.

Otro punto positivo fué el uso de jetty, ya que al utilizar override-web.xml facilita el deployment de opengrok respecto a tomcat en el sentido de que según las instrucciones de instalación hay que buscar el archivo web.xml y modificarlo manualmente (o con sed).