From 29d84742c02b7487e01ab373f0d0a4b6bdfb76a0 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 13:16:42 +0200 Subject: [PATCH 1/9] docs/Makefile.am: *.adoc-parsed: add support for GHSA links [#3594] Signed-off-by: Jim Klimov --- docs/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Makefile.am b/docs/Makefile.am index 25bb22bee0..e57bbc1c1c 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -458,6 +458,8 @@ MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no -e 's%\(link:https*://github.com/networkupstools/[a-zA-Z0-9./-]*/[1-9][0-9]*/*\[[^]]*\)\#\([1-9][0-9]*\)%\1\#\#\2%g' \ -e 's%\[\([^]]*\)](\(https*://[^ ]*\))%link:\2[\1]%g' \ -e 's%\(link:https*://github.com/[^ ]*\)\.\.\.\([^ ]*\)%\1..\2%g' \ + -e 's%\(\[\#*\)\(GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]\)\(\]\)%[link:https://github.com/networkupstools/nut/security/advisories/\2[\2]]%g' \ + -e 's%\(advisory\) *\#*\(GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]\)\([^A-Za-z0-9]\|$$\))%link:https://github.com/networkupstools/nut/security/advisories/\2[\1 \2]\3%g' \ -e 's%\(issue\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/issues/\2[\1 \#\#\2]\3%g' \ -e 's%\(PR\|pull request\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/pull/\2[\1 \#\#\2]\3%g' \ -e 's%\([[ ,]\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/nut/issues/\2[\#\#\2]\3%g' \ From 6fde795aa03c25977a532ecf4c1d33f13013238f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 13:31:33 +0200 Subject: [PATCH 2/9] tools/asciidoc-github-links.pl: DOCBUILD_FILTER_GITHUB_LINKS: transplant the stack of Makefile inline SED expressions into a more flexible separate perl script [#1953] Signed-off-by: Jim Klimov --- docs/Makefile.am | 16 +--------- tools/Makefile.am | 3 +- tools/asciidoc-github-links.pl | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) create mode 100755 tools/asciidoc-github-links.pl diff --git a/docs/Makefile.am b/docs/Makefile.am index e57bbc1c1c..f590a5b4a5 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -454,21 +454,7 @@ MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no ls -lad $@ $< || true ; \ stat $@ $< || true ; \ fi ; \ - cat '$<' | { $(SED) \ - -e 's%\(link:https*://github.com/networkupstools/[a-zA-Z0-9./-]*/[1-9][0-9]*/*\[[^]]*\)\#\([1-9][0-9]*\)%\1\#\#\2%g' \ - -e 's%\[\([^]]*\)](\(https*://[^ ]*\))%link:\2[\1]%g' \ - -e 's%\(link:https*://github.com/[^ ]*\)\.\.\.\([^ ]*\)%\1..\2%g' \ - -e 's%\(\[\#*\)\(GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]\)\(\]\)%[link:https://github.com/networkupstools/nut/security/advisories/\2[\2]]%g' \ - -e 's%\(advisory\) *\#*\(GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]\)\([^A-Za-z0-9]\|$$\))%link:https://github.com/networkupstools/nut/security/advisories/\2[\1 \2]\3%g' \ - -e 's%\(issue\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/issues/\2[\1 \#\#\2]\3%g' \ - -e 's%\(PR\|pull request\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/pull/\2[\1 \#\#\2]\3%g' \ - -e 's%\([[ ,]\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/nut/issues/\2[\#\#\2]\3%g' \ - -e 's%\(issue\) networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/issues/\3[\1 \2\#\#\3]\4%g' \ - -e 's%\(PR\|pull request\) *networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/pull/\3[\1 \2\#\#\3]\4%g' \ - -e 's%\([[ ,]\)networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/\2/issues/\3[\2\#\#\3]\4%g' \ - -e 's%\#\(\#[1-9][0-9]*\)%\1%g' \ - -e 's,\(https*://[^ \+]*\)[\]*[+],\1%2B,g' \ - ; } > "$@.tmp.$$$$" \ + $(top_srcdir)/tools/asciidoc-github-links.pl < '$<' > "$@.tmp.$$$$" \ && test -s "$@.tmp.$$$$" \ && mv -f "$@.tmp.$$$$" '$@' \ || { RES="$$?" ; rm -f "$@.tmp.$$$$" ; exit $$RES ; } diff --git a/tools/Makefile.am b/tools/Makefile.am index 62406a12ee..8340aed46f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -26,7 +26,8 @@ PYTHON_DEFAULT = @PYTHON_DEFAULT@ EXTRA_DIST = nut-usbinfo.pl nut-recorder.sh nut-ddl-dump.sh nut-dumpdiff.sh \ gitlog2changelog.py.in gitlog2version.sh semver-compare.sh \ - nut-snmpinfo.py.in driver-list-format.sh check-source-nonascii.pl + nut-snmpinfo.py.in driver-list-format.sh check-source-nonascii.pl \ + asciidoc-github-links.pl # These files are generated for nut-scanner builds (and cleaned as any others), # and can change as respective SNMP/USB subdriver sources are iterated by a diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl new file mode 100755 index 0000000000..6a101985fb --- /dev/null +++ b/tools/asciidoc-github-links.pl @@ -0,0 +1,55 @@ +#!/usr/bin/env perl +# +# Convert certain text patterns into ASCIIDOC markup for GitHub links to +# issues, PRs, security advisories, etc. +# +# Copyright (C) 2023-2026 by Jim Klimov +# Based on earlier work with a stack of SED expressions in NUT::docs/Makefile.am + +use strict; + +my $ghsa_id_re = "GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]"; + +local $/ = undef; +while (<>) { + # 1. link to a sibling project's issue/pull/advisory e.g. [networkupstools/nut#2048] + s/(link:https*:\/\/github\.com\/networkupstools\/[a-zA-Z0-9.\/-]+\/[1-9][0-9]*\/*\[[^]]*)\#([1-9][0-9]*)/$1##$2/g; + + # 2. markdown links [text](url) -> link:url[text] + s/\[([^]]*)\]\((https*:\/\/[^ ]*)\)/{ "link:" . $2 . "[" . $1 . "]" }/ge; + + # 3. link ellipsis ... + s/(link:https*:\/\/github\.com\/[^ ]*)\.\.\.([^ ]*)/$1..$2/g; + + # 4. [#GHSA-...] + s%(\[#*)($ghsa_id_re)(\])%{ "[link:https://github.com/networkupstools/nut/security/advisories/" . $2 . "[" . $2 . "]]" }%ge; + + # 5. advisory #GHSA-... (multiple words / space separated, can be broken across lines) + s%\b(advisory)\s*\#*($ghsa_id_re)([^A-Za-z0-9]|$)%{ "link:https://github.com/networkupstools/nut/security/advisories/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; + + # 6. issue #123 + s%\b(issue)\s*\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/nut/issues/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; + + # 7. PR #123 or pull request #123 (multi-word pull request can be broken across lines) + s%\b(PR|pull\s+request)\s*\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/nut/pull/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; + + # 8. [[ ,]#123 + s%([[,\s])\#([1-9][0-9]*)([^0-9]|$)%{ $1 . "link:https://github.com/networkupstools/nut/issues/" . $2 . "[##" . $2 . "]" . $3 }%ge; + + # 9. issue networkupstools/foo#123 + s%\b(issue)\s+networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/" . $2 . "/issues/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; + + # 10. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) + s%\b(PR|pull\s+request)\s+networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/" . $2 . "/pull/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; + + # 11. [ ,]networkupstools/foo#123 + s%([,\s])networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ $1 . "link:https://github.com/networkupstools/" . $2 . "/issues/" . $3 . "[" . $2 . "##" . $3 . "]" . $4 }%ge; + + # 12. ##123 -> #123 + s/\#(\#[1-9][0-9]*)/$1/g; + + # 13. URL plus sign encoding + s/(https*:\/\/[^ \+]*)([\]]*\+)/$1%2B/g; + + print $_; +} From b0533ede4ee98631055b93082c169fec9ded8953 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 14:03:10 +0200 Subject: [PATCH 3/9] tools/asciidoc-github-links.pl: streamline with separate definitions of GH URI parts [#1953] This way the script can be more easily reused by other projects and is easier to maintain with symbolic names for repetititve sequences. Signed-off-by: Jim Klimov --- tools/asciidoc-github-links.pl | 61 +++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl index 6a101985fb..21dfbb34ef 100755 --- a/tools/asciidoc-github-links.pl +++ b/tools/asciidoc-github-links.pl @@ -8,48 +8,77 @@ use strict; +# These may be eventually overridden by caller to re-use with other projects +# (need to add CLI or envvar inputs): +my $gh_orgname = "networkupstools"; +my $gh_prjname = "nut"; + +# NOTE: Schema in regexes would vary, but in injected URLs must be specific +my $gh_schema_re = "[Hh][Tt][Tt][Pp][Ss]?://"; +my $gh_schema = "https://"; +my $gh_hostname_re = "github\.com"; +my $gh_hostname = "github.com"; + +# URI parts (under a project base URI) for singular item; note not all are +# consistently named singular/plural - for item vs. list). Also note that +# historically "issues" and "pulls" were handled by the same github-side +# handler so their URI parts could be interchangeable: +my $gh_uripart_pull = "pull"; +my $gh_uripart_issue = "issues"; +my $gh_uripart_secadv = "security/advisories"; + +my $issue_id_re = "[1-9][0-9]*"; my $ghsa_id_re = "GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]"; +# NOTE: Here backslashed dollars are a way to store the literal dollar +# character in the string to be used for regex below: +my $end_issue_id_re = "[^0-9]|\$"; +my $end_ghsa_id_re = "[^A-Za-z0-9]|\$"; + +# Values for easier substitution below: +my $gh_url_site = "${gh_schema}${gh_hostname}"; +my $gh_url_org = "${gh_url_site}/${gh_orgname}"; +my $gh_url_prj = "${gh_url_org}/${gh_prjname}"; local $/ = undef; while (<>) { # 1. link to a sibling project's issue/pull/advisory e.g. [networkupstools/nut#2048] - s/(link:https*:\/\/github\.com\/networkupstools\/[a-zA-Z0-9.\/-]+\/[1-9][0-9]*\/*\[[^]]*)\#([1-9][0-9]*)/$1##$2/g; + s/(link:${gh_schema_re}${gh_hostname_re}\/${gh_orgname}\/[a-zA-Z0-9.\/-]+\/[1-9][0-9]*\/*\[[^]]*)\#([1-9][0-9]*)/$1##$2/g; # 2. markdown links [text](url) -> link:url[text] - s/\[([^]]*)\]\((https*:\/\/[^ ]*)\)/{ "link:" . $2 . "[" . $1 . "]" }/ge; + s/\[([^]]*)\]\((${gh_schema_re}[^ ]*)\)/{ "link:" . $2 . "[" . $1 . "]" }/ge; # 3. link ellipsis ... - s/(link:https*:\/\/github\.com\/[^ ]*)\.\.\.([^ ]*)/$1..$2/g; + s/(link:${gh_schema_re}${gh_hostname_re}\/[^ ]*)\.\.\.([^ ]*)/$1..$2/g; - # 4. [#GHSA-...] - s%(\[#*)($ghsa_id_re)(\])%{ "[link:https://github.com/networkupstools/nut/security/advisories/" . $2 . "[" . $2 . "]]" }%ge; + # 4. single [#GHSA-...] + s%(\[#*)(${ghsa_id_re})(\])%{ "[link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $2 . "]]" }%ge; - # 5. advisory #GHSA-... (multiple words / space separated, can be broken across lines) - s%\b(advisory)\s*\#*($ghsa_id_re)([^A-Za-z0-9]|$)%{ "link:https://github.com/networkupstools/nut/security/advisories/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; + # 5. "advisory GHSA-..." or "advisory #GHSA-..." (multiple words / space separated, can be broken across lines) + s%\b(advisory)\s*\#*(${ghsa_id_re})(${end_ghsa_id_re})%{ "link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; # 6. issue #123 - s%\b(issue)\s*\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/nut/issues/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; + s%\b(issue)\s*\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; - # 7. PR #123 or pull request #123 (multi-word pull request can be broken across lines) - s%\b(PR|pull\s+request)\s*\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/nut/pull/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; + # 7. PR #123 or pull request #123 (multi-word "pull request" can be broken across lines) + s%\b(PR|pull\s+request)\s*\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_prj}/${gh_uripart_pull}/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; # 8. [[ ,]#123 - s%([[,\s])\#([1-9][0-9]*)([^0-9]|$)%{ $1 . "link:https://github.com/networkupstools/nut/issues/" . $2 . "[##" . $2 . "]" . $3 }%ge; + s%([[,\s])\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[##" . $2 . "]" . $3 }%ge; # 9. issue networkupstools/foo#123 - s%\b(issue)\s+networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/" . $2 . "/issues/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; + s%\b(issue)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; # 10. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) - s%\b(PR|pull\s+request)\s+networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ "link:https://github.com/networkupstools/" . $2 . "/pull/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; + s%\b(PR|pull\s+request)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_pull . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; # 11. [ ,]networkupstools/foo#123 - s%([,\s])networkupstools\/([^ \s]+)\#([1-9][0-9]*)([^0-9]|$)%{ $1 . "link:https://github.com/networkupstools/" . $2 . "/issues/" . $3 . "[" . $2 . "##" . $3 . "]" . $4 }%ge; + s%([,\s])${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $2 . "##" . $3 . "]" . $4 }%ge; # 12. ##123 -> #123 - s/\#(\#[1-9][0-9]*)/$1/g; + s/\#(\#${issue_id_re})/$1/g; # 13. URL plus sign encoding - s/(https*:\/\/[^ \+]*)([\]]*\+)/$1%2B/g; + s/(${gh_schema_re}[^ \+]*)([\]]*\+)/$1%2B/g; print $_; } From f23aebe783ebc227d2d0653bbec3411b9f08ed4a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 15:34:24 +0200 Subject: [PATCH 4/9] tools/asciidoc-github-links.pl: use `qr/.../` to define regexes [#1953] Signed-off-by: Jim Klimov --- tools/asciidoc-github-links.pl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl index 21dfbb34ef..3fe5a87eea 100755 --- a/tools/asciidoc-github-links.pl +++ b/tools/asciidoc-github-links.pl @@ -14,9 +14,9 @@ my $gh_prjname = "nut"; # NOTE: Schema in regexes would vary, but in injected URLs must be specific -my $gh_schema_re = "[Hh][Tt][Tt][Pp][Ss]?://"; +my $gh_schema_re = qr/[Hh][Tt][Tt][Pp][Ss]?:\/\//; my $gh_schema = "https://"; -my $gh_hostname_re = "github\.com"; +my $gh_hostname_re = qr/github\.com/; my $gh_hostname = "github.com"; # URI parts (under a project base URI) for singular item; note not all are @@ -27,12 +27,11 @@ my $gh_uripart_issue = "issues"; my $gh_uripart_secadv = "security/advisories"; -my $issue_id_re = "[1-9][0-9]*"; -my $ghsa_id_re = "GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]"; -# NOTE: Here backslashed dollars are a way to store the literal dollar -# character in the string to be used for regex below: -my $end_issue_id_re = "[^0-9]|\$"; -my $end_ghsa_id_re = "[^A-Za-z0-9]|\$"; +my $issue_id_re = qr/[1-9][0-9]*/; +my $ghsa_id_re = qr/GHSA-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]-[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]/; + +my $end_issue_id_re = qr/[^0-9]|$/; +my $end_ghsa_id_re = qr/[^A-Za-z0-9]|$/; # Values for easier substitution below: my $gh_url_site = "${gh_schema}${gh_hostname}"; From d14341346554a3d6ae798782cdf5c73e1d600892 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 14:56:53 +0200 Subject: [PATCH 5/9] tools/asciidoc-github-links.pl, NEWS.adoc: handle lists started with plural "PRs, issues, advisories" [#1953, #3594] Signed-off-by: Jim Klimov --- NEWS.adoc | 6 +++ docs/nut.dict | 5 ++- tools/asciidoc-github-links.pl | 72 +++++++++++++++++++++++++++------- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/NEWS.adoc b/NEWS.adoc index 8da073ce8e..a754d4c7eb 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -480,6 +480,12 @@ https://github.com/networkupstools/nut/milestone/13 Directory names are based on hashes of strings that identify the content, which are size-limited to some 8 characters. [issues #3108, #3390, #1711, #3526, PR #3109] + * Introduced `tools/asciidoc-github-links.pl` to simplify `docs/Makefile.am` + generation of `*.adoc-parsed` files with substituted GitHub links, and to + allow that logic to be executed separately from `make` and potentially be + re-used by other projects. Added support for lists of PRs/issues as used + in this document, and support for GitHub Security Advisories (GHSA). + [PR #3594, issue #1953] * Rearranged the GHA job to prepare Dist and Docs Tarballs. [PR #3460] * Updated `scripts/Windows/dllldd.sh` helper script to better detect DLL names not exposed with dynamic linking metadata (e.g. some Mozilla NSS diff --git a/docs/nut.dict b/docs/nut.dict index 2fb4a9e1da..e8aeb4b415 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3818 utf-8 +personal_ws-1.1 en 3819 utf-8 AAC AAS ABI @@ -449,6 +449,7 @@ GES GETADDRINFO GETPID GHA +GHSA GID GIO GITREV @@ -3153,10 +3154,10 @@ renderer renderers renice repindex +replug repo reportId reposurgeon -replug repotec req resetter diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl index 3fe5a87eea..ed202a3ead 100755 --- a/tools/asciidoc-github-links.pl +++ b/tools/asciidoc-github-links.pl @@ -49,34 +49,78 @@ # 3. link ellipsis ... s/(link:${gh_schema_re}${gh_hostname_re}\/[^ ]*)\.\.\.([^ ]*)/$1..$2/g; - # 4. single [#GHSA-...] - s%(\[#*)(${ghsa_id_re})(\])%{ "[link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $2 . "]]" }%ge; - - # 5. "advisory GHSA-..." or "advisory #GHSA-..." (multiple words / space separated, can be broken across lines) - s%\b(advisory)\s*\#*(${ghsa_id_re})(${end_ghsa_id_re})%{ "link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; - - # 6. issue #123 + # 4. Lists of references: PRs/issues/advisories token followed by + # comma and/or space-separated identifiers, with state memory + s%\b(PRs|issues|advisories)\b(.*)%{ + my $plural = $1; + my $rest = $2; + my $out = ""; + + while ($rest ne "") { + my $uripart = + ($plural eq 'PRs') ? $gh_uripart_pull : + ($plural eq 'issues') ? $gh_uripart_issue : + $gh_uripart_secadv; + + $out .= $plural; + my $id_matcher = $plural eq 'advisories' ? qr/\#?(${ghsa_id_re})/ : qr/\#(${issue_id_re})/; + while ($rest =~ s/^(\s*(?:[;,]\s*)?)${id_matcher}//s) { + my $sep = $1; + my $id = $2; + + $out .= $sep; + if ($id =~ /^${ghsa_id_re}/) { + $out .= "link:${gh_url_prj}/${uripart}/" . $id . "[" . $id . "]"; + } + else { + my $num = $id; + $num =~ s/^\#+//; + $out .= "link:${gh_url_prj}/${uripart}/" . $num . "[#" . $num . "]"; + } + } + + if ($rest =~ s/^([;,]?\s*)(PRs|issues|advisories)(.*)//s) { + my $sep = $1; + $plural = $2; + $rest = $3; + + $out .= $sep; + } else { + last; + } + } + + $out . $rest; + }%ges; + + # 5. single [#GHSA-...] + s%(\[#?)(${ghsa_id_re})(\])%{ "[link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $2 . "]]" }%ge; + + # 6. "advisory GHSA-..." or "advisory #GHSA-..." (multiple words / space separated, can be broken across lines) + s%\b(advisory)\s*\#?(${ghsa_id_re})(${end_ghsa_id_re})%{ "link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; + + # 7. issue #123 s%\b(issue)\s*\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; - # 7. PR #123 or pull request #123 (multi-word "pull request" can be broken across lines) + # 8. PR #123 or pull request #123 (multi-word "pull request" can be broken across lines) s%\b(PR|pull\s+request)\s*\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_prj}/${gh_uripart_pull}/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; - # 8. [[ ,]#123 + # 9. [[ ,]#123 s%([[,\s])\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[##" . $2 . "]" . $3 }%ge; - # 9. issue networkupstools/foo#123 + # 10. issue networkupstools/foo#123 s%\b(issue)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; - # 10. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) + # 11. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) s%\b(PR|pull\s+request)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_pull . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; - # 11. [ ,]networkupstools/foo#123 + # 12. [ ,]networkupstools/foo#123 s%([,\s])${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $2 . "##" . $3 . "]" . $4 }%ge; - # 12. ##123 -> #123 + # 13. ##123 -> #123 s/\#(\#${issue_id_re})/$1/g; - # 13. URL plus sign encoding + # 14. URL plus sign encoding s/(${gh_schema_re}[^ \+]*)([\]]*\+)/$1%2B/g; print $_; From e02d076a0d841d673108aad90718c6168cff40dc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 16:33:07 +0200 Subject: [PATCH 6/9] tools/asciidoc-github-links.pl: do not re-evaluate patterns in links generated earlier [#1953] Signed-off-by: Jim Klimov --- tools/asciidoc-github-links.pl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl index ed202a3ead..ca2cbe8497 100755 --- a/tools/asciidoc-github-links.pl +++ b/tools/asciidoc-github-links.pl @@ -94,7 +94,7 @@ }%ges; # 5. single [#GHSA-...] - s%(\[#?)(${ghsa_id_re})(\])%{ "[link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $2 . "]]" }%ge; + s%(^|[^A-Za-z0-9])\[#?(${ghsa_id_re})\]%{ $1 . "[link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $2 . "]]" }%ge; # 6. "advisory GHSA-..." or "advisory #GHSA-..." (multiple words / space separated, can be broken across lines) s%\b(advisory)\s*\#?(${ghsa_id_re})(${end_ghsa_id_re})%{ "link:${gh_url_prj}/${gh_uripart_secadv}/" . $2 . "[" . $1 . " " . $2 . "]" . $3 }%ge; @@ -105,22 +105,25 @@ # 8. PR #123 or pull request #123 (multi-word "pull request" can be broken across lines) s%\b(PR|pull\s+request)\s*\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_prj}/${gh_uripart_pull}/" . $2 . "[" . $1 . " ##" . $2 . "]" . $3 }%ge; - # 9. [[ ,]#123 - s%([[,\s])\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[##" . $2 . "]" . $3 }%ge; + # 9. " #123" or ",#123" + s%([,\s])\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[##" . $2 . "]" . $3 }%ge; - # 10. issue networkupstools/foo#123 + # 10. "...[#123..." + s%(^|\D)\[\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "[link:${gh_url_prj}/${gh_uripart_issue}/" . $2 . "[##" . $2 . "]" . $3 }%ge; + + # 11. issue networkupstools/foo#123 s%\b(issue)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; - # 11. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) + # 12. PR networkupstools/foo#123 or pull request networkupstools/foo#123 (multi-word) s%\b(PR|pull\s+request)\s+${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_pull . "/" . $3 . "[" . $1 . " " . $2 . "##" . $3 . "]" . $4 }%ge; - # 12. [ ,]networkupstools/foo#123 + # 13. [ ,]networkupstools/foo#123 s%([,\s])${gh_orgname}\/([^ \s]+)\#(${issue_id_re})(${end_issue_id_re})%{ $1 . "link:${gh_url_org}/" . $2 . "/" . $gh_uripart_issue . "/" . $3 . "[" . $2 . "##" . $3 . "]" . $4 }%ge; - # 13. ##123 -> #123 + # 14. ##123 -> #123 s/\#(\#${issue_id_re})/$1/g; - # 14. URL plus sign encoding + # 15. URL plus sign encoding s/(${gh_schema_re}[^ \+]*)([\]]*\+)/$1%2B/g; print $_; From edc8bf5d74112c9bf60284248f13ad4f05a5a6f7 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 17:30:34 +0200 Subject: [PATCH 7/9] docs/Makefile.am: handle possible absence of perl [#1953] Signed-off-by: Jim Klimov --- docs/Makefile.am | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/Makefile.am b/docs/Makefile.am index f590a5b4a5..446e658ce9 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -449,15 +449,20 @@ MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no fi ; \ exit 0 ; \ fi ; \ - echo " DOC-ASCIIDOC-GITHUB-LINKS Parsing GitHub link patterns $< => $@"; \ - if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ - ls -lad $@ $< || true ; \ - stat $@ $< || true ; \ - fi ; \ - $(top_srcdir)/tools/asciidoc-github-links.pl < '$<' > "$@.tmp.$$$$" \ - && test -s "$@.tmp.$$$$" \ - && mv -f "$@.tmp.$$$$" '$@' \ - || { RES="$$?" ; rm -f "$@.tmp.$$$$" ; exit $$RES ; } + if perl -e 1; then \ + echo " DOC-ASCIIDOC-GITHUB-LINKS Parsing GitHub link patterns $< => $@"; \ + if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ + ls -lad $@ $< || true ; \ + stat $@ $< || true ; \ + fi ; \ + $(top_srcdir)/tools/asciidoc-github-links.pl < '$<' > "$@.tmp.$$$$" \ + && test -s "$@.tmp.$$$$" \ + && mv -f "$@.tmp.$$$$" '$@' \ + || { RES="$$?" ; rm -f "$@.tmp.$$$$" ; exit $$RES ; } ; \ + else \ + echo " DOC-ASCIIDOC-GITHUB-LINKS SKIP: perl not available" >&2 ; \ + cat '$<' > '$@' ; \ + fi @if [ x'$@' = x'$(top_builddir)/ChangeLog.adoc-parsed' ] ; then \ touch -r '$@' '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' || touch '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' ; \ fi From d16912c6e9c8b615a5b282894b8fed5bc2c8a66a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 17:31:04 +0200 Subject: [PATCH 8/9] tools/Makefile.am: add check-asciidoc-github-links goal [#1953] Signed-off-by: Jim Klimov --- tools/Makefile.am | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/Makefile.am b/tools/Makefile.am index 8340aed46f..c6ff505852 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -165,6 +165,20 @@ dist-hook: echo "----------------------------------------------------------------------"; \ fi +# Using $? here for "sources newer than target", +# note that $< is not portable in non-suffix rules: +check-asciidoc-github-links: $(top_srcdir)/tools/asciidoc-github-links.pl + @echo "Checking for perl support of github links parser..." + @if perl -e 1; then \ + OUT="`echo 'Some changes. [#333, PRs #123, #345; issues #789, #99, advisories GHSA-1234-5678-90ab, #12345]' | perl '$?'`" || exit ; \ + test x"$$OUT" = x'Some changes. [link:https://github.com/networkupstools/nut/issues/333[#333], PRs link:https://github.com/networkupstools/nut/pull/123[#123], link:https://github.com/networkupstools/nut/pull/345[#345]; issues link:https://github.com/networkupstools/nut/issues/789[#789], link:https://github.com/networkupstools/nut/issues/99[#99], advisories link:https://github.com/networkupstools/nut/security/advisories/GHSA-1234-5678-90ab[GHSA-1234-5678-90ab], link:https://github.com/networkupstools/nut/issues/12345[#12345]]' || exit ; \ + echo "OK: $? returned expected output" ; \ + else \ + echo "SKIPPED: perl not available"; \ + fi + +check-local: check-asciidoc-github-links + MAINTAINERCLEANFILES = Makefile.in .dirstamp # Can be recreated by `make` or `configure`, From bd2d572339df673e48087cfbe6cdc51fe0193cdb Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 30 Aug 2026 17:44:46 +0200 Subject: [PATCH 9/9] tools/asciidoc-github-links.pl: do not match standalone plus (asciidoc paragraph glue) on a line after a link [#1953] Signed-off-by: Jim Klimov --- tools/asciidoc-github-links.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/asciidoc-github-links.pl b/tools/asciidoc-github-links.pl index ca2cbe8497..fdcda95b92 100755 --- a/tools/asciidoc-github-links.pl +++ b/tools/asciidoc-github-links.pl @@ -124,7 +124,10 @@ s/\#(\#${issue_id_re})/$1/g; # 15. URL plus sign encoding - s/(${gh_schema_re}[^ \+]*)([\]]*\+)/$1%2B/g; + s/(${gh_schema_re}[^\s\+]*)([\]]*\+)/{ + "$1%2B"; + # printf stderr "[%2B]: Matched for '$1'\n"; + }/ge; print $_; }