public static DockerImage fromString(String s) {
        if (s.isEmpty()) return EMPTY;

        int repositoryStart = s.lastIndexOf('/', s.lastIndexOf('/') - 1);
        if (repositoryStart < 0) throw new IllegalArgumentException("Expected to find at least 2 path segments in: " + s);

        String registry = s.substring(0, repositoryStart);
        String repository = s.substring(repositoryStart + 1);

        int tagStart = repository.indexOf(':');
        Optional<String> tag = tagStart < 0 ? Optional.empty() : Optional.of(repository.substring(tagStart + 1));

        if (tagStart >= 0) repository = repository.substring(0, tagStart);
        if (repository.isEmpty()) throw new IllegalArgumentException("Repository must be non-empty in '" + s + "'");
        return new DockerImage(registry, repository, tag);
    }
@Test
    void parse_invalid() {
        List<String> tests = List.of(
                               "registry.example.com",
                               "registry.example.com/",
                               "registry.example.com/repository",
                               "registry.example.com/repository:",
                               "foo",
                               "foo:1.2.3"
        );
        for (var value : tests) {
            try {
                DockerImage.fromString(value);
                fail("Expected failure for: " + value);
            } catch (IllegalArgumentException ignored) {
            }
        }
    }