2008-11-20 22 views
40

Tengo una secuencia de comandos groovy que necesita una biblioteca en un frasco. ¿Cómo lo agrego al classpath? Quiero que el script sea ejecutable, así que estoy usando #!/usr/bin/env groovy en la parte superior de mi script.¿Cómo incluyo jarras en un guión maravilloso?

+2

Parece que esto ya se ha preguntado: http://stackoverflow.com/questions/254385/how-do-i-auto-load-a-database-jar-in-groovy-without-using-the-cp- cambiar – timdisney

Respuesta

30

Si realmente tiene que también se puede cargar un archivo JAR en tiempo de ejecución:

this.getClass().classLoader.rootLoader.addURL(new File("file.jar").toURL()) 
+0

Heh, definitivamente me perdí la sección "Agregar cosas a la ruta de clases" la primera vez que leí eso. – timdisney

+0

No pude conseguir que el cargador de clases funcione ... ¿alguien más puede usarlo? – Zombies

+4

Existen limitaciones que no se cubren en la documentación cuando se ejecuta con un shebang (#!). Los expliqué más [abajo] (http://stackoverflow.com/a/8945888/54396). @Zombies, la técnica del cargador de clases solo funciona cuando no es necesario importar clases desde ese .jar. Las importaciones se resuelven antes de que se ejecute el script e importar los .jar – Patrick

4

Al igual que lo haría en Java.

Este es un ejemplo de ejecución de un script de supervisión de estado MySQL. mysql.jar contiene el conector MySQL que llamo desde el script status.groovy.

maravilloso CT1 -cp mysql.jar status.groovy

20

Se pueden añadir los frascos a $ HOME/.groovy/lib

+0

funciona para mí (usando Groovy 2.1.2 con Windows 7) – pinei

+0

Esto es genial, excepto cuando está ejecutando tantos procesos Groovy que agota sus archivos abiertos límite. –

10

También puede probar maravilloso uva. Le permite usar anotaciones para modificar el classpath. Es experimental ahora, pero bastante genial. Ver docs.groovy-lang.org/.../grape

44

El inicio de una secuencia de comandos groovy con #!/usr/bin/env groovy tiene una limitación muy importante - No se pueden agregar argumentos adicionales. No se puede configurar ningún classpath, no se ejecuta groovy con define o en depuración. Este no es un tema groovy, pero una limitación en cómo funciona el tinglado (#!) - todos los argumentos adicionales son tratados como único argumento por lo #!/usr/bin/env groovy -d está diciendo /usr/bin/env para ejecutar el comando Rathen groovy -d continuación groovy con un argumento de d.

Hay una solución para el problema, que implica el arranque de groovy con bash en la secuencia de comandos groovy.

#!/bin/bash                                         
//usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" [email protected]; exit $? 

import org.springframework.class.from.jar 
//other groovy code 
println 'Hello' 

Toda la magia ocurre en las dos primeras líneas. La primera línea nos dice que este es un script bash. bash comienza a ejecutarse y ve la primera línea. En bash# es para los comentarios y // se colapsó a / que es el directorio raíz. Entonces, bash ejecutará /usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" [email protected], que comienza genial con todos nuestros argumentos deseados. El "$0" es la ruta a nuestro script, y [email protected] son los argumentos. Ahora Groovy se ejecuta e ignora las dos primeras líneas y ve nuestro guión maravilloso y luego vuelve a bash. bash luego sale (exit $?1) con el código de estado de groovy.

+0

¿Se puede hacer esto con un archivo por lotes de Windows? – djangofan

+2

Bonito consejo: aunque parece que no funciona en un shell de Windows Cygwin, ya que la doble barra en // usr/bin/env no está contraída. – Henry

+0

Consejo realmente bueno –

19

Mi forma favorita de hacer esto es con Groovy Grapes. Éstos acceden al Repositorio Central de Maven, descargan el jar referenciado y luego lo colocan en el classpath. Entonces puede usar la biblioteca como cualquier otra biblioteca. La sintaxis es muy simple:

@Grab(group='com.google.collections', module='google-collections', version='1.0') 

se puede leer más detalles here. Una ventaja importante aquí es que no necesita distribuir sus dependencias cuando distribuye su script. El único inconveniente de este método es que Jar debe estar en el repositorio de Maven.

+0

Enlace roto aquí – Leo

3

Agregando a @Patrick su respuesta, que me ayudó mucho, descubrí recientemente otro truco.

Si agrega muchos tarros al classpath todo en una línea, las cosas pueden volverse ilegibles.¡Pero puedes hacer lo siguiente!

#!/bin/bash 
//bin/true && OPTS="-cp blah.jar -Dmyopt=value" 
//bin/true && OPTS="$OPTS -Dmoreopts=value2" 
//usr/bin/env groovy $OPTS "$0" [email protected]; exit $? 

println "inside my groovy script" 

dejar volar su imaginación salvaje de la complejidad de una línea de comandos se puede romper de esta manera en trozos manejables

Maarten

3

A continuación se muestra una combinación de Patrick's solution, Maarteen Boekhold's solution, y el comentario de foozbar que funciona tanto con Linux y Cygwin:

#!/bin/bash 
// 2>/dev/null; SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 
// 2>/dev/null; OPTS="-cp $SCRIPT_DIR/lib/extra.jar:$SCRIPT_DIR/lib/spring.jar" 
// 2>/dev/null; OPTS="$OPTS -d" 
// 2>/dev/null; OPTS="$OPTS -Dlog4j.configuration=file:/etc/myapp/log4j.xml" 
// 2>/dev/null; exec groovy $OPTS "$0" "[email protected]"; exit $? 

import org.springframework.class.from.jar 
//other groovy code 
println 'Hello' 

como funciona:

  • // es un comentario groovy válido, por lo que Groovy ignora todos los comandos bash.
  • // devolverá un error, pero el resultado del error se redirigirá a /dev/null y, por lo tanto, no se muestra.
  • bash ejecuta comandos siguiendo un punto y coma a pesar de que el comando anterior falló.
  • exec reemplaza el programa actual en el proceso actual sin forzar un nuevo proceso. De este modo, se ejecuta maravilloso dentro del proceso de escritura original (ps muestra el proceso que el script en lugar del ejecutable maravilloso)
  • La declaración exit $? siguiente exec groovy impide fiesta de tratar de interpretar el resto de la secuencia de comandos como una escritura del golpe, y también conserva el código de retorno de la secuencia de comandos groovy.

El truco de bash anterior es más conveniente en algunos casos que the RootLoader trick porque puede utilizar sentencias de importación regulares dentro del script. Usar el truco de RootLoader te obliga a cargar todas las clases usando reflexión. Esto está bien en algunas situaciones (como cuando necesita cargar un controlador JDBC), pero inconveniente en otras.

Si sabe que su secuencia de comandos nunca se ejecutará en Cygwin, entonces el uso de la solución de Patrick o Maarteen probablemente dará como resultado un rendimiento ligeramente mejor, ya que evitan la sobrecarga de generar y tirar un error.

1

Si desea utilizarlo de inmediato antes de las declaraciones import es posible como esto :):

// printEmployees.groovy 
this.class.classLoader.rootLoader.addURL(
    new URL("file:///C:/app/Dustin/product/11.1.0/db_1/jdbc/lib/ojdbc6.jar")) 
import groovy.sql.Sql 
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr", 
         "oracle.jdbc.pool.OracleDataSource") 
sql.eachRow("SELECT employee_id, last_name, first_name FROM employees") 
{ 
    println "The employee's name is ${it.first_name} ${it.last_name}." 
} 

Tomado de esta javaworld.com article.

Cuestiones relacionadas