diff options
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | LICENSE | 338 | ||||
| -rw-r--r-- | README.md | 162 | ||||
| -rw-r--r-- | nvchecker.toml | 438 | ||||
| -rwxr-xr-x | nvtable | 272 |
5 files changed, 1216 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92f1131 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# nvchecker state, written next to the config at runtime +old_ver.json +new_ver.json +*.json~ +*.bak +keys.toml @@ -0,0 +1,338 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 2 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 <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Moe Ghoul>, 1 April 1989 + Moe Ghoul, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce22136 --- /dev/null +++ b/README.md @@ -0,0 +1,162 @@ +# danix-nvchecker + +A unified [nvchecker](https://github.com/lilydjwg/nvchecker) configuration plus +`nvtable`, a small Bash tool that answers the question nvchecker alone cannot: + +> upstream released a new version, but **do I have it installed**, and does the +> SlackBuild in my repo still ship the old one? + +`nvcmp` compares upstream against its own last-seen state. `nvtable` adds the +two columns that matter in practice, the version installed on this machine and +the version shipped by the SlackBuild repo that packages it. + +``` + package upstream installed repo + 🔴 discord 1.0.152 1.0.151 my 1.0.152 + 🔴🟡 nuclei 3.11.1 3.11.0 sbo 3.11.0 + 🔴 signal-desktop 8.22.0 8.20.0 -- + 🟢 qarma 1.1.1 1.1.1 my 1.1.1 + + 26 to upgrade · 2 repos to bump · 32 current · 13 not installed +``` + +| marker | meaning | +|--------|---------| +| 🔴 | installed version is behind upstream | +| 🟡 | the repo `.info` still ships an older version, so it needs a bump | +| 🟢 | installed and packaged versions both match upstream | +| ⚪ | not installed on this host (tracked only) | + +A row can carry two markers: 🔴🟡 means upstream moved and neither the system +nor the SlackBuild has caught up. + +## Contents + +- `nvchecker.toml` - one config covering everything tracked: software installed + on this machine, packages maintained in three SlackBuild repos, and services + running elsewhere. +- `nvtable` - the comparison tool. + +## nvchecker.toml + +Merged from a personal config and the `.extras/nvchecker.toml` of three +SlackBuild repositories, deduplicated. The per-repo configs are kept in their +repos for standalone sweeps; this one is the superset used day to day. + +Two conventions make the joins work without a lookup table: + +- **The stanza name is the Slackware package name** wherever a package exists, + so results join directly against `/var/log/packages` and against + `<pkg>/<pkg>.info`. Where they genuinely differ (`kvantum` builds both + `kvantum-qt5` and `kvantum-qt6`) `nvtable` carries a small alias map. +- **A `# repo=` comment marks which repository ships the package**: `sbo`, + `my`, `sps`, or nothing for tracked-only entries. + +Watch for two nvchecker details that cause silent wrong answers: + +- A stanza name containing a dot **must be quoted**. `[llama.cpp-vulkan]` parses + as a nested `llama` table and fails with `no source specified`; write + `["llama.cpp-vulkan"]`. +- Omitting `prefix = "v"` on a `use_latest_release` GitHub source yields + `v8.30.1` rather than `8.30.1`, which then never matches a `.info` VERSION. + +## nvtable + +### Requirements + +`bash`, `jq`, and nvchecker's `nvcmp`/`nvtake`. `flatpak` is optional and used +only if present. + +### Usage + +``` +nvtable [-a] [-n] [-C] [-E] + + -a, --all show every tracked package, not just those needing action + -n, --no-take do not run nvtake on caught-up packages + -C, --no-color plain output + -E, --no-emoji ASCII status markers instead of emoji +``` + +By default only actionable rows print. Packages that are current, and packages +not installed on this host, are folded into the summary line. Color is disabled +automatically when output is not a terminal. + +### Where the three versions come from + +**upstream** is read from nvchecker's `new_ver.json`. `nvtable` never fetches +anything itself, so it is fast enough to run on every login; refreshing that +file is nvchecker's job. + +**installed** is resolved from three sources, in order: + +1. `/var/log/packages` for Slackware packages +2. `~/.local/state/appimage-updater/installed.json` for AppImages managed by + [appimage-updater](https://git.danix.xyz/appimage-updater/) +3. `flatpak list` for flatpak apps + +**repo** is the `VERSION=` line of `<repo>/<category>/<pkg>/<pkg>.info` across +the configured SlackBuild repositories. + +### Version comparison + +Versions arrive from unrelated sources and rarely agree on formatting, so they +are normalised before comparison: a leading `v` is stripped, `-` and `_` fold to +`.`, and case is ignored. + +Installed versions also carry build metadata that upstream never has, for +instance `r8125` installs as `9.018.00_6.18.41` (version plus kernel) against an +upstream `9.018.00`. An installed version that merely *extends* upstream at a +component boundary counts as equal, otherwise every such package would report as +permanently behind. + +One related trap: a Slackware package filename is `PRGNAM-VERSION-ARCH-BUILD`, +but VERSION may itself contain a dash (`solvespace-3.1-659215d`), so the +PRGNAM/VERSION boundary cannot be found by counting dashes. Lookups anchor on +the package name being searched for instead. + +### nvtake + +When a package's installed version matches upstream, `nvtable` runs +`nvtake` for it, so nvchecker's `old_ver.json` tracks the state of this system +rather than only what upstream last did. Pass `-n` to disable. + +Because a login shell can start while another is still running, the take is +serialised with `flock`; `nvtake` rewrites `old_ver.json` without locking of its +own. If the lock is held the take is skipped, and the next run picks it up. + +## Installation + +``` +ln -s "$PWD/nvtable" ~/bin/nvtable +cp nvchecker.toml ~/.config/nvchecker/nvchecker.toml +``` + +The config expects a GitHub token in `~/.config/nvchecker/keys.toml`, without +which the many GitHub sources exhaust the anonymous rate limit: + +```toml +[keys] +github = "ghp_..." +``` + +To show the table at login, call `nvtable` where `nvcmp` would have gone. The +repository paths `nvtable` scans are the `REPOS` array at the top of the script. + +## Notes + +`nvtable` reads `new_ver.json` and does not refresh it. If that file is stale, +for example right after renaming stanzas, the table reports the old names as +untracked until `nvchecker` runs again. + +## License + +GPLv2 (v2 only). See [LICENSE](LICENSE). + +## Development Approach + +This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback. + +All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions. + +The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability. diff --git a/nvchecker.toml b/nvchecker.toml new file mode 100644 index 0000000..5a3c990 --- /dev/null +++ b/nvchecker.toml @@ -0,0 +1,438 @@ +# Unified nvchecker config: system + all maintained repos. +# Merged from ~/.config/nvchecker/nvchecker.toml and the .extras/nvchecker.toml +# of sbo-slackbuilds, my-slackbuilds and Slackware-Pentesting-Suite. +# +# Stanza name == Slackware package name wherever a package exists, so results +# join directly against /var/log/packages and against <pkg>/<pkg>.info VERSION. +# +# repo= comments mark which repository ships the package: +# sbo = sbo-slackbuilds my = my-slackbuilds sps = Slackware-Pentesting-Suite +# Entries with no repo= are tracked-only (not packaged by me). + +[__config__] +oldver = "old_ver.json" +newver = "new_ver.json" +keyfile = "~/.config/nvchecker/keys.toml" + + +# --------------------------------------------------------------------------- +# Packaged: sbo-slackbuilds +# --------------------------------------------------------------------------- + +[UrbanTerror] # repo=sbo +source = "regex" +url = "https://www.urbanterror.info/downloads/" +regex = "UrbanTerror(\\d+)_full\\.zip" +from_pattern = "(\\d)(\\d)(\\d)" +to_pattern = "\\1.\\2.\\3" + +[r8125] # repo=sbo +source = "jq" +url = "https://www.realtek.com/Download/ListAllDownloadItem?cate_id=584" +filter = '.Data.DownloadItems["Unix (Linux)"][] | select(.Name | startswith("r8125")) | .Version' + + +# --------------------------------------------------------------------------- +# Packaged: my-slackbuilds +# --------------------------------------------------------------------------- + +[qarma] # repo=my +source = "github" +github = "luebking/qarma" +use_latest_release = true +prefix = "v" + +[hstr] # repo=my +source = "github" +github = "dvorka-oss/hstr" +use_latest_release = true +prefix = "v" + +[kitty] # repo=my (installs as pkg 'kitty') +source = "github" +github = "kovidgoyal/kitty" +use_latest_release = true +prefix = "v" + +[opencode-bin] # repo=my +source = "github" +github = "anomalyco/opencode" +use_latest_release = true +prefix = "v" + +[kvantum] # repo=my (shared source with kvantum-qt5, rebuild both) +source = "github" +github = "tsujan/Kvantum" +use_latest_release = true +prefix = "V" + +[gitleaks] # repo=my +source = "github" +github = "gitleaks/gitleaks" +use_latest_release = true +prefix = "v" + +[discord] # repo=my +source = "httpheader" +url = "https://discord.com/api/download?platform=linux&format=tar.gz" +regex = "discord-(.*)\\.tar.*" + +[solvespace] # repo=my +source = "github" +github = "solvespace/solvespace" +use_latest_release = true +prefix = "v" + +[gamescope] # repo=my (no GitHub Releases, tags only) +source = "github" +github = "ValveSoftware/gamescope" +use_max_tag = true + +[nvchecker] # repo=my +source = "github" +github = "lilydjwg/nvchecker" +use_max_tag = true +prefix = "v" + +["llama.cpp-vulkan"] # repo=my (quoted: dot would nest the table) +source = "github" +github = "ggml-org/llama.cpp" +use_latest_release = true + +[claude-desktop-bin] # repo=my +source = "cmd" +cmd = "curl -fsSL https://downloads.claude.ai/claude-desktop/apt/stable/dists/stable/main/binary-amd64/Packages | awk '/^Version:/{print $2}' | sort -V | tail -1" + +[claude-code] # repo=my (installs as pkg 'claude-code') +source = "github" +github = "anthropics/claude-code" +use_latest_release = true +prefix = "v" + +[megasync-bin] # repo=my +source = "github" +github = "meganz/MEGAsync" +use_max_tag = true +include_regex = ".*_Linux$" +prefix = "v" +from_pattern = "_Linux$" +to_pattern = "" + +[mutagen] # repo=my (quodlibet audio tag lib, NOT mutagen-io sync tool) +source = "github" +github = "quodlibet/mutagen" +use_latest_release = true +prefix = "release-" + +[hyprsunset-qt] # repo=my (own cgit server, no GitHub mirror) +source = "git" +git = "https://git.danix.xyz/hyprsunset-qt" +use_max_tag = true +prefix = "v" + +[firefly-cli] # repo=my (tags, no Releases) +source = "github" +github = "danixland/firefly-cli" +use_max_tag = true +prefix = "v" + +[gitea-cli] # repo=my (upstream is gitea.com/gitea/tea) +source = "git" +git = "https://gitea.com/gitea/tea.git" +use_max_tag = true +prefix = "v" + +[playwright-cli] # repo=my (npm package, not a GitHub repo) +source = "npm" +npm = "@playwright/cli" + +[click] # repo=my +source = "pypi" +pypi = "click" + +[python3-structlog] # repo=my +source = "pypi" +pypi = "structlog" + +[python3-platformdirs] # repo=my +source = "pypi" +pypi = "platformdirs" + +[python3-awesomeversion] # repo=my +source = "pypi" +pypi = "awesomeversion" + +[python3-fsspec] # repo=my +source = "pypi" +pypi = "fsspec" + +[python3-packaging] # repo=my +source = "pypi" +pypi = "packaging" + +[python3-annotated-doc] # repo=my +source = "pypi" +pypi = "annotated-doc" + +[python3-typer] # repo=my +source = "pypi" +pypi = "typer" + +[python3-huggingface_hub] # repo=my +source = "pypi" +pypi = "huggingface-hub" + +[python3-telethon] # repo=my +source = "pypi" +pypi = "telethon" + + +# --------------------------------------------------------------------------- +# Packaged: Slackware-Pentesting-Suite +# --------------------------------------------------------------------------- + +[SecLists] # repo=sbo,sps +source = "github" +github = "danielmiessler/SecLists" +use_latest_release = true + +[gobuster] # repo=sbo,sps +source = "github" +github = "OJ/gobuster" +use_latest_release = true +prefix = "v" + +[ffuf] # repo=sbo,sps +source = "github" +github = "ffuf/ffuf" +use_latest_release = true +prefix = "v" + +[feroxbuster] # repo=sbo,sps +source = "github" +github = "epi052/feroxbuster" +use_latest_release = true +prefix = "v" + +[nuclei] # repo=sbo,sps +source = "github" +github = "projectdiscovery/nuclei" +use_latest_release = true +prefix = "v" + +[exploitdb] # repo=sbo,sps +source = "gitlab" +gitlab = "exploit-database/exploitdb" +use_max_tag = true + +[exploitdb-bin-sploits] # repo=sbo,sps +source = "gitlab" +gitlab = "exploit-database/exploitdb-bin-sploits" +use_max_tag = true + +[metasploit-framework] # repo=sbo,sps +source = "regex" +url = "https://apt.metasploit.com/" +regex = "metasploit-framework_([A-Za-z0-9._-]+)~.*_amd64.deb" + +[hashcat] # repo=sps +source = "github" +github = "hashcat/hashcat" +use_latest_release = true +prefix = "v" + +[john] # repo=sps +source = "regex" +url = "https://www.openwall.com/john/" +regex = "john-(\\d+\\.\\d+\\.\\d+)\\.tar\\.xz" + +[cadaver] # repo=sps +source = "github" +github = "notroj/cadaver" +use_latest_tag = true +prefix = "v" + +[netexec] # repo=sps +source = "github" +github = "Pennyw0rth/NetExec" +use_latest_release = true +prefix = "v" + +[webshells] # repo=sps +source = "regex" +url = "https://pkg.kali.org/pkg/webshells" +regex = "version:<.+>\n\\s+([A-Za-z0-9.-_]+)\\+kali8" + +[windows-binaries] # repo=sps +source = "regex" +url = "https://pkg.kali.org/pkg/windows-binaries" +regex = "version:<.+>\n\\s+([A-Za-z0-9.-_]+)" + + +# --------------------------------------------------------------------------- +# Tracked only: installed from Slackware/SBo or upstream, not packaged by me +# --------------------------------------------------------------------------- + +[borgbackup] +source = "github" +github = "borgbackup/borg" +use_latest_release = true + +[signal-desktop] +source = "github" +github = "signalapp/Signal-Desktop" +use_latest_release = true +prefix = "v" + +[telegram] +source = "github" +github = "telegramdesktop/tdesktop" +use_latest_release = true +prefix = "v" + +[vscodium] +source = "github" +github = "VSCodium/vscodium" +use_latest_release = true + +[neovim] +source = "github" +github = "neovim/neovim" +use_latest_release = true +prefix = "v" + +[obsidian] +source = "github" +github = "obsidianmd/obsidian-releases" +use_latest_release = true +prefix = "v" + +[syncthing] +source = "github" +github = "syncthing/syncthing" +use_latest_release = true +prefix = "v" + +[hugo] +source = "github" +github = "gohugoio/hugo" +use_latest_release = true +prefix = "v" + +[conky] +source = "github" +github = "brndnmtthws/conky" +use_latest_release = true +prefix = "v" + +[ddgr] +source = "github" +github = "jarun/ddgr" +use_latest_release = true +prefix = "v" + +[hydra] +source = "github" +github = "vanhauser-thc/thc-hydra" +use_latest_release = true +prefix = "v" + +[pcmanfm-qt] +source = "github" +github = "lxqt/pcmanfm-qt" +use_latest_release = true + +[waybar] +source = "github" +github = "Alexays/Waybar" +use_latest_release = true + +[uv-bin] +source = "github" +github = "astral-sh/uv" +use_latest_release = true + +[nessus] +source = "regex" +url = "https://www.tenable.com/downloads/nessus" +regex = "Nessus-([0-9.]+)-ubuntu.*amd64\\.deb" + +[powershell] +source = "github" +github = "PowerShell/PowerShell" +use_latest_release = true +prefix = "v" + +[slackrepo] +source = "github" +github = "idlemoor/slackrepo" +use_max_tag = true + +[slackrepo-hints] +source = "github" +github = "idlemoor/slackrepo-hints" +use_max_tag = true + + +# --------------------------------------------------------------------------- +# Tracked only: AppImage / manual installs (no /var/log/packages entry) +# --------------------------------------------------------------------------- + +[Feishin] +source = "github" +github = "jeffvli/feishin" +use_latest_release = true +prefix = "v" + +[OrcaSlicer] +source = "github" +github = "SoftFever/OrcaSlicer" +use_latest_release = true +prefix = "v" + +[cherrytree] +source = "github" +github = "giuspen/cherrytree" +use_latest_release = true +prefix = "v" + + +# --------------------------------------------------------------------------- +# Tracked only: services running elsewhere (not on this host) +# --------------------------------------------------------------------------- + +[Jellyfin] +source = "github" +github = "jellyfin/jellyfin" +use_latest_release = true +prefix = "v" + +[firefly-III] +source = "github" +github = "firefly-iii/firefly-iii" +use_latest_release = true +prefix = "v" + +[fmd-server] +source = "gitlab" +gitlab = "Nulide/findmydeviceserver" +use_max_tag = true +prefix = "v" + +["pi-hole/pi-hole"] +source = "github" +github = "pi-hole/pi-hole" +use_latest_release = true +prefix = "v" + +["pi-hole/web"] +source = "github" +github = "pi-hole/web" +use_latest_release = true +prefix = "v" + +["pi-hole/FTL"] +source = "github" +github = "pi-hole/FTL" +use_latest_release = true +prefix = "v" @@ -0,0 +1,272 @@ +#!/bin/bash +# nvtable - compare upstream (nvchecker) vs installed vs shipped-in-repo versions. +# +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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. +# +# Three version sources per tracked name: +# upstream - nvchecker new_ver.json +# installed - /var/log/packages, then appimage-updater state, then flatpak +# repo - VERSION= in <repo>/<pkg>/<pkg>.info +# +# When installed == upstream the row is caught up, and nvtake records it so +# old_ver tracks the system. See take_caught_up() for the locking. + +set -uo pipefail + +CONF="${NVTABLE_CONF:-$HOME/.config/nvchecker/nvchecker.toml}" +NEWVER="${NVTABLE_NEWVER:-$HOME/.config/nvchecker/new_ver.json}" +AI_STATE="${XDG_STATE_HOME:-$HOME/.local/state}/appimage-updater/installed.json" +LOCK="${TMPDIR:-/tmp}/nvtable-$UID.lock" + +REPOS=( + "sbo:$HOME/Programming/GIT/sbo-slackbuilds" + "my:$HOME/Programming/GIT/GITHUB/my-slackbuilds" + "sps:$HOME/Programming/GIT/GITHUB/Slackware-Pentesting-Suite" +) + +# Stanza name -> installed package name(s), space separated for one-to-many. +# Only for names that differ; everything else joins directly. +declare -A ALIAS=( + [kvantum]="kvantum-qt5 kvantum-qt6" + [metasploit-framework]="metasploit-framework-bin" +) + +# Stanza name -> SlackBuild directory name, where the repo dir differs from the +# stanza (a -bin build tracked under its plain upstream name). +declare -A REPO_ALIAS=( + [kitty]="kitty-bin" + [claude-code]="claude-code-bin" + [kvantum]="kvantum-qt6" + [metasploit-framework]="metasploit-framework-bin" +) + +SHOW_ALL=0; NO_TAKE=0; NO_COLOR=0; NO_EMOJI=0 +for a in "$@"; do + case "$a" in + -a|--all) SHOW_ALL=1 ;; + -n|--no-take) NO_TAKE=1 ;; + -C|--no-color) NO_COLOR=1 ;; + -E|--no-emoji) NO_EMOJI=1 ;; + -h|--help) + cat <<EOF +usage: nvtable [-a] [-n] [-C] [-E] + -a, --all show every tracked package, not just those needing action + -n, --no-take do not run nvtake on caught-up packages + -C, --no-color plain output + -E, --no-emoji ASCII status markers instead of emoji +EOF + exit 0 ;; + *) echo "nvtable: unknown option $a" >&2; exit 2 ;; + esac +done + +[[ -t 1 ]] || NO_COLOR=1 +if (( NO_COLOR )); then + R=""; B=""; DIM=""; RED=""; GRN=""; YEL=""; CYA=""; WHT="" +else + R=$'\e[0m'; B=$'\e[1m'; DIM=$'\e[2m'; RED=$'\e[1;31m' + GRN=$'\e[1;32m'; YEL=$'\e[1;33m'; CYA=$'\e[1;36m'; WHT=$'\e[1;37m' +fi + +# Status markers. Emoji are double-width, so each ASCII fallback is padded to +# two columns to keep the name column aligned either way. +if (( NO_EMOJI )); then + E_UP="!!" E_REPO="~ " E_OK="ok" E_NA="- " +else + E_UP="🔴" E_REPO="🟡" E_OK="🟢" E_NA="⚪" +fi + +command -v jq >/dev/null || { echo "nvtable: jq required" >&2; exit 1; } +[[ -r $NEWVER ]] || { echo "nvtable: no $NEWVER (run nvchecker first)" >&2; exit 1; } + +# --- installed versions ----------------------------------------------------- +# Package files are PRGNAM-VERSION-ARCH-BUILD, but VERSION may itself contain a +# dash (solvespace-3.1-659215d), so the PRGNAM/VERSION boundary cannot be found +# by counting dashes. Drop ARCH-BUILD from the right, then keep the whole +# remainder; lookup_installed() anchors on the name it is searching for. +declare -A PKGREST +while IFS= read -r f; do + rest=${f%-*} # drop BUILD + rest=${rest%-*} # drop ARCH -> "PRGNAM-VERSION" + [[ -n $rest ]] && PKGREST[$rest]=1 +done < <(/bin/ls -1 /var/log/packages 2>/dev/null) + +declare -A INST +for rest in "${!PKGREST[@]}"; do + # Default split: last dash. Correct for the common case, fixed up below for + # any name that a tracked stanza claims explicitly. + INST[${rest%-*}]=${rest##*-} +done + +# Given an exact package name, take everything after it as the version. The +# match is anchored on "<want>-" and strips exactly that many characters, so a +# VERSION containing dashes survives and a longer sibling package (kvantum-qt5 +# when asked for kvantum) is never mistaken for a match. +pkg_version() { + local want=$1 rest + for rest in "${!PKGREST[@]}"; do + if [[ ${rest,,} == "${want,,}-"* ]]; then + rest=${rest:${#want}+1} + # Reject when what follows is not a version (another name component). + [[ $rest == [0-9]* ]] || continue + echo "$rest"; return 0 + fi + done + return 1 +} + +# AppImages tracked by appimage-updater (its state is authoritative for those). +if [[ -r $AI_STATE ]]; then + while IFS=$'\t' read -r k v; do + [[ -n $k ]] && INST[$k]=$v + done < <(jq -r 'to_entries[]|"\(.key)\t\(.value.version)"' "$AI_STATE" 2>/dev/null) +fi + +# Flatpak apps, keyed on the last dot-component of the app id. +if command -v flatpak >/dev/null 2>&1; then + while IFS=$'\t' read -r app v; do + [[ -n $app ]] || continue + INST[${app##*.}]=$v + done < <(flatpak list --app --columns=application,version 2>/dev/null) +fi + +installed_of() { # echoes "version" or "" ; handles alias + case-insensitive + local n=$1 cand v + for cand in ${ALIAS[$n]:-$n}; do + # Anchored lookup first: correct even when VERSION contains a dash. + v=$(pkg_version "$cand") && { echo "$v"; return; } + [[ -n ${INST[$cand]:-} ]] && { echo "${INST[$cand]}"; return; } + for k in "${!INST[@]}"; do + [[ ${k,,} == "${cand,,}" ]] && { echo "${INST[$k]}"; return; } + done + done +} + +# --- repo .info versions ---------------------------------------------------- +declare -A RVER RWHICH +for entry in "${REPOS[@]}"; do + tag=${entry%%:*}; dir=${entry#*:} + [[ -d $dir ]] || continue + while IFS= read -r inf; do + pkg=$(basename "$inf" .info) + v=$(sed -n 's/^VERSION="\(.*\)"$/\1/p' "$inf" | head -1) + [[ -n $v ]] || continue + if [[ -n ${RVER[$pkg]:-} ]]; then + RWHICH[$pkg]="${RWHICH[$pkg]},$tag" + else + RVER[$pkg]=$v; RWHICH[$pkg]=$tag + fi + done < <(find "$dir" -mindepth 2 -maxdepth 3 -name '*.info' 2>/dev/null) +done + +# --- compare ---------------------------------------------------------------- +# Versions come from unrelated sources, so normalise before comparing: strip a +# leading v, fold - and _ to dots, lowercase. +norm() { local s=${1,,}; s=${s#v}; s=${s//[-_]/.}; echo "$s"; } + +# Some packages append build metadata the upstream version never carries: +# a kernel version (r8125 9.018.00_6.18.41) or a git hash (solvespace +# 3.1-659215d). Treat installed as equal when it merely extends upstream at a +# component boundary. +vers_equal() { + local a b; a=$(norm "$1"); b=$(norm "$2") + [[ $a == "$b" ]] && return 0 + [[ -n $a && -n $b && $b == "$a".* ]] && return 0 + return 1 +} + +rows=(); take=(); n_up=0; n_repo=0; n_ok=0; n_na=0 +while IFS=$'\t' read -r name uver; do + [[ -n $name ]] || continue + iver=$(installed_of "$name") + rkey=$name + if [[ -z ${RVER[$rkey]:-} ]]; then + for cand in ${REPO_ALIAS[$name]:-} ${ALIAS[$name]:-}; do + [[ -n ${RVER[$cand]:-} ]] && { rkey=$cand; break; } + done + fi + rver=${RVER[$rkey]:-}; rwhich=${RWHICH[$rkey]:-} + + same_inst=0; [[ -n $iver ]] && vers_equal "$uver" "$iver" && same_inst=1 + same_repo=1; [[ -n $rver ]] && { vers_equal "$uver" "$rver" || same_repo=0; } + + if (( same_inst )) && (( same_repo )); then + (( n_ok++ )); take+=("$name") + (( SHOW_ALL )) || continue + else + (( same_inst )) || { [[ -n $iver ]] && (( n_up++ )); } + (( same_repo )) || (( n_repo++ )) + # Nothing installed and the .info already matches upstream: there is no + # action to take on this host, so keep it out of the default view. + if [[ -z $iver ]] && (( same_repo )); then + (( n_na++ )) + (( SHOW_ALL )) || continue + fi + fi + # Packed with | not tab: read collapses runs of whitespace IFS chars, which + # would shift every field left whenever installed or repo is empty. + rows+=("$name|$uver|$iver|$rver|$rwhich|$same_inst|$same_repo") +done < <(jq -r '.data|to_entries[]|"\(.key)\t\(.value.version // .value)"' "$NEWVER") + +# --- output ----------------------------------------------------------------- +if ((${#rows[@]})); then + # Widen the name column to the longest actual name, so a long stanza does not + # shunt every later column out of alignment. + w=22 + for r in "${rows[@]}"; do n=${r%%|*}; (( ${#n} > w )) && w=${#n}; done + printf '%s %-*s %-14s %-14s %s%s\n' "$DIM" "$w" "package" "upstream" "installed" "repo" "$R" + for r in "${rows[@]}"; do + IFS='|' read -r name uver iver rver rwhich si sr <<<"$r" + if [[ -z $iver ]]; then ic="$DIM"; ishow="--" + elif (( si )); then ic="$GRN"; ishow=$iver + else ic="$RED"; ishow=$iver + fi + # Installed-behind and repo-behind are independent, and a row can be both + # (upstream moved, and neither the system nor the .info has caught up), so + # the marker shows each dimension rather than collapsing to the worst one. + if [[ -z $iver ]]; then mark="$E_NA" + elif (( si )); then mark="$E_OK" + else mark="$E_UP" + fi + (( sr )) || mark+="$E_REPO" + if [[ -z $rver ]]; then rc="$DIM"; rtxt="--" + elif (( sr )); then rc="$GRN"; rtxt="$rwhich $rver" + else rc="$YEL"; rtxt="$rwhich $rver" + fi + # Pad the marker cell to a fixed width: rows carrying both markers must not + # push the name column right relative to rows carrying one. + if (( NO_EMOJI )); then mcell=$(printf '%-5s' "$mark") + else mcell=$mark; (( ${#mark} > 1 )) || mcell="$mark " + fi + printf ' %s %s%-*s%s %-14s %s%-14s%s %s%s%s\n' \ + "$mcell" "$WHT" "$w" "$name" "$R" "$uver" "$ic" "$ishow" "$R" "$rc" "$rtxt" "$R" + done + echo +fi +printf ' %s%d%s to upgrade · %s%d%s repo%s to bump · %s%d%s current' \ + "$RED" "$n_up" "$R" "$YEL" "$n_repo" "$R" "$( ((n_repo==1)) || echo s )" \ + "$GRN" "$n_ok" "$R" +(( n_na )) && printf ' · %s%d%s not installed' "$DIM" "$n_na" "$R" +echo + +# --- nvtake ----------------------------------------------------------------- +# Record caught-up packages so old_ver reflects the system. flock serialises +# concurrent logins: nvtake rewrites old_ver.json without locking of its own. +take_caught_up() { + ((${#take[@]})) || return 0 + command -v nvtake >/dev/null || return 0 + exec 9>"$LOCK" || return 0 + flock -n 9 || return 0 # another shell is taking; skip, next run catches it + nvtake -c "$CONF" --ignore-nonexistent "${take[@]}" >/dev/null 2>&1 + exec 9>&- +} +(( NO_TAKE )) || take_caught_up |
