{"id":18011646,"url":"https://github.com/renatoathaydes/jgrab","last_synced_at":"2025-03-26T16:30:37.684Z","repository":{"id":57717515,"uuid":"89067898","full_name":"renatoathaydes/jgrab","owner":"renatoathaydes","description":"Runs Java code without a build system, grabbing dependencies declared in the Java file itself.","archived":false,"fork":false,"pushed_at":"2024-05-01T16:26:52.000Z","size":394,"stargazers_count":16,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-02T13:09:14.916Z","etag":null,"topics":["java","rust","script-engine"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/renatoathaydes.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-04-22T12:26:49.000Z","updated_at":"2024-05-01T16:26:55.000Z","dependencies_parsed_at":"2024-04-25T20:01:25.241Z","dependency_job_id":null,"html_url":"https://github.com/renatoathaydes/jgrab","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renatoathaydes%2Fjgrab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renatoathaydes%2Fjgrab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renatoathaydes%2Fjgrab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renatoathaydes%2Fjgrab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/renatoathaydes","download_url":"https://codeload.github.com/renatoathaydes/jgrab/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222155920,"owners_count":16940424,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","rust","script-engine"],"created_at":"2024-10-30T03:12:17.415Z","updated_at":"2024-10-30T03:12:18.038Z","avatar_url":"https://github.com/renatoathaydes.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JGrab\n\n[![Actions Status](https://github.com/renatoathaydes/jgrab/workflows/Build%20And%20Test%20on%20All%20OSs/badge.svg)](https://github.com/renatoathaydes/jgrab/actions)\n[![Maven Central](https://img.shields.io/maven-central/v/com.athaydes.jgrab/jgrab.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/com.athaydes.jgrab/jgrab)\n\nRuns Java code without a build system, grabbing dependencies declared in the Java file itself.\n\nTo make it fast to run Java code, JGrab employs a daemon which runs in the background, ready to run\ncode once it is started up.\n\nIt also uses an in-memory compiler, \n[osgiaas-javac](https://github.com/renatoathaydes/osgiaas/blob/master/docs/lang/osgiaas-javac.md), which is\nbased on the [JavaCompiler](https://docs.oracle.com/javase/7/docs/api/javax/tools/JavaCompiler.html) mechanism.\n\n❇️ Go to the [Getting Started](#getting-started-with-jgrab) section for installation instructions.\n\n## Example usage\n\nRun a Java file or code snippet:\n\n```shell\n# Run Java class\n▶ jgrab MyJavaCode.java\n\n# Run expression\n▶ jgrab -e 'java.lang.Math.pow(2, 3)'\n\n# Run statement (must end with semicolon)\n▶ jgrab -e 'System.out.println(\"Hello JGrab\");'\n```\n\nThe Java class must either have a main function or implement `Runnable`.\n\nMaven dependencies can be declared in the Java file itself\nusing comments like `// #jgrab org:module:version`, as shown in this example:\n\n```java\n// #jgrab com.google.guava:guava:33.1.0-jre\npackage example;\n\nimport com.google.common.collect.ImmutableMap;\n\npublic class UsesGuava {\n    public static void main(String[] args) {\n        var items = ImmutableMap.of(\"coin\", 3, \"glass\", 4, \"pencil\", 1);\n        for (var fruit: items.entrySet()) {\n            System.out.println(fruit);\n        }\n    }\n}\n```\n\nRunning the above for the first time should print the following:\n\n```\n▶ jgrab UsesGuava.java\n=== JGrab Client - Starting daemon ===\n=== JGrab Client - Daemon started, pid=78018 ===\n=== JGrab Client - Connected! ===\ncoin=3\nglass=4\npencil=1\n```\n\nIt starts a deamon, downloads the necessary dependencies and then compiles and runs the Java file.\n\n\u003e All dependencies are downloaded to `~/.jgrab/jbuild-cache/`.\n\nThe next time you run a Java file with the same dependencies, it reuses the deamon and the cached dependencies:\n\n```\n▶ time jgrab UsesGuava.java\ncoin=3\nglass=4\npencil=1\njgrab UsesGuava.java   0.00s  user 0.01s system 5% cpu 0.179 total\n```\n\nTo stop the deamon, run:\n\n```\n# -s stops the deamon, -t starts it. Use -h for help.\n▶ jgrab -s\n=== JGrab Daemon stopped ===\n```\n\n## Goals of this project\n\n- [x] to make it extremely easy and fast to run a single Java file or snippet.\n- [x] to allow the Java file to use any dependency without a build system by\n  declaring dependencies directly in the source ([JBuild](https://github.com/renatoathaydes/jbuild) is used internally to download deps).\n- [x] to provide a daemon that circumvents the JVM startup and warmup slowness. \n  This is why Rust is used for the jgrab-client.\n- [x] to make downloading and installing JGrab a one-command process.  \n\n\u003e This project is inspired by the awesome Groovy \n  [@Grab](http://docs.groovy-lang.org/latest/html/documentation/grape.html) annotation.\n  The Rust client is also inspired by efforts from the Groovy community such as \n  [GroovyServ](https://kobo.github.io/groovyserv/).\n\nIt is **NOT a goal** of this project:\n\n* to become a full build system.\n* to accept more than one Java file or snippet as input. That's what build systems are for.\n\n## Getting Started with JGrab\n\nTo get JGrab, run the following command:\n\n```\n▶ curl https://raw.githubusercontent.com/renatoathaydes/jgrab/master/releases/install.sh -sSf | sh\n```\n\nThis will download and unpack the JGrab archive into `$HOME/.jgrab/`.\n\n\u003e To change JGrab's home directory, set the `JGRAB_HOME` env var to another directory.\n\nAlternatively, download JGrab from the [Releases](https://github.com/renatoathaydes/jgrab/releases) page.\n\nInstall it somewhere in your `PATH` by linking it, for example:\n\n```shell\n▶ sudo ln -s ~/.jgrab/jgrab-client /usr/local/bin/jgrab\n```\n\nMake sure it's working:\n\n```\n▶ jgrab -e '2 + 2'\n=== JGrab Client - Starting daemon ===\n=== JGrab Client - Created JGrab jar at: /Users/renato/.jgrab/jgrab.jar ===\n=== JGrab Client - Daemon started, pid=79341 ===\n=== JGrab Client - Connected! ===\n4\n```\n\nThe daemon starts first time you run some code, or when you run `jgrab -t`.\n\nWhile JGrab's daemon is running, it can run Java code much faster.\n\nTo stop the daemon, run `jgrab -s`.\n\n### Uninstalling\n\nTo uninstall JGrab, delete its home directory:\n\n```shell\n▶ rm -rf ~/.jgrab\n```\n\nAlso delete any symlinks or shell aliases you may have created.\n\n### Running JGrab with just `java`\n\nIf you don't care too much about speed, or you have trouble using the daemon (e.g. you need access to `stdin`),\nyou can run JGrab directly with `java`:\n\n```\n▶ java -jar ~/.jgrab/jgrab.jar --help\n```\n\n\u003e If the jar doesn't exist, run any Java code with jgrab first. That will create the JGrab jar\n\u003e at `~/.jgrab/jgrab.jar` (it is extracted from the executable itself).\n\nIf your shell supports aliases, add an alias like the following, so that you can \njust type `jgrab \u003cargs\u003e` to run JGrab, similarly to the jgrab-client:\n\n```\n▶ alias jgrab='java -jar $HOME/.jgrab/jgrab.jar $@'\n```\n\nNow, this should work:\n\n```\n▶ jgrab -e 'System.out.println(\"Hello world!\");'\n```\n\n### Running Java classes\n\nJGrab can run any class containing a standard main method (`public static void main(String[] args)`)\nor that implements the `java.lang.Runnable` interface.\n\nFor example, create the following file with name `Hello.java`:\n\n```java\npublic class Hello implements Runnable {\n    public void run() {\n        System.out.println(\"Hello JGrab\");\n    }\n}\n```\n\nTo run this file with JGrab, just pass the file name to it as an argument:\n\n\u003e The class name must match the file name, as with any valid public Java class.\n  The package, however, does not matter, so any package can be declared regardless of the file location.\n\n``` \n▶ jgrab Hello.java\nHello JGrab\n```\n\n### Running Java snippets\n\nJGrab can also run simple Java code snippets using the `-e` option:\n\n```\n# expressions (anything that returns a value)\n# must not be terminated with ';'\n▶ jgrab -e 2 + 2\n4\n# statements MUST be terminated with ';'\n▶ jgrab -e 'System.out.println(\"Hello JGrab\");'\nHello JGrab\n```\n\n\u003e Hint: always use single-quotes around code snippets to stop the shell from interpreting double-quotes.\n\n### Piping Java code as input\n\nJGrab reads from stdin if not given any arguments.\n\nThis allows piping to work seamlessly:\n\n```\n▶ cat Hello.java | jgrab\nHello JGrab\n```\n\n### Declaring external dependencies\n\nJGrab lets you declare external dependencies within Java files using a comment processor of the form \n`// #jgrab groupId:artifactId[:version]`.\n \nFor example, you can create a Java class that requires Guava:\n\n```java\n// #jgrab com.google.guava:guava:19.0\nimport com.google.common.collect.ImmutableMap;\n\npublic class UsesGuava {\n\n    public static void main(String[] args) {\n        ImmutableMap\u003cString, Integer\u003e items = ImmutableMap.of(\n                \"one\", 1, \"two\", 2, \"three\", 3);\n        \n        items.entrySet().stream().forEach(System.out::println);\n    }\n}\n```\n\nThe first time you run this class, it will download Guava if necessary before compiling and running it,\nso it may take a few seconds.\n\nHowever, it will run very fast after that! \n\n## Debugging\n\n### Enabling JGrab Logging\n\nTo enable JGrab logging, start the Java daemon using the following command:\n\n```\n▶ java -Dorg.slf4j.simpleLogger.defaultLogLevel=debug -jar ~/.jgrab/jgrab.jar -d\n```\n\nFrom another shell, just use JGrab normally. The daemon process will log pretty much everything it does.\n\nFor even more information, use the `trace` level instead of `debug`.\n\n### Debugging Java classes run by JGrab\n\nJust start the JGrab daemon with the Java debugger enabled, then attach to it via your favourite IDE with the\nsources you will run added to the IDE's build path.\n\nYou can start the JGrab daemon with the Java debugger enabled on port 5005 with the following command: \n\n```\n▶ java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar ~/.jgrab/jgrab.jar --daemon\n```\n\nTo attach the debugger to this process from IntelliJ:\n \n * right-click on the folder containing your source code, then select `Mark directory as \u003e Source Roots`.\n * select `Run \u003e Attach to Local Process...` from the top menu, and select the JGrab daemon process.\n * from a shell, run your Java file containing breakpoints using JGrab.\n \nThe IntelliJ debugger should stop on all breakpoints marked in the Java file you ran.\n\n## Building\n\nRun the following command to build and test both the Java runner and the Rust client:\n\n```shell\n./gradlew build\n```\n\nTo build only the Java code:\n\n```shell\n./gradlew fatJar\n```\n\nTo build only the Rust client (requires the Java code to be built first):\n\n```shell\ncd jgrab-client\ncargo build\n```\n\nRequirements:\n\n* Java 11+\n* Cargo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenatoathaydes%2Fjgrab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenatoathaydes%2Fjgrab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenatoathaydes%2Fjgrab/lists"}