crush depth

CoffeePick Shipilev.net Edition!

Big thanks to Aleksey Shipilev for adding file lists and sizes to builds.shipilev.net so that CoffeePick can efficiently enumerate builds on the site.

A new repository provider has been added to CoffeePick that can fetch nightly builds from the builds.shipilev.net repository:

User directory: /home/rm/local/coffeepick
Loading repositories…
INFO com.io7m.coffeepick.client.vanilla.CoffeePickCatalog: setting up repository from provider net.shipilev.builds (urn:net.shipilev.builds)
INFO com.io7m.coffeepick.client.vanilla.CoffeePickCatalog: setting up repository from provider net.java.jdk (urn:net.java.jdk)
INFO com.io7m.coffeepick.client.vanilla.CoffeePickCatalog: setting up repository from provider net.adoptopenjdk.raw (urn:net.adoptopenjdk.raw)

[coffeepick]$ catalog repository:urn:net.shipilev.builds
ID                                                                     | Arch         | Platform | Version      | VM       | Conf | Size       | Repository                   | Tags
41640365d898abb9c333cc7137a0b9a97ed05ad8                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 106.13  MB | urn:net.shipilev.builds      | fastdebug nightly
5b4c02ea37cedf1ba3c5cee208749e4a539ce808                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 112.88  MB | urn:net.shipilev.builds      | nightly release
37e1d1e3c93e4aae6dc7dac233f50f149ba40806                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 112.88  MB | urn:net.shipilev.builds      | nightly release
187b3c3f00e6f808964fc2486383ef73d1cb6a0c                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 106.15  MB | urn:net.shipilev.builds      | fastdebug nightly
5f232d58300791fba0452c41710390c630df959a                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 76.31   MB | urn:net.shipilev.builds      | nightly slowdebug
f48f5257256b6ef01398cbbcc077af81bde4f817                               | aarch64      | linux    | 11.0.1+13    | hotspot  | jdk  | 76.31   MB | urn:net.shipilev.builds      | nightly slowdebug
8b7b663db1b82ebc4f886b60b9adca34e3a9ca28                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 96.43   MB | urn:net.shipilev.builds      | fastdebug nightly
4c65bbb79e7f28d11b292618977a65242881eed8                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 103.26  MB | urn:net.shipilev.builds      | nightly release
e9d61d87e265ee8f2b167f9e83bfccc450adf823                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 71.16   MB | urn:net.shipilev.builds      | nightly slowdebug
048d498ab77c049a34da88d70b1e838bae2c1947                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 96.43   MB | urn:net.shipilev.builds      | fastdebug nightly
0abf8507da0c49e425cd689bb63b9b66336edc5c                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 103.25  MB | urn:net.shipilev.builds      | nightly release
8e86c6d5b7705e97e3401361638a405640b0b3e4                               | arm32-hflt   | linux    | 11.0.1+13    | hotspot  | jdk  | 71.17   MB | urn:net.shipilev.builds      | nightly slowdebug
7ef78d8a19a9b7cf51b34e2e6d51ce0500fd29ef                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 72.42   MB | urn:net.shipilev.builds      | nightly slowdebug
397837245e66717feed96b27fac7af28c0597cab                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 101.83  MB | urn:net.shipilev.builds      | fastdebug nightly
53a22d756a40af3cc968d71adcf77664dd6c50ca                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 72.41   MB | urn:net.shipilev.builds      | nightly slowdebug
74e15bb1e3d6ca67015b8ae58db3f9db525d4ab6                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 104.80  MB | urn:net.shipilev.builds      | nightly release
fa1e016a654eb31b255a03a2328e8bdd82d5a72d                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 104.81  MB | urn:net.shipilev.builds      | nightly release
5b46c15abbafb4b8a7e684e5144b109f6bce939a                               | ppc64le      | linux    | 11.0.1+13    | hotspot  | jdk  | 101.84  MB | urn:net.shipilev.builds      | fastdebug nightly
7f78d67f3a8268a70bf399d15d88e4292dfa0544                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 102.60  MB | urn:net.shipilev.builds      | nightly release
664bd29cad89d18f63bc8000d1f598577fe1afae                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 74.13   MB | urn:net.shipilev.builds      | nightly slowdebug
a6d23644361b735bafb00a687aa8c008b24dfedd                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 99.01   MB | urn:net.shipilev.builds      | fastdebug nightly
191333a141ca461e4957327f58a94f603c3facc4                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 102.60  MB | urn:net.shipilev.builds      | nightly release
aea5eacb3ae7a1f2591e55b5a4fdd0704765478a                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 99.01   MB | urn:net.shipilev.builds      | fastdebug nightly
721b3beaba3612c851853ba3bcd898255630809c                               | s390x        | linux    | 11.0.1+13    | hotspot  | jdk  | 74.14   MB | urn:net.shipilev.builds      | nightly slowdebug
ed79993ad7f3c45b06c574729e508702c7d80ce7                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 75.74   MB | urn:net.shipilev.builds      | nightly slowdebug
abb921fbf12ea8078f84d02ed849f04c79b8a356                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 75.74   MB | urn:net.shipilev.builds      | nightly slowdebug
5bccd1116c63498c7a818e6fb0b5177dc297e89c                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 100.89  MB | urn:net.shipilev.builds      | fastdebug nightly
a96ae066a52ee2104925cfb78c9c364c537e86f1                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 105.84  MB | urn:net.shipilev.builds      | nightly release
c56dd229eae9fdf17f0386eb97b21e5d8199828d                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 105.83  MB | urn:net.shipilev.builds      | nightly release
3d0fa3fd4b21766d4ac97cfba195ce851120aa7a                               | x32          | linux    | 11.0.1+13    | hotspot  | jdk  | 100.90  MB | urn:net.shipilev.builds      | fastdebug nightly
19d78ca22dc1d3271c1bece1a282bf521968f5b3                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 118.52  MB | urn:net.shipilev.builds      | fastdebug nightly
38d9f40ec59efa9004ac17ca0e71cd34f8b8a571                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 84.17   MB | urn:net.shipilev.builds      | nightly slowdebug
0644ad607da9baf66c921d8ca70f3377d04dbb61                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 116.13  MB | urn:net.shipilev.builds      | nightly release
59f8d3fd009ba14aa1996ab6398cbd0d646eb334                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 84.21   MB | urn:net.shipilev.builds      | nightly slowdebug
bb38ac99481d336ebb6fa7e19bbdec0827bc46a7                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 118.51  MB | urn:net.shipilev.builds      | fastdebug nightly
97e000c96535e3bc3efdb381828a218820a8ecdb                               | x64          | linux    | 11.0.1+13    | hotspot  | jdk  | 116.13  MB | urn:net.shipilev.builds      | nightly release
da39a3ee5e6b4b0d3255bfef95601890afd80709                               | x64          | linux    | 12+17        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | nightly panama release
af012b2040669390547481a2452217d09353e0e1                               | x64          | linux    | 12+17        | hotspot  | jdk  | 259.83  MB | urn:net.shipilev.builds      | nightly panama release
0cf94d49148737b832167122d6f5f4fdaf801ae3                               | x64          | linux    | 12+17        | hotspot  | jdk  | 483.00  MB | urn:net.shipilev.builds      | fastdebug nightly panama
3ebbf4488ceaaab2d228f6efe2628c13f4bc9e28                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 78.04   MB | urn:net.shipilev.builds      | nightly portola slowdebug
d069f34f3e0db3fd70269c8f547ae57754bc3c0b                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 78.04   MB | urn:net.shipilev.builds      | nightly portola slowdebug
49862778ffae5a5cc97b253aee542bcdcd3a1884                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 115.82  MB | urn:net.shipilev.builds      | nightly portola release
e0f8da3c26430dfee6481f7f0adafbfd06f8ffe0                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 115.82  MB | urn:net.shipilev.builds      | nightly portola release
4307401874eb05bffa22ed29b9399d9abe0d73a6                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 108.33  MB | urn:net.shipilev.builds      | fastdebug nightly portola
8955e33a74f18861248f98127c5179dc3f2617e6                               | aarch64      | linux    | 12+19        | hotspot  | jdk  | 108.32  MB | urn:net.shipilev.builds      | fastdebug nightly portola
16672bc7757b6bc9ecd5e2794c991a0efbe10b49                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 72.11   MB | urn:net.shipilev.builds      | nightly portola slowdebug
345f3a07d1e33f6222e6161b67d1f708c1575b9f                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 97.88   MB | urn:net.shipilev.builds      | fastdebug nightly portola
3fab8c3241645d865d7e03656d0a08b549ff05ad                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 97.90   MB | urn:net.shipilev.builds      | fastdebug nightly portola
bc89b28ec9bd43f4bbb412c5ed7b3e55ad433a34                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 105.73  MB | urn:net.shipilev.builds      | nightly portola release
2c709cfa67ea4f8100252b7782d0a4fb38a8b86d                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 105.75  MB | urn:net.shipilev.builds      | nightly portola release
115a35a0d94b334d86c166650969491194e84687                               | arm32-hflt   | linux    | 12+19        | hotspot  | jdk  | 72.10   MB | urn:net.shipilev.builds      | nightly portola slowdebug
e0aaf73d5d3f7f646b455c2c0373d1ddd9f231c5                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 74.06   MB | urn:net.shipilev.builds      | nightly portola slowdebug
b8251432135b5531696dd242ae836972afdc9702                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 107.41  MB | urn:net.shipilev.builds      | nightly portola release
ec09bec89d375ccf4a0dd1e52fb406b29bb40fd3                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 107.42  MB | urn:net.shipilev.builds      | nightly portola release
f1be1843c36b638cd18cbf9f65850fa70fbd064d                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 104.03  MB | urn:net.shipilev.builds      | fastdebug nightly portola
3a64a1ea13b212c619d044de07c4a59abdefd00e                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 74.07   MB | urn:net.shipilev.builds      | nightly portola slowdebug
7904aee58d724134490c00e1d832ebb4038ba441                               | ppc64le      | linux    | 12+19        | hotspot  | jdk  | 104.03  MB | urn:net.shipilev.builds      | fastdebug nightly portola
3dcb14f1467a5167b018409a5969efe8c1981f23                               | s390x        | linux    | 12+19        | hotspot  | jdk  | 105.12  MB | urn:net.shipilev.builds      | nightly portola release
7e66bb2d88f84789cd3b07ae147e5ebf833f6b68                               | s390x        | linux    | 12+19        | hotspot  | jdk  | 75.90   MB | urn:net.shipilev.builds      | nightly portola slowdebug
0100a992f9766cd24c503f0bf46ab7e048b5439d                               | s390x        | linux    | 12+19        | hotspot  | jdk  | 101.13  MB | urn:net.shipilev.builds      | fastdebug nightly portola
ee1566ff3b73fa2e158a6f010efc537b42d786dc                               | x32          | linux    | 12+19        | hotspot  | jdk  | 103.12  MB | urn:net.shipilev.builds      | fastdebug nightly portola
6ced70a0ad89236fd5a984c9ec5086f35d0d18de                               | x32          | linux    | 12+19        | hotspot  | jdk  | 77.18   MB | urn:net.shipilev.builds      | nightly portola slowdebug
4c34a20445e3d18e5a3d9f30b3ee259d16d70c6d                               | x32          | linux    | 12+19        | hotspot  | jdk  | 103.12  MB | urn:net.shipilev.builds      | fastdebug nightly portola
73d44c8f77437a996fb41a540200f3922c83938c                               | x32          | linux    | 12+19        | hotspot  | jdk  | 108.36  MB | urn:net.shipilev.builds      | nightly portola release
946be78a0bded6ca6ff29180ba3eb29716138bbc                               | x32          | linux    | 12+19        | hotspot  | jdk  | 108.36  MB | urn:net.shipilev.builds      | nightly portola release
3ab16dd10776df10db8ff1ca8b86a820095fa7f6                               | x32          | linux    | 12+19        | hotspot  | jdk  | 77.18   MB | urn:net.shipilev.builds      | nightly portola slowdebug
e9cf741f9f1041288acba6ef51a58f56734c9453                               | x64          | linux    | 12+19        | hotspot  | jdk  | 90.48   MB | urn:net.shipilev.builds      | nightly portola slowdebug
77dae05ff29d75be451cc338c7e4d2d4db173ad1                               | x64          | linux    | 12+19        | hotspot  | jdk  | 125.29  MB | urn:net.shipilev.builds      | fastdebug nightly portola
a4948372aadb182e969a6f6a8b9c50ce06083038                               | x64          | linux    | 12+19        | hotspot  | jdk  | 123.17  MB | urn:net.shipilev.builds      | nightly portola release
173e23107b290aaf5ab02ee412bdbe28afa85e61                               | x64          | linux    | 12+19        | hotspot  | jdk  | 90.46   MB | urn:net.shipilev.builds      | nightly portola slowdebug
16b2ebbb175d07e42e1e870f57cbf3a18ce2b3c7                               | x64          | linux    | 12+19        | hotspot  | jdk  | 125.31  MB | urn:net.shipilev.builds      | fastdebug nightly portola
014622da9eeef042e637547351810167b7554d53                               | x64          | linux    | 12+19        | hotspot  | jdk  | 123.18  MB | urn:net.shipilev.builds      | nightly portola release
67d50df977a824e5f7402ea45fa501206d6cb649                               | x64          | windows  | 12+19        | hotspot  | jdk  | 184.64  MB | urn:net.shipilev.builds      | nightly portola release
a91f415b5cb19ebd634345ee63d949d090065b40                               | x64          | windows  | 12+19        | hotspot  | jdk  | 73.52   MB | urn:net.shipilev.builds      | nightly portola slowdebug
4b691a3ef30c725b180e6a354f975d22452fd045                               | x64          | windows  | 12+19        | hotspot  | jdk  | 73.61   MB | urn:net.shipilev.builds      | fastdebug nightly portola
2876e3343569b9951d99e2c8f7cfc7007e75b44d                               | x64          | linux    | 12+20        | hotspot  | jdk  | 379.91  MB | urn:net.shipilev.builds      | fastdebug loom nightly
3250317ea3d23e01156953cdd65301a29ccebf58                               | x64          | linux    | 12+20        | hotspot  | jdk  | 303.42  MB | urn:net.shipilev.builds      | loom nightly slowdebug
9e7ad5a7b31ca6c6b9a9306dcb8d1962c5850145                               | x64          | linux    | 12+20        | hotspot  | jdk  | 176.75  MB | urn:net.shipilev.builds      | loom nightly release
36205f634a9cdd5abafb30b42636a1c5e5ad99c5                               | x64          | windows  | 12+20        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | loom nightly release
fec8d2443b4a57ce8f18a88703583741e8c1dc9a                               | x64          | windows  | 12+20        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | fastdebug loom nightly
73973947e6a1d2c7a6eaf9791673f719bd6a497b                               | x64          | windows  | 12+20        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | loom nightly slowdebug
e5813af65d68c5010c3aa800d352e19cc68de947                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 274.82  MB | urn:net.shipilev.builds      | nightly slowdebug
87f957dfeca75e33cdd674454512a44e0068fa2a                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 79.25   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
8c19561bf207fccd4c7cb2f51a48480d8e09870d                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 105.63  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
11819eed76a7d55ad0a9885341b59d8d9462cb57                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 76.97   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
d720238f22652fd0e3ecdf97c1bdfff6e48def65                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 111.91  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
ddf0983c023a040fdef297fe016a9a053f42cd3c                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 339.94  MB | urn:net.shipilev.builds      | fastdebug nightly
5ff676fed75604c289aa1d911240aef54abbd60d                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 105.63  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
e9de27d1fc1d0ae90c5dc85f1ebd89fa978108a8                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 105.49  MB | urn:net.shipilev.builds      | fastdebug nightly
745d065650be81df59dd5245b69e7abf8e284ebb                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 116.27  MB | urn:net.shipilev.builds      | nightly release
e07a73ef61a4900ebd9f9924e5cd7704a31d154d                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 116.45  MB | urn:net.shipilev.builds      | nightly release shenandoah
145562434577023a90f9d5dcefb40c9cf49f18ef                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 116.46  MB | urn:net.shipilev.builds      | nightly release shenandoah
0b1d2725e89945ec939eeedc1bcf849d96b4a0fb                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 76.95   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
fde14b9d88d1bd39b00df2ee65ab2b0cd34cdffe                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 111.91  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
91757fdcf3091bdbdf60c127f164fb2dab645891                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 169.43  MB | urn:net.shipilev.builds      | nightly release
68e33ab821e388b847d9f9eef094ddd135866e0c                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 116.01  MB | urn:net.shipilev.builds      | nightly release zgc
7bce94de96e795e2137db8915e7021d0b0da2a71                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 116.01  MB | urn:net.shipilev.builds      | nightly release zgc
b964c60f4b21b5fb7ab5bcb54e67d6f515fc1880                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 76.79   MB | urn:net.shipilev.builds      | nightly slowdebug
5b22a84933715acb1d5169276e6c7521fa306913                               | aarch64      | linux    | 12+21        | hotspot  | jdk  | 79.25   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
a5be0c9af101bd34305dfddc97d7df1e61e5416e                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 70.92   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
67e74172581ab59f4f000e65aefc4ffb911ce251                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 95.62   MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
b7cfa6c0a54ce5c8309ec788e81be5b73c5bc54d                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 95.76   MB | urn:net.shipilev.builds      | fastdebug nightly
41622e65270925a1a8a696dbf8d89c12e907d521                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 106.06  MB | urn:net.shipilev.builds      | nightly release
ca5fb73145626725c668439e4fec401b218e70f9                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 70.97   MB | urn:net.shipilev.builds      | nightly slowdebug
30d584ded81fbf583564bfe5166f0d9e62e1d535                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 250.91  MB | urn:net.shipilev.builds      | nightly slowdebug
1e3f5090105343b2955007c1ea0427ae9490e6dc                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 95.64   MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
21ca3b4736eaa4689ccfdcc7cd9366a19958b9ec                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 305.88  MB | urn:net.shipilev.builds      | fastdebug nightly
db009a073a939053d68c901063bac086ec65daa4                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 154.30  MB | urn:net.shipilev.builds      | nightly release
add362e2af9be1dff3d3e09f3b749560f54c77c1                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 70.93   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
9440a6662ba6776ac84f31f3d9a2626cdc99dfa8                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 105.91  MB | urn:net.shipilev.builds      | nightly release shenandoah
faf12911c10d7a90d24c8e7d7b2a506107234c04                               | arm32-hflt   | linux    | 12+21        | hotspot  | jdk  | 105.91  MB | urn:net.shipilev.builds      | nightly release shenandoah
8001cc7e39326c2ad90ba7f81b0f2c2f8f4dc41d                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 73.12   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
9ca213b6984e2a59b9a8cbdd15734acb4b83d05c                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 107.82  MB | urn:net.shipilev.builds      | nightly release
309d7f83aa3f3911559fec2a2db448b0f65c35ec                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 101.18  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
57dec4a8b440ce20439ae4c60c979adbc1ab18a5                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 107.50  MB | urn:net.shipilev.builds      | nightly release zgc
5f58fc923aa14d4a28091182e6070cf84ab25eec                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 101.02  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
1f267dd83d3454cc27909fcb21251b115aa3755c                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 107.63  MB | urn:net.shipilev.builds      | nightly release shenandoah
f1672419cffc73f65991589fc4d2966ab8755f07                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 101.18  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
e05087155a4cde6201de2849f3c043028fee24a0                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 101.06  MB | urn:net.shipilev.builds      | fastdebug nightly
eb75e81d9858b4fad890303d14fb13477b2ad819                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 73.11   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
2fc657d94df0dfe74f786aa62ca3048aef5892c5                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 257.30  MB | urn:net.shipilev.builds      | nightly slowdebug
cb0664a9e43b8cc26b8dbdf5d874724f3f7f314e                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 73.11   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
afb0a462f644d2c68408765dd1a692dd001cbbfd                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 156.31  MB | urn:net.shipilev.builds      | nightly release
d7d78ff0162d1251d2a4c5a11bd234c173b0982d                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 73.10   MB | urn:net.shipilev.builds      | nightly slowdebug
abdba847d213b4c84cebc72b1920ddd521f45f9a                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 73.12   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
7344bd9d9d749d70ad58c1111e2ee6a41847d4ac                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 101.02  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
104ba8c7b56d0256716abff98ec74b3e10253a9b                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 322.07  MB | urn:net.shipilev.builds      | fastdebug nightly
1fca94fcf26db7db1896cf4caf48a82b2dd4e7ec                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 107.63  MB | urn:net.shipilev.builds      | nightly release shenandoah
05f59d96b70ddd546f4aed9c54ddc722ad07a44c                               | ppc64le      | linux    | 12+21        | hotspot  | jdk  | 107.50  MB | urn:net.shipilev.builds      | nightly release zgc
c24fa177beb636bc4043709051e1a53a600ebeaf                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 105.45  MB | urn:net.shipilev.builds      | nightly release
9cf0e943adfc9f186437a4b9162fc9d3578b951b                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 152.38  MB | urn:net.shipilev.builds      | nightly release
034582f7d1a49e3067770dfd6eec54bac34f376c                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 98.23   MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
e784339a639620f422ef6bab3ba0360e2e3e73c0                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 105.29  MB | urn:net.shipilev.builds      | nightly release shenandoah
e996a57c6e86892f3b53a293b0769ec2708de9c2                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 75.01   MB | urn:net.shipilev.builds      | nightly slowdebug
bd2490e07483fe4dc6df4a43f4d55a1348995743                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 105.30  MB | urn:net.shipilev.builds      | nightly release shenandoah
946ed299ababd8560768910e90b1bf75df296b08                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 264.21  MB | urn:net.shipilev.builds      | nightly slowdebug
bcacf4f5e8708394e11e331d43c79cde232d84c9                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 74.93   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
7b8c02f653a0ee3256a1e30223e30bd43cac16ec                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 74.93   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
fdfd03951755776c5db961f4dc1ec60e65843045                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 98.23   MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
62124b09185f58c3b6f2d50948979a36b187eaf0                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 98.27   MB | urn:net.shipilev.builds      | fastdebug nightly
402783861b1e81dbc202363e5498732adb8ba579                               | s390x        | linux    | 12+21        | hotspot  | jdk  | 319.23  MB | urn:net.shipilev.builds      | fastdebug nightly
e58528f487d5f482b15d585dcacd3c9629a88a5c                               | x32          | linux    | 12+21        | hotspot  | jdk  | 78.63   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
2c0d6c37670ee24604f6c7f8a5f98400e950a88e                               | x32          | linux    | 12+21        | hotspot  | jdk  | 78.63   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
101b3c93f013bae3efcede5fa9310b9af5bc5fc4                               | x32          | linux    | 12+21        | hotspot  | jdk  | 100.89  MB | urn:net.shipilev.builds      | fastdebug nightly
baca17de2f8610d24b6a7c8776097ee892c5e29d                               | x32          | linux    | 12+21        | hotspot  | jdk  | 266.56  MB | urn:net.shipilev.builds      | nightly slowdebug
1dcf07ede6ae50d1d61eeeb5110dd3b0fd70232d                               | x32          | linux    | 12+21        | hotspot  | jdk  | 157.08  MB | urn:net.shipilev.builds      | nightly release
38dc2e007077d591f46967924c1b71f290c350bd                               | x32          | linux    | 12+21        | hotspot  | jdk  | 105.91  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
a13d4a7609b853e313b22fefe59d10cb9453460d                               | x32          | linux    | 12+21        | hotspot  | jdk  | 109.11  MB | urn:net.shipilev.builds      | nightly release shenandoah
6a754e756eb7b580e1569f5d653dbd75f90b167c                               | x32          | linux    | 12+21        | hotspot  | jdk  | 108.71  MB | urn:net.shipilev.builds      | nightly release
1311873abaf6ee8c9c0e39a5dd350d87f95cd4bb                               | x32          | linux    | 12+21        | hotspot  | jdk  | 76.19   MB | urn:net.shipilev.builds      | nightly slowdebug
89103696a64b2672c83562fc8e6d9212a6d9088a                               | x32          | linux    | 12+21        | hotspot  | jdk  | 109.11  MB | urn:net.shipilev.builds      | nightly release shenandoah
55ce34bcdd6c52d64e1c4f55738eabf68a392306                               | x32          | linux    | 12+21        | hotspot  | jdk  | 322.27  MB | urn:net.shipilev.builds      | fastdebug nightly
be3085029dcc7a570c6dbda09ff8c4ccce3ad974                               | x32          | linux    | 12+21        | hotspot  | jdk  | 105.92  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
46191f013fd6f2ad933bfaec560b5927dbac2f72                               | x64          | linux    | 12+21        | hotspot  | jdk  | 122.87  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
8ceeb1cf23de4e2268c0f195363998508577a50b                               | x64          | linux    | 12+21        | hotspot  | jdk  | 123.40  MB | urn:net.shipilev.builds      | nightly release zgc
a8dc8e9bf881e768be61bbca115ef52a543b87b0                               | x64          | linux    | 12+21        | hotspot  | jdk  | 89.48   MB | urn:net.shipilev.builds      | loom nightly slowdebug
cccf24287365606b8120c43d2fa7b6cf3e830072                               | x64          | linux    | 12+21        | hotspot  | jdk  | 123.41  MB | urn:net.shipilev.builds      | nightly release zgc
f8d7c8653c936bde5f0ec99fdf91975ec951fc88                               | x64          | linux    | 12+21        | hotspot  | jdk  | 89.12   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
8997d72aeccb14610c2e74c7a766ca28f262a828                               | x64          | linux    | 12+21        | hotspot  | jdk  | 89.13   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
37fd186be5781152eeae5862feaa9ee54a7d985a                               | x64          | linux    | 12+21        | hotspot  | jdk  | 124.30  MB | urn:net.shipilev.builds      | nightly release shenandoah
ef6219fae585243ecca7735dc2482cdabccc559c                               | x64          | linux    | 12+21        | hotspot  | jdk  | 302.38  MB | urn:net.shipilev.builds      | nightly slowdebug
9e702a1dcc96f6a02c1622f2bc5c7f5975ecc58f                               | x64          | linux    | 12+21        | hotspot  | jdk  | 91.91   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
ca757f348952c504f5a88e3c5b462be853c130f3                               | x64          | linux    | 12+21        | hotspot  | jdk  | 123.71  MB | urn:net.shipilev.builds      | nightly release
058d0a8f765a74418309541ca1b9eb4f21880718                               | x64          | linux    | 12+21        | hotspot  | jdk  | 88.93   MB | urn:net.shipilev.builds      | nightly slowdebug
9717cd9993ef98c7f8e11e9c5f8afd231b59531c                               | x64          | linux    | 12+21        | hotspot  | jdk  | 129.18  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
215871aa40df935b3e2f428c4ef91b600071e4ad                               | x64          | linux    | 12+21        | hotspot  | jdk  | 129.17  MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
716b372d8c0ceae9b97b486b98a83fb6d3f6d0b2                               | x64          | linux    | 12+21        | hotspot  | jdk  | 122.86  MB | urn:net.shipilev.builds      | fastdebug nightly zgc
4f58887133e0577e711332368d90b3fad4514156                               | x64          | linux    | 12+21        | hotspot  | jdk  | 123.73  MB | urn:net.shipilev.builds      | loom nightly release
8a86b4d7e128872038069c8b9948a975b3c577a6                               | x64          | linux    | 12+21        | hotspot  | jdk  | 377.94  MB | urn:net.shipilev.builds      | fastdebug nightly
6f7d6c1269e00ba7186a6fbd24056c244e42fb35                               | x64          | linux    | 12+21        | hotspot  | jdk  | 124.30  MB | urn:net.shipilev.builds      | nightly release shenandoah
119303d7130d42c048502745e8a3d7e0710d17b8                               | x64          | linux    | 12+21        | hotspot  | jdk  | 91.92   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
4d4b9fda3681ca911c015a05b48bc0e3e964e9f0                               | x64          | linux    | 12+21        | hotspot  | jdk  | 122.66  MB | urn:net.shipilev.builds      | fastdebug nightly
f693ac944176ce4351d44356c32d1fe66613e900                               | x64          | linux    | 12+21        | hotspot  | jdk  | 176.80  MB | urn:net.shipilev.builds      | nightly release
9c8be5a107ec2f7b2075aedce863d802bef3ed74                               | x64          | windows  | 12+21        | hotspot  | jdk  | 73.96   MB | urn:net.shipilev.builds      | nightly shenandoah slowdebug
9fbf055805d4d5767e5e1a06e200c09c1e40288c                               | x64          | windows  | 12+21        | hotspot  | jdk  | 184.56  MB | urn:net.shipilev.builds      | nightly release zgc
32cde4bbe4af9623af19833663ac68a4c59e6e86                               | x64          | windows  | 12+21        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | fastdebug loom nightly
29d1cf3b48a16c35f00b62052b7b9ee684e6acde                               | x64          | windows  | 12+21        | hotspot  | jdk  | 240.33  MB | urn:net.shipilev.builds      | nightly release
8badae50d2e782ccd023c9abbee606febd67e9b3                               | x64          | windows  | 12+21        | hotspot  | jdk  | 73.70   MB | urn:net.shipilev.builds      | fastdebug nightly zgc
beca288685a5f3c077dfb5d79f960c456017a558                               | x64          | windows  | 12+21        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | loom nightly release
948b5248ea66c1e376ddff4e878b2315b6ce2e5b                               | x64          | windows  | 12+21        | hotspot  | jdk  | 205.90  MB | urn:net.shipilev.builds      | fastdebug nightly
29384ff9b699b7d8d8675ca521bc457ecc953ae8                               | x64          | windows  | 12+21        | hotspot  | jdk  | 73.60   MB | urn:net.shipilev.builds      | nightly slowdebug zgc
42c5e89cbffe1bad79efcf7ea90e654e5fcecb83                               | x64          | windows  | 12+21        | hotspot  | jdk  | 189.06  MB | urn:net.shipilev.builds      | nightly release shenandoah
2ef36f7bb3856ee92e2080accb186c639961b330                               | x64          | windows  | 12+21        | hotspot  | jdk  | 0.00    MB | urn:net.shipilev.builds      | loom nightly slowdebug
450217456d789a9508e706098f74162dfab73e93                               | x64          | windows  | 12+21        | hotspot  | jdk  | 74.09   MB | urn:net.shipilev.builds      | fastdebug nightly shenandoah
c4828da3ed447e7046000dc467d68b44430ee72b                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 105.47  MB | urn:net.shipilev.builds      | fastdebug nightly
daa855eaaf2b40ae6e3f34d7d01793857c66aecc                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 116.07  MB | urn:net.shipilev.builds      | nightly release
fa11c1973f987aa8d1923e8c23c8b539044e0d6b                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 76.78   MB | urn:net.shipilev.builds      | nightly slowdebug
20bea8ab498eb71e2984080895740c84995d3ea8                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 116.08  MB | urn:net.shipilev.builds      | nightly release
d99ad721c511248f985c272c6f914c55165d20c9                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 105.47  MB | urn:net.shipilev.builds      | fastdebug nightly
abfb427010e0e79ee4f2ad7785e126c53869584b                               | aarch64      | linux    | 12+22        | hotspot  | jdk  | 76.77   MB | urn:net.shipilev.builds      | nightly slowdebug
ade576f034a7608b69be5c95b77a28d98a986822                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 105.89  MB | urn:net.shipilev.builds      | nightly release
2dbab8e9d43cd02852076dba034ec1f09df09565                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 105.89  MB | urn:net.shipilev.builds      | nightly release
63fd16add4a56597ea11bdeb3d46cc841f480fa0                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 70.91   MB | urn:net.shipilev.builds      | nightly slowdebug
e2336c0905eaaf36921bdd69fe1f36c8c7a37328                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 95.63   MB | urn:net.shipilev.builds      | fastdebug nightly
4ead3442d37850050b9a7eb5e270a16373db7fa1                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 95.63   MB | urn:net.shipilev.builds      | fastdebug nightly
edbc20db468b286c9fe9cfbdb071e9174e8c597a                               | arm32-hflt   | linux    | 12+22        | hotspot  | jdk  | 70.91   MB | urn:net.shipilev.builds      | nightly slowdebug
8832b45a9778af07bf411a235b267e71d2740a45                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 101.05  MB | urn:net.shipilev.builds      | fastdebug nightly
cb16f5f55b578bc5c8317c9458443752f33f61f9                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 101.06  MB | urn:net.shipilev.builds      | fastdebug nightly
d85ae765bfb08882d534b31c6dc0f5d2eebd287d                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 73.09   MB | urn:net.shipilev.builds      | nightly slowdebug
deffdd0a4ac6c31ba93f8af8be60f4a2e405f0cf                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 73.04   MB | urn:net.shipilev.builds      | nightly slowdebug
b1fea013f575e060197d3fdf03d3d5ece70f29b2                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 107.58  MB | urn:net.shipilev.builds      | nightly release
f9a0711959cc2c3aa551174229fcdb6a8214966a                               | ppc64le      | linux    | 12+22        | hotspot  | jdk  | 107.59  MB | urn:net.shipilev.builds      | nightly release
11fc3c55e8c402ef283e37cb9d17b22cf15d7e8a                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 74.93   MB | urn:net.shipilev.builds      | nightly slowdebug
5bc8eb499eeccd85958b97feb000d4628001bb17                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 98.27   MB | urn:net.shipilev.builds      | fastdebug nightly
91cda32d77b6e393438e06ae2e1b2118b5d84c9b                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 74.92   MB | urn:net.shipilev.builds      | nightly slowdebug
f1036a7750c38a8b968f6e9e18f11f9204c31217                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 105.26  MB | urn:net.shipilev.builds      | nightly release
14a4ea6969efbbc04253f7e22d7c0120b96031b5                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 105.27  MB | urn:net.shipilev.builds      | nightly release
0df043bbfa95203e85b612170f52f8454db7de8f                               | s390x        | linux    | 12+22        | hotspot  | jdk  | 98.27   MB | urn:net.shipilev.builds      | fastdebug nightly
cdd533589be7e38f87d4e98a97587c73cd73c1b5                               | x32          | linux    | 12+22        | hotspot  | jdk  | 100.85  MB | urn:net.shipilev.builds      | fastdebug nightly
5f9cec29fa4f2c93f157cc2640c2981b4a69440c                               | x32          | linux    | 12+22        | hotspot  | jdk  | 76.11   MB | urn:net.shipilev.builds      | nightly slowdebug
ff71f742221c502896f8bad84ad3729aab48c367                               | x32          | linux    | 12+22        | hotspot  | jdk  | 108.51  MB | urn:net.shipilev.builds      | nightly release
0f479807949d04a7af905c6ae81f2b4e036d9175                               | x32          | linux    | 12+22        | hotspot  | jdk  | 76.14   MB | urn:net.shipilev.builds      | nightly slowdebug
1703f27550bd19944f34413a0f2e45bb66d06eab                               | x32          | linux    | 12+22        | hotspot  | jdk  | 100.85  MB | urn:net.shipilev.builds      | fastdebug nightly
6d6b52663c3f9573d3c9d0c8bab700b3cb9c5e1e                               | x32          | linux    | 12+22        | hotspot  | jdk  | 108.51  MB | urn:net.shipilev.builds      | nightly release
930431b22fc11f6c025b1ca3bfe9d05bc266ae5a                               | x64          | linux    | 12+22        | hotspot  | jdk  | 88.94   MB | urn:net.shipilev.builds      | nightly slowdebug
6ec8da134510d02a7f9a33c8ce4bef1892b087c4                               | x64          | linux    | 12+22        | hotspot  | jdk  | 88.89   MB | urn:net.shipilev.builds      | nightly slowdebug
02e57db05c0d922a967646a5704a347f3a5585bc                               | x64          | linux    | 12+22        | hotspot  | jdk  | 123.50  MB | urn:net.shipilev.builds      | nightly release
d9e0cdbc7681b46a83cfb2744fa9e0fc37c2cbf9                               | x64          | linux    | 12+22        | hotspot  | jdk  | 123.49  MB | urn:net.shipilev.builds      | nightly release
dc92b0c4108f2d451c2d91d382d89a98bde38609                               | x64          | linux    | 12+22        | hotspot  | jdk  | 122.63  MB | urn:net.shipilev.builds      | fastdebug nightly
d8ae2e75adca53ba039f814029a823d3b605fe46                               | x64          | linux    | 12+22        | hotspot  | jdk  | 122.61  MB | urn:net.shipilev.builds      | fastdebug nightly
68d8667ef7cc5fa6c37c1cd6c061f38f41a4ebb9                               | x64          | windows  | 12+22        | hotspot  | jdk  | 184.55  MB | urn:net.shipilev.builds      | nightly release
75bd2660224ccde06c14989cf6dc260cd561d930                               | x64          | windows  | 12+22        | hotspot  | jdk  | 73.60   MB | urn:net.shipilev.builds      | nightly slowdebug
2d8be6d22c8e0d28a2f495eb50cfc44f9da15420                               | x64          | windows  | 12+22        | hotspot  | jdk  | 73.71   MB | urn:net.shipilev.builds      | fastdebug nightly

[coffeepick]$ download 2d8be6d22c8e0d28a2f495eb50cfc44f9da15420
[    5.20 MB /    73.71 MB] |+++++                                                       | 5.20MB/s
[   10.59 MB /    73.71 MB] |+++++++++                                                   | 5.39MB/s
[   15.93 MB /    73.71 MB] |+++++++++++++                                               | 5.34MB/s
[   21.11 MB /    73.71 MB] |++++++++++++++++++                                          | 5.18MB/s
[   24.51 MB /    73.71 MB] |++++++++++++++++++++                                        | 3.41MB/s
[   28.25 MB /    73.71 MB] |+++++++++++++++++++++++                                     | 3.74MB/s
[   32.54 MB /    73.71 MB] |+++++++++++++++++++++++++++                                 | 4.29MB/s
[   36.15 MB /    73.71 MB] |++++++++++++++++++++++++++++++                              | 3.60MB/s
[   40.32 MB /    73.71 MB] |+++++++++++++++++++++++++++++++++                           | 4.18MB/s
[   45.22 MB /    73.71 MB] |+++++++++++++++++++++++++++++++++++++                       | 4.90MB/s
[   50.30 MB /    73.71 MB] |+++++++++++++++++++++++++++++++++++++++++                   | 5.08MB/s
[   53.58 MB /    73.71 MB] |++++++++++++++++++++++++++++++++++++++++++++                | 3.28MB/s
[   58.12 MB /    73.71 MB] |++++++++++++++++++++++++++++++++++++++++++++++++            | 4.54MB/s
[   62.97 MB /    73.71 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++        | 4.85MB/s
[   66.97 MB /    73.71 MB] |+++++++++++++++++++++++++++++++++++++++++++++++++++++++     | 4.00MB/s
[   70.62 MB /    73.71 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  | 3.66MB/s
Download finished
Runtime archive: /home/rm/local/coffeepick/inventory/2d8be6d22c8e0d28a2f495eb50cfc44f9da15420/archive

In his own words:

... the binaries there are very volatile by nature, many rotate daily, so hooking them up to something more or less permanent would be problematic.

Expect to have to run repository-update urn:net.shipilev.builds every day if you use the repository!

Lurking Between Releases

A while back, I talked about moving to the bndtools suite of Maven plugins in preference to the Felix bundle plugin. The reason for this is better cross-IDE compatibility: Eclipse only really works with bndtools, whilst Intellij IDEA only really works with the Felix maven-bundle-plugin. This means that the plugin you choose to use in your Maven project ends up dictating which IDE developers must use in order to work with it. That's not great! However, I discovered that Intellij IDEA could be configured to use the OSGi manifest file that the bndtools Maven plugin creates, and therefore that means that developers can use either IDE as long as I use the bndtools plugins in my own projects.

Unfortunately, upon switching to the bndtools plugin in the primogenitor, I soon ran into MNG-6059 and MNG-5951. Briefly, Maven has some baked-in behaviour that is intended to produce metadata that follows the conventions people used when everyone used SVN to manage source code. However, those conventions result in Maven producing metadata that's essentially incorrect with regards to modern conventions. Specifically, Maven will automatically append module names to URIs specified in your project, because it assumes that you've laid out files in a particular way on remote servers. This automatic name appending could not previously be turned off. However, Maven 3.6.0 provided support for some attributes that you could place into your pom.xml files that would disable this automatic appending. Additionally, 3.6.0 comes with numerous fixes for working with Java 11 bytecode. As I recently decided that Java 11 was the new minimum version that I was going to support, 3.6.0 is really a requirement moving forward.

Unfortunately, this has now lead to further problems! One problem is that it's not possible to push a pom.xml file containing the new attributes to Maven Central because the version of Nexus running on Central can't parse the new POM files yet. The second problem is that the attributes are not inherited. I currently have over 850 pom.xml files spread over close to a hundred projects. There's just no way I'm going to edit each and every pom.xml file and add those attributes by hand. I want to specify them once in the primogenitor and have them apply everywhere. I've raised both points on the Maven mailing list, and my cries have been heard. All of this will hopefully be fixed in 3.6.1.

After all is said and done, this means that I can't start moving projects to Java 11 just yet or even do a full 3.0.0 release of the primogenitor because I need Maven 3.6.1 to do so. I wasn't available to test 3.6.0 much before it was released, but I can do plenty of testing for 3.6.1. It looks like I'll temporarily be in limbo for a couple of months!

Choosing Coffee

Now that jlink exists, it's become fashionable to bundle a JVM along with your Java bytecode. In applications that use the JPMS, the jlink tool can calculate the transitive closure of required modules and produce a tiny JVM that contains your application modules and only those platform modules required to run the application.

Because I'm using OSGi, I don't care about this particular aspect of jlink. What I am interested in is that, because of jlink, it has become a lot easier to bundle a JVM with an application. Projects such as AdoptOpenJDK produce production-ready builds of JVMs for a large range of platforms and architectures, including Hotspot and OpenJ9 VMs.

Now there is a downside to this: Java applications should, by their very nature, be completely platform-independent. If I give someone a jar file of Java 11 bytecode, it should run correctly on any JVM on any platform supporting Java 11+. If I instead start producing one distribution per platform and architecture including a bundled JVM, then by definition my application distributions are no longer platform-independent. Worse, even though jlink still bundles your application's bytecode along with the produced JVM, that bytecode is (by default) stored in an undocumented binary format along with the platform modules as one indivisible lump. I don't believe it's possible for the user to say "well, I don't want to use the bundled JVM, I'll just point my system JVM at the classes and use that".

What I would much rather do is still produce one distribution that contains a bundled JVM for each of the common platforms and architectures (let's say Linux x86_64, Windows x86_64, and MacOS x86_64) but also provide a basic shell script that can be used to start the application from a system JVM if the user so wishes (with the support caveat that if it doesn't work, they're on their own). The bytecode should still be stored exactly as it was in the original jar files (and in my case, would actually have to be stored like this because the jar files are OSGi bundles).

The ideal situation would be if I could have a Maven plugin that, given a range of platforms and architectures, automatically fetched one runtime suitable for each platform/architecture and then packaged up the whole application including all of the runtimes into one platform-independent distribution archive.

So, I've decided to write one!

The CoffeePick project provides an API and an interactive shell used to search for and download Java runtimes. The API works via a pluggable service provider model where new repositories of runtimes can be added at build-time or, if running on OSGi, at run-time.

Currently, arguably the two most popular places to get JVMs are:

The CoffeePick project currently contains providers for both of those repositories, and the AdoptOpenJDK module automatically finds new builds as the AdoptOpenJDK project publishes them.

There now follows small demo of the interactive shell.

First, we start up the shell:

$ java -jar com.io7m.coffeepick.shell/target/com.io7m.coffeepick.shell-0.0.1-main.jar
User directory: /home/rm/local/coffeepick
Loading repositories…
INFO com.io7m.coffeepick.client.vanilla.CoffeePickCatalog: setting up repository from provider net.java.jdk (urn:net.java.jdk)
INFO com.io7m.coffeepick.client.vanilla.CoffeePickCatalog: setting up repository from provider net.adoptopenjdk.raw (urn:net.adoptopenjdk.raw)

The shell uses jline3 internally and so has a full command-line history and limited tab-completion for command names.

Let's say we want to grab a Java 11 compatible runtime that will execute on Linux on the x86_64 architecture. The CoffeePick API refers to the current set of runtimes that we can download as the catalog. The catalog command, without any arguments, will list every available runtime:

[coffeepick]$ catalog
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
8eee0aede947b804f9a5f49c8a38b52aace8a30a9ebd9383b7d06042fb5a237c       | aarch64  | linux    | 8        | hotspot  | jdk  | 75.38   MB | urn:net.adoptopenjdk.raw     | production
b0b3923a48243fa98b71c7fd8ff96def453e07b33156e90cb6851b7b7cacd4b1       | aarch64  | linux    | 8        | hotspot  | jre  | 39.53   MB | urn:net.adoptopenjdk.raw     | production
4f245d8bb2e6b84876edcc3573d9f8609e7596cb99102419b2174ed146aca642       | ppc64    | aix      | 8        | openj9   | jdk  | 87.50   MB | urn:net.adoptopenjdk.raw     | production
af2532a428fbeb6e6896279a874a3d4b574b74a6ebeae16e4771d7ad517f653a       | ppc64le  | linux    | 8        | openj9   | jdk  | 89.53   MB | urn:net.adoptopenjdk.raw     | production
e7fd779a6448259641565ca31f258d11052c9997e762bc63bbaa2b5776de98f1       | ppc64le  | linux    | 8        | openj9   | jre  | 48.62   MB | urn:net.adoptopenjdk.raw     | production
b092f4e6553a7c50872b0963f4de2b3a2bce78ce11d1bf1905a2ad5a6576924b       | s390x    | linux    | 8        | openj9   | jdk  | 90.37   MB | urn:net.adoptopenjdk.raw     | production
f0bc82fa49a2a02e881d403170cd8b273fc3d1585a4e65ff639666f056ce7362       | x64      | linux    | 8        | openj9   | jdk  | 90.12   MB | urn:net.adoptopenjdk.raw     | large-heap production
fd7035c60ad3060fccf7ab67c15b722302a1863ebddd3141dc3dd98bd0b25a68       | x64      | linux    | 8        | openj9   | jdk  | 90.24   MB | urn:net.adoptopenjdk.raw     | production
d1ee522053bb4135536b1d3173be8224bf54563d166e882b7ee2ccf609c2517f       | aarch64  | linux    | 9        | hotspot  | jdk  | 190.65  MB | urn:net.adoptopenjdk.raw     | production
36e4955c0fec6ff6494c5274e6950fdd45e73b11ebe97efdcb9768e07981f626       | aarch64  | linux    | 9        | hotspot  | jre  | 37.12   MB | urn:net.adoptopenjdk.raw     | production
d304cbfc9674ff1e1b0caf916b59c32ee9c477e5be6cfa071131b866cd54ec4c       | ppc64    | aix      | 9        | hotspot  | jdk  | 198.43  MB | urn:net.adoptopenjdk.raw     | production
359c65179f839c5ba0959710803c556c3ce2046dcb0762f2165595706b9b8272       | ppc64le  | linux    | 9        | hotspot  | jre  | 36.84   MB | urn:net.adoptopenjdk.raw     | production
bd4736feea702c859102bb78145fe3c7dbf6774ce1d66d00a9fc582d6bbeb564       | ppc64le  | linux    | 9        | hotspot  | jdk  | 190.36  MB | urn:net.adoptopenjdk.raw     | production
6382fe043c0ef1cf5b38cf3f70cc300bbdd66f16fa6e9b1ffbfe6a9cdda9011d       | ppc64le  | linux    | 9        | hotspot  | jdk  | 190.49  MB | urn:net.adoptopenjdk.raw     | production
84bbfca72cbabf04a2fd0e35d0faba03f91977573600edc23714b03aa1ec6fd9       | ppc64le  | linux    | 9        | hotspot  | jre  | 36.86   MB | urn:net.adoptopenjdk.raw     | production
0510af0db7531eb45bb8723810a10e146a80223cf5b72da077bc41e0e66724e3       | s390x    | linux    | 9        | hotspot  | jre  | 38.52   MB | urn:net.adoptopenjdk.raw     | production
7bfdc389c25820e08a85eb3a32c4193189f13945847619b14966f7fd45a5c345       | s390x    | linux    | 9        | hotspot  | jdk  | 193.60  MB | urn:net.adoptopenjdk.raw     | production
aa4fc8bda11741facaf3b8537258a4497c6e0046b9f4931e31f713d183b951f1       | x64      | linux    | 9        | hotspot  | jdk  | 207.46  MB | urn:net.adoptopenjdk.raw     | production
b58848cb7229a1dc2c135dbb85cce56cee33ab29849aa432e2ba26bf8f517dca       | x64      | linux    | 9        | hotspot  | jre  | 41.55   MB | urn:net.adoptopenjdk.raw     | production
b6a14f8dda60528bbb890877b62b7cf6e81bbbe19256bfd38a3ba4390c4eca5e       | x64      | linux    | 9        | hotspot  | jre  | 41.53   MB | urn:net.adoptopenjdk.raw     | production
ebe1eaad73584f70ab4e587ab9367fb15af820745979e68350fe80fadf615df8       | x64      | linux    | 9        | hotspot  | jdk  | 207.33  MB | urn:net.adoptopenjdk.raw     | production
bbe348baab3cca097b77f7fff6c8465858e642ad42c5851bde33a1553ca12653       | x64      | macos    | 9        | hotspot  | jdk  | 189.34  MB | urn:net.adoptopenjdk.raw     | production
f92931d258486d77dd986fa0fd2574075569e2f76624822d50bfae01ed72e7e7       | x64      | macos    | 9        | hotspot  | jre  | 35.70   MB | urn:net.adoptopenjdk.raw     | production
0373b5be04f98c0077c5b87c2020ecac2fedd36f68e75bbae38d433753506323       | x64      | windows  | 9        | hotspot  | jre  | 36.21   MB | urn:net.adoptopenjdk.raw     | production
b2de88155b2eaad123c2615f7eb3c0442d77545046bf85cfbcfe44fc97931dbd       | x64      | windows  | 9        | hotspot  | jdk  | 192.42  MB | urn:net.adoptopenjdk.raw     | production
3bb2faaba9f1a4f6e212ff34c5f2cfb4d5f083c1623cd2ad24108e0bb542e394       | x64      | windows  | 9        | hotspot  | jre  | 36.25   MB | urn:net.adoptopenjdk.raw     | production
709baaf217d24503dff3194fd66aa25ae5976b3f52ed3a564cdd270b6f5eef40       | x64      | windows  | 9        | hotspot  | jdk  | 192.27  MB | urn:net.adoptopenjdk.raw     | production
b66121b9a0c2e7176373e670a499b9d55344bcb326f67140ad6d0dc24d13d3e2       | aarch64  | linux    | 11       | hotspot  | jdk  | 193.39  MB | urn:net.adoptopenjdk.raw     | production
0f4edea90e57765562740721d052946408273e9744093266f65c02a7fb26800c       | ppc64    | aix      | 11       | openj9   | jre  | 46.93   MB | urn:net.adoptopenjdk.raw     | production
eaae79f3a89a6d71f34e9b41cbdfdb14f70988284d9e76427ed705514c614cc3       | ppc64    | aix      | 11       | openj9   | jdk  | 196.64  MB | urn:net.adoptopenjdk.raw     | production
39f97d76a0121f9a2b6e26bc201194921797fcc6c2181871086f09f8bce5862f       | ppc64    | aix      | 11       | openj9   | jdk  | 196.64  MB | urn:net.adoptopenjdk.raw     | production
001fd98ca5b5215eac616ed26341052ac1b426d7a55bbca7d28d48137fa9f295       | ppc64    | aix      | 11       | openj9   | jdk  | 196.65  MB | urn:net.adoptopenjdk.raw     | production
43f727ce6bca1ed826181f1a924c9f64a43728e3a222284fd2fbfbe9e4ef199c       | ppc64    | aix      | 11       | openj9   | jdk  | 196.65  MB | urn:net.adoptopenjdk.raw     | production
35e36d7a20a773e291b728de5d4977485a0d44a54f1433cdf6e6288c331557ea       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.51  MB | urn:net.adoptopenjdk.raw     | production
4577350c35f4193430b3ae0094e54869b54aadbc76a50c1518069937a63d54d8       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.52  MB | urn:net.adoptopenjdk.raw     | production
747c4613b36f6e86ee4a10848b1a7f009d1bde729acf31bb6350c3cc08a7475d       | ppc64le  | linux    | 11       | openj9   | jre  | 41.38   MB | urn:net.adoptopenjdk.raw     | production
fcc9a2b183a9238e1927d6088d7c99031f517d62026e8b33d02dfd883b1ca95e       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.55  MB | urn:net.adoptopenjdk.raw     | production
c18364a778b1b990e8e62d094377af48b000f9f6a64ec21baff6a032af06386d       | ppc64le  | linux    | 11       | hotspot  | jdk  | 179.52  MB | urn:net.adoptopenjdk.raw     | production
fb3f4ddaf3e2a9490e34b385e00d76cf6142806d47bd619ef7c193c12acfbb01       | s390x    | linux    | 11       | openj9   | jdk  | 197.27  MB | urn:net.adoptopenjdk.raw     | production
249ad469735c42fa80fcf4123bc76f7e398ff3349ce6fb4bfa65a850fb70f6f8       | s390x    | linux    | 11       | openj9   | jdk  | 197.27  MB | urn:net.adoptopenjdk.raw     | production
119bd9d9faf1bb596b9ca74740f12cc23c20fe9331d312f1c2b59eb15a76625f       | x32      | windows  | 11       | hotspot  | jdk  | 174.24  MB | urn:net.adoptopenjdk.raw     | production
0b6050cc670eefd9465370ab19ae70401476430fca329e65f0dd636ca9cce9bd       | x64      | linux    | 11       | openj9   | jdk  | 195.41  MB | urn:net.adoptopenjdk.raw     | large-heap production
ef9bf07cba79082285a9d426ea4eb3e8df57561ce2afe07cc5f299a8fa203279       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
10b2400add0070b64db91026f12b798708e59772a81492fd2b638638f71ed14f       | x64      | linux    | 11       | hotspot  | jdk  | 186.61  MB | urn:net.java.jdk             | early-access valhalla
cac1fe096ea161613d5afe8a04ce3294dc1b535f5f4ea1a4235ce425b2610678       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
765947ab9457a29d2aa9d11460a4849611343c1e0ea3b33b9c08409cd4672251       | x64      | linux    | 11       | openj9   | jdk  | 195.50  MB | urn:net.adoptopenjdk.raw     | production
e0446e80eeb90ab97fd59f91ae094bdd658c354943d4e33e0ddf691714f9da4d       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
518e9330f2aeb020bca31a07034a08c3a568823e703fc503e03206acdad9dae5       | x64      | linux    | 11       | openj9   | jre  | 40.91   MB | urn:net.adoptopenjdk.raw     | large-heap production
9306fa569d2d5abf982df0b4ffa5d30c652cf16139d7b2268db30d2886f3adbf       | x64      | linux    | 11       | openj9   | jdk  | 195.42  MB | urn:net.adoptopenjdk.raw     | large-heap production
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
a016413fd8415429b42e543fed7a1bee5010b1dbaf71d29a26e1c699f334c6ff       | x64      | linux    | 11       | openj9   | jre  | 40.96   MB | urn:net.adoptopenjdk.raw     | production
11cb48e3592f46f2c2dab095e3b9a4fec60b89199827f2b737a14b54dc5fd68d       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
c5e9b588b4ac5b0bd5b4edd69d59265d1199bb98af7ca3270e119b264ffb6e3f       | x64      | macos    | 11       | openj9   | jdk  | 180.99  MB | urn:net.adoptopenjdk.raw     | production
0901dc5946fdf967f92f7b719ddfffdcdde5bd3fef86a83d7a3f2f39ddbef1f8       | x64      | macos    | 11       | openj9   | jre  | 38.63   MB | urn:net.adoptopenjdk.raw     | production
92494f79cc296625778a50d04816aabedca9cd9666b7bab8f1c3b96f06c82f97       | x64      | macos    | 11       | hotspot  | jdk  | 180.75  MB | urn:net.java.jdk             | early-access valhalla
c9a816d6a3f8aac9dc5b3b41c5a9e4e5460af433a06e003ae25d5a06dea8375f       | x64      | macos    | 11       | openj9   | jdk  | 180.95  MB | urn:net.adoptopenjdk.raw     | production
67785f46b264f7a91358cea41e4f7e0880685175a2a18f1f3890828a577fe067       | x64      | macos    | 11       | openj9   | jdk  | 180.95  MB | urn:net.adoptopenjdk.raw     | production
e219e7e2d586ed09ae65f4ec390fca5d5f0c37a61b47677648610194daf1aaa7       | x64      | macos    | 11       | hotspot  | jdk  | 189.91  MB | urn:net.adoptopenjdk.raw     | production
f34ced35547e53dd400c1ee99a63d8bf68e45370bc7b098e32f0b7107a60e00b       | x64      | macos    | 11       | openj9   | jdk  | 181.00  MB | urn:net.adoptopenjdk.raw     | production
b8960753a66190fa81982682357a2449b4183f3e23c20a5e3b4cf01e2989846b       | x64      | macos    | 11       | openj9   | jdk  | 181.00  MB | urn:net.adoptopenjdk.raw     | production
ef7c411c3b3e06f93874b15b598c36020b192a1a3096c5d9d5eae7799f8bcd49       | x64      | windows  | 11       | openj9   | jdk  | 196.96  MB | urn:net.adoptopenjdk.raw     | production
d104c7337ff3cd03fb37d048860192a3de5cbab4b158a681bc20cc521b6da954       | x64      | windows  | 11       | openj9   | jdk  | 196.90  MB | urn:net.adoptopenjdk.raw     | production
b1eb84f5bfce03058f266d7303ad02fcf4d6f2b05c989989ae7b0bd5a663a5a7       | x64      | windows  | 11       | hotspot  | jdk  | 192.97  MB | urn:net.adoptopenjdk.raw     | production
106c242e946a74ba71ff22b5a980c375b7cd13fd4550fb3698333e06a1f33243       | x64      | windows  | 11       | hotspot  | jdk  | 180.82  MB | urn:net.java.jdk             | early-access valhalla
d33551f15f8d4bc5f97471bca669872665e5db15cc8a5ac88f068e23f56bb129       | x64      | windows  | 11       | openj9   | jre  | 40.06   MB | urn:net.adoptopenjdk.raw     | production
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production
fa07eee08fa0f3de541ee1770de0cdca2ae3876f3bd78c329f27e85c287cd070       | x64      | macos    | 11.0.1   | hotspot  | jdk  | 182.09  MB | urn:net.java.jdk             | production
289dd06e06c2cbd5e191f2d227c9338e88b6963fd0c75bceb9be48f0394ede21       | x64      | windows  | 11.0.1   | hotspot  | jdk  | 187.42  MB | urn:net.java.jdk             | production
33a5f5b063dde3a66a98cf691bd00b21c012950ae1af253e19dcc68d74a75f65       | x64      | linux    | 12       | hotspot  | jdk  | 304.88  MB | urn:net.java.jdk             | early-access panama
95a033710ed71962c33b226afdbb222442bf0098ea3705448f0d14f0b3044bab       | x64      | macos    | 12       | hotspot  | jdk  | 233.21  MB | urn:net.java.jdk             | early-access panama

As can be seen, there are currently rather a lot of runtimes. We can start narrowing down the runtimes that we want by passing in search parameters. Searching is provided by the API directly and the API for this is believed to be stable, however the syntax for the shell is currently subject to change and may even be outdated by the time you read this. Let's limit ourselves to Linux runtimes:

[coffeepick]$ catalog platform:linux
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
8eee0aede947b804f9a5f49c8a38b52aace8a30a9ebd9383b7d06042fb5a237c       | aarch64  | linux    | 8        | hotspot  | jdk  | 75.38   MB | urn:net.adoptopenjdk.raw     | production
b0b3923a48243fa98b71c7fd8ff96def453e07b33156e90cb6851b7b7cacd4b1       | aarch64  | linux    | 8        | hotspot  | jre  | 39.53   MB | urn:net.adoptopenjdk.raw     | production
af2532a428fbeb6e6896279a874a3d4b574b74a6ebeae16e4771d7ad517f653a       | ppc64le  | linux    | 8        | openj9   | jdk  | 89.53   MB | urn:net.adoptopenjdk.raw     | production
e7fd779a6448259641565ca31f258d11052c9997e762bc63bbaa2b5776de98f1       | ppc64le  | linux    | 8        | openj9   | jre  | 48.62   MB | urn:net.adoptopenjdk.raw     | production
b092f4e6553a7c50872b0963f4de2b3a2bce78ce11d1bf1905a2ad5a6576924b       | s390x    | linux    | 8        | openj9   | jdk  | 90.37   MB | urn:net.adoptopenjdk.raw     | production
fd7035c60ad3060fccf7ab67c15b722302a1863ebddd3141dc3dd98bd0b25a68       | x64      | linux    | 8        | openj9   | jdk  | 90.24   MB | urn:net.adoptopenjdk.raw     | production
f0bc82fa49a2a02e881d403170cd8b273fc3d1585a4e65ff639666f056ce7362       | x64      | linux    | 8        | openj9   | jdk  | 90.12   MB | urn:net.adoptopenjdk.raw     | large-heap production
d1ee522053bb4135536b1d3173be8224bf54563d166e882b7ee2ccf609c2517f       | aarch64  | linux    | 9        | hotspot  | jdk  | 190.65  MB | urn:net.adoptopenjdk.raw     | production
36e4955c0fec6ff6494c5274e6950fdd45e73b11ebe97efdcb9768e07981f626       | aarch64  | linux    | 9        | hotspot  | jre  | 37.12   MB | urn:net.adoptopenjdk.raw     | production
359c65179f839c5ba0959710803c556c3ce2046dcb0762f2165595706b9b8272       | ppc64le  | linux    | 9        | hotspot  | jre  | 36.84   MB | urn:net.adoptopenjdk.raw     | production
bd4736feea702c859102bb78145fe3c7dbf6774ce1d66d00a9fc582d6bbeb564       | ppc64le  | linux    | 9        | hotspot  | jdk  | 190.36  MB | urn:net.adoptopenjdk.raw     | production
6382fe043c0ef1cf5b38cf3f70cc300bbdd66f16fa6e9b1ffbfe6a9cdda9011d       | ppc64le  | linux    | 9        | hotspot  | jdk  | 190.49  MB | urn:net.adoptopenjdk.raw     | production
84bbfca72cbabf04a2fd0e35d0faba03f91977573600edc23714b03aa1ec6fd9       | ppc64le  | linux    | 9        | hotspot  | jre  | 36.86   MB | urn:net.adoptopenjdk.raw     | production
0510af0db7531eb45bb8723810a10e146a80223cf5b72da077bc41e0e66724e3       | s390x    | linux    | 9        | hotspot  | jre  | 38.52   MB | urn:net.adoptopenjdk.raw     | production
7bfdc389c25820e08a85eb3a32c4193189f13945847619b14966f7fd45a5c345       | s390x    | linux    | 9        | hotspot  | jdk  | 193.60  MB | urn:net.adoptopenjdk.raw     | production
aa4fc8bda11741facaf3b8537258a4497c6e0046b9f4931e31f713d183b951f1       | x64      | linux    | 9        | hotspot  | jdk  | 207.46  MB | urn:net.adoptopenjdk.raw     | production
ebe1eaad73584f70ab4e587ab9367fb15af820745979e68350fe80fadf615df8       | x64      | linux    | 9        | hotspot  | jdk  | 207.33  MB | urn:net.adoptopenjdk.raw     | production
b58848cb7229a1dc2c135dbb85cce56cee33ab29849aa432e2ba26bf8f517dca       | x64      | linux    | 9        | hotspot  | jre  | 41.55   MB | urn:net.adoptopenjdk.raw     | production
b6a14f8dda60528bbb890877b62b7cf6e81bbbe19256bfd38a3ba4390c4eca5e       | x64      | linux    | 9        | hotspot  | jre  | 41.53   MB | urn:net.adoptopenjdk.raw     | production
b66121b9a0c2e7176373e670a499b9d55344bcb326f67140ad6d0dc24d13d3e2       | aarch64  | linux    | 11       | hotspot  | jdk  | 193.39  MB | urn:net.adoptopenjdk.raw     | production
35e36d7a20a773e291b728de5d4977485a0d44a54f1433cdf6e6288c331557ea       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.51  MB | urn:net.adoptopenjdk.raw     | production
4577350c35f4193430b3ae0094e54869b54aadbc76a50c1518069937a63d54d8       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.52  MB | urn:net.adoptopenjdk.raw     | production
747c4613b36f6e86ee4a10848b1a7f009d1bde729acf31bb6350c3cc08a7475d       | ppc64le  | linux    | 11       | openj9   | jre  | 41.38   MB | urn:net.adoptopenjdk.raw     | production
fcc9a2b183a9238e1927d6088d7c99031f517d62026e8b33d02dfd883b1ca95e       | ppc64le  | linux    | 11       | openj9   | jdk  | 196.55  MB | urn:net.adoptopenjdk.raw     | production
c18364a778b1b990e8e62d094377af48b000f9f6a64ec21baff6a032af06386d       | ppc64le  | linux    | 11       | hotspot  | jdk  | 179.52  MB | urn:net.adoptopenjdk.raw     | production
fb3f4ddaf3e2a9490e34b385e00d76cf6142806d47bd619ef7c193c12acfbb01       | s390x    | linux    | 11       | openj9   | jdk  | 197.27  MB | urn:net.adoptopenjdk.raw     | production
249ad469735c42fa80fcf4123bc76f7e398ff3349ce6fb4bfa65a850fb70f6f8       | s390x    | linux    | 11       | openj9   | jdk  | 197.27  MB | urn:net.adoptopenjdk.raw     | production
e0446e80eeb90ab97fd59f91ae094bdd658c354943d4e33e0ddf691714f9da4d       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
0b6050cc670eefd9465370ab19ae70401476430fca329e65f0dd636ca9cce9bd       | x64      | linux    | 11       | openj9   | jdk  | 195.41  MB | urn:net.adoptopenjdk.raw     | large-heap production
518e9330f2aeb020bca31a07034a08c3a568823e703fc503e03206acdad9dae5       | x64      | linux    | 11       | openj9   | jre  | 40.91   MB | urn:net.adoptopenjdk.raw     | large-heap production
9306fa569d2d5abf982df0b4ffa5d30c652cf16139d7b2268db30d2886f3adbf       | x64      | linux    | 11       | openj9   | jdk  | 195.42  MB | urn:net.adoptopenjdk.raw     | large-heap production
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
a016413fd8415429b42e543fed7a1bee5010b1dbaf71d29a26e1c699f334c6ff       | x64      | linux    | 11       | openj9   | jre  | 40.96   MB | urn:net.adoptopenjdk.raw     | production
ef9bf07cba79082285a9d426ea4eb3e8df57561ce2afe07cc5f299a8fa203279       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
10b2400add0070b64db91026f12b798708e59772a81492fd2b638638f71ed14f       | x64      | linux    | 11       | hotspot  | jdk  | 186.61  MB | urn:net.java.jdk             | early-access valhalla
11cb48e3592f46f2c2dab095e3b9a4fec60b89199827f2b737a14b54dc5fd68d       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
cac1fe096ea161613d5afe8a04ce3294dc1b535f5f4ea1a4235ce425b2610678       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
765947ab9457a29d2aa9d11460a4849611343c1e0ea3b33b9c08409cd4672251       | x64      | linux    | 11       | openj9   | jdk  | 195.50  MB | urn:net.adoptopenjdk.raw     | production
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production
33a5f5b063dde3a66a98cf691bd00b21c012950ae1af253e19dcc68d74a75f65       | x64      | linux    | 12       | hotspot  | jdk  | 304.88  MB | urn:net.java.jdk             | early-access panama

That narrows things down a little, but there are still far too many matching runtimes. Let's specify that we want Linux, x86_64 (the CoffeePick API refers to 32-bit x86 as x32 and 64-bit x86 as x64 for uniformity), and let's specify a version range that says that we want any version of Java greater than or equal to 11 but less than 12:

[coffeepick]$ catalog platform:linux arch:x64 version:[11,12)
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
e0446e80eeb90ab97fd59f91ae094bdd658c354943d4e33e0ddf691714f9da4d       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
a016413fd8415429b42e543fed7a1bee5010b1dbaf71d29a26e1c699f334c6ff       | x64      | linux    | 11       | openj9   | jre  | 40.96   MB | urn:net.adoptopenjdk.raw     | production
ef9bf07cba79082285a9d426ea4eb3e8df57561ce2afe07cc5f299a8fa203279       | x64      | linux    | 11       | openj9   | jdk  | 195.55  MB | urn:net.adoptopenjdk.raw     | production
10b2400add0070b64db91026f12b798708e59772a81492fd2b638638f71ed14f       | x64      | linux    | 11       | hotspot  | jdk  | 186.61  MB | urn:net.java.jdk             | early-access valhalla
0b6050cc670eefd9465370ab19ae70401476430fca329e65f0dd636ca9cce9bd       | x64      | linux    | 11       | openj9   | jdk  | 195.41  MB | urn:net.adoptopenjdk.raw     | large-heap production
11cb48e3592f46f2c2dab095e3b9a4fec60b89199827f2b737a14b54dc5fd68d       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
cac1fe096ea161613d5afe8a04ce3294dc1b535f5f4ea1a4235ce425b2610678       | x64      | linux    | 11       | openj9   | jdk  | 195.36  MB | urn:net.adoptopenjdk.raw     | large-heap production
518e9330f2aeb020bca31a07034a08c3a568823e703fc503e03206acdad9dae5       | x64      | linux    | 11       | openj9   | jre  | 40.91   MB | urn:net.adoptopenjdk.raw     | large-heap production
9306fa569d2d5abf982df0b4ffa5d30c652cf16139d7b2268db30d2886f3adbf       | x64      | linux    | 11       | openj9   | jdk  | 195.42  MB | urn:net.adoptopenjdk.raw     | large-heap production
765947ab9457a29d2aa9d11460a4849611343c1e0ea3b33b9c08409cd4672251       | x64      | linux    | 11       | openj9   | jdk  | 195.50  MB | urn:net.adoptopenjdk.raw     | production
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production

We are making progress. Let's assume, for the sake of this example, that we know our application isn't compatible with OpenJ9. We can require that the VM implementation be Hotspot:

[coffeepick]$ catalog platform:linux arch:x64 version:[11,12) vm:hotspot
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
10b2400add0070b64db91026f12b798708e59772a81492fd2b638638f71ed14f       | x64      | linux    | 11       | hotspot  | jdk  | 186.61  MB | urn:net.java.jdk             | early-access valhalla
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production

Let's also assume that we're only interested in builds that are production-ready. The CoffeePick API allows for repositories to provide arbitrary tags to builds in order to further distinguish them beyond the standard metadata defined by the API. The convention is to tag production-ready builds with the production tag, so let's list builds that have that tag:

[coffeepick]$ catalog platform:linux arch:x64 version:[11,12) vm:hotspot require-tag:production
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production

We've narrowed it down to two builds. We can see from the Repository column that one of those builds comes from the jdk.java.net repository and the other comes from AdoptOpenJDK. Let's arbitrarily decide that we want the one from jdk.java.net and download it:

[coffeepick]$ download 7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd
[    2.10 MB /   187.60 MB] |+                                                           | 2.10MB/s
[    4.20 MB /   187.60 MB] |++                                                          | 2.10MB/s
[    7.72 MB /   187.60 MB] |+++                                                         | 3.52MB/s
[   10.49 MB /   187.60 MB] |++++                                                        | 2.77MB/s
[   12.60 MB /   187.60 MB] |+++++                                                       | 2.11MB/s

(Time passes...)

[  178.69 MB /   187.60 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  | 2.35MB/s
[  180.67 MB /   187.60 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  | 1.98MB/s
[  182.67 MB /   187.60 MB] |+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 2.00MB/s
[  184.81 MB /   187.60 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| 2.14MB/s
[  187.15 MB /   187.60 MB] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++| 2.34MB/s
Download finished
Runtime archive: /home/rm/local/coffeepick/inventory/7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd/archive

For safety reasons, the CoffeePick API automatically verifies that the downloaded archive matches the published checksum. This should provide a minimum level of confidence that you actually downloaded the right runtime, and that the runtime made it onto the disk without malicious or accidental modification. It's possible to manually verify an already-downloaded runtime at any time in the future with the verify command:

[coffeepick]$ verify 7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd
Verified:
  Algorithm: SHA-256
  Received:  7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd

Now that the runtime has been downloaded, it will appear in the inventory. In the CoffeePick API, the inventory is the set of runtimes that you currently have downloaded. The inventory command lists the downloaded runtimes and supports all of the same search parameters as the catalog command:

[coffeepick]$ inventory
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1       | x64      | linux    | 11       | hotspot  | jdk  | 195.71  MB | urn:net.adoptopenjdk.raw     | production
a016413fd8415429b42e543fed7a1bee5010b1dbaf71d29a26e1c699f334c6ff       | x64      | linux    | 11       | openj9   | jre  | 40.96   MB | urn:net.adoptopenjdk.raw     | production
d33551f15f8d4bc5f97471bca669872665e5db15cc8a5ac88f068e23f56bb129       | x64      | windows  | 11       | openj9   | jre  | 40.06   MB | urn:net.adoptopenjdk.raw     | production
7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd       | x64      | linux    | 11.0.1   | hotspot  | jdk  | 187.60  MB | urn:net.java.jdk             | production

[coffeepick]$ inventory vm:openj9
ID                                                                     | Arch     | Platform | Version  | VM       | Conf | Size       | Repository                   | Tags
a016413fd8415429b42e543fed7a1bee5010b1dbaf71d29a26e1c699f334c6ff       | x64      | linux    | 11       | openj9   | jre  | 40.96   MB | urn:net.adoptopenjdk.raw     | production
d33551f15f8d4bc5f97471bca669872665e5db15cc8a5ac88f068e23f56bb129       | x64      | windows  | 11       | openj9   | jre  | 40.06   MB | urn:net.adoptopenjdk.raw     | production

Of course, a runtime isn't much use sitting there in the on-disk storage area. The unpack command unpacks a downloaded runtime into a user-specified directory:

[coffeepick]$ unpack --output /tmp/jdk11-linux-x64 --strip-leading-directory 7e9904e1bfa197e6e72570207cb2bd63dd7cc4bf5f97bc5454c1fc5a559a8bf1
[coffeepick]$

Now, in an ordinary shell:

$ ls -alF /tmp/jdk11-linux-x64/
total 4
drwxr-xr-x  10 rm   rm    220 2018-11-18 14:23 ./
drwxrwxrwt 198 root root 4420 2018-11-18 14:23 ../
drwxr-xr-x   2 rm   rm    680 2018-11-18 14:23 bin/
drwxr-xr-x   4 rm   rm    140 2018-11-18 14:23 conf/
drwxr-xr-x   4 rm   rm    100 2018-11-18 14:23 demo/
drwxr-xr-x   3 rm   rm    180 2018-11-18 14:23 include/
drwxr-xr-x   2 rm   rm   1440 2018-11-18 14:23 jmods/
drwxr-xr-x  72 rm   rm   1440 2018-11-18 14:23 legal/
drwxr-xr-x   6 rm   rm   1040 2018-11-18 14:23 lib/
drwxr-xr-x   4 rm   rm    100 2018-11-18 14:23 man/
-rw-r--r--   1 rm   rm   1202 2018-11-18 14:23 release

$ cat /tmp/jdk11-linux-x64/release 
IMPLEMENTOR="AdoptOpenJDK"
IMPLEMENTOR_VERSION="AdoptOpenJDK"
JAVA_VERSION="11.0.1"
JAVA_VERSION_DATE="2018-10-16"
MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.vm.ci jdk.management jdk.unsupported jdk.internal.vm.compiler jdk.aot jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.le jdk.internal.opt jdk.internal.vm.compiler.management jdk.jartool jdk.javadoc jdk.jcmd jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported.desktop jdk.xml.dom jdk.zipfs"
OS_ARCH="x86_64"
OS_NAME="Linux"
SOURCE=""

Finally, it's possible tell repository providers to self-update. This is useful in the case of a repository such as AdoptOpenJDK where new runtime builds are published frequently.

$ repository-update urn:net.adoptopenjdk.raw
Update of urn:net.adoptopenjdk.raw started…
[ 0.00   % ] |                                                            |
[ 1.79   % ] |++                                                          |
[ 3.57   % ] |+++                                                         |
[ 5.36   % ] |++++                                                        |
[ 7.14   % ] |+++++                                                       |

(Time passes...)

[ 91.07  % ] |+++++++++++++++++++++++++++++++++++++++++++++++++++++++     |
[ 92.86  % ] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++    |
[ 94.64  % ] |+++++++++++++++++++++++++++++++++++++++++++++++++++++++++   |
[ 96.43  % ] |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  |
[ 98.21  % ] |+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
Update of urn:net.adoptopenjdk.raw finished.

Subsequent executions of the catalog command will then show new releases (if any are available) in addition to those that were already available.

Future directions for the project:

  1. A Maven plugin

    I want to be able to do all of the above in an automated manner during builds. The API already allows for electively downloading or reusing cached runtimes, and runtimes can be specified directly by hash value for reproducibility in builds.

  2. Add shipilev.net builds

    Aleksey Shipilëv publishes various early-access builds so that people can try out new JDK features. I'd like to get his builds included into a repository provider (ideally with some way to find new builds without having to crawl over his entire site to discover them).

  3. A standard schema for repository metadata

    I already have a very strict XSD schema that describes a format for repository metadata. It would just be a matter of persuading others to use it, and allowing the API to consume XML metadata.

You Cannot Put That There

Maven 3.6.0 was released today. It adds the ability to add a child.inherit.append.path attribute to various places within a POM file to turn off Maven's automatic appending of child module names to various paths. This has been a long-standing complaint with Maven as it had essentially baked-in SVN path semantics to the model in a way that couldn't be turned off or worked around sanely.

Unfortunately, the Maven Central rules can't accept POM files that contain the new attributes:

[ERROR] Rule failure while trying to close staging repository with ID "comio7m-1402".
[ERROR] 
[ERROR] Nexus Staging Rules Failure Report
[ERROR] ==================================
[ERROR] 
[ERROR] Repository "comio7m-1402" failures
[ERROR]   Rule "sources-staging" failures
[ERROR]     * Illegal POM: /com/io7m/primogenitor/com.io7m.primogenitor/3.0.0-beta0018/com.io7m.primogenitor-3.0.0-beta0018.pom Unknown attribute 'child.inherit.append.path' for tag 'project' (position: START_TAG seen ...ache.org/xsd/maven-4.0.0.xsd\n  child.inherit.append.path=false>... @6:37) 
[ERROR]   Rule "javadoc-staging" failures
[ERROR]     * Illegal POM: /com/io7m/primogenitor/com.io7m.primogenitor/3.0.0-beta0018/com.io7m.primogenitor-3.0.0-beta0018.pom Unknown attribute 'child.inherit.append.path' for tag 'project' (position: START_TAG seen ...ache.org/xsd/maven-4.0.0.xsd\n  child.inherit.append.path=false>... @6:37) 
[ERROR]   Rule "pom-staging" failures
[ERROR]     * Invalid POM: /com/io7m/primogenitor/com.io7m.primogenitor/3.0.0-beta0018/com.io7m.primogenitor-3.0.0-beta0018.pom: Parsing Error: Unknown attribute 'child.inherit.append.path' for tag 'project' (position: START_TAG seen ...ache.org/xsd/maven-4.0.0.xsd\n  child.inherit.append.path=false>... @6:37) 
[ERROR] 
[ERROR] 
[ERROR] Cleaning up local stage directory after a Rule failure during close of staging repositories: [comio7m-1402]
[ERROR]  * Deleting context 2a74942ea74dc7.properties
[ERROR] Cleaning up remote stage repositories after a Rule failure during close of staging repositories: [comio7m-1402]
[ERROR]  * Dropping failed staging repository with ID "comio7m-1402" (Rule failure during close of staging repositories: [comio7m-1402]).

I've filed a bug.

Java 11 and Maven 3.6.0

Java 11 is out, and is the current LTS release (at least if you're using the Oracle JDK).

I'll be moving all of my code to start requiring JDK 11 at a minimum as of now.

Additionally, Maven 3.6.0 is currently in the process of being released, and it contains a fix for an issue that's important to me, so I suspect I'm also going to start requiring Maven 3.6.0 everywhere too.

No More OpenGL

I'm dropping OpenGL in favour of Vulkan.

No more broken drivers (probably). No more dealing with source code level management of shader code at runtime (no more sombrero). No more broken GLSL shader compilers, for that matter. No more weak typing (no more jcanephora). No more logarithmic depth buffer - Vulkan has reversed floating-point depth buffers accessible without extensions.

Planning to rewrite r2 using Vulkan, yielding r3. A few design issues that were imposed by the OpenGL 3.3 core requirement can be corrected.

Still need to give the Vulkan API a friendly face though, to make it feel like a Java API instead of a C++ API.

Maven Central Signing

A while ago I started having a problem with signature verification when trying to upload to Maven Central.

After three months of intense debugging and a rather long conversation with Sonatype, it turned out that the issue was actually with the signing key.

At the start of 2018, I'd switched to ed25519 signing keys. It turned out that the version of Nexus running on Maven Central didn't support ed25519. To work around this, I created a new RSA key solely intended for signing Maven packages. Bizarrely, this key didn't work either. Nobody could work out why the signatures were failing, and the problem was escalated twice to Sonatype's internal support people.

It turned out that the problem was an ed25519 signature on the new RSA key!

The moral of the story: If you want to deploy to Maven Central, use only RSA keys and make sure that the signatures on those RSA keys only come from other RSA keys. If you fail to do this, you won't get an actionable error message when you try to deploy packages, you'll just get a "Signature verification failed" message. Sonatype are updating their documentation to ensure that nobody else has to lose time to this.

Thanks to Joel Orlina for being patient during those three months and for handling the support teams.

Competing Module Systems

It's been about eight months since the release of Java 9.

I won't bore anyone with the details of everything it introduced as that information is available just about anywhere you care to look. The main thing it added, however, is the subject of this post: The Java Platform Module System.

The JPMS was introduced, and programmers reacted in the normal way that people working in a field that's supposed to demand a rational and critical mind react: They started frothing at the mouth, claiming that Oracle were trying to kill Java, and planning a mass exodus to other more hip languages. Kotlin or Rust, probably. Needless to say, Oracle weren't trying to kill Java. If Oracle wanted to kill Java, they could certainly find a way to do it that didn't require seven expensive years of intense, careful, and painful software engineering. So far, the exodus appears to have been quietly called off.

I'm guessing the people that complained the loudest are the sort of people that write a ton of fragile, error-prone, unsupported reflection hacks and then spew bile when some tiny aspect of the platform changes and their code breaks.

I have a ton of code, none of which I'd describe as legacy. I'm somewhat invested in OSGi for reasons I'll go into shortly.

Today: I'm conflicted and slightly nervous!

I decided when Java 9 came out that I was going to pursue full modularization for all of my projects. As I've said before, my code is already modular because I've been designing it around OSGi. However, in order for it to become modular in the JPMS sense, I'd have to write module descriptors for each project.

I'm developing a commercial (but open-source) game, where the game itself and third party modifications are handled by a well-specified, strongly-versioned module system. Consider something that (from the user's perspective) behaves a bit like the system in OpenTTD (except with the entire game delivered this way, not just third-party addons):

OpenTTD

I briefly considered stopping using OSGi and using the JPMS to power the whole system. That experiment fairly quickly ended, though. Let's look at some of the things that OSGi does or has that are important to me:

  1. OSGi has a full repository specification that gives applications the ability to download and install packages at run-time. You tell the system what packages you want, and it fetches those and all of their dependencies. Everything is standardized, from the API to the actual metadata served by repository implementations. Here's an example of a standard repository index (albeit styled with an XSL stylesheet).

  2. OSGi bundles have rich metadata associated with them, including very fine-grained and versioned dependency metadata. If you have a bundle, you can find out very easily what else you need in order to be able to use it. The metadata can also express things beyond simple package dependencies.

  3. OSGi can load and unload modules at run-time, and has standard APIs to do so (and standard APIs that application code can implement in order to react to modules being loaded and unloaded).

  4. OSGi has wide support; it's fairly rare these days to find a Java project that isn't also implicitly an OSGi project. Making something OSGi-compatible is often just a case of adding a single Maven plugin invocation (assuming that the code doesn't make a lot of unfounded assumptions about class loaders).

Let's see what the JPMS has (or hasn't), in comparison:

  1. The JPMS doesn't have anything like a repository specification. The closest analogy is probably fetching things off of Maven Central, but there's no standard API for doing this. Essentially, obtaining modules is Someone Else's Problem.

  2. JPMS modules don't have much metadata associated with them. A module says what packages it exports and upon which other modules it depends. However, it doesn't say anything about which versions of those modules are required. Essentially, you're expected to use a system like Maven. This is Someone Else's Problem.

  3. The JPMS can, in some sense, load modules at run-time via ModuleLayers. There's no support for explicitly unloading a module. There are no standard APIs that code can use to be notified that a module has been loaded. Essentially, you're expected to build your own ad-hoc OSGi-like system on top of module layers. This is Someone Else's Problem.

  4. Most projects haven't even begun to modularize their code. Even in a well-staffed and extremely fundamental project like Google Protobuf, I'm still waiting after six months for them to make a harmless one-line JAR manifest update. I cannot begin to imagine what it would take to push full modularization through a system that slow moving. If a project you depend on hasn't modularized, you're not going to be modularizing either.

The first three points mean that I'd have to invent my own OSGi-like system. I'd have to come up with a uniform, platform-agnostic metadata standard that could be inserted into JAR files in order to specify dependency information. Third party projects (at least those that aren't written specifically for my game engine) aren't going to be interested in adding metadata for the sake of one man's low budget module system. I can't trust JAR files to contain Maven pom.xml files (although many do), as there are plenty of other build systems in use that don't include that information. Even then, you can't just parse a Maven pom.xml, you need to evaluate it. This would mean pulling in Maven APIs as a dependency, and those neither work in a JPMS modular context (because they're not modularized and never will be) nor an OSGi context (because they use their own incompatible module system called Plexus).

Let's assume by some miracle that I get a good percentage of the Java ecosystem to include dependency metadata in a format I can consume. I now need to come up with an API and tools to fetch modules from a repository. That's not hard, but it's still more than not having to do it at all. I'd want version ranges, so I'd also need to write code to solve the versioning problem which is NP-complete. Tricky.

So let's assume by now that I can, given the name of a module, fetch the dependencies at run-time using my shiny new API and metadata. I still need to be able to load and unload that set of modules at run-time, and have code in other modules react properly to that occurring. There aren't any standard APIs to do this in the JPMS, and so I'd have to write my own. Right now, the JPMS is not actually capable of expressing the kind of things that are possible with OSGi bundles, so any system I built would be strictly less capable than the existing OSGi system. At least part of the problem appears to come down to missing APIs in the JPMS, so at least some of this might be less of an issue in the future. Still, it's work I'd have to do.

So let's assume that I can fetch, load, and unload modules at run-time, and code in modules can react to this happening. I still need modules to put in the system, and not many Java projects are modularized. I tried, for a few months, to use only projects that have either added Automatic-Module-Name entries to their JAR manifests, or have fully modularized. It was fairly painful. I'd be limiting myself to a tiny percentage of the vast Java ecosystem if I did this. This, however, is something that OSGi also went through in the early days and is no longer a problem. It's just a matter of time.

So why am I nervous and still conflicted?

The default effect suggests that, just because the JPMS is the default Java module system, the JPMS is the one that developers will turn to. Tool support for JPMS modules is already vastly better in Intellij IDEA than it is for OSGi. In Eclipse, the support is about equal.

The OSGi R7 JAR files will not contain Automatic-Module-Name entries which means that if you have any dependency on any part of OSGi (including parts that are not even used at run-time, like the annotations), your code cannot be fully modularized. If developers are forced to choose between supporting that old module system that nobody uses or that shiny new default module system that everyone's talking (or possibly frothing) about, which one do you think they'll pick?

I'm also aware that this kind of dynamic module loading and unloading is not something that most applications need. For years people were happy with a static (although extremely error-prone) class path mechanism, and the majority of applications are just recompiled and re-deployed when updated. The JPMS can support this kind of deployment sufficiently. Previously, if developers wanted any kind of safe module system at all, they had to turn to OSGi. They might only use it in the context of a static application that is not dynamically updated, but they'd still use it. Why would those same developers still turn to OSGi when the JPMS exists?

Finally, I pay attention to the various new developments to the Java language and JVM and, fairly often, new features are proposed that have subtle (or not-so-subtle) dependencies on the new module system. There are various optimization strategies, for example, that can be enabled if you know that instances of a given type are completely confined to a single module. Unless the VM can be magically persuaded that OSGi bundles are JPMS modules (this is unlikely to happen), then code running in OSGi is very much going to become a second-class citizen.

So, I'm nervous and conflicted. I don't want to build some sort of ad-hoc OSGi-lite system on the JPMS. I don't want to do the work, I don't want to maintain it, and I don't think the result would be very good anyway. I also, however, am unsure about continuing to base my code on a system that's going to have to work hard not to be considered irrelevant. I believe OSGi is the superior choice, but it's not the default choice, and I think that's going to matter more than it should.

I suspect I'm going to finish assisting any remaining projects that I've started helping to modularize, and not do any more. I had decided that I was going to push hard to move all of my projects to requiring Java 9 as part of the modularization effort, but unfortunately this would leave me unable to deploy code on FreeBSD as there's no JDK 9 there and likely won't be. With the new six-month release cycle (and 18-month long-term release cycle), porting efforts will likely be directed towards JDK 11. This means that I won't be able to deploy anything newer than Java 8 bytecode on FreeBSD for at least another six months.

IPv6 And Linux

I wrote a while back about issues with IPv6 on Linux. It turns out that most of the pain occurs for two reasons:

  1. Linux doesn't accept router advertisements by default. If you configure your router to tell everyone on the network that it has a nonstandard MTU, Linux will ignore the advertisements.

  2. Linux will act upon any Packet Too Large messages it receives and in fact will create a temporary route (visible from the ip route command) that has the correct reduced MTU but, for whatever reason, most programs won't use the new route without a restart. That is, if my mail client hangs due to a Packet Too Large message, it won't be able to send any mail until I restart the program.

The first point can be addressed by adding the following to /etc/sysctl.conf:

net.ipv6.conf.default.accept_ra=1
net.ipv6.conf.default.accept_ra_mtu=1

Usually, net.ipv6.conf.default.accept_ra_mtu is already set to 1, but it's worth being explicit about it.

I also add net.ipv6.conf.default.autoconf=0 because I statically assign addresses.

The second point can be addressed by restarting the program, as sad as that is.

Module Chasing

https://github.com/io7m/modulechaser

modulechaser

I'm trying to get to the point where all of my projects are fully modularized as JPMS modules. My code already follows a very modular architecture thanks to designing it around OSGi, but it's necessary to write module descriptors to complete the picture. To write module descriptors, the projects upon which a project depends must first be modularized. This can either mean writing module descriptors for those projects, or it can simply mean assigning an Automatic-Module-Name. Writing a full module descriptor is better, because this means that the project can be used in combination with jlink to produce tiny custom JVM distributions.

My problem is that I have rather a large number of dependencies across all of my projects, and I need to know the most efficient order in which to approach maintainers in order to get them to modularize their projects. If a project A depends on project B, then project A can't be modularized before project B so it's a waste of my time to go asking project A's maintainers before B is modularized.

I wrote a Maven plugin to assist with this problem. It produces reports like this.

The plugin tells me if the current version of a dependency is modularized, if the latest version of the dependency on Maven Central is modularized, and whether the dependency has been fully modularized or simply assigned a name. The table of dependencies is shown in reverse topological order: Start at the top of the table and work downwards, contacting each project maintainer as you go.

Some dependencies will, of course, never be modularized. Whomever published the javax.inject jar, for example, didn't even bother to create a manifest in the jar file. I'm not sure that even constitutes a valid jar file according to the specification. Some dependencies, like javaslang, were renamed (javaslang became vavr) and so code should move to using the newer names instead. Some projects can barely manage to publish to Maven Central (like Xerces) and still appear to use tools and processes from the previous century, so are unlikely to be modularizing any time soon.

Let's Encrypt For Woe And Loss

In a crippling bout of sinusitis, and after reading that Chrome is going to mark http sites as insecure, I decided to put good sense aside and deploy Let's Encrypt certificates on the io7m servers.

I've complained about the complexity of this before, so I started thinking about how to reduce the number of moving parts, and the number of protection boundary violations implied by the average ACME setup.

I decided the following invariants must hold:

  • The web server must not have write access to its own configuration, certificates, or logs. This is generally a given in any server setup. Logging is actually achieved by piping log messages to a log program such as svlogd which is running as a different user. In my case, I can actually go much further and state that the web server must not have write access to anything in the filesystem. This means that if the web server is compromised (by a buffer overflow in the TLS library, for example), it's not possible for an attacker to write to any data or code without first having to find a way to escalate privileges.

  • The web server must have read access to a challenge directory. This is the directory containing files created in response to a Let's Encrypt (LE) challenge.

  • The acme client must have read and write access to the certificates, and it must have write access to a challenge directory, but nothing else in the filesystem. Specifically, the client must not have write access to the LE account key or the directory that the web server is serving. This means that if the client is compromised, it can corrupt or reissue certificates but it can't substitute its own account key and request certificates on behalf of someone else.

  • The acme client must not have any kind of administrative access to the web server. I don't want the acme client helpfully restarting the web server because it thinks it's time to do so.

There are some contradictions here: The acme client must not be able to write to the directory that the web server is serving, and yet the web server must be able to serve challenge responses to the LE server. The acme client must not be able to restart the web server, and yet the web server must be restarted in order to pick up new certificates when they're issued.

I came up with the following:

  • An httpd-reloader service sends a SIGHUP signal to the web server every 30 minutes. This causes the web server to re-read its own configuration data and reload certificates, but does not kill any requests that are in the process of being served and specifically does not actually restart the web server.

  • The acme client writes to a private challenge directory, and a private certificates directory. It doesn't know anything about the web server and is prevented from accessing anything other than those directories via a combination of access controls and chrooting.

  • The web server reads from a read-only nullfs mount of a wwwdata directory, and the challenge directory above is placed in wwwdata/.well-known/acme-challenge via another read-only nullfs mount. The web server also reads from a read-only nullfs mount of the certificates directory above in order to access the certificates that the acme client creates.

  • The acme client is told to update certificates hourly, but the acme client itself decides if it's really necessary to update the certificates each time (based on the time remaining before the certificates expire).

  • The intrusion detection system has to be told that the web server's certificates are permitted to change. The account key is never permitted to change. I don't want notifications every ~90 days telling me the certificates have been modified.

Data flow

I set up all of the above and also took some time to harden the configuration by enabling various HTTP headers such as Strict-Transport-Security, Content-Security-Policy, Referrer-Policy, etc. I'm not going to require https to read io7m.com and I'm not going to automatically redirect traffic from the http site to the https site. As far as I'm concerned, it's up to the people reading the site to decide whether or not they want https. There are plenty of browser addons that can tell the browser to try https first, and I imagine Chrome is already doing this without addons.

The Qualys SSL Labs result:

Result

Now we can all sleep soundly in the knowledge that a third party that we have no reason whatsoever to trust is telling us that io7m.com is safe.

Checkstyle Rules

I'm going to start making all projects use a common set of Checkstyle rules rather than having each project carry its own rules around. I can't remember exactly why I avoided doing this in the beginning. I think it may've been that I wasn't confident that I could write one set of rules that would work everywhere. I've decided instead that I'll beat code with a shovel until it follows the rules, rather than beat the rules with a shovel until they follow the code.

https://github.com/io7m/checkstyle_rules

Chasing Modules

I've been moving all of the projects I still maintain to Java 9 modules. In order to do this, however, I've needed to assist third party projects upon which I have dependencies to either modularize their projects or publish Automatic-Module-Name entries in their jar manifests. If you try to specify a dependency on a project that either hasn't been modularized or hasn't published an Automatic-Module-Name entry, you'll see this when building with Maven:

[WARNING] ********************************************************************************************************************
[WARNING] * Required filename-based automodules detected. Please don't publish this project to a public artifact repository! *
[WARNING] ********************************************************************************************************************

The reasons for this are documented on Stephen Colebourne's blog.

Here's a table of all of the third party projects upon which I depend, and an indication of the current state of modularization (I'll try to keep this updated as projects are updated):

Project State Updated
fastutil Considering 2018-02-07
jcpp Considering 2018-02-08
ed25519-java Considering 2018-02-09
LWJGL Fully Modularized 2018-02-07
Dyn4j Fully Modularized 2018-02-07
protobuf Ignored? 2018-02-07
antlr In Progress 2018-02-11
autovalue In Progress 2018-02-07
rome In Progress 2018-02-07
JGraphT Automatic Module Names (Full modularization in progress) 2018-02-11
Vavr Automatic Module Names 2018-02-07
commonmark-java Automatic Module Names 2018-02-07
javapoet Automatic Module Names 2018-02-07
xom Unclear 2018-02-07

Generally, if a project isn't planning to either modularize or publish automatic module names, then I'm looking for a replacement for that project.

Signing Issues

I'm having trouble deploying packages to Maven Central. The repository claims that it cannot validate the signatures I provide. I've filed a bug but haven't gotten a response. I'm wondering if it's down to me switching to Curve25519 PGP keys...

New PGP Keys

New PGP keys have been published.

Fingerprint                                       | UID
-----------------------------------------------------------------------------------
B84E 1774 7616 C617 4C68 D5E5 5C1A 7B71 2812 CC05 | Mark Raynsford (2018 personal)
F8C3 C5B8 C86A 95F7 42B9 36D2 97E0 2011 0410 DFAF | io7m.com (2018 release-signing)
Verifying blog.io7m.com... Again

See the the previous blog post:

$ gpg --recv-keys 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8
$ wget -r http://blog.io7m.com
$ cd blog.io7m.com
$ gpg < checksum.asc | sha512sum --check

Better.

How To Verify blog.io7m.com

This blog was designed to be verifiable:

$ gpg --recv-keys 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8
$ wget -r http://blog.io7m.com
$ find blog.io7m.com -name '*.asc' -exec gpg --verify {} \;

Note that the 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8 key ID assumes you're reading this in 2017. By the time 2018 comes around, this blog will be signed with a new key (and a new one for each passing year).

Possible points of failure:

  1. A malicious actor gets the remote keyserver to serve a different key than the one with fingerprint 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8. Does gnupg verify that a received key had the fingerprint that the user specified on the command line? What if the user specified my name and key comment instead of a fingerprint? The actor at this point might be able to convince you that the signatures on files on blog.io7m.com are invalid. It might be able to convince you that its own key is mine.

  2. A malicious actor modifies the files and signatures when wget downloads them. The actor can't generate valid signatures for the key 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8 (unless it can break RSA), but it can try to convince you that its own key is actually my key and therefore have you trust that the data you're seeing is unmodified and was signed by me. If the actor managed to perform step 1 above, then you're completely compromised.

  3. A malicious actor removes some of the signatures. If you didn't know exactly how many pages there should be, you'd not notice if gpg didn't verify one of them.

Step 1 has no technical solution; you need to verify the keys you receive and check the signatures on those keys assuming they come from other keys that you trust. If you're lucky, there is a chain of signatures leading to a key that you do trust with certainty. I have yearly expiring keys, and I sign each new year's keys with the old keys. Unless my keys have been compromised yearly, there's a reasonable chance that the keys you see are mine!

Step 2 is partially mitigated by https, assuming that the actor doesn't have backdoor access to the CA issuing the certificate. The actor can have the CA issue a new certificate, redirect you to a server that the actor controls, decrypt the traffic, modify it, and then re-encrypt it. You'd never know anything was wrong.

Step 3 is manually mitigated by reading the posts by year page and checking that you have at least as many signatures as pages. I may start publishing a CHECKSUMS file that just contains signed SHA512 hashes of every file on the site.

I'm considering using keybase in addition to publishing PGP keys on the public keyservers. I don't do social media, so I'm not sure how much it'd apply to me. I do use GitHub heavily though.

New PGP Key
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

2017-12-17T14:19:49+0000

Pushed a new key for signing commits in Android work. I'll still be
releasing new personal and release signing keys in January (and I'll
be switching to ed25519 keys from RSA).

E134 3512 A805 115A C1A0 1D15 C578 C3C0 C9B1 2BFF
Mark Raynsford (2018 android commit signing)

-----BEGIN PGP SIGNATURE-----

iQJCBAEBCgAsFiEEgWja4isV0+3HIsI9DxW30G+oDLgFAlo2fa4OHG1hcmtAaW83
bS5jb20ACgkQDxW30G+oDLjKiA/9HRrc0F7d/4C4ybdKFpp8N3S/RT/NJLfrYOTV
XQvt9Nw+eJydsygY8IbaZiWo9hkxddI1DLuWtahcrXFWGQ/VpAUmZcIondaJzLna
42Ui5jFpkweOVH2VYmuuDTV5rpkfH7IkTml5m2OsnsVU4hO9V1DGoNL+/5p2xv0E
sLkopFX/9qaRtw0qJ7u8Bl5217kodlI2inEMfomI8QcMp+JarkTogEdkkzFBz7Qo
/XGevkdeIBMCQ0NpsvoQmclGbgOtu6js1LvoQjDaXoVtT1yyIM831FDgFxbKCMw8
gzxx0f/TZjoRizIE0fNIwPmLYG5HXLCt6wN7iT6MYhp7ijBABZB8tH7cffCF1sM5
QE+eg8bzOL4FT57XLPpp9eDXZmLqmy6EdrWedaWughPPjUofqaIw0Bar1iIp4pY0
lIkAUTsqtEI32sAdInJ0PPar8nYVM8COSoyZ08kdxImO3DHRGerI7DSi88JpTiRy
vX96LZ0UvwyUhFxUSJQuxXYd82bQgoBhdjsLWiurZZYdZC5EGCwA7m5zapLWF76m
SJloK1ogK628TygNrhnNNsUirrEsDJM2CaNnp8/viN1eFlWMb13dgyLOQijyFyYV
8Q56XeILyckUY3ERw+v5BPN5g3qdF4nL5O23L3zrSQKcn6yUGgcFa6gia9cc1/Hm
EiTv9cc=
=D3uo
-----END PGP SIGNATURE-----
Back To Java

I initially wrote jstructural as a set of XSLT stylesheets. That quickly became unmaintainable as the complexity of the stylesheets increased. I rewrote them in Java. I eventually got tired of writing documentation in XML (I didn't know that better XML editors existed) so I ended up wanting to add the ability to write documents as S-expressions.

The right way to do this was to redesign jstructural so that it defined a core AST type and added multiple parsers that all produced values of this core type. Converting between documents of different types would then be a matter of parsing using one syntax, and then serializing the AST using another.

The most natural way to express an AST is as a large algebraic data type. Java doesn't have direct support for these yet (although it's slowly getting them via Project Amber). I therefore looked at other JVM languages that did support them, and the choice was either Scala or Kotlin. I chose Kotlin, after multiple nasty experiences with Scala. kstructural was born.

Fast forward to the present day, and I'm utterly sick of working on Kotlin code. The tools are slow. Compilation is slow. The people in charge of the ecosystem think devolving to special snowflake imperative build tools like Gradle is a good idea.

I'm going to do a new Java implementation of the structural language, and I'm probably going to redesign the language to make it even easier to implement. Nowadays, XML editing is fast and painless thanks to various tools (with real-time validation errors). XOM is essentially unmaintained, so I'll replace the XML parsing code with an efficient SAX parser (and actually get lexical information in the parsed AST, unlike with XOM).

DKIM

Deployed DKIM on the mail server today. All mail that originates from io7m.com will be signed, and I've published DMARC and ADSP policies that tell other servers to be suspicious of any mail that isn't signed. Seems to be working well.

TLS

I've enabled TLS on all io7m.com domains.

I'm using certificates from CaCert.org. These aren't trusted by all browsers, but I don't care all that much. If trust becomes a serious issue at some point, I'll buy real TLS certs. I PGP sign all text on the server anyway, so anyone that really cares about checking to see if some nefarious third party has changed the data in transit can do so, albeit manually.

No, I'm not using Let's Encrypt. I've looked into it several times and I just can't get around the fact that it requires a huge number of moving parts and that the average ACME client requires a ridiculous level of privileges to work properly: If you want any possibility of security, this is what it takes to get it.

At a minimum:

  • The client has to be able to make connections to a remote server in order to download an extremely security-critical bit of data (the certificate). If this step fails for any reason (the remote side being unavailable, breakage in the client), the existing certificate expires and the https service is dead.

  • The client has to be intelligent enough to know when to try to get a new certificate. When is the right time? Who knows. Trying to request a new certificate a minute before the current one expires is suicidally reckless. Trying to do it the day before might be acceptable, but what if it goes wrong? Is a day long enough to try to fix a problem in something as gruesomely complex as the average ACME client? The availability of your https service essentially becomes tied to the availability of the ACME server. This wouldn't be so bad if the update was a yearly thing and could be planned for, but LE certificates are valid for 90 days.

  • The client has to be able to write to the directory being served by the http server in order to be able to respond to challenges. If the client is compromised, it has the ability to trash the served web site(s). I run my services in a highly compartmentalized manner, and having to allow this would be horrible. There are other challenge types, such as publishing a DNS record containing a response to a challenge, but those have the same problem of what should be an unprivileged program having to cross a security boundary and threatening the integrity of another service's data.

  • The client has to be able to write to the http server's configuration data (in order to publish the new certificate). Again, if the client is compromised, it can trash the http server's configuration. If the update fails here, the existing certificate expires and the https service is dead.

  • Assuming that the client actually does manage to respond to a challenge and get a certificate issued, and does actually manage to write that certificate to the filesystem, the problem then becomes getting the https server to use it. Most servers read certificates once on startup and don't reread them. Therefore, the client needs privileges to restart the server. This is totally unacceptable; no service should ever be able to forcefully restart another.

There are so many possible points of failure and every single one results in a broken https service at best, or a system compromise at worst. I'm vaguely surprised at how little in the way of criticism I've seen online of the complexity of Let's Encrypt given the usual reaction of information security experts to any new software system. To paraphrase Neal Stephenson, the usual reaction is to crouch in a fetal position under a blanket, screaming hoarsely that the new system is way too complex and is a security disaster. I have to wonder how many unpublished attacks against the ACME protocol there are out there.

Contrast this to a typical TLS certificate provider: I download a text file once a year and put it on the server. I then restart the https service. Done. No extra software running, no other points of failure.

Maven JavaDoc Plugin Fixed

The Maven JavaDoc plugin 3.0.0 is finally ready for release. This means that I can migrate 60+ projects to Java 9 and finally get the new versions pushed to Central.

Big thanks to Robert Scholte who worked hard to ensure that everything worked properly, and even got my rather unusual usage of the plugin (aggregating documentation into a single module) working as well.

Obstructing JavaDoc

I've been anxiously awaiting the 3.0.0 release of the maven-javadoc-plugin for weeks, and in an ironic twist of fate, I'm now responsible for delaying the release even further.

I found two rather nasty bugs in the version that was to become 3.0.0, but submitted a fix for the first and had it merged. The second problem seems like it's going to take rather more work to fix though, and my message asking for implementation advice to the javadoc-dev list is currently sitting in a moderation queue.

Expected But Got

Inference

What To Save And Throw Away

What to save and throw away?

pr?The last hour is on us both?mr.s?tuck this little kitty into the impenetrable brainpan?

pr?Contents under pressure?Do not expose to excessive heat, vacuum, blunt trauma, immersion in liquids, disintegration, reintegration, hypersleep, humiliation, sorrow or harsh language?

pr?When the time comes, whose life will flash before yours?

pr?A billion paths are here inside me? pr?yes, yes, yes, Bernhard, 110? pr?potential, jewels, jewels, yes, jewels? %

Decided to kill off some old packages. jnull and jfunctional in particular I've used in just about every project I've ever worked on. There's really very little reason for them to exist anymore though. Java 8 added Objects.requireNotNull which standardized terse null checking. Noone cares about the @NonNull annotations (including myself). The entire contents of jfunctional were made redundant by Java 8. Both of these packages served their purposes well back in the days of Java 6 when they were first designed, but now they're just a burden.

It's good to throw away code.

Maven Java 9 Bugs

I'm still waiting on a set of issues to be resolved in order to push modules to all of my projects.

  • MJAVADOC-489 causes JavaDoc generation to fail when one module requires another.

  • MDEP-559 causes the dependency:analyze goal to fail. I use this goal as part of all my builds in order to keep dependencies clean and correct. Getting this fixed depends on MSHARED-660.

I've also removed japicmp from all of my builds. I don't want to disparage the project at all; it's good at what it does, but using it would require using custom MAVEN_OPTS on JDK 9, and that's just not good enough. I'm in the process of writing a replacement for japicmp and will announce it within the next few weeks.

TCP MSS Clamping

Instead of using a non-default MTU on my network, I've instead implemented TCP MSS clamping.

Specifically, I reset all of the interfaces on my networks back to using an MTU of 1500 (including those on the router), and added the following pf rule:

scrub on $nic_ppp max-mss 1440

That rule clamps the maximum TCP segment length on the PPP interface to 1440. Why 1440? It's essentially down to the per-packet overhead of each protocol that's involved. Typically, that'll be 40 or so bytes for an IPv6 packet header, 8 bytes for PPPoE, and some loose change.

So far, nothing has broken with the new settings. No TLS handshake failures, no sudden broken pipes on SSH sessions, no issues sending mail.

IPv6 And MTU Woes

I've just recently deployed IPv6. Everything went well except for one painful issue that is still not really resolved my satisfaction. To recount the story requires covering quite a bit of ground and digging through a pile of acronyms. Hold on tight!

My ISP provides a native /48 network per customer. That means that I get a mere 1208925819614629174706176 public IP addresses spread over 65536 /64 networks to use as I please.

I want to use my existing FreeBSD router to do the routing for the individual networks. I want to do this for several reasons:

  1. The ISP-provided box is a standard consumer router and is fairly limited in what it can do. It's not actively harmful; it's a respectable brand and fairly powerful hardware, but it's still only a consumer-grade box with a web interface.

  2. I'd rather have the intricate configuration details of my network be stored in text configuration files on commodity hardware and on an operating system that I mostly trust. The ISP-provided box runs Linux on proprietary hardware and only provides shell access via an undocumented (authenticated) backdoor (side-door?).

  3. I trust myself to write safe pf rules.

  4. Exposing the FreeBSD machine directly to the WAN eliminates one routing hop.

However, in order to allow my FreeBSD machine to do the routing of the individual networks (as opposed to letting the entirely optional ISP-provided box do it), I had to get it to handle the PPP connection. The machine doesn't have a modem, so instead I have to run the ISP-provided modem/router in bridging mode and get the FreeBSD machine to send PPP commands using the PPPoE protocol. Encouragingly, my ISP suggested that yes, I should be using FreeBSD for this. It's a testament to the quality of IDNet: They are a serious technical ISP, they don't treat their customers like idiots, and they respect the freedom of choice of their customers to use whatever hardware and software they want.

For those that don't know, limitations in PPPoE mean that the MTU of the link is limited to at most 1492. For reference, most networks on the internet are using an MTU of 1500. In IPv4, if you send a packet that's larger than your router's MTU, the packet will be fragmented into separate pieces and then reassembled at the destination. This has, historically, turned out to be a rather nasty way to deal with oversized packets and therefore, in IPv6, packets that are larger than the MTU will be rejected by routers and will result in Packet Too Large ICMPv6 messages being returned to the sender.

In effect, this means that IPv6 networks are somewhat less tolerant of misconfigured MTU values than IPv4 networks. Various companies have written extensively about fragmentation issues.

So why am I mentioning this? Well, shortly after I'd enabled IPv6 for the network and all services, I suddenly ran into a problem where I couldn't send mail. The symptom was that my mail client would connect to the SMTP server, authenticate successfully, send an initial DATA command, and then sit there doing nothing. Eventually, the server would kick the client due to lack of activity. After asking on the mailing list for my mail client, Andrej Kacian pointed me at a thread that documented someone dealing with MTU issues. After some examination with Wireshark, I realized that my workstation was sending packets that were larger than the PPPoE link's MTU of 1492. My FreeBSD machine was dilligently responding with Packet Too Large errors, but for whatever reason, my Linux workstation was essentially ignoring them. Some conversations on the #ipv6 Freenode IRC channel have suggested that Linux handles this very badly. Worse, it seems that the MTU related issues are sporadic: Sometimes it works without issue, other times not.

The "solution" seems to be this: Set the MTUs of all interfaces on all machines in my network to 1492. If I, for example, set the MTU of my workstation's network interface to 1500 and set the FreeBSD router's interfaces to 1492, I can no longer SSH reliably into remote sites, and the majority of TLS handshakes fail. No Packet Too Large errors are generated, which seems counter to my understanding of how this stuff is supposed to work. I very much dislike having to use a non-default MTU on my network: It seems like I will inevitably forget to set it on one or more machines and will run into bizarre and intermittent network issues on that machine.

Some further conversation on the #ipv6 IRC channel suggests that I should not have to do this at all. However, I've so far spent roughly ten hours trying to debug the problem and am exhausted. Using a non-standard MTU in my LAN(s) works around the issue for now, and I'll re-examine the problem after my capacity for suffering has been replenished.

2018-02-23: Update: IPv6 And Linux

Maven Plugins Are Not Ripe Yet

I wanted to start moving all my projects to Java 9, but quickly discovered that a lot of Maven plugins I depend on aren't ready for Java 9 yet.

Chemriver

Chemriver/A on Vimeo

Chemriver/A

Chemriver/B on Vimeo

Chemriver/B

Sources available at GitHub.