[Releng] Improve the repo analyzer to display the UID of the pgp key
diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIndex.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIndex.java
index 3a29d51..a7356c6 100644
--- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIndex.java
+++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIndex.java
@@ -84,11 +84,11 @@
   protected static final String _51 = "<!----------->";
   protected static final String _52 = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
   protected static final String _53 = "</a>";
-  protected static final String _54 = "</a> report.";
-  protected static final String _55 = "</a>.";
-  protected static final String _56 = "</a>.</p>";
-  protected static final String _57 = "</a></li>";
-  protected static final String _58 = "</a></span>";
+  protected static final String _54 = "</a> ";
+  protected static final String _55 = "</a> report.";
+  protected static final String _56 = "</a>.";
+  protected static final String _57 = "</a>.</p>";
+  protected static final String _58 = "</a></li>";
   protected static final String _59 = "</aside>";
   protected static final String _60 = "</b>";
   protected static final String _61 = "</body>";
@@ -475,20 +475,20 @@
   protected final String _423 = _259 + NL_9 + _150;
   protected final String _424 = _249 + NL_7 + _53;
   protected final String _425 = NL_8 + _178 + NL_10 + _245 + NL_10 + _87 + NL_12 + _147;
-  protected final String _426 = _54 + NL_8 + _72 + NL_8 + _181;
+  protected final String _426 = _55 + NL_8 + _72 + NL_8 + _181;
   protected final String _427 = NL_8 + _180 + NL_8 + _224;
   protected final String _428 = NL_10 + _165;
   protected final String _429 = NL_8 + _80;
   protected final String _430 = NL_8 + _178 + NL_10 + _243 + NL_10 + _86;
   protected final String _431 = _260 + NL_12 + _147;
   protected final String _432 = _53 + NL_10 + _358;
-  protected final String _433 = _55 + NL_8 + _72;
+  protected final String _433 = _56 + NL_8 + _72;
   protected final String _434 = NL_8 + _139 + NL_8 + _178;
   protected final String _435 = NL_8 + _137 + NL_8 + _178;
   protected final String _436 = NL_8 + _135 + NL_10 + _238 + NL_8 + _65;
   protected final String _437 = NL_8 + _119 + NL_10 + _145;
   protected final String _438 = _262 + NL_10 + _189;
-  protected final String _439 = _58 + NL_8 + _63;
+  protected final String _439 = _76 + NL_8 + _63;
   protected final String _440 = NL_8 + _135 + NL_10 + _230;
   protected final String _441 = NL_8 + _197;
   protected final String _442 = NL_8 + _65;
@@ -544,7 +544,7 @@
   protected final String _492 = _305 + NL_12 + _95;
   protected final String _493 = _16 + NL_12 + _144;
   protected final String _494 = _262 + NL_12 + _189;
-  protected final String _495 = _58 + NL_12 + _193;
+  protected final String _495 = _76 + NL_12 + _193;
   protected final String _496 = _21 + NL_10 + _63 + NL_10 + _211;
   protected final String _497 = NL_12 + _164 + NL_14 + _86;
   protected final String _498 = _53 + NL_12 + _69;
@@ -675,7 +675,7 @@
     stringBuffer.append(entry.getValue());
     stringBuffer.append(_265);
     stringBuffer.append(entry.getKey());
-    stringBuffer.append(_57);
+    stringBuffer.append(_58);
     }
     }
     stringBuffer.append(_402);
@@ -766,7 +766,7 @@
     stringBuffer.append(reporter.getReportSource());
     stringBuffer.append(_261);
     stringBuffer.append(reporter.getReportSource());
-    stringBuffer.append(_56);
+    stringBuffer.append(_57);
     Map<String, String> allReports = indexReport.getAllReports();
     if (allReports != null && !allReports.isEmpty()) {
     stringBuffer.append(_427);
@@ -775,7 +775,7 @@
     stringBuffer.append(entry.getValue());
     stringBuffer.append(_265);
     stringBuffer.append(entry.getKey());
-    stringBuffer.append(_57);
+    stringBuffer.append(_58);
     }
     stringBuffer.append(_429);
     }
@@ -811,12 +811,15 @@
     stringBuffer.append(_436);
     for (PGPPublicKey pgpPublicKey : pgpKeys) {
           String fingerPrint = PGPPublicKeyService.toHexFingerprint(pgpPublicKey);
+          String uid = report.getUID(pgpPublicKey);
     stringBuffer.append(_437);
     stringBuffer.append(report.getSignedImage(true));
     stringBuffer.append(_438);
     stringBuffer.append(report.getKeyServerURL(pgpPublicKey));
     stringBuffer.append(_258);
     stringBuffer.append(fingerPrint);
+    stringBuffer.append(_54);
+    stringBuffer.append(uid);
     stringBuffer.append(_439);
     }
       }
@@ -1143,6 +1146,7 @@
     for (Map.Entry<PGPPublicKey, Map<String, IInstallableUnit>> entry : pgpKeys.entrySet()) {
         PGPPublicKey pgpPublicKey = entry.getKey();
         String fingerPrint = PGPPublicKeyService.toHexFingerprint(pgpPublicKey);
+        String uid = report.getUID(pgpPublicKey);
         String id = "pgpKeys" + ++idCount;
     stringBuffer.append(_491);
     stringBuffer.append(2);
@@ -1156,6 +1160,8 @@
     stringBuffer.append(report.getKeyServerURL(pgpPublicKey));
     stringBuffer.append(_258);
     stringBuffer.append(fingerPrint);
+    stringBuffer.append(_54);
+    stringBuffer.append(uid);
     stringBuffer.append(_495);
     stringBuffer.append(entry.getValue().size());
     stringBuffer.append(_496);
diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIntegrityAnalyzer.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIntegrityAnalyzer.java
index 25eaa9b..abb5907 100644
--- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIntegrityAnalyzer.java
+++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/RepositoryIntegrityAnalyzer.java
@@ -78,6 +78,7 @@
 import org.eclipse.equinox.internal.p2.metadata.repository.io.XMLConstants;
 import org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryIO;
 import org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryState;
+import org.eclipse.equinox.internal.provisional.p2.repository.DefaultPGPPublicKeyService;
 import org.eclipse.equinox.p2.core.ProvisionException;
 import org.eclipse.equinox.p2.metadata.IArtifactKey;
 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
@@ -160,6 +161,7 @@
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -2054,8 +2056,14 @@
           {
             try
             {
-              Set<PGPPublicKey> pgpPubliKeys = PGPPublicKeyStore.readPublicKeys(IOUtil.readUTF8(pgpKeyFile));
-              return pgpPubliKeys;
+              Set<PGPPublicKey> pgpPublicKeys = PGPPublicKeyStore.readPublicKeys(IOUtil.readUTF8(pgpKeyFile));
+              PGPPublicKeyService keyService = getKeyService();
+              Set<PGPPublicKey> result = new LinkedHashSet<>();
+              for (PGPPublicKey pgpPublicKey : pgpPublicKeys)
+              {
+                result.add(keyService.getKey(pgpPublicKey.getFingerprint()));
+              }
+              return result;
             }
             catch (Exception ex)
             {
@@ -2065,6 +2073,53 @@
           return Set.of();
         }
 
+        private Map<PGPPublicKey, String> uids = new ConcurrentHashMap<>();
+
+        @Override
+        public String getUID(PGPPublicKey key)
+        {
+          return uids.computeIfAbsent(key, k -> computeUID(k, true));
+        }
+
+        public String computeUID(PGPPublicKey key, boolean recursive)
+        {
+          for (Iterator<String> it = key.getUserIDs(); it.hasNext();)
+          {
+            String userID = it.next();
+            Matcher matcher = UID_PATTERN.matcher(userID);
+            if (matcher.matches())
+            {
+              return matcher.group(1);
+            }
+          }
+
+          if (recursive)
+          {
+            try
+            {
+              Set<PGPPublicKey> verifiedCertifications = getKeyService().getVerifiedCertifications(key);
+              for (PGPPublicKey certifyingKey : verifiedCertifications)
+              {
+                if (certifyingKey != key)
+                {
+                  String uid = computeUID(certifyingKey, false);
+                  if (!StringUtil.isEmpty(uid))
+                  {
+                    return uid;
+                  }
+                }
+              }
+            }
+            catch (RuntimeException ex)
+            {
+              ex.printStackTrace();
+              //$FALL-THROUGH$
+            }
+          }
+
+          return "";
+        }
+
         @Override
         public String getKeyServerURL(PGPPublicKey key)
         {
@@ -3792,6 +3847,13 @@
     return getAgent().getArtifactRepositoryManager();
   }
 
+  private PGPPublicKeyService getKeyService()
+  {
+    DefaultPGPPublicKeyService service = (DefaultPGPPublicKeyService)getAgent().getProvisioningAgent().getService(PGPPublicKeyService.class);
+    service.setKeyServers(Set.of("keyserver.ubuntu.com"));
+    return service;
+  }
+
   private static String format(float size)
   {
     NumberFormat instance = NumberFormat.getInstance(Locale.US);
@@ -3865,6 +3927,8 @@
 
   public static abstract class Report implements Reporter
   {
+    static Pattern UID_PATTERN = Pattern.compile(".*<([^>]+)>.*");
+
     private static final URI NO_LICENSE_URI = URI.createURI("");
 
     public static class LicenseDetail
@@ -4201,6 +4265,8 @@
 
     public abstract Map<List<Certificate>, Map<String, IInstallableUnit>> getCertificates();
 
+    public abstract String getUID(PGPPublicKey key);
+
     public abstract String getKeyServerURL(PGPPublicKey key);
 
     public abstract Map<PGPPublicKey, Map<String, IInstallableUnit>> getPGPKeys();
diff --git a/plugins/org.eclipse.oomph.p2.core/templates/index.htmljet b/plugins/org.eclipse.oomph.p2.core/templates/index.htmljet
index 0a87105..6821742 100644
--- a/plugins/org.eclipse.oomph.p2.core/templates/index.htmljet
+++ b/plugins/org.eclipse.oomph.p2.core/templates/index.htmljet
@@ -545,10 +545,11 @@
              PGP Keys
            </h3>
       <%for (PGPPublicKey pgpPublicKey : pgpKeys) {
-          String fingerPrint = PGPPublicKeyService.toHexFingerprint(pgpPublicKey);%>
+          String fingerPrint = PGPPublicKeyService.toHexFingerprint(pgpPublicKey);
+          String uid = report.getUID(pgpPublicKey);%>
            <div class="font-smaller">
              <img alt="Signed" class="fit-image" src="../<%=report.getSignedImage(true)%>"/>
-             <span class="text-nowrap"><a href="<%=report.getKeyServerURL(pgpPublicKey)%>" target="keyserver">0x<%=fingerPrint%></a></span>
+             <span class="text-nowrap"><a href="<%=report.getKeyServerURL(pgpPublicKey)%>" target="keyserver">0x<%=fingerPrint%></a> <%=uid%></span>
            </div>
       <%}
       }
@@ -789,12 +790,13 @@
     <%for (Map.Entry<PGPPublicKey, Map<String, IInstallableUnit>> entry : pgpKeys.entrySet()) {
         PGPPublicKey pgpPublicKey = entry.getKey();
         String fingerPrint = PGPPublicKeyService.toHexFingerprint(pgpPublicKey);
+        String uid = report.getUID(pgpPublicKey);
         String id = "pgpKeys" + ++idCount;%>
            <li>
              <div class="font-smaller" style="margin-left: <%=2%>em; text-indent: -4em;">
                <button id="<%=id%>_arrows" class="orange bb" style="margin-left: 1em;" onclick="expand_collapse('<%=id%>');">&#x25B7;</button>
                <img alt="Signed" class="fit-image" src="<%=report.getSignedImage(true)%>"/>
-               <span class="text-nowrap"><a href="<%=report.getKeyServerURL(pgpPublicKey)%>" target="keyserver">0x<%=fingerPrint%></a></span>
+               <span class="text-nowrap"><a href="<%=report.getKeyServerURL(pgpPublicKey)%>" target="keyserver">0x<%=fingerPrint%></a> <%=uid%></span>
                <span style="color: DarkCyan; font-size: 110%;">(<%=entry.getValue().size()%>)</span>
              </div>
              <ul class="font-smaller" style="list-style-type: none; display:none; margin-left: -3em;" id="<%=id%>">