gnodet-bot commented on code in PR #29428:
URL: https://github.com/apache/camel/pull/29428#discussion_r4508136258


##########
dsl/camel-jbang/camel-launcher/src/main/java/org/apache/camel/dsl/jbang/launcher/selfupdate/ManifestFetcher.java:
##########
@@ -210,6 +266,79 @@ static Manifest parse(byte[] content) {
         return new Manifest(version, values.get("tar_sha256"), 
values.get("zip_sha256"));
     }
 
+    // Package-visible for unit testing. The highest X.Y.Z-SNAPSHOT of 
<versions>; other entries are ignored.
+    static String parseLatestSnapshotVersion(byte[] content) {
+        String latest = null;
+        NodeList versions = parseXml(content).getElementsByTagName("version");
+        for (int i = 0; i < versions.getLength(); i++) {
+            String version = versions.item(i).getTextContent().strip();
+            if (Nightly.isSnapshotVersion(version)
+                    && (latest == null || VersionHelper.compare(base(version), 
base(latest)) > 0)) {
+                latest = version;
+            }
+        }
+        if (latest == null) {
+            throw new SelfUpdateException("the snapshot repository lists no 
X.Y.Z-SNAPSHOT version");
+        }
+        return latest;
+    }
+
+    // Package-visible for unit testing. The <value> of the bin tar.gz 
<snapshotVersion> (Maven 3 metadata), or else
+    // the <timestamp>-<buildNumber> of the <snapshot> (Maven 2 metadata, 
which Nexus 2 serves to a client it does not
+    // take for Maven 3, such as the JDK HTTP client), as all the files of one 
deploy share them. It must be a nightly
+    // build of snapshotVersion: it is used in a directory name and a download 
URL.
+    static String parseNewestBuild(byte[] content, String snapshotVersion) {
+        Document document = parseXml(content);
+        String build = null;
+        NodeList entries = document.getElementsByTagName("snapshotVersion");
+        for (int i = 0; i < entries.getLength() && build == null; i++) {
+            Element entry = (Element) entries.item(i);
+            if ("bin".equals(childText(entry, "classifier")) && 
"tar.gz".equals(childText(entry, "extension"))) {
+                build = String.valueOf(childText(entry, "value"));

Review Comment:
   ⚠️ **Bug:** `String.valueOf(null)` returns the literal string `"null"`, not 
`null`. When `childText(entry, "value")` returns `null` (element missing), 
`build` is set to `"null"` (a non-null string), so the `if (build == null)` 
fallback below is skipped. `Nightly.isBuild("null")` then fails with a 
confusing error message.
   
   ```suggestion
                   build = childText(entry, "value");
   ```



##########
dsl/camel-jbang/camel-launcher/src/install/install.sh:
##########
@@ -252,6 +309,112 @@ activate() {
     mv -f "$tmp_link" "$bin_dir/camel"
 }
 
+# The snapshot version of main: the highest X.Y.Z-SNAPSHOT listed in the 
snapshot repository metadata (the
+# maintenance branches publish nightly builds too, under lower versions). 
Maven writes one element per line.
+latest_snapshot_version() {
+    sed -n 's|.*<version>\([^<]*\)</version>.*|\1|p' "$1" | while IFS= read -r 
lsv; do
+        is_valid_snapshot "$lsv" && printf '%s\n' "${lsv%-SNAPSHOT}"
+    done | sort -t. -n -k1,1 -k2,2 -k3,3 | tail -1
+}
+
+# The newest nightly build of a snapshot version ($2, X.Y.Z) from its metadata 
($1): the <value> of the bin tar.gz
+# <snapshotVersion> (Maven 3 metadata), or else the <timestamp>-<buildNumber> 
of the <snapshot> (Maven 2 metadata,
+# which Nexus 2 serves to a client it does not take for Maven 3), as all the 
files of one deploy share them.
+newest_nightly() {
+    awk -v base="$2" '
+        /<snapshotVersion>/ { inside = 1; c = ""; e = ""; v = "" }
+        inside && /<classifier>/ { c = $0; 
gsub(/.*<classifier>|<\/classifier>.*/, "", c) }
+        inside && /<extension>/ { e = $0; 
gsub(/.*<extension>|<\/extension>.*/, "", e) }
+        inside && /<value>/ { v = $0; gsub(/.*<value>|<\/value>.*/, "", v) }
+        /<\/snapshotVersion>/ { if (c == "bin" && e == "tar.gz") { found = v } 
inside = 0 }
+        /<timestamp>/ && ts == "" { ts = $0; 
gsub(/.*<timestamp>|<\/timestamp>.*/, "", ts) }
+        /<buildNumber>/ && bn == "" { bn = $0; 
gsub(/.*<buildNumber>|<\/buildNumber>.*/, "", bn) }
+        END {
+            if (found != "") { print found } else if (ts != "" && bn != "") { 
print base "-" ts "-" bn }
+        }
+    ' "$1"
+}
+
+# Removes all but the newest three nightly builds, never the one just 
installed: a command that still runs from one
+# of them keeps its files. Releases are never removed.
+prune_nightlies() {
+    keep_build="$1"
+    ls "$data_root" | while IFS= read -r pn_dir; do
+        is_valid_nightly "$pn_dir" && printf '%s %s\n' "${pn_dir#*-}" "$pn_dir"
+    done | sort -r | awk 'NR > 3 { print $2 }' | while IFS= read -r pn_old; do

Review Comment:
   ⚠️ **Bug:** `sort -r` uses lexicographic ordering on the sort key 
`YYYYMMDD.HHMMSS-N`. When two builds share the same timestamp (possible on 
rapid retries), the `-N` suffix is compared as text: `9 > 24` 
lexicographically, so build 9 would be kept and build 24 pruned. Use numeric 
sort on the build number field:
   
   ```suggestion
       done | sort -t- -k1,1r -k2,2rn | awk 'NR > 3 { print $2 }' | while IFS= 
read -r pn_old; do
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to