diff --git a/src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java b/src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java index bd8e57f..82a7fe1 100644 --- a/src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java +++ b/src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java @@ -18,8 +18,11 @@ package io.linuxserver.fleet.dockerhub.util; import io.linuxserver.fleet.v2.types.docker.DockerTag; +import io.linuxserver.fleet.v2.types.docker.DockerTagManifestDigest; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; public class DockerTagFinder { @@ -32,11 +35,46 @@ public class DockerTagFinder { DockerTag namedTagForBranch = tagBranchName.get(); Optional versionedLatestTag = tags.stream() - .filter(tag -> !tag.equals(namedTagForBranch) && tag.getSize() == namedTagForBranch.getSize()).findFirst(); + .filter(tag -> !tag.equals(namedTagForBranch) && allManifestsMatch(namedTagForBranch, tag)).findFirst(); return versionedLatestTag.orElse(namedTagForBranch); } return tags.isEmpty() ? null : tags.get(0); } + + private static boolean allManifestsMatch(final DockerTag namedTag, final DockerTag toCheck) { + + final List namedDigests = namedTag.getDigests(); + final List digestsToCheck = toCheck.getDigests(); + + boolean allMatch = true; + + if (namedDigests.size() == digestsToCheck.size()) { + + final Map namedDigestsAsMap = toMapKeyedByArch(namedDigests); + + for (DockerTagManifestDigest digestToCheck : digestsToCheck) { + + final String archPlusVariant = digestToCheck.getArchitecture() + digestToCheck.getArchVariant(); + final String foundDigest = namedDigestsAsMap.get(archPlusVariant); + + allMatch = allMatch && (null != foundDigest) && foundDigest.equals(digestToCheck.getDigest()); + } + + } else { + allMatch = false; + } + + return allMatch; + } + + private static Map toMapKeyedByArch(final List initialList) { + + final Map map = new HashMap<>(); + for (DockerTagManifestDigest digest : initialList) { + map.put(digest.getArchitecture() + digest.getArchVariant(), digest.getDigest()); + } + return map; + } } diff --git a/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java b/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java index f1b240b..e3312fd 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java @@ -17,6 +17,9 @@ package io.linuxserver.fleet.v2.types.docker; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -55,4 +58,9 @@ public class DockerTag { public LocalDateTime getBuildDate() { return buildDate; } + + @Override + public final String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } } diff --git a/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java b/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java index 8f5562a..e2570a5 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java @@ -48,4 +48,8 @@ public class DockerTagManifestDigest { return archVariant; } + @Override + public final String toString() { + return architecture + "/" + archVariant + "[" + digest + "]"; + } } diff --git a/src/main/resources/static/assets/images/favicon-32x32.png b/src/main/resources/static/assets/images/favicon-32x32.png index e6d2947..79387cf 100644 Binary files a/src/main/resources/static/assets/images/favicon-32x32.png and b/src/main/resources/static/assets/images/favicon-32x32.png differ diff --git a/src/main/resources/static/assets/images/favicon.ico b/src/main/resources/static/assets/images/favicon.ico index 14b0c95..fdebbe0 100644 Binary files a/src/main/resources/static/assets/images/favicon.ico and b/src/main/resources/static/assets/images/favicon.ico differ diff --git a/src/main/resources/static/assets/images/logo.png b/src/main/resources/static/assets/images/logo.png index fa096fe..da8fdbc 100644 Binary files a/src/main/resources/static/assets/images/logo.png and b/src/main/resources/static/assets/images/logo.png differ diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties index 11c7267..a3eab74 100644 --- a/src/main/resources/version.properties +++ b/src/main/resources/version.properties @@ -1,5 +1,5 @@ -#Sat May 09 13:48:27 BST 2020 -app.build.date=2020-05-09T13\:48\:27 +#Sat Jun 27 11:17:44 BST 2020 +app.build.date=2020-06-27T11\:17\:44 app.build.os=Linux app.build.user=josh app.version=2.0.5 diff --git a/src/main/resources/views/pages/image.ftl b/src/main/resources/views/pages/image.ftl index 14cea49..fe27146 100644 --- a/src/main/resources/views/pages/image.ftl +++ b/src/main/resources/views/pages/image.ftl @@ -116,12 +116,19 @@ <@table.halfDisplayRow title="Docker Hub" value=' ${image.fullName}' link="https://hub.docker.com/r/${image.fullName}" /> <@table.halfDisplayRow title="Build Time" value=image.lastUpdatedAsString /> + <#if image.metaData.baseImage?has_content> <@table.halfDisplayRow title="Base Image" value=image.metaData.baseImage?html /> + + <#if image.metaData.category?has_content> + <@table.halfDisplayRow title="Category" value=image.metaData.category?html /> + + <@table.halfDisplayRow title="Synchronised" value=image.syncEnabled?string("Yes", "No") /> <@table.halfDisplayRow title="Stable" value=image.stable?string("Yes", "No") /> <@table.halfDisplayRow title="Deprecated" value=image.deprecated?string("Yes", "No") /> + @@ -141,10 +148,6 @@ - <#if image.metaData.category?has_content> - <@table.halfDisplayRow title="Category" value=image.metaData.category /> - - <#-- Any set external Urls --> <#list image.metaData.externalUrls as url> diff --git a/src/test/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinderTest.java b/src/test/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinderTest.java new file mode 100644 index 0000000..85d4634 --- /dev/null +++ b/src/test/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinderTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 LinuxServer.io + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package io.linuxserver.fleet.dockerhub.util; + +import io.linuxserver.fleet.v2.types.docker.DockerTag; +import io.linuxserver.fleet.v2.types.docker.DockerTagManifestDigest; +import org.junit.Before; +import org.junit.Test; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class DockerTagFinderTest { + + @Test + public void shouldFindCorrectTagIfAllDigestsMatch() { + + final DockerTag named = new DockerTag("latest", 1234L, LocalDateTime.now()); + named.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + named.addDigest(new DockerTagManifestDigest(1234L, "digest2", "arch", "variant2")); + named.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final DockerTag shouldMatch = new DockerTag("v1234", 1234L, LocalDateTime.now()); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest2", "arch", "variant2")); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final DockerTag shouldNotMatch = new DockerTag("v1234", 1234L, LocalDateTime.now()); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest4", "arch", "variant2")); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final List tags = new ArrayList<>(); + tags.add(named); + tags.add(shouldMatch); + tags.add(shouldNotMatch); + + assertThat(DockerTagFinder.findVersionedTagMatchingBranch(tags, "latest"), is(equalTo(shouldMatch))); + } + + @Test + public void shouldReturnFoundNamedTagIfNoOthersMatchFully() { + + final DockerTag named = new DockerTag("latest", 1234L, LocalDateTime.now()); + named.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + named.addDigest(new DockerTagManifestDigest(1234L, "digest2", "arch", "variant2")); + named.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final DockerTag shouldMatch = new DockerTag("v1234", 1234L, LocalDateTime.now()); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest5", "arch", "variant2")); + shouldMatch.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final DockerTag shouldNotMatch = new DockerTag("v1234", 1234L, LocalDateTime.now()); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest1", "arch", "variant1")); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest4", "arch", "variant2")); + shouldNotMatch.addDigest(new DockerTagManifestDigest(1234L, "digest3", "arch", "variant3")); + + final List tags = new ArrayList<>(); + tags.add(named); + tags.add(shouldMatch); + tags.add(shouldNotMatch); + + assertThat(DockerTagFinder.findVersionedTagMatchingBranch(tags, "latest"), is(equalTo(named))); + } +}