Running Java applications with jgo

Running Java applications with jgo#

This example shows how to run an arbitrary package available from a Maven repository using jgo.

import cjdk
import jgo
import os
from contextlib import contextmanager

jgo requires Apache Maven, so we’ll install that first:

# From https://maven.apache.org/download.html
maven_url = "tgz+https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz"
maven_sha512 = "706f01b20dec0305a822ab614d51f32b07ee11d0218175e55450242e49d2156386483b506b3a4e8a03ac8611bae96395fd5eec15f50d3013d5deed6d1ee18224"
maven_dir = cjdk.cache_package("Maven", maven_url, sha512=maven_sha512)
cjdk: Installing Maven to /home/runner/.cache/cjdk
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 maven_dir = cjdk.cache_package("Maven", maven_url, sha512=maven_sha512)

File ~/work/cjdk/cjdk/src/cjdk/_api.py:341, in cache_package(name, url, sha1, sha256, sha512, **kwargs)
    336     else:
    337         raise ValueError(
    338             f"Cannot handle {url!r} URL (must be tgz+https or zip+https)"
    339         )
--> 341 return _install.install_dir(
    342     "misc-dirs", name, url, conf, checkfunc=check_hashes
    343 )

File ~/work/cjdk/cjdk/src/cjdk/_install.py:50, in install_dir(prefix, name, url, conf, checkfunc)
     41     _print_progress_header(conf, name)
     42     _download.download_and_extract(
     43         destdir,
     44         url,
   (...)     47         _allow_insecure_for_testing=conf._allow_insecure_for_testing,
     48     )
---> 50 return _cache.permanent_directory(
     51     prefix,
     52     url,
     53     fetch,
     54     cache_dir=conf.cache_dir,
     55     timeout_for_fetch_elsewhere=300,
     56 )

File ~/work/cjdk/cjdk/src/cjdk/_cache.py:138, in permanent_directory(prefix, key_url, fetchfunc, cache_dir, timeout_for_fetch_elsewhere)
    136 with _create_key_tmpdir(cache_dir, key) as tmpdir:
    137     if tmpdir:
--> 138         fetchfunc(tmpdir)
    139         _move_in_fetched_directory(keydir, tmpdir)
    140         _add_url_file(keydir, key_url)

File ~/work/cjdk/cjdk/src/cjdk/_install.py:42, in install_dir.<locals>.fetch(destdir)
     40 def fetch(destdir):
     41     _print_progress_header(conf, name)
---> 42     _download.download_and_extract(
     43         destdir,
     44         url,
     45         checkfunc=checkfunc,
     46         progress=conf.progress,
     47         _allow_insecure_for_testing=conf._allow_insecure_for_testing,
     48     )

File ~/work/cjdk/cjdk/src/cjdk/_download.py:52, in download_and_extract(destdir, url, checkfunc, progress, _allow_insecure_for_testing)
     50 with tempfile.TemporaryDirectory(prefix="cjdk-") as tempd:
     51     file = Path(tempd) / f"archive.{ext}"
---> 52     download_file(
     53         file,
     54         url,
     55         checkfunc=checkfunc,
     56         progress=progress,
     57         _allow_insecure_for_testing=_allow_insecure_for_testing,
     58     )
     59     extract(destdir, file, progress)

File ~/work/cjdk/cjdk/src/cjdk/_download.py:83, in download_file(dest, url, checkfunc, progress, _allow_insecure_for_testing)
     78         raise NotImplementedError(
     79             f"Cannot handle {scheme} (must be https)"
     80         )
     82 response = requests.get(url, stream=True)
---> 83 response.raise_for_status()
     84 total = response.headers.get("content-length", None)
     85 total = int(total) if total else None

File ~/work/cjdk/cjdk/.nox/docs/lib/python3.14/site-packages/requests/models.py:1026, in Response.raise_for_status(self)
   1021     http_error_msg = (
   1022         f"{self.status_code} Server Error: {reason} for url: {self.url}"
   1023     )
   1025 if http_error_msg:
-> 1026     raise HTTPError(http_error_msg, response=self)

HTTPError: 404 Client Error: Not Found for url: https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz

The Maven .tar.gz file has been extracted into maven_dir; find the bin directory within it:

maven_bin = list(maven_dir.glob("apache-maven-*"))[0] / "bin"
assert (maven_bin / "mvn").is_file()

Let’s write a context manager that we can use to temporarily put the Maven bin directory on PATH.

@contextmanager
def path_prepended(path):
    """
    Context manager to temporarily prepend the given path to PATH.
    """
    save_path = os.environ.get("PATH", "")
    new_path = str(path) + os.pathsep + save_path
    os.environ["PATH"] = new_path
    try:
        yield
    finally:
        os.environ["PATH"] = save_path

Now for the magic: run a program by specifying its Maven coordinates.

The JRE and all required Jars are downloaded (and cached) automatically.

with cjdk.java_env(vendor="zulu-jre", version="8"):
    with path_prepended(maven_bin):
        jgo.main_from_endpoint(
            "com.puppycrawl.tools:checkstyle:9.3",
            primary_endpoint_main_class="com.puppycrawl.tools.checkstyle.Main",
            argv=["--version"],
        )